Skip to content

desktop: session cost stays 0 after 2.2.0 upgrade while tokens are recorded #59634

Open

Description

@Aevienne

Summary

Sessions created after upgrading to 2.2.0 record token usage but persist cost = 0. The desktop app's Total Cost stays at $0.00 while a client that derives cost from tokens shows a real value for the same session.

Environment

  • opencode version: 2.2.0 (desktop app, bundled CLI 2.2.0)
  • OS: Windows 11, 10.0.26200, win32 x64
  • Terminal: desktop app (Electron), no terminal session
  • Shell: PowerShell 5.1 (tool shell)
  • Install/channel: desktop installer, latest
  • Active plugins: none configured. Unrelated: a stale plugin entry for opencode-plugin-opencoder still fails to install with 404.

Reproduction

  1. Install the OpenCode 2.2.0 desktop app on Windows and start a session using opencode-go/deepseek-v4.1-flash.
  2. Send prompts that call tools so usage accumulates.
  3. Inspect the session record: select cost, tokens_input, tokens_output, tokens_reasoning, tokens_cache_read from session_v2 where id = ?.
  4. Compare the desktop app's Total Cost with a mobile client showing the same session.

Expected Behavior

session_v2.cost should reflect price times usage, and the desktop Total Cost should match other clients for the same session.

Actual Behavior

cost = 0.0 for every session created after the 2.2.0 upgrade, while tokens are correct.

Example session, created after upgrading:

tokens_input      362370
tokens_output      53220
tokens_reasoning   85289
tokens_cache_read  37557248
cost               0.0

At the catalog price for deepseek-v4.1-flash (input $0.15/M, output $0.60/M, cache read $0.003/M) that usage is about $0.20, which matches what the mobile client shows for the same session. The desktop app shows $0.00.

select count(*) from session_v2 where time_created > <upgrade timestamp> and cost > 0 returns 0. The last session with a non-zero cost was created before the upgrade (5.9138). Sessions written by the earlier 1.18.x build recorded cost normally, so the regression lines up with 2.2.0.

Rows in session_message for assistant messages contain only agent, content, model, and time. No usage or cost field is present in the stored projection, so the persisted message has no computed price even though session_v2 aggregates the token counters correctly.

Additional Context

  • Usage capture works: input, output, reasoning, and cache read all aggregate correctly into session_v2.
  • Cost is the only missing value, and it is missing for all agents and both the default and max variants.
  • No custom providers, no plugins, no local models involved.
  • Raw detail available on request, session IDs and token counts can be shared without config contents.

Activity

  1. opencode-agent commented on Oct 27, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report and the database queries, they made this easy to trace.

    I think this is a duplicate of #59627, which reports the same thing on 2.2.0: opencode-go sessions (including deepseek-v4.1-flash) record their tokens normally but store cost = 0.

    The $0 comes from a deliberate change in 2.2.0. Since #58562, OpenCode stores the cost the OpenCode gateway reports for each request instead of estimating one from catalog prices. For OpenCode Go, usage within your plan is covered by the subscription, so the gateway reports cost: 0 and sends the amount of plan allowance used as a separate value. Your mobile client calculates cost from token counts at list prices, so it shows an estimate rather than what was charged, and that's why the two clients disagree. The non-zero costs from before the upgrade were also list-price estimates.

    This leaves the desktop app without a per-session figure for Go sessions. The request to show one (a list-price estimate or the allowance used) is tracked in #59627.

    Possible duplicates and related issues, ordered by likelihood:

    The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different, for example if it also happens with a provider other than OpenCode Go.

  2. Saad2012 commented on Oct 28, 2026

    @Saad2012

    Additional evidence narrowing this down, from the same setup (Windows 11 10.0.26200, desktop 2.2.0, opencode-go/deepseek-v4.1-flash, variant: max). Nothing here changes the report — it just scopes it: the failure is version-bound and provider-bound, and the catalog pricing is intact.

    1. The boundary is the app build, not the config

    select version, json_extract(model,'$.providerID'), cost from session_v2, grouped:

    version provider sessions sessions with cost > 0
    2.1.2 opencode-go 5 5
    2.1.4 opencode-go 4 4
    2.2.0 opencode-go 2 0

    Last Go session with a non-zero cost was created 2026-10-27T12:40Z; the first zero-cost one 2026-10-27T13:11Z — immediately after the 2.2.0 desktop build (published 2026-10-27T08:55Z). Token counters in the same rows aggregate correctly, so only cost breaks.

    2. It is specific to the Go provider; the cost engine still works

    A 2.2.0 session on the deepseek provider (own API key, pay-as-you-go) recorded cost = 0.002595636 for 17,270 input / 6 output tokens. So price resolution and accumulation are alive in 2.2.0. Only the opencode-go path persists 0.

    3. Pricing data is present, so this is not a missing-catalog problem

    In the kv table, models-dev:v2:catalog contains a full cost block for this model:

    "opencode-go" -> "deepseek-v4.1-flash"
    "cost": {
      "text": {
        "input":  { "price": 0.15, "cache": { "read": 0.003 } },
        "output": { "price": 0.6 }
      },
      "multipliers": [
        { "when": { "utc_days": { "in": ["mon","tue","wed","thu","fri"] },
                    "any": [ { "utc_hours": { "gte": "01:00", "lt": "04:00" } },
                             { "utc_hours": { "gte": "06:00", "lt": "10:00" } } ] },
          "factor": 2 }
      ]
    }

    The catalog entry is healthy; the 2.2.0 write path simply does not apply it for this provider.

    4. The pre-2.2.0 formula reproduces exactly

    This may be useful for restoring it. For one assistant message (16,803 input, 122 output, 396 reasoning, 0 cache read) written by 2.1.2, the stored value is 0.00283125:

    16,803 × 0.15 / 1e6        = 0.00252045
    (122 + 396) × 0.60 / 1e6   = 0.00031080
                                 ------------
                                 0.00283125   <- exact match
    

    So 2.1.x billed input at the input rate, output + reasoning at the output rate, cache reads at the cache rate, and applied the 2× peak multiplier by UTC window.

    5. Possible lead

    The bundled CLI's embedded migrations contain 20261024002554_session_allowance (adds session_v2.allowance real DEFAULT 0 NOT NULL) immediately followed by 20261024175301_drop_session_allowance (drops the same column). The shipped schema has no allowance column. That is the Go allowance accounting path being reworked two days before 2.2.0 shipped, which fits a regression that starts exactly at this build and only affects Go.

    Impact on a real session

    A Go session with 121,910 input, 13,828 output, 14,833 reasoning and 6,401,024 cache reads persists cost = 0.0 while the desktop footer shows $0.00; at peak rates that usage is ≈ $0.11. Users on the Go plan have no per-session signal of what they are drawing down from the monthly allowance — which is exactly the figure that plan meters.

    (Redacted: no API keys, session IDs, prompts, or workspace identifiers are included above.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions