Provider policy and pricing helpers for cold prompt-cache warnings.
Suppression key for the cold-cache warning in [warnings].suppress.
Named rather than spelled inline at each site: the reader, the writer, and the
/notifications settings row must agree exactly, and a typo in any one would
leave the warning firing after the user asked it to stop, with no error
anywhere to explain why.
How firmly a passed retention window implies the cached prefix is gone.
expired is used when the window is a documented maximum (Anthropic's TTL,
OpenAI's prompt_cache_retention ceilings): once it passes, the entry is gone.
may_be_cold is used when the window is a documented minimum (GPT-5.6+),
where the provider is only guaranteed to have kept the entry that long and may
well have kept it longer.
Which pricing treatment a cold (cache-writing) request receives.
5m prices Anthropic's five-minute ephemeral write premium. generic_write
tags the miss as a cache write, which GPT-5.6+ bills above the plain input
rate; omitting the detail would price the miss at plain input. The premium's
current magnitude comes from the pricing catalog, not from here. generic
covers misses with no write surcharge, which is how OpenAI priced prompt
caching before GPT-5.6.
generic_write is assigned by model-name version (see
_openai_uses_thirty_minute_cache), not by inspecting the catalog, and that
coupling is not enforced: a future 5.6-family model with no published cache
rates would be tagged generic_write and priced at plain input by
estimate_cost, which drops detail keys the catalog cannot price. Models
carrying no cache rates at all already exist in the catalog, so this is a
reachable state rather than a theoretical one.
Why a turn is treated as facing a cold prompt cache.
idle means the last request is older than the policy's retention window.
identity_changed means the model or its cache-affecting params differ from
the last successful turn, so the cached prefix cannot be reused regardless of
age. age_unknown means there is no usable record of when this thread last
reached the model -- a checkpoint written before cold-cache tracking existed,
or one whose timestamp could not be parsed -- so the cache cannot be assumed
warm. Each maps to distinct modal copy; they are not interchangeable, and in
particular age_unknown must not be reported as identity_changed, which
would claim a model change that never happened.
Invocation params that select or invalidate a provider cache entry.
The identity check compares only these. Comparing whole model_params maps
instead would report a model change for every unrelated knob -- /effort
rewrites reasoning_effort wholesale, and temperature or max_tokens are
just as inert for caching -- and the modal would then assert that "the previous
cached prefix cannot be reused" when nothing about the prefix moved. A modal
that fires on a false premise trains users into the permanent suppression.
cache_control is deliberately absent: AnthropicPromptCachingMiddleware
overwrites model_settings["cache_control"] with its own TTL on every
Anthropic request (see _ANTHROPIC_MIDDLEWARE_TTL_SECONDS), so a
user-supplied value never reaches the wire. Comparing it would report an
identity change for a setting the effective requests never differed on.
Build the placeholder policy used by DEEPAGENTS_CODE_DEBUG_COLD_CACHE.
Keeps the modal reachable on providers with no documented cache policy.
Lives here rather than in the caller so the Anthropic window and minimum
stay tied to _ANTHROPIC_MIDDLEWARE_TTL_SECONDS and
_ANTHROPIC_DEFAULT_MINIMUM_TOKENS instead of being re-hardcoded, which
would silently drift the moment either constant is revised.
The provider name is deliberately Anthropic's: under the debug flag the modal may therefore cite Anthropic retention while a different provider is active. The figures are illustrative in that mode, not real estimates.
Return a stable identity for the endpoint that owns a prompt cache.
A missing endpoint means the provider's default API. Only scheme, host,
port, path and a digest of the query are significant; every other spelling
detail is normalized away, including host/scheme case, a trailing slash, a
default port, a trailing root dot, fragments, userinfo, and ;params.
Path and query stay significant because proxies can route them to separate
backends; the query does so via _opaque_digest, which keeps a
credential-bearing query out of the checkpoint. Path case is preserved --
proxies may route on it -- which also means a credential embedded in a path
is recorded verbatim; see _opaque_digest for why that residual is
accepted.
The result is opaque: compare it for equality, never parse it.
Read [warnings].trusted_cache_endpoints as a set of hostnames.
Entries declare that an alternate endpoint forwards cache-affecting request
fields (cache_control, prompt_cache_key, prompt_cache_retention) and
honors the upstream provider's documented retention.
Trust is matched on the exact host: trusting example.com does not trust
gw.example.com. Each host a request may actually reach must be listed.
Malformed content never raises: an unusable entry is dropped and a value that is not a list is ignored wholesale. Because a dropped entry silently leaves the warning disabled -- the opposite of what the user edited the file to achieve -- the offending entry is logged by value and a non-list value by type. Each distinct rejection is logged once per process.
Resolve a documented cache policy for one effective model invocation.
Policies apply only when the endpoint is the provider's official API or a
user-declared trusted endpoint (see load_trusted_cache_endpoints).
A route that crosses wire formats (e.g. an OpenAI-format request routed to
an Anthropic model, spelled openai:anthropic/claude-...) resolves nothing,
because the translation such a hop requires rewrites or drops the caching
fields the policy assumes. See _effective_model_name. Cross-format routing
that is not spelled in the model name cannot be detected -- declaring an
endpoint trusted asserts that it does not do this.
Project the params that participate in prompt-cache identity.
Estimate cold input spend and the incremental cost over a cache hit.
Prices are derived by running two synthetic usage payloads through the
ordinary estimate_cost path -- one billed as a full cache read, one as a
cold request -- so the catalog stays the single source of truth. Outputs
are zeroed on both sides so the delta is input-only.
A provider/model prefix is resolved through _effective_model_name, the
same helper resolve_prompt_cache_policy uses, so a spec that resolved a
policy is priced under the name that policy was chosen for. Letting the two
disagree is what makes a warning silently never fire.
Parse a persisted UTC timestamp, rejecting malformed or naive values.
Format elapsed cache age for compact modal copy.
Format a provider cache window for compact modal copy.
Prompt-cache behavior needed to decide and price a warning.
Keyword-only because window_seconds and minimum_tokens are adjacent
bare ints: positionally, transposing them builds a plausible-looking policy
that silently misprices and mis-gates.
Estimated input cost for a cold prefix and its warm-cache delta.
Both figures are USD, non-negative, and finite; incremental_cost_usd is
the part of cold_cost_usd that a cache hit would have avoided, so it
never exceeds it.
Keyword-only for the same reason as PromptCachePolicy: these are adjacent
bare floats, and transposing them positionally yields copy that reads fine
("may cost up to ~$0.02 ... roughly ~$3.40 more than a warm cache hit")
while being arithmetically impossible.
Validated data needed to render one advisory warning.
Constructed only after every gate has passed -- a policy resolved, the prefix cleared the provider's cache minimum, and the priced delta reached the configured threshold -- so the modal renders it without re-deciding anything.