UNPKG

@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

76 lines (75 loc) • 4.6 kB
/** * Reads token usage out of Grok Build's own session streams. * * Grok Build is xAI's official terminal coding agent (github.com/xai-org/ * grok-build, Rust, installed from x.ai/cli/install.sh as `grok`). An earlier * note in this folder said "grok" named no product, only eight competing npm * packages; it had searched npm for a Rust binary that is not distributed * there, and is retracted here. * * Layout, confirmed by running the real binary against a redirected home: * `$GROK_HOME/sessions/<url-encoded cwd>/<session-id>/`, defaulting to * `~/.grok`. Each session directory holds `updates.jsonl` — the CLI's own * documentation calls it the authoritative conversation log — plus * `summary.json`, `chat_history.jsonl`, `signals.json` and others. The walk * here reads exactly `<group>/<session>/updates.jsonl` and nothing deeper: * a session directory can also hold `compaction_checkpoints/`, and a * checkpoint that snapshots the stream would otherwise be counted twice. * * Each line is a JSON-RPC style record. The ones that matter are * `method: "_x.ai/session/update"` with `params.update.sessionUpdate === * "turn_completed"`; a completed turn that reached a model carries a `usage` * object with `inputTokens`, `outputTokens`, `cachedReadTokens`, * `cacheCreationTokens`, `reasoningTokens`, `modelCalls`, a per-model * `modelUsage` map and `numTurns`. A turn that failed before any model call * carries no `usage` at all, so it excludes itself. `stop_reason` is not an * eligibility test: a truncated or interrupted turn with a usage object was * still billed. A `usage` that is present but is not that ledger (empty, an * array, none of the counters) is a changed format: it is reported, not billed * as a request of zero tokens. * * What the numbers MEAN took a second real turn to settle, and the answer is * neither "per turn" nor "cumulative" but both, by process: * * turn 1 (fresh process) inputTokens 10141 numTurns 1 * turn 2 (`grok -r`, new one) inputTokens 11034 numTurns 1 * * The second record is not 21175, so the usage is not a session-lifetime * counter. But the CLI's own persistence code says the figure is the * process's live ledger, and computes a turn's cost as live minus the * previous live value when the ledger has only grown — a running total within * one process, reset when a new process resumes the session. A reader has no * process boundary to look at; what it has is `numTurns`, the ledger's own * turn counter. Strictly increasing, with every bucket at least as large, * means the same ledger, and the turn's usage is the difference from the * previous record. Anything else means a fresh ledger, and the whole record * counts. Both real records above have numTurns 1, so both count whole, which * is the measured truth. The in-process cumulative branch is taken from the * CLI's source, not from a measurement — headless `-p` runs are one prompt * per process, so no real stream on this machine exercises it. * * Duplicates: a prompt's terminal record can be re-emitted (the persistence * layer folds a late re-emission into the same turn). Dedup is by * `prompt_id`, scoped to the session directory — prompt ids are not * documented as globally unique — keeping the last record seen. A record * with no prompt id is keyed by its line. * * Cost is `unavailable`: the turn record carries no price, and Grok Build is * a subscription product whose custom-model configurations can point at any * OpenAI- or Anthropic-compatible endpoint — the real run here used DeepSeek. * Cache and reasoning counts are reported as stored; every real sample so far * has them at zero, so whether `cachedReadTokens` is a subset of * `inputTokens` has not been measured and nothing is subtracted or folded * until it has. Reasoning tokens in particular are NOT added to output: on the * OpenAI wire they are a subset of completion tokens, and adding them would * double count. * * Not read: the newer per-session `usage.json` the CLI writes from the same * ledger. No real run on this machine produced one — the 1.0.13 binary's * `grok usage` reports "No usage recorded" for these sessions — and a reader * written against a struct definition alone is the guessed-format failure * this folder keeps paying for. When a real file exists it belongs here as a * fallback for a session with no readable stream, never as an addition. */ import type { LocalUsageReader } from "../types/index.js"; export declare function createGrokReader(): Promise<LocalUsageReader>;