/** * @packageDocumentation * EXT-161 — **the one parser for a configured token budget.** * * A token budget is written by a human in one of three forms, and this module is the only place * that knows how to read any of them: * * - a plain count — `300000`, or the string `"300000"`; * - a suffixed count — `"300K"`, `"0.9M"`, `"1.5k"`; * - a fraction of the model's context window — `"80%"`. * * **`K` is 1000 and `M` is 1,000,000 — decimal, never binary.** The number is compared against * provider token counts, and every provider counts tokens in decimal, so a `K` that meant 1024 * would put a quiet 2.4% error between what the user wrote and what the guard enforced. * * **Why one parser and not two.** The same grammar is accepted by the `autocompact` config key and * by the in-session `/autocompact` command. Written twice they would agree on the day they were * written and drift afterwards, so both call sites import {@link parseTokenBudget} and there is no * second implementation to drift from — `packages/core/spec/tokenBudget.spec.ts` pins the grammar * and `packages/agent/spec/autocompactSlashCommand.spec.ts` pins that the command reaches this * function rather than a copy of it. * * **A malformed value is an error that names the text, and never a number.** The failure this * guards against is a bad value silently becoming `NaN`, `0` or LangChain's 4097 default: each of * those is a threshold the user cannot see and did not choose, and a wrong-but-silent threshold is * worse than no compaction at all. */ /** `K` — decimal thousand. Not 1024: provider token counts are decimal everywhere. */ export declare const TOKEN_BUDGET_THOUSAND = 1000; /** `M` — decimal million, for the same reason as {@link TOKEN_BUDGET_THOUSAND}. */ export declare const TOKEN_BUDGET_MILLION = 1000000; /** * A parsed token budget: either an absolute count, or a fraction of a context window that is not * known until a model is resolved. * * The two stay distinct through parsing and are collapsed to one number by * {@link resolveTokenBudget}, because only the caller knows the window — and because a fraction * whose window is unknown must resolve to "no threshold" rather than to a guess. */ export type TokenBudget = { kind: 'tokens'; tokens: number; } | { kind: 'fraction'; fraction: number; }; /** * The error a malformed budget raises, carrying the offending text so the message can name it. * * A distinct class rather than a bare `Error` so config validation can recognise it and turn it * into a field-scoped validation issue without string-matching a message. */ export declare class TokenBudgetError extends Error { /** The text exactly as the user wrote it, for a message that quotes them back. */ readonly offendingValue: string; constructor(offendingValue: string, detail: string); } /** The human-readable list of accepted forms, appended to every rejection so the fix is on screen. */ export declare const TOKEN_BUDGET_FORMS: string; /** * Parse a configured token budget into a {@link TokenBudget}. * * Accepts a `number` (an absolute count) or a `string` in any of the documented forms. Throws a * {@link TokenBudgetError} naming the offending text for everything else — including the values * that would otherwise slip through as numbers: `NaN`, `Infinity`, zero, a negative, and a bare * fraction like `0.8`. * * **A bare `0.8` is rejected on purpose, and this is the one rejection worth explaining.** It is * the obvious way to write "80% of the window", and it is also a perfectly well-formed token count * of under one token. Guessing which was meant would make the threshold depend on a rule the user * never read, so the error points at `80%` instead — the form that cannot be misread. That is why * an absolute count must be a whole number of at least 1. */ export declare function parseTokenBudget(raw: unknown): TokenBudget; /** * Collapse a parsed budget to the absolute token count it means for one model. * * Returns `null` when the budget is a fraction and the window is unknown — the same "unknown means * no trigger" contract `contextWindow.ts` holds, and for the same reason: a percentage of a window * nobody could resolve is not a number, and inventing one is the failure this whole feature exists * to avoid. An absolute count needs no window and is returned as written. */ export declare function resolveTokenBudget(budget: TokenBudget, window: number | null): number | null; /** * Render a budget the way it will be read back — an absolute count as a plain number, a fraction as * a percentage. Used by `/status` and `/autocompact` so what is echoed matches what was accepted. */ export declare function formatTokenBudget(budget: TokenBudget): string;