Skip to content

fix(runtime): emit contextRemaining in token_usage events so the TUI ctx segment renders #1067

Description

@Astro-Han

Problem

The TUI statusline ctx segment (ctx 32k/128k 25%) never renders. The entire pipeline is wired but the source never produces data:

  • TokenUsageEvent.contextRemaining is defined (packages/core/src/events.ts:487)
  • ai-sdk-flow.ts:465-466 forwards it to StoredMessage
  • pi-transcript.ts:478 stores it on state.usage
  • pi-transcript.ts:946 gates the ctx segment on usage.contextRemaining !== undefined

But ai-sdk-backend.ts:1770–1790 constructs the TokenUsageEvent without ever setting contextRemaining. The field is always undefined, so the gate is always false, and the ctx segment is always omitted.

#1064 identified the symptom and #1066 addressed the chrome side (color thresholds, cwd shortening), but deliberately omitted a fallback using token_usage.input because that field is a billing-cumulative sum across tool-loop steps — using it as "used context" would produce misleading percentages (potentially >100%). The correct fix is to set contextRemaining at the source.

Root cause

ai-sdk-backend.ts has both pieces of data needed to compute contextRemaining:

  1. contextWindow — from resolveSelectedModelContextWindow(connection, modelId) (already used for mid-turn capacity compaction at line 2558)
  2. Last step's inputTokens — from the finish-step chunk's stepUsage.inputTokens (captured at line 1525 as stepUsage, accumulated into completedStepUsage)

The last step's inputTokens is the actual prompt token count of the final API request = how much context is in use. contextRemaining = contextWindow - lastStepInputTokens.

tokenUsage.inputTokens (the totalUsage used for the event's input field) is NOT suitable — it is cumulative across all tool-loop steps, which is why #1066 correctly rejected it as a fallback.

Desired outcome

  • Capture the last step's inputTokens from the finish-step handler (not the cumulative totalUsage).
  • When constructing the TokenUsageEvent, compute contextRemaining = max(0, contextWindow - lastStepInputTokens) when both values are available, and include it on the event.
  • The TUI ctx segment renders without any further changes — all downstream plumbing already exists.
  • Desktop's context display (if any) also benefits if it consumes the same field.

Non-goals

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions