Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 0 additions & 61 deletions mobile/src/session/MobileNativeChatView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,68 +157,7 @@ describe('MobileNativeChatView', () => {
})
}

it("holds Stop and says Stopping while this phone's own Stop request is in flight", async () => {
await render({
structuredActivityUi: true,
agentWorking: true,
canStop: true,
turnIndicator: {
thinking: false,
activityText: null,
stopping: true,
stopRequestInFlight: true
}
})
const stop = renderer!.root.find(
(node) => node.type === 'Pressable' && node.props.accessibilityLabel === 'Stopping…'
)
expect(stop.props.disabled).toBe(true)
})

it.each([
['queue', 'Queue a message to run after the stop'],
['send', 'Send a message to run after the stop']
] as const)(
'tells the composer a message sent now runs after the stop (%s)',
async (afterStop, placeholder) => {
await render({
structuredActivityUi: true,
agentWorking: true,
canStop: true,
turnIndicator: { thinking: false, activityText: null, stopping: true, afterStop }
})
const composer = renderer!.root.find((node) => node.type === 'Composer')
expect(composer.props.placeholder).toBe(placeholder)
}
)

// A Stop the provider took and never answered ends only at a repeat Stop.
it('keeps Stop for the repeat that escalates while the host alone says Stopping', async () => {
await render({
structuredActivityUi: true,
agentWorking: true,
canStop: true,
turnIndicator: { thinking: false, activityText: null, stopping: true }
})
const stop = renderer!.root.find(
(node) => node.type === 'Pressable' && node.props.accessibilityLabel === 'Stop the agent'
)
expect(stop.props.disabled).toBe(false)
})

/** Ids of the rows the list is currently rendering. */
it('keeps Stop hidden during a structured dispatch until a provider turn can be cancelled', async () => {
const props = { structuredActivityUi: true, agentWorking: true, canStop: false }
await render(props)
const stops = () =>
renderer!.root.findAll((node) => node.props.accessibilityLabel === 'Stop the agent')
expect(stops()).toHaveLength(0)
await update({ ...props, canStop: true })
expect(stops()).toHaveLength(1)
await update({ agentWorking: true })
expect(stops()).toHaveLength(1)
})

function listIds(): string[] {
return (list().props.data as { id: string }[]).map((row) => row.id)
}
Expand Down
61 changes: 61 additions & 0 deletions mobile/src/session/MobileNativeChatView.turn-status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,67 @@ describe('MobileNativeChatView', () => {
return listNode.props.renderItem({ item: data[index], index })
}

it("holds Stop and says Stopping while this phone's own Stop request is in flight", async () => {
await render({
structuredActivityUi: true,
agentWorking: true,
canStop: true,
turnIndicator: {
thinking: false,
activityText: null,
stopping: true,
stopRequestInFlight: true
}
})
const stop = renderer!.root.find(
(node) => node.type === 'Pressable' && node.props.accessibilityLabel === 'Stopping…'
)
expect(stop.props.disabled).toBe(true)
})

it.each([
['queue', 'Queue a message to run after the stop'],
['send', 'Send a message to run after the stop']
] as const)(
'tells the composer a message sent now runs after the stop (%s)',
async (afterStop, placeholder) => {
await render({
structuredActivityUi: true,
agentWorking: true,
canStop: true,
turnIndicator: { thinking: false, activityText: null, stopping: true, afterStop }
})
const composer = renderer!.root.find((node) => node.type === 'Composer')
expect(composer.props.placeholder).toBe(placeholder)
}
)

// A Stop the provider took and never answered ends only at a repeat Stop.
it('keeps Stop for the repeat that escalates while the host alone says Stopping', async () => {
await render({
structuredActivityUi: true,
agentWorking: true,
canStop: true,
turnIndicator: { thinking: false, activityText: null, stopping: true }
})
const stop = renderer!.root.find(
(node) => node.type === 'Pressable' && node.props.accessibilityLabel === 'Stop the agent'
)
expect(stop.props.disabled).toBe(false)
})

it('keeps Stop hidden during a structured dispatch until a provider turn can be cancelled', async () => {
const props = { structuredActivityUi: true, agentWorking: true, canStop: false }
await render(props)
const stops = () =>
renderer!.root.findAll((node) => node.props.accessibilityLabel === 'Stop the agent')
expect(stops()).toHaveLength(0)
await update({ ...props, canStop: true })
expect(stops()).toHaveLength(1)
await update({ agentWorking: true })
expect(stops()).toHaveLength(1)
})

describe('structured turn status wiring', () => {
const userTurn = (id: string, text: string): NativeChatMessage => ({
id,
Expand Down
Loading