anthropics / anthropics/claude-agent-sdk-typescript
[BUG] sum of output_tokens from "assistant" messages returned by query() doesn't equal output_tokens of the "result" message
- Langage dominant
- Shell
- Étoiles
- 1.8k
- Forks
- 226
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Description
### Bug Description
Cross-posting [this issue from claude-code](https://github.com/anthropics/claude-code/issues/39505) repository as this may be a better place for it.
When iterating over messages generated by the `query()` method of `@anthropic-ai/claude-agent-sdk,` I collect token usage data from the `message.usage` of each `assistant` message and sum their values. However, the total sum of all `output_tokens` doesn't equal the value of `output_tokens` in the final `result` message.
I'm using `@anthropic-ai/claude-agent-sdk` version `0.2.84`.
Model: `claude-opus-4-6`, but this happens for other models too.
I've followed the rules described in the https://platform.claude.com/docs/en/agent-sdk/cost-tracking documentation regarding skipping duplicate usages of messages with the same ID.
I discovered that when setting `includePartialMessages` to `true` and counting `output_tokens` from `stream_event` messages of type `message_delta` (instead of from `assistant` messages), I get the correct sum for `output_tokens`.
I've created a simple Node.js script available in [this gist](https://gist.github.com/smnh/5eda4495888e5adf21d9f887f807b58e) that calls `query()` with a simple prompt to test token usage and print the results.
**Running `query()` with `options.includePartialMessages: false`**
The sum of `output_tokens` from `assistant` messages doesn't equal the value of `output_tokens` in the final result message.
```
MESSAGE USAGE BREAKDOWN
==============================================================================
Message ID | Input | Cache Create | Cache Read | Output
------------------------------------------------------------------------------
msg_01Ea9T1t5eDLV7BZyVjd22bu | 3 | 2197 | 7233 | 30
msg_01NjzSe7a9fHiBq9nWNKWFLZ | 3 | 1137 | 9430 | 47
msg_013WH4Ksf9ZWSokidLhnypYq | 1 | 100 | 10567 | 1
------------------------------------------------------------------------------
Total | 7 | 3434 | 27230 | 78
------------------------------------------------------------------------------
type: result | 7 | 3434 | 27230 | 275
==============================================================================
TOKEN USAGE COMPARISON
========================================================
Token Type | Computed | Result
--------------------------------------------------------
✓ Input Tokens | 7 | 7
✓ Cache Creation Tokens | 3434 | 3434
✓ Cache Read Tokens | 27230 | 27230
✗ Output Tokens | 78 | 275 (diff: -197)
========================================================
✗ Discrepancies in token counts detected
```
**Running `query()` with `options.includePartialMessages: true`**
The sum of `output_tokens` ONLY from `stream_event` messages with event type `message_delta` equals the value of `output_tokens` in the final `result` message.
Tokens in brackets `[]` are ignored when computing totals.
```
MESSAGE USAGE BREAKDOWN
==============================================================================
Message ID | Input | Cache Create | Cache Read | Output
------------------------------------------------------------------------------
msg_01EdnokfMQShjSdfXjGvHivj | 3 | 2197 | 7233 | [24]
type: message_delta | [3] | [2197] | [7233] | 114
msg_01WN1oaCiJBx7yZTEUwHjENZ | 3 | 1662 | 8402 | [53]
type: message_delta | [3] | [1662] | [8402] | 97
msg_01YHKzFDhysvSK1BLRxenY1M | 1 | 254 | 10064 | [7]
type: message_delta | [1] | [254] | [10064] | 45
------------------------------------------------------------------------------
Total | 7 | 4113 | 25699 | 256
------------------------------------------------------------------------------
type: result | 7 | 4113 | 25699 | 256
==============================================================================
TOKEN USAGE COMPARISON
========================================================
Token Type | Computed | Result
--------------------------------------------------------
✓ Input Tokens | 7 | 7
✓ Cache Creation Tokens | 4113 | 4113
✓ Cache Read Tokens | 25699 | 25699
✓ Output Tokens | 256 | 256
========================================================
✓ All token counts match!
```
### What Should Happen?
When using `query()` with `options.includePartialMessages: false`, the sum of `message.usage.output_tokens` from all unique `assistant` messages (deduplicated by message ID, as documented in the cost tracking guide) should equal the `usage.output_tokens` of the final `result` message.
This matches the expected behavior for `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`, which all sum correctly, only `output_tokens` shows this discrepancy.
### Steps to Reproduce
Steps to Reproduce:
1. Run the provided [gist script](https://gist.github.com/smnh/5eda4495888e5adf21d9f887f807b58e) with `includePartialMessages` set to `false` (default in the script).
2. Observe the MESSAGE USAGE BREAKDOWN table - note the "Total" row showing summed `output_tokens` from all `assistant` messages.
3. Compare this total with the "type: result" row showing the final result message's `output_tokens`.
4. Check the TOKEN USAGE COMPARISON section at the bottom.
Expected Result:
- The "Total" and "type: result" rows should have matching `output_tokens` values.
- The script should print `✓ All token counts match!`
Actual Result:
- The `output_tokens` values don't match.
- The script prints `✗ Discrepancies in token counts detected`
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Évaluation
Cette issue n'a pas encore été évaluée.