Repository navigation
feat(web): store turn trajectories and add a download button - #26
Conversation
Each agent turn (CLI and channel bots) is now saved to a new `trajectories` table, keyed by the turn's final assistant message: the system prompt, the turn's messages (tool calls, tool results, reasoning; attachment data redacted) and per-call model, latency and token usage. The web UI shows a "Download trajectory" button under the copy button on replies that have one, served by GET /api/messages/<id>/trajectory. Live replies get it from a new `trajectory` WebSocket frame sent after the turn's last reply. Delete removes trajectories; fork copies them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5eEVdQmx7huUwhT375FY7
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Rikul
left a comment
There was a problem hiding this comment.
Reviewed 46dfeec (single commit). I ran the full suite on the PR head: 460 passed. The trajectory frame ordering holds, and the migration is safe for existing databases. I found one live-path bug, reproduced below, plus a few smaller points.
Main finding: a failed save still shows a download button. _save_trajectory swallows its own errors, but BackgroundAgent.agent_loop then sends the trajectory frame unconditionally. I reproduced this with the save mocked to raise RuntimeError("disk full"): the reply is delivered and on_trajectory_saved is still awaited. The browser then attaches a download button, and clicking it gets a 404 from _trajectory_api. Suggested fix: have _save_trajectory return a bool and only call on_trajectory_saved when it returns True.
- _save_trajectory returns whether it stored anything; BackgroundAgent only sends the trajectory frame when it did, so a failed save no longer shows a button that 404s. - The turn's reply is sent with metadata "final" (web frames carry `final: true`); app.js attaches the trajectory button only to that row, so a stopped or empty turn never puts it on a status line. - Tests run a real turn through BackgroundAgent and WebChannel and check the frames a tab receives (reply marked final, trajectory frame after it, none after a failed save, no final frame for a stopped turn). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5eEVdQmx7huUwhT375FY7
Each agent turn (CLI and channel bots) is now saved to a new
trajectoriestable, keyed by the turn's final assistant message: thesystem prompt, the turn's messages (tool calls, tool results, reasoning;
attachment data redacted) and per-call model, latency and token usage.
The web UI shows a "Download trajectory" button under the copy button
on replies that have one, served by GET /api/messages//trajectory.
Live replies get it from a new
trajectoryWebSocket frame sent afterthe turn's last reply. Delete removes trajectories; fork copies them.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01B5eEVdQmx7huUwhT375FY7