/** * LiteLLM's spend log, read as a usage log. * * `from-claude-code` proved the pattern and `from-otel` generalised it: a pure * converter turns one tool's export into Trazum's usage-log records, and every * door prices it from there. LiteLLM is the gateway a great many teams already * put in front of every provider, so its `LiteLLM_SpendLogs` table is the one * export most likely to already exist on somebody's disk. * * **The format is derived, not guessed.** Every field below is read off * `litellm/proxy/schema.prisma` in BerriAI/litellm, model `LiteLLM_SpendLogs`. * A converter written from memory of an API is a converter that silently * mis-reads somebody's bill, and this project has one rule above all others * about numbers it cannot justify. * * ## What maps * * | LiteLLM | Trazum | * | --- | --- | * | `model` | `model` | * | `prompt_tokens` | `usage.input_tokens` | * | `completion_tokens` | `usage.output_tokens` | * | `startTime` | `ts` | * | `session_id` | `session` | * | `request_tags[0]`, else `metadata.tags[0]`, else `model_group` | `label` | * * ## What deliberately does not cross * * The row carries `messages` and `response` — the prompt itself and the * completion — plus `api_key` (hashed, still credential-shaped), * `requester_ip_address`, `user` and `end_user`. **None of it is read.** The * converter names the fields it takes and takes nothing else, and a fixture * plants a marker in each of them and greps the whole output. * * ## What it refuses to invent * * `cache_hit` is a flag and `cache_key` an identifier; neither is a token * count. A converted record therefore carries no cache split at all, and the * caching questions come back `cannot-tell` rather than answered from a * guess — the same refusal as inventing a price. `cacheFlagged` counts the * rows that said "hit" so the operator can see the gap is real rather than * empty. * * `spend` is LiteLLM's own priced figure and is **never** merged into * Trazum's catalogue-priced total. It is a second measurement of the same * calls, kept apart the way the store's provider-billed standing is kept * apart from the log's, and returned on its own so a caller who wants to * compare the two can, deliberately. */ /** One converted record, shaped exactly as `parseUsageLine` reads it. */ export interface LiteLlmRecord { model: string; ts?: string; label?: string; session?: string; usage: { input_tokens: number; output_tokens: number; }; } export interface LiteLlmConversion { records: LiteLlmRecord[]; /** Rows that were spend logs and converted. */ rows: number; /** Rows naming no model: counted, never guessed at, never dropped silently. */ unnamedModel: number; /** Rows carrying no token counts at all — a logged call nobody can price. */ noTokens: number; /** Rows LiteLLM marked as a cache hit, with no token split to act on. */ cacheFlagged: number; /** * LiteLLM's own total for the converted rows, in USD, or null when no row * carried one. **Never** added to anything Trazum computes: it is the * gateway's arithmetic over the gateway's price table, and merging two * price tables into one figure is how a report becomes quietly wrong. */ reportedSpendUsd: number | null; /** Lines or documents that did not parse as JSON at all. */ unparseable: number; } /** * Convert a LiteLLM spend-log export. * * Accepts a JSON array of rows, a single row, `{ data: [...] }` as the proxy's * own endpoints return it, or newline-delimited rows — so a `psql --json` * dump, an API response and a streamed capture all work. Pure over its input. */ export declare function litellmRecords(text: string): LiteLlmConversion; /** * Whether a file looks like a LiteLLM spend log, by shape. * * Deliberately narrow: `request_id` beside one of the two token columns, and * a field no other export in this project carries. A looser test would claim * an OpenAI usage response, whose rows also have `prompt_tokens`, and refuse * it in this file's words instead of letting the code that can read it try. */ export declare function looksLikeLiteLlm(text: string, prefixBytes?: number): boolean; //# sourceMappingURL=litellm.d.ts.map