Skip to content

P2: render the server-provided agent sub-status indicator #653

Description

@RonenMars

Mobile half of the agent sub-status indicator.
The phase is derived and emitted by the streamer — see threadbase-streamer#538.
Blocked on that shipping, since there is no field to render until it does.

Verified state

Checked 2026-08-12 against origin/main @ 86eeb2a1.

The earlier client-side attempt, PR #647, was closed unmerged, so none of its code is on main — verified individually: lib/agentSubStatus.ts absent, getTailLines zero hits in services/virtual-terminal.ts, "working" zero hits across all four locales.
There is nothing to remove.

What this actually costs

A review pass found the obvious estimate — add a field to a type and render it — to be wrong on three counts.

  • SessionPresentationInput (lib/sessionPresentation.ts:58-72) is standalone, enumerating eleven fields rather than deriving from Session. Adding subStatus to types/api.ts alone leaves deriveSessionPresentation unable to see it.
  • Gate on presentation.live, not raw status. deriveSessionPresentation has branches that never consult statusexternal_live keys off ownership + processLiveness, stale off processLiveness === 'gone' — and status is a loose string by design. A raw-status gate could render a phase indicator beside a badge reading "Idle" or "External". SessionStatusBadge.tsx:47 already uses presentation.live for the LiveDot the indicator sits beside, and SessionCard.tsx:79-82 states the rule: one answer for liveness, not a third derivation.
  • No client-side time decay. The app has no precedent for it, and sessionPresentation.ts is a pure function — nothing re-invokes it when a clock crosses a threshold, so a freshness gate would clear only on an unrelated re-render. The established idiom is processLiveness === 'gone': the server decides liveness and says so. The streamer clears the phase explicitly at turn end.

Theming is bimodal. colorForToken is module-private to components/sessions/SessionStatusBadge.tsx:18 and bridges two closed five-value unions. Reusing an existing token is free; a phase-specific colour means extending the union and the Theme interface and adding the colour to 17 theme objects. Never a hardcoded hex — #647 used #3fb950, invisible on the four light themes.

Question-card suppression should copy components/conversation/ThinkingBubble.tsx:107-134, which correctly covers both the structured question and the PTY-scraped block.
Tree mode (components/sessions/tree/TreeRow.tsx:63) is deliberately out of scope.

Plan

threadbase-streamer#537 -> docs/plans/2026-08-12-agent-sub-status-server-side.md, Part B.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Soon, but does not gate a releaseenhancementNew feature or requestuxUser-facing interaction and polish

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions