Skip to content

[FEATURE] Honor provider-reported cost (usage.cost) from LLM gateways (OpenRouter, LiteLLM, Manifest) #43818

Closed

Description

@guillaumegay13

Problem

opencode computes message cost client-side: token counts × models.dev catalog rates in getUsage (packages/opencode/src/session/session.ts). The only provider-reported cost honored today is the hardcoded Copilot providerMetadata.copilot.totalNanoAiu special case.

LLM gateways/routers report the actual USD cost per request in the response usage block, and opencode ignores it:

  • OpenRouter: usage.cost + usage.cost_details (with usage: {include: true})
  • LiteLLM: include_cost_in_streaming_usage → usage.cost
  • Manifest (mnfst/manifest): stamps usage.cost on proxied OpenAI/Anthropic responses, streaming and non-streaming

For router models (openrouter/auto, manifest/auto, DigitalOcean Inference Routers) local catalog rates can never price the request correctly — the routed upstream model varies per request, so cost shows $0.00 or a wrong amount. Related: #39869, #34877, #40835.

Proposal

  1. Capture usage.cost into step providerMetadata. @ai-sdk/openai-compatible parses usage into its own schema and drops unknown keys like cost, so this needs either a custom fetch wrapper in opencode's provider layer (same pattern as existing per-provider fetch customizations) or an upstream AI SDK change to forward extra usage fields.
  2. Consume it in getUsage: generalize the Copilot branch — when provider metadata carries a reported USD cost, prefer it over catalog rates; fall back to local computation otherwise.
  3. No UI changes needed — assistantMessage.cost is already rendered in the TUI; it just needs the right value.

Notes

  • Works for streaming (final usage chunk) and non-streaming responses.
  • A reported cost of 0 is meaningful (flat-fee subscription routed request) and should still win over catalog rates.
  • Fixes cost display for OpenRouter users today, not just new gateways.

Activity

  1. guillaumegay13 commented on Aug 21, 2026

    @guillaumegay13
    Author

    Worth noting the pricing gap specifically for gateway auto router models — e.g. openrouter/auto, manifest/auto, and Kilo Gateway's auto routes. These have no static per-token price in models.dev because the underlying model varies per request, so local catalog computation always resolves to $0.00 for them regardless of what rates are added.

    The only source that can ever be correct for an auto route is the provider-reported usage.cost in the response. That reinforces the proposed getUsage change: prefer provider-reported cost when present (even 0 is meaningful for flat-fee subscription routes), and fall back to catalog rates otherwise.

  2. chris-prince commented on Oct 1, 2026

    @chris-prince

    This also affects pricing of all OpenRouter models with multiple providers.

    The catalog price is the model's cheapest endpoint, but requests are billed at whichever endpoint actually served them. Example: on deepseek/deepseek-v4.1-flash pinned to AtlasCloud ($0.141/M input vs the catalog's $0.0198/M), OpenCode showed $0.020 for a session that OpenRouter billed about $0.073.

    Thankfully, usage.cost matched AtlasCloud's rates exactly. So making the fix suggested above would fix this case too.

  3. rockad commented on Oct 1, 2026

    @rockad

    Confirming this on opencode v2.0.21 (Linux/WSL2, zsh, no plugins, openrouter provider), with a concrete reproduction for the auto router case.

    Catalog (models.dev) as consumed by opencode:

    • openrouter/free → cost: { input: 0, output: 0 }
    • openrouter/auto → cost: null

    What OpenRouter actually reports for the same two models (usage: { include: true }):

    openrouter/auto  → routed to z-ai/glm-5.3-flash                     → usage.cost = 0.0000046
    openrouter/free  → routed to nvidia/nemotron-3.5-content-safety:free → usage.cost = 0
    

    Observed in the TUI footer:

    • With openrouter/free, the footer shows $0.00.
    • With openrouter/auto, the footer shows no cost field at all.

    Persisted assistant messages (local session db, read-only) for an openrouter/auto session carry cost: 0 with populated tokens and providerState: null — the OpenRouter-reported cost is not persisted, consistent with getUsage computing from catalog rates only.

    Expected: prefer provider-reported usage.cost (including a reported 0) over catalog computation, as proposed. For auto routes this is the only source that can ever be correct, and it also fixes the multi-endpoint OpenRouter billing mismatch reported above.

    Environment: opencode v2.0.21 · Linux 6.18 (WSL2 alyx-wsl) · TERM=xterm-256color · COLORTERM=truecolor · shell zsh · no plugins configured.

  4. chris-prince commented on Oct 2, 2026

    @chris-prince

    The linked PR #52629 should fix the specific cases mentioned in this thread.

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