Expand description
AI cost attribution (DW-079): pricing tables and per-call cost computation.
The pricing table is a COMPILED view of the ai.pricing config map:
provider model identifier -> per-1k-token micro-USD rates. It lives
on the dataplane behind an ArcSwap and is swapped on every config
reload (the same pattern as the AI budget engine), so a pricing
change takes effect on the NEXT request without a restart.
§Cost computation
cost_micros computes integer micro-USD for one call’s usage:
(input_tokens - cached_tokens) * input_per_1k_micros / 1000
+ cached_tokens * cached_input_per_1k_micros / 1000
+ output_tokens * output_per_1k_micros / 1000When batch is true, the batch rates (batch_input_per_1k_micros,
batch_output_per_1k_micros) replace the standard input/output
rates when declared; cached-token pricing is NOT combined with
batch rates (a batch request uses the batch rate for all input
tokens — the provider’s batch API does not report a separate cached
tier). When optional fields are absent, the standard rates apply
(the fallback).
Integer division truncates (the per-1k rate is the provider’s
published unit; sub-micro-USD fractions are lost — the honest
rounding boundary, pinned by tests). Saturating adds guard against
overflow. An UNKNOWN model (no pricing entry) returns None — the
caller applies the unknown_model_policy (allow / fail_closed /
alert, DW-AI-03). The original fail-open behavior (cost 0) is
preserved by the allow policy at the call site.
§Dependency direction
ai depends on config only (see scripts/check_deps.py); this
module reads config::ai::AiConfig and ai::types::Usage, both
same-level or lower. The spend RECORD DTO lives in analytics (a
plain struct, not importing ai::types::Usage) — the dataplane
converts at the call site, keeping the dependency direction
downward.
Structs§
- Pricing
Table - The compiled pricing table (DW-079): provider model -> rates. Built at dataplane refresh from the published config; immutable once built. Stored on the dataplane behind an ArcSwap and swapped on reload, so a pricing change applies to the next request with no restart.