Dsxir. Cost
(dsxir v0.4.0)
Copy Markdown
Provider-independent record of token usage and cost for LM work.
Carries a full breakdown — input/output/cache-read/cache-write/reasoning token
counts and their per-bucket costs, a total_cost, and a currency — plus a
calls counter (1 for a single LM call, N after aggregation via merge/2
or sum/1). Token and cost fields are nil when the provider did not report
them; nil is distinct from 0. Mapping from a specific provider's usage
struct lives in the corresponding Dsxir.LM implementation, not here.
Summary
Functions
Field-wise sum of two costs. nil is the additive identity per field; a field
that is nil in both stays nil. calls always adds. The first non-nil
currency is kept.
Folds a list of costs into one, seeded with zero/0.
Flattens a cost into the numeric measurement map emitted on
[:dsxir, :predictor, :stop]. Keeps the legacy keys :tokens_in,
:tokens_out, and :cost; adds the cache/reasoning token breakdown.
Values stay nil when unreported.
Runs fun and returns {result, %Dsxir.Cost{}} where the cost is the sum of
every predictor call ([:dsxir, :predictor, :stop]) and embedding call
([:dsxir, :lm, :embed, :stop]) emitted within the block — including from
fan-out workers that replay the Dsxir.Settings snapshot.
Additive identity: all token/cost fields nil, calls: 0.
Types
@type t() :: %Dsxir.Cost{ cache_read_cost: float() | nil, cache_read_tokens: non_neg_integer() | nil, cache_write_cost: float() | nil, cache_write_tokens: non_neg_integer() | nil, calls: non_neg_integer(), currency: String.t() | nil, input_cost: float() | nil, input_tokens: non_neg_integer() | nil, output_cost: float() | nil, output_tokens: non_neg_integer() | nil, reasoning_cost: float() | nil, reasoning_tokens: non_neg_integer() | nil, total_cost: float() | nil }
Functions
Field-wise sum of two costs. nil is the additive identity per field; a field
that is nil in both stays nil. calls always adds. The first non-nil
currency is kept.
Folds a list of costs into one, seeded with zero/0.
Flattens a cost into the numeric measurement map emitted on
[:dsxir, :predictor, :stop]. Keeps the legacy keys :tokens_in,
:tokens_out, and :cost; adds the cache/reasoning token breakdown.
Values stay nil when unreported.
@spec track((-> result)) :: {result, t()} when result: var
Runs fun and returns {result, %Dsxir.Cost{}} where the cost is the sum of
every predictor call ([:dsxir, :predictor, :stop]) and embedding call
([:dsxir, :lm, :embed, :stop]) emitted within the block — including from
fan-out workers that replay the Dsxir.Settings snapshot.
Pushes a unique scope id onto the :_cost_scope stack in Dsxir.Settings
(propagated to workers via Settings.run/2) and attaches a telemetry handler
that accumulates matching events in an ephemeral ETS table, folded on exit.
No long-lived process. Handler and table are always torn down, including when
fun raises.
@spec zero() :: t()
Additive identity: all token/cost fields nil, calls: 0.