Skip to content

feat(cli): TUI statusline ctx segment should update per settled provider request, not just at turn end #4545

Description

@me2seeks

Problem

The TUI statusline ctx used/window pct% segment only updates once per turn, when the turn fully ends:

  • contextRemaining is computed and emitted with the token_usage event in the Final usage event block, after the agent loop breaks (packages/runtime/src/ai-sdk-backend.ts, ~L2761).
  • Mid-turn, each step-finish boundary already captures lastStepInputTokens (~L2190), but it only feeds the end-of-turn computation and the durable recordUsageCheckpoint hook — nothing reaches the live event stream.
  • The TUI's only live update path is applyMakaSessionEventToTranscript's case 'token_usage' (packages/cli/src/pi-transcript.ts), and /context is midTurn: 'refuse'.

During a long agentic turn (dozens of tool steps, minutes) — exactly when the context grows fastest and the user most needs the signal to /compact or wrap up — the indicator sits stale at the previous turn's value.

Prior art: desktop already does better

The desktop session inspector shows a context bar that updates per settled provider request, mid-turn:

  • The Host commits a latest-context snapshot at every request settlement (packages/runtime/src/provider-request-telemetry.ts: finalizeemitModelCallAttemptaccounting.record({ attempt, latestContext })).
  • The inspector subscribes to the live session event stream; trace-relevant events (tool_start, tool_result, token_usage, …) trigger a 400 ms-debounced re-read of context.diagnostics.query (apps/desktop/src/renderer/features/workbar/tools/inspector/use-session-trace.ts, session-trace-refresh.ts).

Proposal: reuse the desktop pull model in the TUI

Verified feasible with no protocol changes:

  1. context.diagnostics.query is a plain read (packages/runtime-host/src/server/context-coordinator.ts #queryDiagnostics): header snapshot + run-store read, no execution authority, no busy gate.
  2. The TUI driver already exposes it: runtime-host-session-driver.ts getContextDiagnostics() (L1117). The /context mid-turn refusal is the TUI's own runControl serial lock (pi-tui-runner.ts L882), not a protocol constraint — a refresh hook can call the driver directly.
  3. Hook point exists: onEvent in pi-tui-runner.ts (L1455) sees every live event mid-turn. Attach a debounced refresh on the trace-relevant event set.
  4. No race: the finish part's finalize() (snapshot commit) is awaited before controller.enqueue in the telemetry stream wrapper, so by the time tool_start reaches the UI the snapshot is durable.

Semantics line up: diagnostics.inputTokens is "used"; contextRemaining = contextWindow - inputTokens matches the existing statusline formula. The end-of-turn token_usage stays the authoritative persisted record; the pull only enriches the live turn.

Why pull over a new push event

  • Zero protocol surface: no core event schema, backend emission, host mapper, or persistence-semantics changes.
  • Single source of truth: TUI and desktop read the same latest-context snapshot row — no second derivation path to drift on resume/backfill/compact edges.
  • All changes contained in the CLI package.
  • Free follow-up: /context could become mid-turn-capable over the same query path.

Scope

  • Debounced getContextDiagnostics() refresh on trace-relevant live events; update the statusline ctx segment (used/window/pct) mid-turn.
  • Prefer the diagnostics' contextWindow (measured at settlement) over the catalog value when present.
  • Reuse or share the refresh-coalescer policy with desktop's session-trace-refresh.ts.

Non-goals

  • Token-level "real-time" during a single streaming request — impossible exactly (providers report input tokens at completion); a pre-dispatch bytes/4 estimate is too rough (base64 attachments) to be worth it.
  • Changing token_usage persistence or billing semantics (fix(headless): harden real-provider smoke reliability #972: incomplete usage is no usage).
  • Desktop changes.

Refs: #1053 #1064 #1067 #3371 #4019 (per-turn behavior, all closed), desktop pull model #1625 #2323.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions