Estimate and persist cumulative model cost for each thread.
The graph owns the durable total. CostTrackingMiddleware is the only writer of
_session_cost_usd, so each cost update rides the model checkpoint and works for
local, headless, and remote graph execution without a client-side state update.
The client is a reader: it renders the streamed total and never maintains its own
lifetime figure.
Coverage is not limited to the agent's own model node. Offload/summarization and
the Auto mode classifier invoke a model directly, outside after_model, and
subagents run their own graph. _SessionCostRecorder — a callback handler
installed process-wide for every model request (see _install_recorder) —
collects one record per completed request, keyed by thread, and
CostTrackingMiddleware drains and prices those records on the main agent's
checkpoint path. New side invokes are covered with no extra wiring.
The recorder only collects; the middleware alone prices and writes. The agent's own response is still priced from state, but only when the recorder did not already charge that message ID, so a request is never counted twice. That fallback keeps main-agent cost correct even for a model that never fires callbacks.
Nested agents first checkpoint their own spend on the same private channel. That makes a completed model call durable before a later tool approval can interrupt the subgraph. When the subagent finishes, its middleware transfers the accumulated delta through an owner-scoped state entry. The subagent tool checkpoints that entry on the parent graph even when a sibling interrupts, while the private total itself remains isolated between graphs.
Every caller uses estimate_cost, the only function that imports or calls
genai-prices. The import is lazy so the package and its bundled pricing data
stay off the CLI startup path. On that first successful import a daemon-thread
updater starts refreshing the catalog from upstream hourly (see
_start_price_updater); DEEPAGENTS_CODE_PRICES_AUTO_UPDATE=0 or
[update].prices_auto_update = false in config.toml opts out, and
DEEPAGENTS_CODE_OFFLINE suppresses it along with every other network fetch.
When the active genai-prices catalog -- the bundled data, or the auto-updated
snapshot once one is installed -- has no rates for a model, a local override
catalog is consulted as a fallback-on-miss (see _override_price): the user's
own ~/.deepagents/prices.json first, then a maintainer-curated file shipped
as package data. PRICING.md documents the former for users and
bundled_prices.README.md the latter for maintainers. Unsupported models and
malformed usage return None; pricing must never interrupt a model turn.
Disable network downloads of managed binaries (e.g. ripgrep).
Parsed by is_env_truthy: accepts 1, true, yes, on as enabled. When
truthy, managed_tools.ensure_ripgrep will not attempt to download a binary
and falls back to the existing missing-tool notification + slow Python regex
path.
Custom-stream event type carrying the thread's absolute cumulative cost.
Emitted by the durable writer so the status bar can track spend live without
re-pricing anything. The payload is {"type": ..., "total": <usd>, "thread_id": <id>, "pricing_ok": <bool>}; total is the full thread lifetime estimate,
never a delta, so a client that misses an event still converges on the next one.
thread_id lets a client that has since switched threads discard a total
belonging to the previous one. pricing_ok reports whether price data loaded in
the process that actually did the pricing, which is the only way a client can
tell a broken remote install from models with no published rates.
Return whether env var name is set to a recognizably truthy value.
Unlike bool(os.environ.get(name)), this does not treat "0" or
"false" as enabled. Use this for on/off flags where the user would
reasonably expect VAR=0 to mean "disabled".
Report whether genai-prices is currently able to price a request.
Note that True also covers "not yet attempted", so callers must only
consult this after pricing has been tried -- otherwise a session that has
priced nothing reads as healthy.
Estimate one model request's cost in USD from LangChain usage metadata.
LangChain's input_tokens is the full input count, including cache reads and
writes. genai-prices receives that inclusive total plus the cache, modality,
and reasoning details; it subtracts each detail bucket from the total that
contains it before applying rates, so tokens are not double-counted. Only
buckets the matched model actually publishes a rate for are broken out --
forwarding one the catalog does not price leaves those tokens in the ordinary
input or output total rather than pricing them separately.
Resolve the model and provider attached to a streamed model message.
Extends agent state with per-checkpoint facts restored on resume.
Inherits the shared goal/rubric channels from GoalRubricChannels and adds
the channels unique to resume: the after-model token/spec facts and the
pending-goal proposal awaiting acceptance.
Agent state extended with the cumulative thread-cost channel.
Own the thread's cumulative _session_cost_usd checkpoint value.
The main agent owns the thread total. Nested instances checkpoint local deltas before an interrupt can pause their graph, then transfer the completed subagent total through state for its owning parent graph to checkpoint.