Image-side usage and cost summary. See spec §35.2.4.
Layer A — pure serializable data. :images defaults to 0 so a
freshly-constructed %ImageUsage{} reads as "no work done yet"; the
%ALLM.ImageResponse{} struct's default :usage carries one of these
rather than nil.
Cost types — refinement of spec §35.2.4
Cost fields are typed float() | nil, NOT Decimal.t() | nil as spec
§35.2.4 reads (Phase 13 design Decision #1). Rationale:
ALLM.Usage.costis alreadyfloat()(lib/allm/usage.ex:11); divergingImageUsagetoDecimalwould split the cost type across two structs for no semantic gain.:decimalis not a project dep and adopting it solely for typed nil-or-number adds runtime weight.- Float-summation drift on
total_cost = input_cost + output_costis bounded at ≤1 ULP, well below provider cent-level pricing precision.
A spec PR against steering/allm_engine_session_streaming_spec_v0_2.md
§35.2.4 will land alongside the v0.3.0 release recording this refinement.
Providers that charge by image-count alone (dall-e-2, dall-e-3) populate
:images, :size, :quality, and :total_cost. Providers that charge by
tokens (gpt-image-1) additionally populate :input_tokens / :output_tokens
/ :input_cost / :output_cost.
Summary
Functions
Build an %ImageUsage{} from keyword opts.
Types
@type t() :: %ALLM.ImageUsage{ images: non_neg_integer(), input_cost: float() | nil, input_tokens: non_neg_integer() | nil, output_cost: float() | nil, output_tokens: non_neg_integer() | nil, quality: String.t() | nil, size: String.t() | nil, total_cost: float() | nil }