/** * Session accounting and model availability. * * A deliberate limit shapes this module: subscription quota — how much of a plan is left, when * it resets — is only knowable from the provider's own account API. Claude Code can show that * because Anthropic serves it for its own plans. A router in front of a dozen vendors returns no * rate-limit headers at all (checked: none), and its management API refuses the key a session * holds. So nothing here guesses at a balance. What is shown is measured: tokens actually spent * this session, context actually consumed against the window, budget actually used against the * cap, and whether a model answered when it was last asked. */ export interface SessionUsage { turns: number; promptTokens: number; completionTokens: number; totalTokens: number; startedAt: number; /** Milliseconds spent waiting on the model, as opposed to wall clock. */ apiMs: number; filesChanged: string[]; } /** * Context window for a model, or null when it is not known. Null is returned rather than a * guess: a bar drawn against an invented denominator is worse than no bar. */ export declare function contextWindowFor(model: string): number | null; export type ModelState = 'ok' | 'no-credit' | 'unauthorized' | 'unsupported' | 'limited' | 'unknown'; export interface ModelStatus { model: string; state: ModelState; detail?: string; checkedAt: number; /** * The largest prompt this model has been PROVEN to accept, and the smallest it has refused. * * Learned rather than guessed, and remembered, because rediscovering it costs a turn every time. * A gateway alias reports the window of the biggest model behind it — 1,048,576 for one that * refuses at 4,096 — so the reported number is not evidence about the model that will actually * serve the next request. A refusal is. * * Kept as a pair so the truth can only get sharper: a refusal lowers the ceiling, a success * raises the floor, and neither can be undone by a number somebody else advertised. */ acceptedTokens?: number; refusedAtTokens?: number; } export declare function readModelStatus(home?: string): Record; export declare function writeModelStatus(all: Record, home?: string): void; /** * What is known about how much this model actually takes. * * Deliberately not subject to the status TTL. A rate limit goes away in half an hour; a model's * context window does not, and forgetting it every thirty minutes would mean paying for the same * discovery several times an afternoon. */ export declare function learnedWindow(key: string, home?: string): { accepted?: number; refusedAt?: number; }; /** * Writes down that a prompt of this size was refused. * * Only ever lowered. Two models behind one alias will refuse at different sizes, and the useful * number to remember is the smallest — being cautious costs a slightly leaner prompt, while being * optimistic costs a failed turn. */ export declare function noteRefusedAt(key: string, tokens: number, home?: string): void; /** * Writes down that a prompt of this size went through. * * Only ever raised, and it clears a refusal it disproves — a runtime restarted with a bigger window * is a real thing, and a remembered ceiling that is no longer true would keep the prompt lean for * no reason for ever. */ export declare function noteAcceptedAt(key: string, tokens: number, home?: string): void; /** A cached status, unless it has gone stale. */ export declare function cachedStatus(key: string): ModelStatus | undefined; export declare function recordStatus(key: string, state: ModelState, detail?: string): void; /** * Classifies what a provider said into a state a user can act on. * * Gateways report an exhausted account in several shapes — an HTTP 401 whose body mentions * credits, or a perfectly successful completion whose *content* is "You have run out of * credits". Both mean the same thing to somebody deciding which model to pick. * * The order of these tests carries the meaning. `insufficient_quota` has to be read before the * general mention of a quota, because the two call for opposite responses: a rate limit clears if * you wait, while an exhausted account never will, and calling the second one "limited" invites a * user to keep retrying a model that cannot answer. This is not hypothetical — a free model here * returns exactly `{"code":"insufficient_quota"}`, inside a 200 stream, and was being filed as a * passing rate limit. */ export declare function classifyResponse(status: number | undefined, text: string): ModelState; /** How a state reads in a list, kept short enough to sit beside a model name. */ export declare function stateLabel(state: ModelState): string; /** * A proportion drawn as a bar. Uses eighth-blocks so a value can move without the bar changing * length, which keeps a column of them aligned. */ export declare function bar(fraction: number, width?: number): string; /** * How wide the UI should draw. * * It used to be capped at 120 columns, which left more than half of a 240-column window empty. * The default is now the full terminal; `maxWidth` exists for anyone who prefers a narrow measure * on a very wide screen. A 40-column preference keeps a normal split pane readable, but never * exceeds the actual terminal: forcing 40 into a 12-column pane wraps every Ink frame and leaves * stale copies behind. A reported width of 0 falls back to 80 rather than collapsing the layout. */ export declare function computeUiWidth(termCols: number | undefined, maxWidth?: number): number; /** "1.2k", "18.4k", "200k", "1M", "204" — token counts as people quote them. */ export declare function humanTokens(n: number): string; /** "2m 14s", "45s" — a duration at the precision anyone reads it. */ export declare function humanDuration(ms: number): string; /** What a provider's model listing says about one model, where it says anything at all. */ export interface ModelInfo { id: string; vendor: string; /** * Priced at zero by the provider — inferred from the id, which is where gateways mark it. * * Kept for callers that only ask "is this one of the free ones". It is not evidence that a model * COSTS anything when false: see `cost`. */ free: boolean; /** * What is actually known about paying for it. * * Undefined means nothing is known, which is the commonest case and must be shown as silence * rather than as "paid". Saying "paid" about a model whose price nobody reported is inventing a * fact about somebody's bill — reported after a list of Ollama models on a LAN box, every one of * them labelled paid. */ cost?: 'free' | 'paid' | 'local'; /** Dollars per million prompt tokens, when the provider reported a price. */ promptRate?: number; contextLength?: number; maxOutput?: number; toolCalling?: boolean; reasoning?: boolean; /** * Whether it accepts images. * * Undefined means unknown, which is different from false: a gateway that reports nothing about a * model should not have "cannot see" invented on its behalf. */ vision?: boolean; } export declare function looksVision(id: string): boolean; /** * An alias, rather than a model. * * A gateway resolves one per request, so what serves it can differ between two messages — which is * exactly how a session that had been working all day fails the moment an image is attached. * Nothing about an alias can be assumed, including whether it sees. */ export declare function looksAlias(id: string): boolean; /** * Gateways signal a zero-cost model in the only place the OpenAI listing schema leaves them: * the id. `:free` and `-free` are the two spellings in use. */ export declare function looksFree(id: string): boolean; /** * A price, if the listing carried one. * * Gateways that report pricing disagree about where and in what unit: OpenRouter nests it under * `pricing` as a per-token string, others use `input_cost_per_token`, and a few give dollars per * million. All of them mean the same thing, and a zero from any of them means free — which is a * fact, unlike the absence of a price, which means nothing at all. */ export declare function reportedPromptRate(raw: Record): number | undefined; /** Reads whatever a listing entry actually carries, without inventing the parts it omits. */ export declare function modelInfoFrom(raw: Record, fallbackVendor: string): ModelInfo; /** * Lines added and removed since a tree hash, straight from git. * * Counting edits as the agent makes them would drift — an edit later reverted, or a file written * twice, would each be counted twice. Comparing two states cannot drift, because it ignores the * journey between them. * * The comparison is tree against tree, never tree against the working directory. `git diff * ` consults the real index to decide which paths are tracked, so every untracked file the * snapshot captured comes back as a deletion — which reported 2102 lines removed for a session * that had changed nothing. Snapshotting both sides the same way removes the index from the * question entirely. */ export declare function diffStatSince(cwd: string, baseTree: string | null): Promise<{ added: number; removed: number; files: number; } | null>; //# sourceMappingURL=usage.d.ts.map