feat(mobile): show and drive chat-v3 sessions on mobile
Stacked on #8150. Fixes SUPER-2600.
Summary
With acp-chat on, desktop opens Claude, Codex and Pi as chat-v3 sessions with no PTY behind them. Mobile built every session list from PTYs (terminal.list + terminalAgents.list), so those chats never showed on a phone. A terminal switched to chat disappeared from mobile while it was still running.
This PR shows those chats on mobile and lets you use them there:
- Lists: live chats join the terminal rows in
useHostsTerminals, so they show on home, in the workspace tab strip, and in the sessions sheet. Each row has the agent's mark and an attention state (working, waiting for approval, review). - Chat tab: a transcript in place of the terminal WebView. It shows messages (streamed markdown), thoughts, tool calls and step runs, plans, notices, and turn status.
- Actions: answer approvals (Deny first), Stop, the queue (Steer, Delete, Resume when paused), the approval mode picker, and Load earlier messages.
- Composer: the existing composer sends to the chat. The quick keys are hidden on a chat tab. Attachments go in as worktree paths, the same way terminals take them.
- New sessions: with
acp-chaton, the + sheet opens Claude, Codex and Pi as chats, like desktop does. - Close on a chat tab calls
closeSession. Rename says a chat takes its name from the agent.
How it works
chat-runtime:listSessionsrows now carrylive, i.e. whether a harness is still running behind the session. A closed chat keeps its last status forever, so the status alone can't say whether the chat is open. This only adds an output field.relay: the relay forwards HTTP only for/hosts/:id/trpc/*. This PR adds/hosts/:id/chat-v3/trpc/*to the same handler. The host tunnel already forwards any path with its own secret. Mobile chat on local and remote hosts needs this relay deploy. Cloud workspaces are reached directly and don't need it.- Mobile transport:
lib/chatreuses@superset/chat(useChatSession,deriveTimeline, the outbox). It talks to the host through a tRPC client on/chat-v3/trpc, authed with the same bearer as/trpc. The stream socket mints a fresh relay JWT or sandbox token for every dial, so it stands in as a deferred socket until the token resolves. Hermes has nocrypto.randomUUID, so it is filled in fromexpo-crypto. - Older hosts: if
listSessionshas nolivefield, mobile callsgetSessionon the 10 newest sessions that aren't dead. A host with no chat-v3 at all returns no chats. - Types:
@superset/chat's client types import@superset/chat-runtime. Mobile maps that import to the package source (types only, since Metro strips type imports). That adds no typecheck errors under the Expo config.
Compatibility (trpc-compat)
- Additive only:
listSessionsgains theliveoutput field. No input changes. - New mobile with an older host: the per-session
getSessionfallback above. - New mobile with the relay before this deploy: chat calls through the relay fail and are caught, so terminals behave as before and chats don't show. Cloud workspaces still work.
Known limitations
- The mobile list polls
listSessionsevery 5 s with the terminals. On a host that never used chat, the first call openschat.db. - A new chat from mobile doesn't send the model or effort the home composer remembered. Mobile stores terminal CLI model ids, which ACP agents may not accept.
- The home "new workspace" flow still launches agents in a terminal.
- There's no fork, resume of a dead chat, or chat rename on mobile.
Tests
bun testinpackages/chat-runtime/src/commands: 9 pass, including a new test forliveon listed sessions.- Mobile: new
listLiveChatstests (thelivefilter and the old-host fallback) andchatRowstests (outbox/echo keying and the working line). 4 pass. - Mobile
tsc: 27 errors before and after this change, all the existing better-auth ones. None are in the changed files. apps/relaybun test: the same 4http-exchangefailures with and without this change.check:i18n: 12 new strings, translated in all 16 locales.
Manual QA
- Simulator against prod: a cloud workspace chat lists, streams, takes a prompt, and answers an approval. (In progress.)
- Local host through the relay, which needs the relay change deployed or a local relay.
Summary by cubic
Mobile never showed chat-v3 sessions because its session lists came from PTYs, and desktop ACP chats (Claude, Codex, Pi) have no PTY behind them. Live chats now join the terminal rows on home, in the workspace tab strip, and in the sessions sheet, and open a chat tab with a streamed transcript (messages, thoughts, tool calls, plans, notices), approval answering (Deny first), Stop, queue controls (Steer, Delete, Resume), and the approval mode picker. The existing composer sends prompts to the chat, and with acp-chat on, the + sheet opens those agents as chats instead of terminals.
Rollout
- The relay must deploy before chat works over local and remote hosts; cloud workspaces reach the host directly and don't need it.
listSessionsgains an additiveliveoutput field; hosts without it fall back to probinggetSessionon the newest non-dead sessions.- With an older relay, chat calls fail and are caught, so terminals keep working and chats just don't show.