Image-side usage and cost summary — Layer A 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
Cost fields are typed float | nil. ALLM.Usage.cost is already
float, so the chat and image cost types align; adopting Decimal
solely for typed nil-or-number adds runtime weight without semantic
gain. Float-summation drift on total_cost = input_cost + output_cost
is bounded at ≤1 ULP, well below provider cent-level pricing precision.
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 }