fix(native): render plan proposals inline

Render ExitPlanMode and exit_plan_mode Markdown from input.plan in iOS and Android conversations. Preserve approvals, raw source and diagnostics while hiding empty output placeholders and prewarming plan documents.

Add generated protocol fixtures and native regression coverage for long plans, live updates, recycling, themes and typography.
This commit is contained in:
weishu
2026-09-12 16:06:16 +08:00
parent 418f11f80e
commit d29713aeda
21 changed files with 973 additions and 7 deletions
+24
View File
@@ -7,6 +7,30 @@ import { T0, wireMessage } from './support'
* stream snapshots keyed by data.id.
*/
export const codexCases: FixtureCase[] = [
...(['ExitPlanMode', 'exit_plan_mode'] as const).map((name, index): FixtureCase => {
const plan = '# 实施计划\n\n1. Inspect **input.plan**\n2. Render Markdown\n\n```swift\nlet ready = true\n```\n'
const callId = `codex-proposed-plan:plan-${index}`
const pending = index === 1
const data = [
{ type: 'tool-call', name: 'Read', callId: 'read-before', input: { file_path: '/repo/README.md' } },
{ type: 'tool-call-result', callId: 'read-before', output: 'Readme' },
{ type: 'tool-call', name, callId, input: { plan }, id: `plan-${index}` },
...(!pending ? [{ type: 'tool-call-result', callId, output: null, id: `plan-${index}:result` }] : []),
{ type: 'tool-call', name: 'Read', callId: 'read-after', input: { file_path: '/repo/package.json' } },
{ type: 'tool-call-result', callId: 'read-after', output: '{}' }
]
return {
name: pending ? 'codex-plan-proposal-pending' : 'codex-plan-proposal-completed',
description: 'Proposal Markdown lives in input.plan. Keep it standalone between ordinary tools; null output completes a proposal without inventing approval. The lowercase alias also accepts a pending permission.',
messages: data.map((entry, seq) => wireMessage({
id: `proposal-${index}-${seq}`, seq: seq + 1, createdAt: T0 + seq * 1000,
content: { role: 'agent', content: { type: 'codex', data: entry } }
})),
...(pending ? { agentState: { requests: {
'plan-approval': { tool: name, toolCallId: callId, arguments: { plan }, createdAt: T0 + 2000 }
} } } : {})
}
}),
{
name: 'codex-message-stream-snapshot',
description: 'Codex family: two message payloads sharing a stream id (data.id) are cumulative snapshots. Expects a single agent-text block keyed by that stable stream id, carrying the final snapshot text.',