@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
53 lines (52 loc) • 3.28 kB
TypeScript
/**
* Reads token usage out of Copilot CLI's local SQLite store.
*
* Store: `~/.copilot/session-store.db`. Usage lives on the
* `assistant_usage_events` table — one INSERT-only row per assistant turn,
* with `model`, `input_tokens`, `output_tokens`, `cache_read_tokens`,
* `cache_write_tokens`, `reasoning_tokens` and a `created_at` timestamp
* (ISO-8601 with a `Z` suffix). Confirmed no duplicate `(session_id,
* turn_index)` pair exists on a reference machine, so — like OpenCode's
* `message` table — this needs no dedup logic beyond the table's own
* uniqueness: every row is counted once, matching the `rowid-high-water-mark`
* strategy already established for that reader.
*
* The same database also holds a JSONL-adjacent `session.shutdown` event with
* its own `modelMetrics`/`tokenDetails` payload (written to
* `~/.copilot/session-state/*\/events.jsonl`, not this database). It was
* deliberately NOT used here: cross-checking real sessions confirmed the two
* sources report identical totals for the sessions they both cover, so
* combining them would double-count rather than add coverage. The SQLite
* table is the sole source; the tradeoff is a disclosed gap for any history
* that predates the table's introduction.
*
* `cache_read_tokens` and `cache_write_tokens` are both SUBSETS of
* `input_tokens`, not disjoint — confirmed arithmetically against a real
* `session.shutdown` record (session `c2c38d0b`): `tokenDetails.input.tokenCount
* = 3`, `cache_write = 24047`, and `usage.inputTokens = 24050` — exactly
* `3 + 24047`, with nothing left over for a separate additive interpretation.
* So `inputTokens` here is `input_tokens - cache_read_tokens -
* cache_write_tokens`, the same style of subtraction `codexReader.ts`,
* `qwenCodeReader.ts` and `geminiCliReader.ts` make for the same reason: this
* subsystem's `LocalUsageTotals.inputTokens` + `.cacheReadTokens` must sum to
* the true prompt size without double-counting. `reasoning_tokens` folds into
* output — Copilot's own SDK types (`ShutdownModelMetricUsage`) group it
* alongside `outputTokens` as a further breakdown of output, not a separate
* accounting bucket.
*
* Cost is deliberately `unavailable`. The table's own `request_multiplier`
* and `total_nano_aiu` columns are Copilot's request-quota accounting, not a
* USD figure — the SDK's own generated types tag the closest concept,
* `ShutdownModelMetricUsage.cost`, `@experimental`, and every real sample row
* on the reference machine had `request_multiplier: 0.0`. Modeling a
* per-token dollar figure from public list prices would also ignore that
* Copilot CLI is typically used under a flat-rate Copilot subscription, the
* same reasoning that keeps Codex's confidence `unavailable`. This holds even
* when the underlying model is a metered vendor's (e.g. `claude-haiku-4-5` on
* the reference machine) — Copilot's telemetry layer normalizes across
* backend vendors into its own accounting convention, and this reader has no
* way to tell whether a given row was billed by the minute, by the token, or
* not separately billed at all.
*/
import type { LocalUsageReader } from "../types/index.js";
export declare function createCopilotCliReader(): Promise<LocalUsageReader>;