Read a session's conversation as a chat lens on the phone - #296
Draft
jiweiyuan wants to merge 1 commit into
Draft
Conversation
…phone The terminal stays the interface; this adds the second lens onto the same live session. The host turns an agent's on-disk transcript into an AgentEvent stream clients subscribe to with a cursor, so a phone that reconnects mid-turn asks for the gap rather than the whole conversation, and a dormant session still reads. The phone renders those events natively — prose, tool cards, diffs, plans — and its composer types into the same PTY the Mac terminal owns, so there is one session and no local/remote mode switch. A prompt now waits for the agent's screen to settle before it is typed. Bytes written while a CLI is still painting are read by whatever holds the PTY at the time and are simply gone: the message disappears, no turn starts, and nothing streams back, so the lens looks broken in both directions from one cause.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
The terminal stays the interface. This adds a second lens onto the same live session, for the times a phone is the only screen you have.
How it works
The host turns an agent's on-disk transcript into an
AgentEventstream that clients subscribe to with a cursor, so a phone reconnecting mid-turn asks for the gap rather than the whole conversation, and a dormant session still reads — the transcript outlives the process. A tool event is upserted rather than re-appended, so a card revises in place instead of jumping to the bottom when it finishes.The phone renders those events natively — prose, tool cards, diffs, plans — and its composer types into the same PTY the Mac terminal owns. One session, two lenses, no local/remote mode switch and no session restart.
Sending
A prompt waits for the agent's screen to settle before it is typed. Bytes written while a CLI is still painting are read by whatever holds the PTY at that moment and are simply gone: the message disappears, no turn starts, and nothing streams back — so the lens looked broken in both directions from a single cause. This is a client-side approximation; the Mac is the side that actually knows when the agent is ready, and promoting
promptto a typed wire message with an acknowledgement is the follow-up.Verified
Driven on device and in the simulator against a real Mac companion and a real Claude session: a prompt sent from the lens into a dormant session reconciles from pending to sent and the reply streams back.
AgentEventStoreStreamTestspins the half that cold-replay tests miss — that a turn appended after a subscriber attaches reaches it.Terminal first, chat one tap away
A session opens in the terminal — the product's position rather than a default nobody chose — and each view carries the switch to the other in the same header, so swapping never moves the chrome. Settings ▸ Appearance ▸ Sessions flips which one a session lands on, and back leaves the session from either view rather than making it a two-step.
Reading never starts anything. The Mac creates a session's process on first attach, so the chat subscribes without attaching and only the terminal — or a send — claims the PTY. Asking whether a session is live no longer goes through the call that spawns one either, which meant opening a finished conversation used to resurrect it.
The conversation itself
Events now carry the transcript's own clock, so a conversation read days later groups by the day it happened rather than the day you opened it: day pills between days, a time under your own messages, and grouping that tightens consecutive messages from one speaker. Around that, a jump-to-latest control, long-press to copy, a haptic on send, and a
working…line under the title fed by the same hook-driven status the session list already broadcasts — the chat was simply not listening to it.Measured row heights are fed back as estimates. With one fixed guess, a conversation full of forty-line diffs shifts under your finger every time a row turns out taller than the guess, which is the single loudest way a self-sizing table announces itself.
Three dialect details that were each wrong first: a plan is one row that revises in place, folding both shapes Claude Code writes (
TodoWritesends a whole list,TaskCreate/TaskUpdateone task at a time); a revised event keeps its place in the log and only takes a newseq, without which a cold replay puts every finished tool card below the diff it produced; and the user side of a transcript is filtered of the CLI's own plumbing —isMetarows carrying a skill's body,<command-name>envelopes,<local-command-stdout>— because rendering those in a user bubble claims the human said them.Not in this PR
Approval buttons (the
PreToolUseinteraction plane), the Codex dialect, thetranscript/questionsmanifest blocks, an on-device event store so a chat opens from disk instead of re-downloading, and a turn-level progress row to collapse the tool traffic of a busy turn.Release Notes