Repository navigation
Description
Summary
When a provider's response omits the usage block entirely, OpenCode records 0 tokens / 0% / $0.00 for the session and shows it in the TUI — with no client-side fallback estimate. New / minimal providers that don't yet emit usage stats are rendered invisible in the token counter and context-% meter.
OpenCode version
1.18.7 (TUI, Linux)
Reproduction
Provider: Ollama Cloud (ollama provider), model kimi-k3:cloud (released ~1 hour before this report).
- Start a session on
ollama/kimi-k3:cloudand run a few turns (e.g. a/startbootstrap that triggers several model generations). - The TUI Context panel shows
0 tokens,0% used,$0.00 spentregardless of how much was generated. - Inspect the session DB:
sqlite3 -readonly ~/.local/share/opencode/opencode.db \
"SELECT substr(id,1,16), model, tokens_input, tokens_output, cost
FROM session ORDER BY time_created DESC LIMIT 6"Actual (one kimi-k3 session that completed 19 real assistant turns):
ses_05bc182d5ffe | {"id":"kimi-k3:cloud","providerID":"ollama"} | 0 | 0 | 0.0
ses_05bbb9584ffe | {"id":"glm-5.2:cloud","providerID":"ollama"} | 3271199 | 21691 | 0.0
At the message level the per-turn tokens object is {"total":0,"input":0,"output":0,"reasoning":0,"cache":{"write":0,"read":0}} — i.e. no usage was populated, not even a partial one. The model responded normally (19 assistant messages with content were persisted); only the usage telemetry is missing.
Contrast (same provider, same OpenCode build, different model)
ollama/glm-5.2:cloud over the same ollama provider records full usage correctly (millions of tokens across many sessions). So this is not a provider-adapter parse regression in general — it's specific to a model whose response omits the usage block. kimi-k3:cloud is brand-new; Ollama Cloud appears to ship new models before wiring usage reporting on the server side.
The gap
OpenCode records exactly what the provider returns. When the usage block is absent, every field defaults to 0 and the TUI displays a misleading 0% / 0 tokens, with no indication that the provider simply didn't report usage. (Cost being $0.00 is expected for subscription providers like Ollama Cloud; the token/percent zeros are the problem.)
Proposal
When a provider returns no usage stats for a turn, fall back to a client-side estimate so the context-% meter and token counter keep working:
- Estimate input tokens from the prompt via a tokenizer (or a cheap heuristic — chars/4). Output tokens can be counted from the streamed completion text directly (this is exact, no tokenizer needed).
- Mark the estimate distinctly in the UI (e.g. an
~prefix or a tooltip "estimated — provider did not report usage") so it's not confused with provider-reported numbers. - Alternatively (lower-effort): when usage is absent, show "usage not reported by provider" instead of
0, so users aren't misled into thinking nothing happened.
Related
- Token counter broken in Desktop App with Synthetic provider (cost stuck at $0, usage at 0%, tokens frozen) #39092 — same symptom (tokens frozen at 0, $0, 0%) but on Desktop with the Synthetic provider; the reporter's own hypothesis is "the provider may not return token usage metadata." Same root gap, different provider — confirms this is a general cross-provider issue, not kimi-k3-specific.
- OpenAI-compatible providers report zero tokens_cache_read despite upstream returning cached_tokens #34022 — OpenAI-compatible providers report zero
tokens_cache_readdespite upstream returningcached_tokens(a parsing gap on the openai-compatible path). Adjacent: both are about OpenCode's usage-tracking fidelity for openai-compatible/Ollama-style providers.
Activity
Gr33n93 commentedon Sep 1, 2026
Additional reproducible case: the same misleading zero occurs when usage is only partially reported.
Environment:
1.18.25@ai-sdk/openai-compatibleproviderb10719-5d4a3be26message.reasoning_contentThe server response includes normal aggregate usage, but no
completion_tokens_details.reasoning_tokens:{ "message": { "content": "OK", "reasoning_content": "The user is asking me to just say ..." }, "usage": { "prompt_tokens": 10500, "completion_tokens": 20, "total_tokens": 10520, "prompt_tokens_details": { "cached_tokens": 0 } } }OpenCode correctly creates a non-empty
reasoningpart, but recordsreasoning: 0. In a separate controlled run, the persisted NDJSON contained an 8,327-character reasoning part while itsstep_finishreported:{ "tokens": { "total": 25367, "input": 4, "output": 2983, "reasoning": 0, "cache": { "write": 0, "read": 22380 } } }This reproduced across four reasoning variants (
low,medium,high,max): every response had visible reasoning (6,275 to 15,345 characters), while every step reported zero reasoning tokens.This suggests the fallback should also cover individual missing usage subfields, not only a wholly absent
usageobject. When a non-empty reasoning part exists but the provider omitscompletion_tokens_details.reasoning_tokens,0is semantically wrong: it means "provider did not report the split", not "the model used no reasoning".Even a first-stage UI/data distinction such as
unknownwould avoid misleading telemetry. A marked client-side estimate could follow later. Exact token accounting should remain provider-reported where available.Tarquinen commentedon Oct 20, 2026
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (
opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊