fix: [#836] always emit tokens_input_total + document token semantics
What does this PR do?
Resolves the "Anthropic tokens_input=0 broken" false-positive from telemetry-2026-05-21 (54k Sonnet generations). The field was working as designed — full cache hits legitimately produce tokens_input=0 because tokens_input is normalized to mean uncached input tokens only across providers. The dashboard query needed the inclusive tokens_input_total field, but it was emitted conditionally and absent on non-cache-using providers — making queries return null and reinforcing the confusion.
Three changes:
session/processor.ts— drop the conditional emit, always includetokens_input_total. ~12 bytes per event, negligible.telemetry/index.ts— tighten the schema fromtokens_input_total?: numbertotokens_input_total: number. The always-present contract now lives in the type system.telemetry/index.ts— add a doc-block above thegenerationevent type explicitly documenting the cross-provider semantics. Single biggest documentation gap surfaced by the May 21 triage.
Type of change
- Bug fix (non-breaking change which fixes an issue)
Issue for this PR
Closes #836
How did you verify your code works?
tsgo --noEmit: passbun test test/session/session-getusage.test.ts: 7 pass / 0 fail (new test file)bun test test/session/session-getusage.test.ts test/session/compaction.test.ts test/altimate/training-import.test.ts: 41 pass / 0 fail- Marker check: pass —
altimate_changemarkers applied - 7 new tests pin the cross-provider normalization invariant:
tokens.input + tokens.cache.read + tokens.cache.write === tokens.inputTotal— across Anthropic-style (uncached) and OpenAI-style (inclusive) usage shapes
Checklist
- My code follows the project's code style
- I have performed a self-review of my own code
- My changes generate no new warnings
- I have added tests that prove my fix is effective
- New and existing unit tests pass locally with my changes
- Marker check passes
- Linked to issue #836
Files changed (3):
packages/opencode/src/altimate/telemetry/index.ts— schema doc + tighten typepackages/opencode/src/session/processor.ts— always emitpackages/opencode/test/session/session-getusage.test.ts(new) — 7 invariant tests
Expected impact: Dashboard queries get tokens_input_total on every generation event without null-coalescing. The "Anthropic tokens_input=0 broken" finding disappears once dashboards switch to tokens_input_total for input volume queries. No behavior change for cost calculation.
P0 series progress (telemetry-2026-05-21):
- #827 / #828: finops_* 100% failure
- #830 / #831: project_scan 32% errors
- #832 / #833: build agent 0% completion
- #834 / #835: todowrite runaway
- #836 / this PR: tokens_input semantics
Summary by cubic
Always emit tokens_input_total, clamp negative derived inputs to zero, and document cross‑provider token semantics so input volume queries are reliable and costs never go negative. Resolves #836.
-
Bug Fixes
- Always emit
tokens_input_totalinsession/processor.ts. - Tighten
telemetry/index.tstotokens_input_total: numberand clarifycache_writesemantics (Anthropic/Bedrock/Venice only; OpenAI/OpenRouter is a no‑op). - Clamp uncached input to 0 in
session/index.tsto prevent negative cost when provider counts are inconsistent. - Add tests covering Anthropic/OpenAI,
@ai-sdk/google-vertex/anthropic, Bedrock, and Venice; harden telemetry/processor tests to includetokens_input_total.
- Always emit
-
Migration
- Update dashboards to use
tokens_input_totalfor input volume. - No changes needed for cost calculations.
- Update dashboards to use
Summary by CodeRabbit
-
Improvements
- Total input tokens are now always reported for generation events, improving telemetry consistency.
- Adjusted input token counts are clamped at zero to prevent negative values and incorrect cost calculations.
- Token accounting preserves the invariant: input + cache.read + cache.write == inputTotal.
-
Tests
- Added comprehensive tests covering token normalization, cache accounting, edge cases and multi-provider scenarios.