import type { CacheRetention } from "@kenkaiiii/gg-ai"; /** * Cold-prompt-cache detection (mirrors langchain-ai/deepagents#6477's * `cold_cache.py`): providers keep the conversation prefix cached only for a * TTL, so after a break the next message re-reads the whole context uncached. * * Every TTL below is derived from what gg-ai actually puts on the wire — never * from a provider's marketing maximum we did not request. A provider/route we * cannot pin to a request-side TTL returns `null` (no warning) rather than a * guess. */ export interface CacheTtlPolicy { ttlMs: number; /** * `expired`: the TTL is a documented/requested *maximum* — past it the entry * is gone. `may_be_cold`: the TTL is a guaranteed *minimum* (GPT-5.6+ `30m`), * so past it the prefix may still be warm. */ confidence: "expired" | "may_be_cold"; /** Where the number comes from, for logs/diagnostics. */ source: string; } export interface CacheTtlInput { provider: string; model: string; cacheRetention: CacheRetention; baseUrl?: string; /** OpenAI OAuth (ChatGPT/Codex) routes carry an account id. */ accountId?: string; } /** Resolve the cache TTL our provider code requests for this route. */ export declare function resolveCacheTtl(input: CacheTtlInput): CacheTtlPolicy | null; /** * Prefix size below which the notice is not worth an interruption. At 40k * tokens a cold Anthropic re-read (1.25x write vs 0.1x cached read) costs ~12x * the warm request, roughly a dime on Sonnet-class pricing; below that the delta * is pennies — and compacting first itself re-reads the whole context once, so * on small chats "Compact first" saves nothing. */ export declare const CACHE_EXPIRY_NOTICE_MIN_TOKENS = 40000; export interface CacheTouch { at: number; provider: string; model: string; policy: CacheTtlPolicy; } export interface CacheExpiryStatus { /** Owning session, so clients can key "dismissed once per expiry per chat". */ sessionId?: string; provider: string; ttlMs: number; confidence: CacheTtlPolicy["confidence"]; ttlSource: string; /** Last successful cache-using request (real turn or prewarm), epoch ms. */ lastRequestAt: number | null; /** When the cached prefix lapses/lapsed, epoch ms; null when age is unknown. */ expiresAt: number | null; expired: boolean; /** * `idle`: TTL passed. `age_unknown`: resumed/reset session with no request in * this process. `identity_changed`: provider/model switched since the last * request, so the old prefix cannot be reused. */ reason: "idle" | "age_unknown" | "identity_changed" | null; /** Tokens the next request would re-read (the current context). */ prefixTokens: number; minTokens: number; /** expired AND prefixTokens >= minTokens: worth showing the notice. */ notable: boolean; /** No authoritative pricing exists in GG (turn metric cost is "unavailable"). */ estimatedExtraCostUsd: null; } export interface AssessCacheExpiryInput { /** Policy for the route the NEXT request will take. */ current: { provider: string; model: string; policy: CacheTtlPolicy | null; }; lastTouch: CacheTouch | null; now: number; prefixTokens: number; /** False for an empty chat — nothing to re-read. */ hasHistory: boolean; minTokens?: number; } export declare function assessCacheExpiry(input: AssessCacheExpiryInput): CacheExpiryStatus | null;