feat: model Codex subagent result events#247
Conversation
roborev: Combined Review (
|
|
Addressed the current roborev findings in . Changes:
Re-verified with:
RUN v4.0.18 /home/trent/src/agentsview/frontend ✓ src/lib/utils/messages.test.ts (13 tests) 2ms Test Files 2 passed (2) The local 3-agent roborev hook on this commit came back with no medium-or-higher findings. |
|
Addressed the current roborev findings in Changes:
Re-verified with:
The local 3-agent |
roborev: Combined Review (
|
wesm
left a comment
There was a problem hiding this comment.
I went back and forth looking at this with Claude and Codex for feedback, here is where we landed
Review: Codex subagent approach
The tool_result_events model and "history" panel are well-designed — good foundation for representing Codex's inline subagent data. One issue to address before merging:
Bug: SubagentSessionID links to nonexistent sessions
The parser sets subagent_session_id = "codex:{agent_id}" on spawn_agent tool calls (internal/parser/codex.go:244), and ToolBlock.svelte renders SubagentInline for any tool call with that ID. But no code on this branch creates codex:{agent_id} session rows in the DB. In practice, Codex tool blocks will show a "Subagent session" affordance that fails on expand.
Fix: Remove the annotateSubagentSessions call from ParseCodexSession and ParseCodexSessionFrom. Codex subagents don't have their own session files — there's nothing to link to. The "history" panel already provides the right display for this data.
Why not synthesize virtual child sessions?
Codex subagent data is inherently limited compared to Claude's. You only get:
- The
spawn_agentprompt/description - Periodic
<subagent_notification>status blurbs - Terminal status from
waitoutput
You don't get the subagent's actual conversation turns, tool calls, or intermediate reasoning — Codex doesn't write that to disk. Synthesizing fake session rows would produce nearly-empty child sessions (a prompt and a terminal status), which would look broken in a different way.
Minor corrections
- The incremental fallback doesn't force a full parse for all sessions that have subagents. It only triggers when the newly appended chunk contains a
waitcall, subagent function output, or a terminal<subagent_notification>(codexIncrementalNeedsFullParseincodex.go).
Summary
The tool_result_events infrastructure and history UI are solid — merge after removing the SubagentSessionID annotation for Codex so SubagentInline doesn't render a broken affordance. A purpose-built inline component (timeline/log view instead of nested session) could be a nice follow-up if the generic history panel feels too plain.
internal/db/db.go
Outdated
| // trigger a non-destructive re-sync (mtime reset + skip cache | ||
| // clear) so existing session data is preserved. | ||
| const dataVersion = 6 | ||
| const dataVersion = 8 |
There was a problem hiding this comment.
Oh I bet that's an artifact of it doing v2 against the v1 pass where it initially bumped to 7. Good catch!
|
Sounds good to me, I'll tackle that last piece in a bit. |
|
Addressed Wes's feedback in Changes:
Re-verified with:
The local 3-agent |
roborev: Combined Review (
|
|
Addressed the Changes:
Re-verified with:
The local 3-agent |
|
Addressed the latest roborev finding in Changes:
Re-verified with:
The local 3-agent |
|
I took a look at this locally and it LGTM |
Closes #233.
Supersedes #242.
Summary
tool_result_eventsin SQLite and PostgreSQLtool_calls.result_contentas a derived/latest compatibility summary instead of the canonical storage shapeHow This Differs From #242
#242tried to solve Codex subagent workflows inside the existing single-result model by:wait/<subagent_notification>output into one mutabletool_calls.result_contentThat approach improved the raw JSON problem, but it kept running into ownership and chronology edge cases because Codex subagent status is not actually a single final blob.
This PR switches to a different model:
tool_result_eventstables in both SQLite and PostgreSQLtool_calls.result_contentfrom those events for compatibility/search/compact UIspawn_agentPractical effect:
waitoutput and fallback notifications are stored as canonical event historyDetails
spawn_agentremains aTasktool call and still maps tosubagent_session_idwaitoutput becomestool_result_events<subagent_notification>messages also becometool_result_eventsUpgrade / Rollout
dataVersionbumpagentsview pg push --fullonce, or let the normal full-sync path re-export after resyncKnown limit:
Test Plan
CC=/usr/bin/gcc CXX=/usr/bin/g++ CGO_ENABLED=1 go test -tags fts5 ./internal/parser ./internal/sync ./internal/db ./internal/postgres -count=1cd frontend && npm test -- --run src/lib/components/content/ToolBlock.test.ts src/lib/utils/messages.test.tsLocal Review
codex,claude-code, andgeminireview runs covered bothdefaultandsecuritytool_result_events, blocked-category history leakage, and same-ordinal orphan chronology