/** * Adaptive chars-per-token (CPT) — the fit. * * The profitability gate compares `imageTokens` (exact, from pixel area) against * `textTokens = chars / CPT`. CPT was a hand-tuned constant per call site (4 for * reminders/tool_results, 2.0 for slab/history). Production telemetry showed the * real marginal density is ~1.5 for dense content, so the constant under-counted * text cost and biased the gate toward passthrough — leaving savings on the table. * * This module learns CPT from the events pxpipe already logs. Model: a request's * TEXT token cost decomposes into a per-bucket marginal rate times that bucket's * char count, * * textTokens ≈ Σ_b α_b · chars_b with CPT_b = 1 / α_b * * where `textTokens` is the observed `baseline_tokens` (a free count_tokens probe * on the ORIGINAL uncompressed body) minus the image cost, priced off Anthropic's * 28×28-patch grid. Samples are built offline from events.jsonl by the caller * (see the CHARS_PER_TOKEN provenance note in transform.ts). Solved by ordinary * least squares * via the normal equations `α = (XᵀX)⁻¹ Xᵀy`. XᵀX is at most 6×6, so a hand-rolled * Gauss-Jordan inverse is microseconds and needs no dependency. * * Pure math — no `fs`, no `process`, no `Buffer`. Safe to import from the Workers * build. * * The fit is deliberately conservative: every guard below fails a bucket CLOSED * (back to the baked constant) rather than open. A wrong learned CPT would make * the gate image unprofitably, which costs real money; a missing one just returns * today's behavior. */ import type { BucketName } from './transform.js'; /** Column order for the design matrix. Stable + explicit so a fit is reproducible. */ export declare const CPT_BUCKETS: readonly BucketName[]; /** Minimum events before any fit is trusted. Below this, a slope is noise. */ export declare const MIN_SAMPLES = 20; /** A bucket must actually appear this many times to get its own column; * an all-but-empty column makes XᵀX singular and the slope meaningless. */ export declare const MIN_BUCKET_PRESENCE = 8; /** Plausible CPT band. Real content runs ~1.2 (dense JSON) to ~4 (prose); * anything outside this is a fit artifact, not a measurement. */ export declare const CPT_PLAUSIBLE_MIN = 0.8; export declare const CPT_PLAUSIBLE_MAX = 6; /** Reject the whole fit above this pivot ratio — the buckets are too collinear * to separate (e.g. reminders that always grow with tool_results). */ export declare const MAX_CONDITION = 100000000; /** One request's regressors + target. */ export interface CptSample { /** Pre-compression TEXT chars per bucket (the logged `bucket_chars`). */ bucketChars: Partial>; /** Observed text tokens: `baseline_tokens − imagePixels / 750`. */ textTokens: number; } export interface CptFitResult { /** Learned chars-per-token, per bucket. Absent = use the baked default. */ cpt: Partial>; nSamples: number; /** Why each bucket was NOT learned. Surfaced so a null result is explainable. */ rejected: Partial>; /** Pivot ratio of XᵀX. Higher = less trustworthy; > MAX_CONDITION rejects. */ conditionEstimate: number; /** Buckets that got a column in this fit. */ active: BucketName[]; } /** * Fit per-bucket CPT from samples. Never throws; a fit it cannot trust comes back * with an empty `cpt` and a populated `rejected` explaining why. */ export declare function fitCpt(samples: readonly CptSample[]): CptFitResult; //# sourceMappingURL=cpt-fit.d.ts.map