import { generateConfigHash } from "../../../ops/kv-cache-utils"; import type { CacheMessage } from "../../../../utils/index"; import type { Logger } from "../../../../../logging/types"; export interface TurnHandle { /** Resolved on-disk cache file path the addon will read from / write to. */ readonly cachePath: string; /** * Snapshot of the on-disk saved-message count at `beginTurn` time * (0 if the cache was just primed). Consumed by `decideCachedHistorySlice` * to pick the message tail for the next addon call. */ readonly savedCount: number; } export interface BeginCustomTurnInput { kind: "custom"; /** User-provided session key (`completion({ kvCache: "session-a" })`). */ customKey: string; /** Hash of system prompt + (static) tool names. */ configHash: string; /** * Prime the cache by sending system prompt + (static) tools to the * addon. Called when the cache doesn't exist in-memory OR on disk. * Kept as an injected closure so this module has no dependency on the * model registry / addon — the handler closes over `model` and tools. */ primeIfMissing: (cachePath: string) => Promise; } export interface BeginAutoTurnInput { kind: "auto"; /** Hash of system prompt + (static) tool names. */ configHash: string; /** Conversation history used to compute the pre-response cache key. */ history: CacheMessage[]; /** See `BeginCustomTurnInput.primeIfMissing`. */ primeIfMissing: (cachePath: string) => Promise; } export type BeginTurnInput = BeginCustomTurnInput | BeginAutoTurnInput; export interface StaticCommitResult { kind: "static"; /** `history.length + 1` — recorded at the turn's current `cachePath`. */ messageCount: number; } export interface AutoRenameCommitResult { kind: "autoRename"; /** * Destination path the addon's pre-response cache file should be * renamed to (computed from `cacheMessages + responseText`). The * stale entry at the source path is dropped from `cachedMessageCounts` * and the new count is recorded at this target path. */ targetCachePath: string; /** Number of messages the renamed cache represents (`savedHistory.length`). */ messageCount: number; } export type CommitResult = StaticCommitResult | AutoRenameCommitResult; export interface KvCacheSession { /** * Open a new turn against the cache. Resolves the cache file path, * primes the system-prompt cache if needed (delegated to * `input.primeIfMissing`), marks the cache initialized, and returns a * `TurnHandle` the handler attaches to `ctx.scope.defer(...)` for the * rollback hook. */ beginTurn(input: BeginTurnInput): Promise; /** * Commit a successful turn — records the new saved-message count, * preserves the cache file, and (for auto-cache turns) renames the * addon's pre-response file to the post-response path. Flips the * turn's internal `committed` flag so the deferred `rollback` becomes * a no-op on the happy path. */ commitTurn(turn: TurnHandle, result: CommitResult): Promise; /** * Roll back an in-flight turn — atomically deletes the on-disk cache * file, clears the in-memory `initializedCaches` entry, and forgets * the `cachedMessageCounts` entry. **All three layers, always, in * one place.** Idempotent: a turn that has already been committed * or rolled back is a no-op on subsequent calls. Handlers register * this via `ctx.scope.defer(...)` so it runs regardless of how the * handler exits (success branch removes itself via `commitTurn`). */ rollback(turn: TurnHandle): Promise; /** * Forget the in-memory saved-message count for the turn's path * without unlinking the file or clearing the init flag. Used when * `decideCachedHistorySlice` detects a stale boundary * (`clearStaleCount: true`) — the next turn re-sends the full history * but the cache itself is still usable. */ dropStaleSavedCount(turn: TurnHandle): void; } /** * Construct a session bound to one `(modelId, turn-owning request)` * scope. `options.logger` is the per-instance logger the session emits * through (typically `withRequestContext(getServerLogger(), ctx)`); * falls back to the module-scoped logger when omitted. */ export declare function createKvCacheSession(modelId: string, options?: { logger?: Logger; }): KvCacheSession; /** * Atomically delete every layer of KV-cache state for a * `(kvCacheKey, modelId)` pair, or wipe everything. Single entry point * — the only mutation point for cross-model state outside of * turn-scoped `commitTurn`/`rollback`. * * Why this isn't a method on `KvCacheSession`: deletes are * cross-model (`all: true` has no model; the keyed form has * `modelId` optional on the wire). A session, by contrast, is * created with a *fixed* `modelId` for the duration of a turn. Making * delete a method would force callers to materialise an irrelevant * session for cross-model administrative cleanups. * * Layers cleared, in order: * 1. On-disk: `deleteCache(...)` removes the matching directory * tree (or wipes and recreates the root for `all: true`). * 2. `cachedMessageCounts`: prefix-cleanup by the removed directory * so any per-cache count under the deleted tree is forgotten. * 3. `initializedCaches`: scope clear by `(kvCacheKey[, modelId])`, * matching the on-disk scope. * * Concurrency with in-flight turns: this delete is wire-async with * respect to any turn currently holding a `TurnHandle` for the same * cache key. Worst case the on-disk `.bin` is removed while a turn is * mid-write; the turn's eventual `commitTurn(...)` then fails the * `verifySaveAndRecord` probe (file gone) and rolls back idempotently. * No coordination primitive is needed because every layer's mutation * is idempotent (`unlink` no-ops if missing, `Map.delete` / `Set.delete` * no-op on absent keys). */ export declare function deleteKvCacheState(target: { kvCacheKey: string; modelId?: string; } | { all: true; }): Promise; /** * Test-only access to the module-scoped state. Production code reaches * for cache state exclusively through the session API; the unit suite * for `kv-cache-session.test.ts` needs to seed and inspect raw state * to assert the rollback / commit invariants. Not part of the public * SDK surface. * * @internal */ export declare const __kvCacheSessionTestHooks: { getSavedCount(cachePath: string): number | undefined; setSavedCountForTest(cachePath: string, count: number): void; hasInitializedKey(modelId: string, configHash: string, cacheKey: string): boolean; markInitializedForTest(modelId: string, configHash: string, cacheKey: string): void; resetForTest(): void; }; export { generateConfigHash }; //# sourceMappingURL=kv-cache-session.d.ts.map