Before submitting
Area
apps/mobile
Problem or use case
On long agent sessions it is easy to run out of the model's context window mid-task, but the mobile client gives no indication of how much context a thread has used or has left. A prompt can be sent when the window is nearly full, so the model has to compact or silently drop context on the final message of a session. The web client already solves this with a compact context-window meter next to the composer; the mobile client has no equivalent.
Proposed solution
Show the thread's context-window usage as a thin coloured ring around the send button in the composer. The ring fills (or depletes) with the used percentage and shifts colour as usage climbs (e.g. neutral → amber → red near the limit), so it is obvious at a glance whether there is room left before hitting send. Tapping it could open a small sheet with details — tokens used/max, total processed, and whether the provider auto-compacts — mirroring the web meter's tooltip.
This is effectively a port of the existing web feature:
apps/web/src/components/chat/ContextWindowMeter.tsx renders the SVG donut ring + tooltip.
apps/web/src/lib/contextWindow.ts provides deriveLatestContextWindowSnapshot(activities) and formatContextWindowTokens, which derive the snapshot from context-window.updated thread activities and handle the "provider reports no max" case.
The two send buttons to wrap in apps/mobile/src/features/threads/ThreadComposer.tsx:
- collapsed composer:
ControlPill with icon="arrow.up" / variant="primary" (~line 835)
- expanded composer:
ComposerToolbarButton with icon="arrow.up" / variant="primary" (~line 895)
The data is already present on mobile: apps/mobile/src/lib/threadActivity.ts currently discards the events (if (activity.kind === "context-window.updated") continue; ~line 326), and the full thread detail with its activities is loaded in ThreadRouteScreen.tsx. The snapshot can be derived the same way as the web app and passed into ThreadComposer as a new prop alongside selectedThread.
Why this matters
Mobile users are often away from the desk mid-task. A visible ring means they can see, before sending, whether a thread is near the limit — and either compact, start a fresh thread, or just know what to expect — instead of discovering after the fact that context was lost.
Smallest useful scope
A first pass only needs the collapsed composer's send-button ring, driven by the same deriveLatestContextWindowSnapshot logic as web, updating live as context-window.updated events arrive during a run. The tappable detail sheet and the expanded-composer variant can follow later.
Alternatives considered
- A text indicator (e.g. "74%") beside the composer — informative but harder to scan at a glance and adds clutter on a small screen.
- Showing remaining tokens instead of used — also possible (
maxTokens - usedTokens); the ring can show either, but used % with red overload past ~90% keeps parity with the web client.
Risks or tradeoffs
- The send button is a small target; the ring must not change its size or the expanded/compact layout. The web meter is a separate 28px button; on mobile, wrapping the existing button is the more compact option.
- Some providers do not report a context window (
maxTokens null) — in that case the ring should be hidden or degrade to a plain button, as the web meter already handles.
- The ring should stay visually subtle so it does not compete with the send button.
Examples or references
Contribution
Before submitting
Area
apps/mobile
Problem or use case
On long agent sessions it is easy to run out of the model's context window mid-task, but the mobile client gives no indication of how much context a thread has used or has left. A prompt can be sent when the window is nearly full, so the model has to compact or silently drop context on the final message of a session. The web client already solves this with a compact context-window meter next to the composer; the mobile client has no equivalent.
Proposed solution
Show the thread's context-window usage as a thin coloured ring around the send button in the composer. The ring fills (or depletes) with the used percentage and shifts colour as usage climbs (e.g. neutral → amber → red near the limit), so it is obvious at a glance whether there is room left before hitting send. Tapping it could open a small sheet with details — tokens used/max, total processed, and whether the provider auto-compacts — mirroring the web meter's tooltip.
This is effectively a port of the existing web feature:
apps/web/src/components/chat/ContextWindowMeter.tsxrenders the SVG donut ring + tooltip.apps/web/src/lib/contextWindow.tsprovidesderiveLatestContextWindowSnapshot(activities)andformatContextWindowTokens, which derive the snapshot fromcontext-window.updatedthread activities and handle the "provider reports no max" case.The two send buttons to wrap in
apps/mobile/src/features/threads/ThreadComposer.tsx:ControlPillwithicon="arrow.up"/variant="primary"(~line 835)ComposerToolbarButtonwithicon="arrow.up"/variant="primary"(~line 895)The data is already present on mobile:
apps/mobile/src/lib/threadActivity.tscurrently discards the events (if (activity.kind === "context-window.updated") continue;~line 326), and the full thread detail with its activities is loaded inThreadRouteScreen.tsx. The snapshot can be derived the same way as the web app and passed intoThreadComposeras a new prop alongsideselectedThread.Why this matters
Mobile users are often away from the desk mid-task. A visible ring means they can see, before sending, whether a thread is near the limit — and either compact, start a fresh thread, or just know what to expect — instead of discovering after the fact that context was lost.
Smallest useful scope
A first pass only needs the collapsed composer's send-button ring, driven by the same
deriveLatestContextWindowSnapshotlogic as web, updating live ascontext-window.updatedevents arrive during a run. The tappable detail sheet and the expanded-composer variant can follow later.Alternatives considered
maxTokens - usedTokens); the ring can show either, but used % with red overload past ~90% keeps parity with the web client.Risks or tradeoffs
maxTokensnull) — in that case the ring should be hidden or degrade to a plain button, as the web meter already handles.Examples or references
Contribution