pub struct ProviderAttemptRecord {Show 13 fields
pub attempt: u32,
pub purpose: String,
pub provider_key: ProviderKey,
pub model_key: ModelKey,
pub request_id: String,
pub prompt_version: Option<String>,
pub prompt_ref: Option<PromptRef>,
pub outcome: ProviderAttemptOutcome,
pub latency_ms: Option<u64>,
pub input_tokens: Option<u64>,
pub output_tokens: Option<u64>,
pub temperature: Option<f32>,
pub finish_reasons: Vec<String>,
}Expand description
One model call (spec §20.7: “record every provider attempt”).
§Why attempt is a number and AttemptId is an identifier
A model call leaves nothing behind outside the process. When one fails or
times out, the only thing anyone needs to know is which try it was inside
a stage this record already identifies — the turn, the purpose, the
provider and the model — so a position in that sequence says everything, and
nothing else ever refers to it.
An external effect attempt is the opposite: it may have happened even though
the answer never arrived (spec §16.5), and settling it means naming that
exact attempt to a remote system. That is what AttemptId is for, why
CommandOutcome::OutcomeUnknown carries one, and why
ReplayRecord::reconciliation_attempt_ids lists them. The asymmetry is
the difference between counting retries and naming an effect, not an
oversight.
Note that this record is compared with PartialEq only: temperature is
a float, so Eq would be a promise about NaN that the type cannot keep.
Fields§
§attempt: u321-based attempt number within the stage. A plain ordinal on purpose; see the type documentation.
purpose: StringStage purpose (e.g. "extract").
provider_key: ProviderKeyProvider key.
model_key: ModelKeyModel key.
request_id: StringStable request id sent to the provider.
prompt_version: Option<String>Prompt or template version, when known.
prompt_ref: Option<PromptRef>The exact prompt text this call ran under, when a prompt source supplied it (roadmap: “prompt management, with an optional Langfuse prompt source”).
None for a stage whose instructions are compiled into the library —
which is every stage until an application configures a
turnframe-prompt source — and also for a stage whose configured source
failed and fell back to those built-in instructions. That is deliberate:
the absence of a reference is the audit signal that the text was not the
text the source was asked for.
Unlike prompt_version, which is a bare label,
this carries the digest of the text, so the record can be falsified
rather than merely believed.
outcome: ProviderAttemptOutcomeOutcome.
latency_ms: Option<u64>Latency in milliseconds.
input_tokens: Option<u64>Input tokens, when reported.
output_tokens: Option<u64>Output tokens, when reported.
temperature: Option<f32>Sampling temperature the request carried, when the stage set one.
None means the call left the provider’s default in place, which is not
the same as Some(0.0). An observability bridge reports it as
gen_ai.request.temperature; kept at the request’s own f32 precision
so the audit value is the value that was sent, not a widened copy of it.
finish_reasons: Vec<String>Finish reasons the provider reported for the response, in the order it reported them, verbatim.
Empty when the attempt produced none — a transport failure, a
cancellation, or a provider that does not report them. Providers spell
these differently ("stop", "length", "max_tokens", …) and the
strings are kept as received: normalizing them here would erase the
distinction an audit is being read for. An observability bridge reports
them as gen_ai.response.finish_reasons.