Read Agent SDK session records, and surface ones that cannot render - #133
Conversation
Sessions run on the Agent SDK now, whose records carry a different payload shape (claude_sdk@1). The pinned SDK could not read it, so the chat and `session records` dropped every user and assistant message with no error anywhere: the record still arrived, still advanced the resume cursor, and rendered zero rows. Adopt SDK 0.15.0 for the reader, and make an unrenderable record visible instead of silent -- the footer counts them, since a transcript that quietly omits what was said is worse than one that admits it cannot read it.
There was a problem hiding this comment.
Caution
Changes requested ❌ — 1 issue
Reviewed 62e8756 in 9 minutes, 20 seconds.
- Reviewed
1commit with415lines of code in8files - Ran
1review agent producing1comment where1was posted - This pipeline runs no gatekeeper, so findings are posted as written.
- View full details on ellipsis.dev
This review was created by . You can tag
@ellipsis in this pull request.
| } catch { | ||
| rendered = [] | ||
| } | ||
| if (rendered.length === 0 && r.record_type !== 'system') undisplayed++ |
There was a problem hiding this comment.
The undisplayed count treats records the SDK reader is silent on by design as drops, so healthy sessions get the "this CLI may be out of date" footer; only record_type === 'system' is excluded, but eventToItems also returns [] for kind: 'rate_limit' (part of the persisted claude_sdk@1 union) and codexEventToItems returns [] for every codex frame except item.completed/error/turn.failed.
Verified against the installed 0.15.0 by calling reshapeTranscript directly: a rate_limit record yields {items: [], undisplayed: 1}, and a normal six-record codex turn (thread.started, turn.started, item.started, item.updated, item.completed, turn.completed) yields one rendered row and undisplayed: 5. Since agent session connect does not filter by harness and the platform persists every Codex exec --json ThreadEvent verbatim (source=codex, codex_jsonl@1), connecting to a codex session shows e.g. "37 events could not be displayed, this CLI may be out of date" while rendering the transcript correctly — and because the warning takes the whole meta line and only clears on a send, a watch-only or closed session (canSend false, --no-input) loses status/spend/session id for the rest of the run.
| if (rendered.length === 0 && r.record_type !== 'system') undisplayed++ | |
| // Silent BY DESIGN is not a drop: claude system/rate_limit rows, and the | |
| // codex frames that carry no row of their own (thread/turn/item.started, | |
| // item.updated, turn.completed). | |
| const silentByDesign = | |
| r.source === 'codex' | |
| ? r.record_type !== 'item.completed' && r.record_type !== 'error' | |
| : r.record_type === 'system' || r.record_type === 'rate_limit' | |
| if (rendered.length === 0 && !silentByDesign) undisplayed++ |
Summary
@ellipsis-dev/sdk@0.15.0, whose store reads the Agent SDK record shape (claude_sdk@1: discriminated bykind, flat envelope,cost_usdper turn). The pinned 0.13.0 read the old stream-json shape, so every user and assistant record rendered as zero rows.CCEvent->SdkRecord.Why
session_7U5s22wfghWiHfq7qxeDWzNLJmzXb700wadFz7MHshowed no messages in the CLI while rendering correctly in the dashboard. The server sent all 44 records and the socket held; the CLI received them, advanced its resume cursor, and rendered nothing, becauseeventToItemsreturns[]for a shape it does not recognize. Three layers drop silently (stream JSON parse, unknown frame type, unrenderable payload) and none of them said a word.The footer count addresses the second half of that: the reader is now correct, but the next harness change should not cost a debugging session to notice.
Test plan
bun run test(414 pass)bunx tsc --noEmitagent session records session_7U5s…prints the user and assistant text where it previously printed raw JSONreshapeTranscriptover that session's real records: 5 rows,undisplayed: 0agent session connectagainst a live session -- transcript renders, footer shows no warningImportant
Adopts
@ellipsis-dev/sdk@0.15.0, whose agent records use a new discriminated shape (kindfield, flatcontent) and scale rates in millicents instead of cents. Surfaces unrenderable records in the footer so wire changes do not render invisibly.kindinstead oftype, havecontentdirectly instead of nested inmessage, and userecord_format: 'claude_sdk@1'to discriminate across harness versions.input_cents_per_1m_tokens→input_millicents_per_1m_tokens(1000x multiplier).rateDollarsupdated to divide by 100,000 instead of 100.reshapeTranscriptnow returns{ items, undisplayed }counting agent records that arrive but render nothing — from unrecognizedrecord_format, empty content, or reader errors.undisplayed > seen, clearing on your next send so only new drops are visible.CCEvent→SdkRecord, updated test fixtures to includerecord_formatfield.This description was created by
for 62e8756. It will automatically update as commits are pushed.