Skip to content

ACP PromptResponse.usage reports only the turn's final assistant message #41660

Closed

Description

@cameronalizadeh-distyl

Description

ACP documents PromptResponse.usage as "Token usage for this turn", but OpenCode fills it
from the turn's final assistant message only. Each tool-call step gets its own assistant
message (session/prompt.ts:1188), so a turn with N tool calls reports 1 of N+1 model
requests.

Measured on a 3-tool-call turn (4 requests) — reported vs summed from opencode export:

reported: input=1 output=15  cache_read=11439 cache_write=140
actual:   input=6 output=232 cache_read=33894 cache_write=11579

The reported row is byte-identical to the final request's. The skew is uneven — the first
request pays the large cache write — so any hit rate derived from it reads high, 98.8% vs
74.6% here. Single-request turns are exact.

buildUsage (packages/opencode/src/acp/usage.ts:90) takes a single message;
totalSessionCost just below it already reduces over the list, and the cost path accumulates
where the token path assigns (session/processor.ts:444-445).

Happy to PR this. Should the sum be bounded to the initiating user message, and do subtask
and compaction messages (same session, same parentID) count toward the turn?

Plugins

none

OpenCode version

1.18.16

Steps to reproduce

  1. Drive opencode over ACP and send a prompt that makes at least one tool call.
  2. Read PromptResponse.usage from the session/prompt response.
  3. Run opencode export <sessionID> and sum tokens across the turn's assistant messages.
  4. The value from step 2 equals the final message's row, not the sum.

The aggregation half also reproduces without a model:
UsageService.buildUsage(UsageService.latestAssistantMessage(messages)) returns the last
message's tokens by construction.

Screenshot and/or share link

No response

Operating System

macOS 26.5 (Darwin 25.5.0)

Terminal

n/a — driven over ACP, not the TUI

Activity

  1. Ehesp commented on Sep 27, 2026

    @Ehesp

    Still reproduces on 1.18.32 (latest), and promptResponse on dev (b471c2b) still builds usage from the final assistant message only (UsageService.buildUsage(info) in packages/opencode/src/acp/service.ts).

    Another data point, with a different provider (google/gemini-3.8-flash, driven over ACP). Prompt: write two files with two shell commands, cat both, then summarise. That's 4 model requests.

    PromptResponse.usage:              input=8,559   output=25
    opencode export, 4 step-finish parts summed:  input=33,942  output=117
    

    The reported numbers equal the last request's row, as described above.

    #42489 fixes exactly this: it sums the turn's assistant messages and has tests. It was closed by the automated stale-PR cleanup, not in review. Could a maintainer reopen it and take a look? Happy to test it against this repro.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions