feat(mobile): show and drive chat-v3 sessions on mobile

Draft
HA
20d ago
+2021-35

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-chat on, 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: listSessions rows now carry live, 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/chat reuses @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 no crypto.randomUUID, so it is filled in from expo-crypto.
  • Older hosts: if listSessions has no live field, mobile calls getSession on 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: listSessions gains the live output field. No input changes.
  • New mobile with an older host: the per-session getSession fallback 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 listSessions every 5 s with the terminals. On a host that never used chat, the first call opens chat.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 test in packages/chat-runtime/src/commands: 9 pass, including a new test for live on listed sessions.
  • Mobile: new listLiveChats tests (the live filter and the old-host fallback) and chatRows tests (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/relay bun test: the same 4 http-exchange failures 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.
  • listSessions gains an additive live output field; hosts without it fall back to probing getSession on 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.