-
Notifications
You must be signed in to change notification settings - Fork 68
Description
Summary
codex-acp sends UsageUpdate notifications and can populate PromptResponse.usage, but UsageUpdate.cost is always null.
ACP clients cannot report cumulative session cost for Codex ACP sessions, and many render this as $0.00 — which is misleading because the data is unavailable rather than zero.
Current state
PromptResponse.usage: fixable incodex-acp(covered by Populate PromptResponse.usage from Codex token usage #210)UsageUpdate.used/UsageUpdate.size: available todayUsageUpdate.cost: alwaysnull
Root cause
The OpenAI Responses API does not return any cost or pricing information — only token counts (input_tokens, output_tokens, cached_tokens, reasoning_tokens, total_tokens). The upstream Codex event stream (TokenCountEvent) faithfully forwards these counts but carries no cost signal.
For comparison, the Claude Agent SDK exposes total_cost_usd on result messages, which is why claude-agent-acp can populate UsageUpdate.cost today.
Why this matters
ACP defines cumulative cost on UsageUpdate.cost, and clients (OpenHands, Zed, benchmark harnesses) already consume it when present. Without it:
- Benchmark runs cannot compare spend across ACP and non-ACP agents
- Client telemetry remains incomplete
- UIs show a misleading
$0.00instead of "unknown"
Upstream request
Filed openai/codex#16258 requesting that Codex expose an authoritative cumulative session cost in its event stream. Codex is the only component that knows the model, service tier, and billing method — making it the right place to compute cost. This is the ideal long-term fix.
Interim solution: derive cost from token counts
Until the upstream is addressed, codex-acp could compute an estimated cost locally using the token breakdown already available in TokenCountEvent and a model pricing table.
Available signals at the point where UsageUpdate is sent:
| Signal | Available | Source |
|---|---|---|
| Model name | Yes | self.get_current_model() |
| Input tokens | Yes | TokenCountEvent.info.last_token_usage |
| Cached input tokens | Yes | TokenCountEvent.info.last_token_usage |
| Output tokens | Yes | TokenCountEvent.info.last_token_usage |
| Reasoning tokens | Yes | TokenCountEvent.info.last_token_usage |
| Auth method | Yes | CodexAuthMethod (ChatGpt / CodexApiKey / OpenAiApiKey) |
| Service tier | No | Not exposed (see openai/codex#13794) |
Proposed approach:
- Maintain a pricing table mapping model slug → per-million-token rates (input / cached input / output / reasoning)
- On each
TokenCountEvent, compute incremental cost fromlast_token_usageand accumulate across the session - For
CodexAuthMethod::ChatGpt(subscription users): setcost: None— no meaningful per-token cost - For API-key auth: set
cost: Some(Cost::new(amount, "USD"))
Caveats:
- Service tier: Codex can reroute to different tiers with different pricing. Without a tier signal, this computes against base model rates — may undercount for
/fastmode. (Also tracked in openai/codex#13794.) - Pricing drift: model pricing changes occasionally, requiring table updates
- Cached input discount: OpenAI charges ~50% less for cached tokens on most models — known and can be applied
Even with these limitations, an estimate is significantly better than null / $0.00 for API-key users, and the field can be upgraded to the authoritative upstream signal once openai/codex#16258 is addressed.
Related
- PromptResponse.usage, UsageUpdate notifications, and InitializeResponse.agentInfo are not populated #165 — earlier telemetry umbrella issue
- Support session usage for codex-acp #167 — added session usage support (
used/size), cost still missing - Populate PromptResponse.usage from Codex token usage #210 — populates
PromptResponse.usage - openai/codex#16258 — upstream request for authoritative cost signal
- openai/codex#13794 — service tier not in session logs