Skip to content

feat(acp-adapter): Support displaying context length usage in Zed ACP like Codex - #2412

Open
iluv7 wants to merge 6 commits into
MoonshotAI:mainfrom
iluv7:feature/acp-context-window-display
Open

feat(acp-adapter): Support displaying context length usage in Zed ACP like Codex#2412
iluv7 wants to merge 6 commits into
MoonshotAI:mainfrom
iluv7:feature/acp-context-window-display

Conversation

@iluv7

@iluv7 iluv7 commented Jul 30, 2026

Copy link
Copy Markdown

Description

Closed #2346

Pushes live context window usage from the agent core through the ACP usage_update session notification so ACP clients (Zed, JetBrains) can render a real-time token consumption indicator. Every agent.status.updated event from the engine is mapped to the ACP protocol's UsageUpdate type (@experimental, SDK v0.23+) and dispatched as a fire-and-forget notification on the stdio ndjson stream. Verified on Zed 1.13.1 — the circular progress indicator at the bottom of the Agent panel renders the data natively.

What Changed

contextUsageToUsageUpdate() (packages/acp-adapter/src/events-map.ts)

New builder that constructs an ACP SessionNotification with discriminator sessionUpdate: 'usage_update'. Mirrors the existing pattern of assistantDeltaToSessionUpdate, thinkingDeltaToSessionUpdate, etc.

agent.status.updated event           →    ACP UsageUpdate
─────────────────────────────────────────────────────────
event.contextTokens                  →    used
event.maxContextTokens               →    size
(cost tracking deferred)             →    cost (unset)

Both input fields are number | undefined (matching AgentStatusUpdatedEvent from packages/protocol/src/events.ts:483-495). Returns null when either is missing — callers silently skip degenerate events rather than pushing a zero-filled update.

agent.status.updated handler (packages/acp-adapter/src/session.ts)

A new branch in runTurnBody()'s onEvent chain catches agent.status.updated events:

  • Sub-agent events filtered by the existing isFromMainAgent() guard.
  • Builder called with event.contextTokens / event.maxContextTokens.
  • Non-null result pushed via conn.sessionUpdate() as fire-and-forget — same pattern as agent_message_chunk and agent_thought_chunk.
  • Push failures logged to log.warn; never crash the turn loop.

Exports (packages/acp-adapter/src/index.ts)

contextUsageToUsageUpdate added to the events-map re-export block, alongside the existing assistantDeltaToSessionUpdate, toolCallStartToSessionUpdate, etc.

Testing

  • plan-and-commands.test.ts: 7 new tests added (4 unit + 3 e2e)
    • Unit: valid notification builds correct { sessionUpdate: 'usage_update', size, used } shape; returns null for missing contextTokens, missing maxContextTokens, and both missing
    • E2E: main-agent agent.status.updated forwarded as usage_update; sub-agent events filtered out; events with missing fields skipped
  • Full suite green: packages/acp-adapter (36 files, 333 tests)
  • Manual: Zed 1.13.1 on macOS 24.3.0, local kimi-code build — sent "hi", circular indicator appeared showing ~20K baseline token consumption (system prompt + tool definitions)
image

…ification

Map agent.status.updated events to the ACP protocol UsageUpdate type
(size/used fields), dispatched as fire-and-forget session notifications
so ACP clients (Zed, JetBrains) can render a real-time context
consumption indicator.

- events-map.ts: add contextUsageToUsageUpdate() builder
- session.ts: subscribe to agent.status.updated in runTurnBody()
- index.ts: export new function
- plan-and-commands.test.ts: 7 tests (4 unit + 3 e2e)
@changeset-bot

changeset-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 894912a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44a2049415

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1101 to +1107
if (event.type === 'agent.status.updated') {
if (!isFromMainAgent(event)) return;
const update = contextUsageToUsageUpdate(
sessionId,
event.contextTokens,
event.maxContextTokens,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Forward usage updates after ACP compaction

When the user runs ACP /compact, prompt() routes to runBuiltInCommand/runCompactCommand instead of runTurnBody, so this newly added agent.status.updated handler is not installed. The core updates the context token count during compaction via emitStatusUpdated(), but runCompactCommand has its own event listener that ignores that event, leaving clients such as Zed showing the pre-compaction usage until a later normal prompt happens. Please share this forwarding with the command/compaction event path or emit a usage_update after compaction completes.

Useful? React with 👍 / 👎.

@iluv7 iluv7 Jul 31, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — runCompactCommand now pushes a one-shot usage_update via getStatus() after compaction completes. Best-effort with its own try-catch so a status refresh failure never turns a successful compaction into an error.

After compaction, the core updates context token counts via
emitStatusUpdated(), but the agent.status.updated handler only runs
inside runTurnBody().  Push a one-shot usage_update after compaction
completes so the client reflects the compacted context size immediately
instead of waiting for the next normal prompt.

Co-Authored-By: Claude <noreply@anthropic.com>
@iluv7
iluv7 force-pushed the feature/acp-context-window-display branch from 6c903df to 48d2674 Compare July 31, 2026 13:45
@iluv7

iluv7 commented Jul 31, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48d26746e7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/acp-adapter/src/session.ts Outdated
Comment on lines +973 to +978
const status = await this.session.getStatus();
const update = contextUsageToUsageUpdate(
this.id,
status.contextTokens,
status.maxContextTokens,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Keep /compact success independent of status refresh

When /compact succeeds but Session.getStatus() rejects or stalls after the compaction completion event, this new await throws out to runBuiltInCommand's catch after the success message has already been emitted, so ACP clients can see a spurious /compact failed for a completed compaction and the prompt response now depends on an optional usage refresh. Since the usage notification is best-effort like the following sessionUpdate call, wrap this status-read/update path in its own catch and leave the compaction result intact.

Useful? React with 👍 / 👎.

@iluv7 iluv7 Jul 31, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed — wrapped the status-read/update block in its own try-catch so a failed getStatus() never turns a successful compaction into a failure.

@iluv7
iluv7 force-pushed the feature/acp-context-window-display branch from 48d2674 to db9db41 Compare July 31, 2026 14:55
@iluv7

iluv7 commented Jul 31, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: db9db41936

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

contextTokens: number | undefined,
maxContextTokens: number | undefined,
): SessionNotification | null {
if (contextTokens === undefined || maxContextTokens === undefined) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid sending zero-sized usage updates

When a model/provider does not advertise a context-window capability, the SDK's v1 getStatus() normalizes that to maxContextTokens: 0, but this guard treats 0 as a valid ACP size. ACP clients compute the display percentage from used / size and the usage RFD says agents should skip usage_update when there is no meaningful context window size; after /compact or any status event carrying 0, this can push size: 0 to Zed/JetBrains and produce a bogus/undefined context indicator. Please skip maxContextTokens <= 0 as well.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already fixed — maxContextTokens <= 0 now returns null in that same commit. Also addressed the other review feedback:

  • Added pushContextUsage() so session load/resume/new pushes context usage immediately instead of waiting for the first prompt.
  • Wrapped the post-compaction status refresh in its own try-catch so a getStatus() failure doesn't turn a successful compaction into a failure.

iluv7 and others added 2 commits July 31, 2026 23:03
…sion setup

- Guard maxContextTokens <= 0 in contextUsageToUsageUpdate to prevent
  degenerate { size: 0 } updates, matching existing guards in
  formatStatusReport and emitStatusUpdated.
- Add AcpSession.pushContextUsage() (best-effort, typeof-guarded) and
  call it after newSession, loadSession replay, and resumeSession so
  clients see context usage immediately instead of waiting for the
  next active turn.
- Update session-new test to expect two getStatus calls (thinking
  effort resolution + pushContextUsage).
@iluv7

iluv7 commented Jul 31, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 894912a6cc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support displaying context length usage in Zed ACP like Codex

1 participant