Fix mobile structured turn state

This commit is contained in:
Merge Sim
2026-08-30 17:49:06 -07:00
parent 3d9adf7bbd
commit a05404645c
3 changed files with 41 additions and 5 deletions
@@ -1,6 +1,7 @@
import { createElement, type ComponentProps } from 'react'
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { AgentJournalRenderItem } from '../../../src/shared/agent-session-journal-types'
import type { MobileNativeChatSessionOptionsController } from './use-mobile-native-chat-session-options'
import { MobileStructuredAgentSessionView } from './MobileStructuredAgentSessionView'
@@ -47,6 +48,18 @@ function options(): MobileNativeChatSessionOptionsController {
}
}
const ACTIVE_TURN_ITEM: AgentJournalRenderItem = {
itemId: 'status-1',
revision: 1,
body: {
kind: 'status',
text: 'working',
turnLifecycle: { turnId: 'turn-1', state: 'running' }
},
sequence: 1,
observedAt: 1
}
describe('MobileStructuredAgentSessionView command seam', () => {
let renderer: ReactTestRenderer | null = null
const onSend = vi.fn(async () => true)
@@ -144,6 +157,18 @@ describe('MobileStructuredAgentSessionView command seam', () => {
expect(empty.props.children[0].props.children).toBe('New Claude chat')
})
it('marks session options working while a turn is active', () => {
act(() => {
renderer!.update(
createElement(MobileStructuredAgentSessionView, props({ items: [ACTIVE_TURN_ITEM] }))
)
})
expect(
renderer!.root.findByType('MobileNativeChatComposer').props.sessionOptions
).toMatchObject({ isWorking: true })
})
it('keeps the composer enabled and routes stable TUI ownership through its bridge', async () => {
act(() => {
renderer!.update(
@@ -100,6 +100,7 @@ export function MobileStructuredAgentSessionView(props: Props): React.JSX.Elemen
props.handoff === null ||
props.handoff === undefined ||
(props.handoff.owner === 'native' && props.handoff.phase === 'idle')
const isWorking = turnId !== null
const composerEnabled = props.status === 'ready' && (stableNativeOwner || stableTuiOwner)
const rows = useMemo(
() => buildMobileStructuredTimeline(props.items, props.outbox),
@@ -131,7 +132,7 @@ export function MobileStructuredAgentSessionView(props: Props): React.JSX.Elemen
<View style={styles.root}>
<MobileStructuredHandoffBanner
status={props.handoff}
isWorking={turnId !== null}
isWorking={isWorking}
onRequest={props.onRequestHandoff}
/>
<FlatList
@@ -276,7 +277,7 @@ export function MobileStructuredAgentSessionView(props: Props): React.JSX.Elemen
}}
agent={props.agent}
slashCommands={slashCommands}
sessionOptions={{ controller: props.sessionOptions, isWorking: false }}
sessionOptions={{ controller: props.sessionOptions, isWorking }}
onAttachImage={props.onAttachImage}
attachments={allAttachments}
onRemoveAttachment={(id) => {
@@ -1,18 +1,28 @@
import {
dispatchStructuredAgentSessionComposerCommand,
isStructuredAgentSessionComposerCommand,
structuredAgentSessionSlashCommands,
STRUCTURED_AGENT_SESSION_SLASH_COMMANDS,
type StructuredAgentSessionCommandOutcome
} from '../../../src/shared/structured-agent-session-composer'
import { getVerifiedNativeChatCommands } from '../../../src/shared/native-chat-agent-profiles'
import type { SlashCommandSuggestion } from '../../../src/shared/native-chat-slash-commands'
import type { MobileStructuredAgent } from './mobile-structured-session-create'
import type { MobileNativeChatSessionOptionsController } from './use-mobile-native-chat-session-options'
export const MOBILE_STRUCTURED_SLASH_COMMANDS = STRUCTURED_AGENT_SESSION_SLASH_COMMANDS
export type MobileStructuredCommandOutcome = StructuredAgentSessionCommandOutcome
export function mobileStructuredSlashCommands(agent: MobileStructuredAgent) {
return structuredAgentSessionSlashCommands(agent)
const STRUCTURED_COMMAND_PREFIX: readonly SlashCommandSuggestion[] = [
{ name: 'model', description: 'Choose the model and reasoning effort' },
{ name: 'effort', description: 'Choose reasoning effort' }
]
export function mobileStructuredSlashCommands(
agent: MobileStructuredAgent
): readonly SlashCommandSuggestion[] {
return agent === 'codex'
? STRUCTURED_AGENT_SESSION_SLASH_COMMANDS
: [...STRUCTURED_COMMAND_PREFIX, ...getVerifiedNativeChatCommands(agent)]
}
export function isMobileStructuredComposerCommand(