fix(codex): improve web rendering for Codex events (#544)

* test(codex): add web event rendering harness

* fix(codex): surface plan updates in web

* fix(codex): render MCP tool calls in web

* fix(codex): improve terminal and context display

* fix(codex): format token usage events

* fix(codex): show status context in web

* fix(codex): preserve tool result errors
This commit is contained in:
CoColate
2026-04-29 17:22:45 +08:00
committed by GitHub
parent a612be50d6
commit e76738aa5a
27 changed files with 1138 additions and 15 deletions
@@ -100,6 +100,75 @@ describe('AppServerEventConverter', () => {
}]);
});
it('maps MCP tool call items', () => {
const converter = new AppServerEventConverter();
const started = converter.handleNotification('item/started', {
item: {
id: 'call-1',
type: 'mcpToolCall',
server: 'hapi',
tool: 'change_title',
arguments: { title: 'MCP Title' }
}
});
expect(started).toEqual([{
type: 'mcp_tool_call_begin',
call_id: 'call-1',
server: 'hapi',
tool: 'change_title',
invocation: {
server: 'hapi',
tool: 'change_title',
arguments: { title: 'MCP Title' }
}
}]);
const completed = converter.handleNotification('item/completed', {
item: {
id: 'call-1',
type: 'mcpToolCall',
server: 'hapi',
tool: 'change_title',
result: {
content: [{ type: 'text', text: 'done' }]
}
}
});
expect(completed).toEqual([{
type: 'mcp_tool_call_end',
call_id: 'call-1',
server: 'hapi',
tool: 'change_title',
result: {
content: [{ type: 'text', text: 'done' }]
}
}]);
});
it('maps MCP tool call item errors', () => {
const converter = new AppServerEventConverter();
const completed = converter.handleNotification('item/completed', {
item: {
id: 'call-1',
type: 'mcpToolCall',
server: 'hapi',
tool: 'change_title',
error: 'boom'
}
});
expect(completed).toEqual([{
type: 'mcp_tool_call_end',
call_id: 'call-1',
server: 'hapi',
tool: 'change_title',
result: { Err: 'boom' }
}]);
});
it('maps reasoning deltas', () => {
const converter = new AppServerEventConverter();
@@ -144,6 +213,51 @@ describe('AppServerEventConverter', () => {
expect(second).toEqual([]);
});
it('maps turn plan updates into update_plan events', () => {
const converter = new AppServerEventConverter();
const events = converter.handleNotification('turn/plan/updated', {
plan: [
{ step: 'Inspect Codex events', status: 'completed' },
{ content: 'Render plan state', status: 'in_progress' },
{ title: 'Verify web DOM', status: 'pending' }
]
});
expect(events).toEqual([{
type: 'plan_update',
plan: [
{ step: 'Inspect Codex events', status: 'completed' },
{ step: 'Render plan state', status: 'in_progress' },
{ step: 'Verify web DOM', status: 'pending' }
]
}]);
});
it('unwraps wrapped codex plan updates', () => {
const converter = new AppServerEventConverter();
const events = converter.handleNotification('codex/event/plan_update', {
msg: {
type: 'plan_update',
update: {
items: [
{ text: 'Plan from wrapped event', status: 'completed' }
]
}
}
});
expect(events).toEqual([{
type: 'plan_update',
plan: [
{ step: 'Plan from wrapped event', status: 'completed' }
]
}]);
});
it('maps diff updates', () => {
const converter = new AppServerEventConverter();