Skip to content

sessions: token totals carry no API cost #27

Description

@Mark-Life

Labels: enhancement


Problem:

A session shows how many tokens it burned and never what those tokens are worth. Someone on a Claude subscription knows the monthly fee and has no idea that one afternoon of agent work would have priced at $40 on the API — or $4. The number that makes people change how they work is the money one, and Peektrace has every input needed to compute it and does not.

Everything required is already parsed. Turn carries the model string alongside all four token classes that price differently:

// packages/core/src/services/sessions/schema.ts:151
export const Turn = Schema.Struct({
  requestId: Schema.String,
  ts: Schema.optional(Schema.String),
  model: Schema.String,
  contextTokens: Schema.Number,
  inputTokens: Schema.Number,
  cacheReadTokens: Schema.Number,
  cacheCreationTokens: Schema.Number,
  outputTokens: Schema.Number,
  eventIndexes: Schema.Array(Schema.Number),
});

AnalyzedSession (schema.ts:267) aggregates those into totalOutputTokens and peakCacheReadTokens, and stops there. No cost field exists anywhere in the analyzed output.

There is one exception that makes the gap sharper: the OpenCode reader lifts a cost straight off OpenCode's own SQLite rows at packages/core/src/services/sessions/opencode/reader.ts:189 and :397. So one agent reports cost because its storage happened to record it, and Claude, Codex and Pi report none — cost is passed through where it is handed over and derived nowhere.

Line numbers are against 9be1ea1.

Proposed solution:

A model-to-price table, applied per turn rather than per session, since the model can change mid-session and Turn.model already records which one ran. The four token classes must price separately — cache reads are roughly a tenth of input and cache creation is above it, so a flat input rate would misprice cached sessions badly, and cached sessions are most of them. Sum the turns into a session total on AnalyzedSession, then surface it next to the existing token totals in the TUI and the inspector.

Where OpenCode already reports its own cost, that stays authoritative and the computed figure is the fallback.

Open: where the price table lives and how it stays current. Models.dev publishes model pricing as a queryable JSON API, which is a candidate over a hardcoded table that rots — at the cost of a network dependency in a local-first tool, so it likely wants to be vendored with a refresh command rather than fetched at read time. Also undecided: whether an unrecognised model reports zero, reports nothing, or is a visible "unpriced" state, and whether subagent transcripts roll their cost up into the parent session or stay separate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions