Skip to content

feat: populate usage telemetry in PromptResponse and UsageUpdate#166

Closed
simonrosenberg wants to merge 2 commits intozed-industries:mainfrom
simonrosenberg:feat/telemetry-usage
Closed

feat: populate usage telemetry in PromptResponse and UsageUpdate#166
simonrosenberg wants to merge 2 commits intozed-industries:mainfrom
simonrosenberg:feat/telemetry-usage

Conversation

@simonrosenberg
Copy link

Summary

  • Handles EventMsg::TokenCount events (previously ignored with a "TODO" comment) to extract token usage data from the Codex engine
  • Sends UsageUpdate session notifications with cumulative token counts and context window size
  • Returns populated Usage in PromptResponse (input tokens, output tokens, cached input tokens, reasoning tokens, total tokens)
  • These fields are gated behind the unstable_session_usage feature flag in agent-client-protocol, which codex-acp already enables via features = ["unstable"]

Details

The Codex engine emits EventMsg::TokenCount events containing TokenUsageInfo with:

  • total_token_usage: TokenUsage — cumulative session totals
  • last_token_usage: TokenUsage — per-turn counts
  • model_context_window: Option<i64> — context window size

These events were being ignored with a comment: "In the future we can use this to update usage stats". This PR implements that future:

  1. TokenCount handler extracts total_token_usage and builds an ACP Usage object, stores it in PromptState.last_usage
  2. UsageUpdate notification is sent via SessionUpdate::UsageUpdate with token totals and context window
  3. TurnComplete handler passes last_usage back through the response channel alongside StopReason
  4. CodexAgent::prompt() attaches the Usage to the PromptResponse via .usage()

Test plan

  • All existing tests updated to destructure the new (StopReason, Option<Usage>) return type
  • cargo build — requires Rust toolchain (not available in dev environment, but types and patterns follow existing code exactly)
  • cargo test — existing tests should pass unchanged (usage is None in mock scenarios)
  • Integration test with real Codex inference to verify non-zero token counts

Resolves #165

🤖 Generated with Claude Code

…fications

The ACP protocol defines `PromptResponse.usage` and `UsageUpdate` session
notifications (gated behind the `unstable_session_usage` feature), but they
were never populated. Clients relying on these fields for benchmarking
cost/token tracking received empty data.

This change:
- Handles `EventMsg::TokenCount` events instead of ignoring them
- Extracts `TokenUsageInfo` (total token counts, context window) and
  builds an ACP `Usage` object with input/output/cached/reasoning tokens
- Sends `UsageUpdate` session notifications when token counts arrive
- Returns the `Usage` object in the `PromptResponse` at turn completion

Resolves zed-industries#165

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@simonrosenberg simonrosenberg marked this pull request as draft February 24, 2026 12:08
…tive totals

UsageUpdate.used should represent "tokens currently in context" — the
actual context window utilization. The previous implementation passed
total_tokens (cumulative session total of input+output+cached+reasoning)
which has two problems:

1. It was cumulative across all turns, so after N turns it showed N*X
   tokens even though the actual context was only X tokens
2. It included output and reasoning tokens, which are the model's
   response, not context window consumption — this could make used
   exceed size (e.g., 210K used / 200K size) which is misleading

Now uses last_token_usage (per-turn) with only input + cached_input
tokens, which reflects the actual context sent to the model.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@simonrosenberg
Copy link
Author

Closing in favor of #167 by @josevalim — his approach is cleaner: uses the canonical tokens_in_context_window() method and correctly guards against size: 0. The PromptResponse.usage population from this PR can be added as a follow-up if needed.

@josevalim
Copy link
Contributor

Oops, I didn't see there was already an open PR. In any case, I do think mine is clearer for the usage bits but it doesn't do the token bits. Perhaps you may want to submit that as a PR once mine is merged!

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.

PromptResponse.usage, UsageUpdate notifications, and InitializeResponse.agentInfo are not populated

2 participants