/** * KEEPING THE PREFIX THE PROVIDER ALREADY HOLDS, BYTE FOR BYTE. * * A request that goes out re-serialised is a cache MISS even when every field * in it is unchanged. The provider matches its cache on bytes, not on meaning, * and `JSON.stringify` does not reproduce the bytes it was given: the captures * here are indented, `stringify` emits compact, and the two agree for exactly * the 57 characters of `{"model":"...","messages":` before the first newline * of the original. So an arm could decline to touch a single message behind * the client's `cache_control` marker -- which is what the strategies do -- and * still destroy the hit on the way out, paying a 1.25x cache WRITE for a prefix * it had every right to send back at the 1.0x read rate. * * The fix is not to serialise that part at all. Whatever leading run of * messages came back unchanged is copied out of the ORIGINAL buffer at its * original offsets, and only the tail is stringified. * * WHY THIS IS A SCANNER AND NOT A PARSER. We need byte offsets, and * `JSON.parse` discards them. The scanner below walks the top-level object * once, recording where each element of `messages` ends, and understands just * enough JSON to do that: strings with escapes, and bracket depth. It never * interprets a value. * * EVERY REFUSAL HERE RETURNS null AND THE CALLER RE-SERIALISES. A wrong splice * would emit malformed JSON to the provider, so anything unexpected -- a key * order we did not predict, a value the strategy edited ahead of `messages`, a * text that does not scan -- falls back to the behaviour that was always there. */ export interface PrefixSpan { key: string; /** Offsets bounding the key's value as the original spelled it. */ start: number; end: number; } export interface PrefixScan { /** Top-level keys in the order the original spelled them, before `messages`. */ keysBefore: PrefixSpan[]; /** Offsets bounding each element of `messages`, as the original spelled it. */ messages: Array<{ start: number; end: number; }>; /** Offset of the `]` that closes `messages`. */ arrayEnd: number; } /** * Walks the top-level object of an Anthropic-shaped request and records where * each message ends. Returns null if the text is not a single object with a * `messages` array, or does not scan cleanly. */ export declare function scanRequest(text: string): PrefixScan | null; /** * Re-emits `next` while keeping the longest leading run of messages that came * back unchanged EXACTLY as `original` spelled them. * * BOTH SIDES OF EVERY COMPARISON COME FROM THE ORIGINAL BYTES. The parsed * request the strategies receive is edited in place, so it is not a record of * what arrived; comparing against it would let an edited message match itself * and be re-emitted from the original text, quietly reverting the edit. Reading * the old side back out of `original` makes that impossible: whatever gets * copied is, by construction, what the provider already holds. * * Returns null when nothing can be preserved or when preserving would risk a * malformed body -- the caller then serialises as it always did. */ export declare function serialiseKeepingPrefix(original: string, next: { messages?: unknown[]; } & Record): string | null; //# sourceMappingURL=cached-prefix.d.ts.map