Refine codex app controls and message navigation

This commit is contained in:
shiyue
2026-06-13 23:55:11 +08:00
parent 4a1c988990
commit 382c5accb7
7 changed files with 876 additions and 26 deletions

View File

@@ -161,6 +161,69 @@ function completeTurn(thread, turnId, text, status = 'completed') {
});
}
if (/subagent|collab/i.test(text)) {
send({
method: 'item/started',
params: {
threadId: thread.id,
turnId,
startedAtMs: Date.now(),
item: {
id: 'tool-collab',
type: 'collabAgentToolCall',
tool: 'spawn_agent',
prompt: '整理前端改动并回报状态',
receiverThreadIds: ['child-thread-a', 'child-thread-b'],
agentsStates: {
'child-thread-a': {
name: '实现代理',
role: 'frontend',
status: 'in_progress',
summary: '正在补充结构化渲染与样式',
},
'child-thread-b': {
name: '验证代理',
role: 'qa',
status: 'completed',
summary: '已完成基础事件链检查',
},
},
status: 'inProgress',
},
},
});
send({
method: 'item/completed',
params: {
threadId: thread.id,
turnId,
completedAtMs: Date.now(),
item: {
id: 'tool-collab',
type: 'collabAgentToolCall',
tool: 'spawn_agent',
prompt: '整理前端改动并回报状态',
receiverThreadIds: ['child-thread-a', 'child-thread-b'],
agentsStates: {
'child-thread-a': {
name: '实现代理',
role: 'frontend',
status: 'completed',
summary: '结构化渲染已完成',
},
'child-thread-b': {
name: '验证代理',
role: 'qa',
status: 'completed',
summary: '事件链与持久化检查通过',
},
},
status: 'completed',
},
},
});
}
send({
method: 'thread/tokenUsage/updated',
params: {

View File

@@ -811,6 +811,17 @@ async function main() {
assert(/"hasCcwebMcpConfig": true/.test(codexAppDynamicTool.result || ''), 'Codex App thread/start should pass ccweb MCP config');
await nextMessage(messages, ws, (msg) => msg.type === 'done' && msg.sessionId === codexAppSession.sessionId);
ws.send(JSON.stringify({ type: 'message', text: 'codexapp subagent prompt', sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' }));
const codexAppCollabTool = await nextMessage(messages, ws, (msg) => msg.type === 'tool_end' && msg.sessionId === codexAppSession.sessionId && msg.toolUseId === 'tool-collab');
assert(codexAppCollabTool.kind === 'collab_agent_tool_call', 'Codex App should surface collab agent tool calls');
assert(/child-thread-a/.test(codexAppCollabTool.result || ''), 'Codex App collab tool should include child thread ids');
await nextMessage(messages, ws, (msg) => msg.type === 'done' && msg.sessionId === codexAppSession.sessionId);
storedCodexApp = JSON.parse(fs.readFileSync(path.join(sessionsDir, `${codexAppSession.sessionId}.json`), 'utf8'));
const hasCollabTool = storedCodexApp.messages
.flatMap((message) => Array.isArray(message.toolCalls) ? message.toolCalls : [])
.some((tool) => tool.kind === 'collab_agent_tool_call');
assert(hasCollabTool, 'Codex App collab tool should be persisted into session history');
ws.send(JSON.stringify({ type: 'message', text: 'codexapp collaboration plan probe', sessionId: codexAppSession.sessionId, mode: 'plan', agent: 'codexapp' }));
const codexAppPlanCollab = await nextMessage(messages, ws, (msg) => msg.type === 'text_delta' && msg.sessionId === codexAppSession.sessionId && /collaboration mode:/.test(msg.text || ''));
assert(/"mode":"plan"/.test(codexAppPlanCollab.text || ''), 'Codex App Plan mode should pass plan collaboration mode');