pub struct Completion {
pub text: String,
pub model: Option<String>,
pub tool_calls: Vec<ToolCall>,
pub usage: Usage,
pub stop_reason: Option<String>,
pub truncated: bool,
pub structured: Option<Value>,
pub continuation: Option<ProviderContinuation>,
pub reasoning: Option<String>,
pub commentary: Option<String>,
pub compacted: Option<Compacted>,
pub stopped: bool,
}Expand description
What came back.
Fields§
§text: String§model: Option<String>The model that actually answered, as the provider reported it.
Not the model that was asked for — that is on the effect’s descriptor and
in its provenance source, and it is hashed into the effect key. This is
the provider’s own word about which weights served the request, and the
two differ whenever an alias resolves (claude-opus-latest), a
deployment is moved under a pinned name, or a gateway routes elsewhere.
Without it a run’s evidence says only which model was requested, and a
substitution is invisible to the party the journal exists to convince.
None where the wire does not say. Bedrock’s Converse response is the
shipped case: it carries no model field, and reporting the requested one
here would hide exactly the substitution this field exists to expose.
tool_calls: Vec<ToolCall>Tools the model asked to call.
Empty for an ordinary answer, and empty for the forced-tool path used to obtain structured output: that tool is this crate’s mechanism for “answer in this shape”, not a request for the runtime to do anything, and surfacing it would make every schema-shaped completion look like a tool invocation.
Filled identically by the buffered and streaming paths. Streaming is the default, so a field populated only when buffering would be silently empty in most deployments — which is worse than absent, because callers would build loops on it and see them never fire.
usage: Usage§stop_reason: Option<String>Why generation stopped, in the provider’s words.
Passed through unnormalised on purpose: end_turn, max_tokens,
incomplete:max_output_tokens and stop mean subtly different things to
the providers that emit them, and flattening them into a shared
vocabulary would lose exactly the detail a caller debugging a truncated
answer needs. The one thing a caller must not have to parse out of it
is whether the answer is complete — see truncated.
truncated: boolWhether the answer was cut short.
A typed field rather than a string a caller has to recognise, and its own
field rather than an error, for the same reason the worklist reports
truncated beside its page: a partial answer returned as a whole one is
a silent truncation, which this crate refuses everywhere else (P7).
It is not an error because a cut-off answer is often still useful — prose
that stops early is readable, and the caller is the only one who knows
whether they were parsing JSON. What they must not be able to do is
overlook it, and a bool in the struct they already destructure is
harder to overlook than a stop reason they have to compare against a
provider-specific string.
structured: Option<Value>The answer parsed as JSON, when a schema was asked for.
None when no schema was declared. When one was, this is the parsed
value and text still holds the raw string.
Provider constrained decoding prevents malformed output before tokens
are emitted; this crate then validates the parsed value locally as
defense in depth. Provider bugs and forced-tool best-effort behavior are
therefore loud, metered Unusable responses rather than malformed data
reaching downstream code. External schema references are not resolved:
validation performs no hidden file or network I/O.
continuation: Option<ProviderContinuation>Provider-owned response items required to continue this exact turn.
This is deliberately opaque to the runtime. OpenAI uses complete
Responses output items (including encrypted reasoning); Anthropic uses
the complete assistant content blocks (including signed thinking). The
next request returns the value only to the provider that issued it.
Keeping it in the journal makes continuation independent of expiring
provider-side conversation state and reproducible on replay.
reasoning: Option<String>The provider’s readable summary of how the model reasoned, when the call asked for one and the provider gave one.
The model’s own account, and only that: never the signed, encrypted or
redacted reasoning the continuation carries,
which stays the provider’s to read. It is part of the answer, so it is
journaled and replayed with it and carries its label — a summary of
reasoning over hostile input is as untrusted as the text beside it.
None when the call did not ask, and when it asked and the provider
summarised nothing this turn — a short answer often has no summary.
commentary: Option<String>What the model said beside its calls, where the wire marks it apart from the answer.
Responses sends a model’s narration on its way to a tool call as a
message in the commentary phase, and text leaves it
out so a schema-bearing answer still parses. Every other wire marks no
phase, so the same words are in text and this is None. Part of the
answer: journaled, replayed and labelled with it.
compacted: Option<Compacted>The provider compacted the conversation during this call, when the call asked it to.
The compaction itself lives in continuation,
which the next call sends back; this says that it happened, so a reader
of the journal knows the model worked from a summary from here on.
stopped: boolThe call was stopped while it streamed.
text is what arrived before the stop, and
usage is what the wire had reported by then — a floor,
since most providers report output tokens only at the end. A half-sent
tool call is not a request, so tool_calls is
empty, and there is no continuation: the turn did not finish.
Implementations§
Trait Implementations§
Source§impl Clone for Completion
impl Clone for Completion
Source§impl Debug for Completion
impl Debug for Completion
Source§impl Default for Completion
impl Default for Completion
Source§impl<'de> Deserialize<'de> for Completion
impl<'de> Deserialize<'de> for Completion
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl PartialEq for Completion
impl PartialEq for Completion
Source§impl Serialize for Completion
impl Serialize for Completion
impl StructuralPartialEq for Completion
Auto Trait Implementations§
impl Freeze for Completion
impl RefUnwindSafe for Completion
impl Send for Completion
impl Sync for Completion
impl Unpin for Completion
impl UnsafeUnpin for Completion
impl UnwindSafe for Completion
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more