Uh oh!
There was an error while loading. Please reload this page.
fix(grok): show context-window usage in the composer - #9206
Conversation
Grok ACP does not emit usage_update. Occupancy lives on session/update _meta.totalTokens. Map that onto the existing thread.token-usage.updated path so ContextWindowMeter can render. Do not use prompt-response usage.totalTokens; that is billed API tokens, not context fill. Closespingdotgg#8382
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6af161d. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This change adds a cross-cutting production pipeline that turns ACP session metadata into persisted context-window updates for Grok and Cursor, including a new 500,000-token fallback displayed by the composer meter. A cancellation race can also allow stale usage to overwrite the meter, so the runtime behavior and fallback semantics need human review. Not approved because:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
Keep lastKnownMaxTokens in sync when sendTurn switches models. Dedup occupancy snapshots on used+emitted max so a later window size is not dropped.
| if (event._tag === "UsageUpdated") { | ||
| const usageTurnId = resolveNotificationTurnId(ctx); | ||
| if (usageTurnId !== undefined && ctx.interruptedTurnIds.has(usageTurnId)) { |
There was a problem hiding this comment.
🟡 MediumLayers/GrokAdapter.ts:1374
A queued UsageUpdated from a cancelled prompt is emitted as thread.token-usage.updated after interruptTurn clears activeTurnId, so stale usage overwrites the composer context meter. Treat usageTurnId === undefined as stale here, in addition to checking interruptedTurnIds.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/GrokAdapter.ts around line 1374:
A queued `UsageUpdated` from a cancelled prompt is emitted as `thread.token-usage.updated` after `interruptTurn` clears `activeTurnId`, so stale usage overwrites the composer context meter. Treat `usageTurnId === undefined` as stale here, in addition to checking `interruptedTurnIds`.

Closes#8382
What Changed
Grok threads never showed the composer context-window meter. The live adapter did not emit
thread.token-usage.updated, soContextWindowMeterhad nothing to render.This maps occupancy onto that existing path:
sessionUpdate: "usage_update"when presentsession/update_meta.totalTokens_meta(contextWindowTokens/contextWindow/maxTokens), else the current model'savailableModels[]._meta.totalContextTokens, else 500kInterrupted turns do not overwrite the last snapshot. Cursor gets the shared
UsageUpdatedcase so the ACP union stays exhaustive.No new UI. The existing composer meter is enough.
Why
Codex already shows used / max / %. Grok did not, even though
grok agent stdioalready streams fill on_meta.totalTokens.Live Grok ACP still does not send
usage_update. Occupancy lives on session/update_meta.totalTokens. Prompt-responseusage.totalTokensis billed API tokens, not context fill. On a greeting turn those were 1615 occupancy vs 20554 billed. This PR does not use the prompt-response number, which is the difference from #5405.UI Changes
Uses the existing context-window meter in the composer.
session/update, Grok shows the same ring + used/max tooltip as Codex.Validation
vp test run src/provider/acp/AcpRuntimeModel.test.ts src/provider/acp/AcpCoreRuntimeEvents.test.ts src/provider/acp/GrokAcpSupport.test.ts— 50 passed_meta.totalTokensis occupancy; promptusage.totalTokensis billed tokens;signals.jsonhascontextWindowTokens: 500000spawn EFTYPEon the.shwrapper). That is existing, not introduced here. The new adapter test is inGrokAdapter.test.tsfor Linux CI.Checklist
Note
Low Risk
Provider-adapter and event-mapping changes only; no auth or persistence changes, with deduplication and explicit exclusion of billed-token metadata reducing wrong-meter risk.
Overview
Grok threads can now drive the existing composer context-window meter by emitting
thread.token-usage.updatedfrom ACP session traffic, matching what Codex already had.ACP parsing gains a
UsageUpdatedpath for explicitusage_updatenotifications and for Grok’s live signal:session/update_meta.totalTokens(with window size from_metakeys or model metadata). Prompt-response_meta.usage.totalTokensis intentionally ignored so billed API tokens are not shown as context fill.makeAcpTokenUsageEventmaps occupancy into the canonical runtime event (positive used tokens only, clamped to max).GrokAdapter dedupes snapshots, seeds max window from session setup
availableModels[]._meta.totalContextTokens, refreshes on model change, and skips updates for interrupted turns. CursorAdapter handles the sameUsageUpdatedbranch for exhaustiveness. The mock ACP agent can simulate occupancy viaT3_ACP_EMIT_CONTEXT_USAGE.Reviewed by Cursor Bugbot for commit a2087c9. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add context-window usage events for Grok ACP adapter
makeAcpTokenUsageEventfactory in AcpCoreRuntimeEvents.ts that converts positive usage measurements intothread.token-usage.updatedevents with rounded, maximum-bounded token countsusage_updatenotifications andtotalTokensmetadata intoUsageUpdatedparsed eventsmakeGrokAdapterin GrokAdapter.ts now processesUsageUpdatednotifications, deduplicates snapshots, refreshes the cached window on model change, and emits token-usage events using the event-provided or model-derived window (default 500,000)parseSessionUpdateEventnow emitsUsageUpdatedfor any session-update containingtotalTokensmetadata; adapters or consumers that did not expect this event type on session updates need to handle itMacroscope summarized a2087c9.