Skip to content

opencode adapter appends cumulative turn cost once per step, over-counting multi-step turns #1036

Description

@EvolveAegis

Bug Description

The opencode adapter's message.updated handler (src/adapters/opencode/plugin.ts:544-579) fires on every step-finish within a turn. The event's .cost is the CUMULATIVE turn cost (the comment at plugin.ts:558-564 states "cost is cumulative for the turn"). Each firing calls db.insertEvent(sessionId, usageEvent), which INSERTs a new agent_usage row (src/session/db.ts:1185). The dedup check (checkDuplicate, keyed on type + data_hash over the last 5 events, db.ts:1175-1178) does not hit because the data string includes the per-step token snapshot, which changes each step.

Result: a 3-step turn writes 3 agent_usage rows, each carrying the cumulative cost so far (e.g. $0.02, $0.04, $0.05). The events are forwarded to the platform with cost_usd in the top-level envelope (src/session/extract.ts:1898, 1941), where the natural additive reading sums them to $0.11 instead of the true $0.05.

The code comment claims "re-emitting is idempotent at the cost column", but there is no cost-column update: each firing appends a row. This is the same cumulative-cost class that the task-usage path explicitly guards against by stripping cost_usd and tagging usage_scope="task_cumulative" (src/session/extract.ts:56-59); the opencode adapter reintroduces it.

Steps To Reproduce

  1. Configure context-mode with the opencode adapter.
  2. Run a turn that triggers multiple steps (e.g. a tool-calling turn with 3 model calls).
  3. Observe: agent_usage events in session_events : one row per step, each with the cumulative cost_usd.
  4. Sum cost_usd across the rows for the turn (the natural additive reading, and what the platform receives): the total exceeds the turn's actual cost.

Expected Behavior

The turn's cost should be emitted exactly once (or as deltas), so additive aggregation yields the true cost.

Actual Behavior

Multi-step turns emit one cumulative-cost row per step; additive aggregation over-counts by the sum of the intermediate cumulative values.

Environment

  • context-mode main (e27c143)
  • opencode adapter
  • macOS 15

Suggested fix

Emit the usage event once per turn (e.g. only on the final step-finish / message completion), or upsert/replace the previous agent_usage row for the same assistant message, or store per-step deltas instead of cumulative values on multi-fire rows. Update the misleading "idempotent at the cost column" comment either way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions