web: surface core's turn modeling in the transcript, header, and inspect panel - #18
Merged
Conversation
Surface core's Turn state machine in the browser projection instead of flattening it away: - mqueue: listen to turn_started SSE (core already emitted it; the browser dropped it), keep turnsBySessionId, mark turns failed on turn_failed, and merge turns from runtime snapshots and send responses. - mqueue: build TurnGroup[] from the flat timeline. Attribution: tool calls via turn_id, streaming transients via the stream_<turn_id> synthetic id, user messages via trigger_ref, everything else via the input_through_session_seq watermark. Unattributable items fall into envelope-less groups so old data always renders. - mqueue: extract the projection write surface into projection.ts; it owns every mutation that keeps messages, the flat timeline, and the turn-grouped timeline consistent. - hooks: replace useSessionTimeline with useSessionTurnTimeline. - web: Transcript renders turn groups; a failed turn shows TURN FAILED with its error_text in place in the transcript, and the composer notice suppresses errors a failed turn already carries. Verified live: history rebuild, streaming send, SSE turn_failed, HTTP-rebuilt failed turns, and recovery after provider restore.
- A pending (streaming) message shows 'generating…' in place of its timestamp instead of rendering identically to a fixed message. - The header busy chip derives its label from the running turn's actual phase — 'running tool' while a tool call awaits its result, 'generating' while a pending message streams, 'thinking' otherwise, with 'sending' as the no-turn fallback. The chip system stays quiet-by-default. Verified live: 'generating' chip during a streaming reply, normal completion afterwards.
The runtime snapshot (selectAndGet already fetches it) was stored in the projection but nothing read it. Sign for it: - mqueue/hooks: re-export the runtime domain types (SoulSession, Compact, SessionEffect, SessionRuntimeSnapshot) and add useSessionRuntime() plus a refreshRuntime action. - web: an Inspect toggle in the chat header swaps the transcript for a read-only panel showing the soul session's memory (with its last-seen seq watermark), compaction summaries with the seq ranges they replace, and hook effect statuses. Switching sessions returns to the transcript; opening the panel refreshes the snapshot. First visible landing of the 'transparent, inspectable local agent' direction. Verified live: panel renders memory/compacts/effects empty states with real seq watermark, toggle restores the transcript.
…d ledger - hooks: useSessionPreviews() exposes the first user-authored line of each loaded session; the rail falls back title -> preview -> raw id, so untitled sessions stop reading as sess_<uuid>. - README: record core capabilities deliberately not yet surfaced in the web UI (forking, image parts, message edit/delete, soul-view timeline, effects detail), each with its unlock condition, so deferral stays distinguishable from neglect. Verified live: a fresh untitled session shows its raw id until the first send, then the rail row switches to the message preview.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
"Turn closure": surface core's already-modeled agent runtime in the UI instead of flattening it into a message list. Zero core/contracts changes — the whole PR is mqueue → hooks → web.
d146b20): mqueue now listens toturn_started(core emitted it; the browser dropped it), keepsturnsBySessionId, and buildsTurnGroup[]with attribution rules (tool calls viaturn_id, streaming transients viastream_<turn_id>, user messages viatrigger_ref, the rest via theinput_through_session_seqwatermark; unattributable items fall into envelope-less groups so old data always renders). Turn failures render in place in the transcript with theirerror_text; the composer notice suppresses errors a failed turn already carries. The projection write surface moved toprojection.ts.adfa850): pending messages showgenerating…instead of a timestamp; the header busy chip names the running turn's actual phase (running tool/generating/thinking).c6dffe6): the runtime snapshot was fetched and stored but never read.useSessionRuntime()+ an Inspect toggle in the header showing session memory (with seq watermark), compaction summaries, and effect statuses.ad89db2): untitled sessions show their first user message instead ofsess_<uuid>; README records core capabilities deliberately not yet surfaced, each with its unlock condition.Test plan
turn_failedin-place rendering, HTTP-rebuilt failed turns, recovery after provider restore, inspect panel toggle, rail preview switch on first sendpnpm -r typecheck/ build clean; pre-commit (fmt, flavor, sidecar) green per commit🤖 Generated with Claude Code