@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
TypeScript
/**
* 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>;