Skip to content

[FEATURE] Client-side token estimate fallback when a provider omits usage stats (Ollama Cloud kimi-k3:cloud shows 0 tokens) #39144

Closed as not planned

Description

@hardes11

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).

  1. Start a session on ollama/kimi-k3:cloud and run a few turns (e.g. a /start bootstrap that triggers several model generations).
  2. The TUI Context panel shows 0 tokens, 0% used, $0.00 spent regardless of how much was generated.
  3. 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

Activity

  1. Gr33n93 commented on Sep 1, 2026

    @Gr33n93

    Additional reproducible case: the same misleading zero occurs when usage is only partially reported.

    Environment:

    • OpenCode 1.18.25
    • custom @ai-sdk/openai-compatible provider
    • llama.cpp server build b10719-5d4a3be26
    • a Qwen reasoning model returning message.reasoning_content

    The 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 reasoning part, but records reasoning: 0. In a separate controlled run, the persisted NDJSON contained an 8,327-character reasoning part while its step_finish reported:

    {
      "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 usage object. When a non-empty reasoning part exists but the provider omits completion_tokens_details.reasoning_tokens, 0 is 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 unknown would avoid misleading telemetry. A marked client-side estimate could follow later. Exact token accounting should remain provider-reported where available.

  2. Tarquinen commented on Oct 20, 2026

    @Tarquinen
    Member

    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 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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