Skip to content

Show a run's execution timeline, and follow it live - #21

Merged
DrDrewCain merged 1 commit into
mainfrom
feature/agent-history-timeline
Sep 13, 2026
Merged

DrDrewCain merged 1 commit into
mainfrom
feature/agent-history-timeline

Conversation

@DrDrewCain

Copy link
Copy Markdown
Contributor

What

When the host advertises agents.history (native PR #94's replay + SSE routes), every opened run shows an Execution timeline below its results: one numbered entry per retained position — observation start/end, turns, model and tool calls with timing, tool outcomes by status and size, and the sequences the collector did not see. Prompts, tool arguments, answers and reasoning are never in these events; an entry carrying any other field is withheld with an alert, not shown. Retention-removed positions are named.

  • Load more reads the next page from the host's cursor (/v1/agent-runs/{id}/history?limit=50&after=).
  • Follow live opens /history/stream from the last cursor (query + Last-Event-ID), accepts a page only when the SSE id names it, reconnects from the cursor while the run is active when the host closes an observation window, and stops — saying so — after three windows without a new event, when the run is no longer active, or when the collector records observation finished. error frames surface the host's fixed reason. Nothing restarts a run or calls a model.
  • Parsing mirrors the standalone SDK decoder: exact field sets, contiguous positions, cursor shape/generation/position, retention continuity, collection identity/continuity, model binding against the saved plan (task and handoff routes).

Files: src/agents/history.ts (parsers + describeEntry), src/agents/history-stream.ts (frame reader), src/agents/HistoryTimeline.tsx, ApiClient.historyStream, capability agents.history, README.

Verification

  • tests/agent-history.test.ts (9): page reading and descriptions; operations/tool outcomes described without content; refusals (space/run, continuity, extra field, binding, digest, route, collection identity, unavailable, cursor); unavailable page; retention disclosure (omitted exactness, generation); frames page-by-page with keep-alives to end; id mismatch, error frame, cut mid-frame, foreign page, unknown event; resume continuity; capability parsing. Five rules mutation-checked (id names page, retention continuity, binding, position continuity, generation) — each flips the suite to failing.
  • tests/api.test.ts (+1): cursor both ways, no Last-Event-ID without a cursor, bad ids/cursor/limits rejected before any request, non-SSE and redirect refused, 401 expires the session.
  • scripts/test-agents.cjs (+4 journeys, desktop + mobile): timeline renders three recorded entries, Follow live resumes from position 3 and reaches the collector's end with no private text on the page and no horizontal scroll; a leaking entry is withheld; no capability → no timeline. 28/28 native journeys (Playwright 1.57, cached Chromium 1200), 519 unit tests, tsc and vite build clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_012aNJobunWMPFEa8mjsFQqY

A host that advertises agents.history records what a run did as it
ran -- observation start and end, turns, model and tool calls with
their timing, tool outcomes by status and size, and the sequences the
collector did not see -- and the console showed none of it. Every
opened run now carries an Execution timeline below its results, one
numbered entry per retained position, read the way the standalone SDK
reads it: every field checked, positions contiguous, the cursor naming
its page, the model binding matching the saved plan, and an entry that
carries any field beyond metadata withheld with an alert rather than
shown. Positions removed by retention are named.

Load more reads the next page from the host's cursor. Follow live opens
the text/event-stream route from the last cursor, sending it as the
query and as Last-Event-ID; a page is accepted only when the frame's id
names it; the host's end frame closes an observation window, and the
console reconnects from the cursor while the run is active, stopping
and saying so after three windows without a new event, when the run is
no longer active, or when the collector records that observation
finished. An error frame is a refusal with the host's fixed reason.
Nothing here restarts a run or calls a model.

history.ts holds the page and event parsers and the plain-words
description of each entry; history-stream.ts reads frames; the API
client gains historyStream with the same secure request shape as the
conversation stream; the capability is agents.history.

Nine unit tests cover the parsers, descriptions, refusals, retention
disclosure, frame reading and resumption; the API client test checks
the headers, cursor validation and non-SSE refusal; four browser
journeys (desktop and mobile) show the timeline, follow it to the
collector's end, withhold a leaking entry, and offer no timeline
without the capability. 28 native journeys and 519 unit tests pass;
typecheck and build are clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aNJobunWMPFEa8mjsFQqY
@DrDrewCain
DrDrewCain merged commit 9526ada into main Sep 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant