pub struct CompletionResponse {
pub text: Option<String>,
pub tool_calls: Vec<ToolCall>,
pub usage: Option<Usage>,
pub model: Option<String>,
pub finish_reason: Option<String>,
pub ttft_ms: Option<u64>,
}Expand description
One model completion.
Construct with ..Default::default() for forward compatibility — fields are
added in minor releases (e.g. usage in 0.2.0).
use io_harness::{CompletionResponse, ToolCall, Usage};
let response = CompletionResponse {
tool_calls: vec![ToolCall {
name: "write_file".into(),
arguments: serde_json::json!({ "path": "NOTES.md" }),
}],
usage: Some(Usage { prompt_tokens: 1_200, completion_tokens: 80, total_tokens: 1_280,
..Default::default() }),
// Which model actually served this call, as the provider named it in its
// own answer — not the slug that was asked for, and not the vendor.
model: Some("claude-sonnet-4".into()),
finish_reason: Some("tool_use".into()),
..Default::default()
};
// The branch a run loop takes: tool calls first, in the order the model made
// them, and free text only when there are none. A model may return both, and
// reading `text` first would drop the work it asked for.
if let Some(call) = response.tool_calls.first() {
assert_eq!(call.name, "write_file");
} else {
println!("the model answered instead of acting: {:?}", response.text);
}
// Usage is what the step's budget draw is made from; `None` means the provider
// said nothing, which is why the field is an `Option` rather than a zero.
assert_eq!(response.usage.map(|u| u.total_tokens), Some(1_280));
// Nothing measured the stream here, so time-to-first-token is unknown rather
// than instant. The trace keeps that distinction.
assert_eq!(response.ttft_ms, None);Fields§
§text: Option<String>Any free text the model returned.
tool_calls: Vec<ToolCall>Tool calls the model requested, in order.
usage: Option<Usage>Token usage, when the provider reports it. None if unknown.
model: Option<String>(0.18.0) The model that served this call, as the provider identified it.
None when the provider did not say.
This is the field that makes a fallback auditable: runs.provider holds
one label for a whole run, and stops being true the moment a
Fallback swaps vendors mid-run.
finish_reason: Option<String>(0.18.0) Why the model stopped — stop_reason on Anthropic,
finish_reason on the OpenAI wire, recorded verbatim rather than
normalised, because a vendor’s own word for it is what its documentation
explains. None when the provider did not say.
A turn that ended on a length cap and one that finished are different facts, and only this field tells them apart after the run.
ttft_ms: Option<u64>(0.18.0) Milliseconds from the request being sent to the first content-bearing chunk arriving.
None — never zero — when nothing measured it: a provider that does not
stream, or a test double. An unmeasured wait and an instant one are
different facts and averaging the second into a latency report would be
wrong in the direction that flatters the provider.
Trait Implementations§
Source§impl Clone for CompletionResponse
impl Clone for CompletionResponse
Source§fn clone(&self) -> CompletionResponse
fn clone(&self) -> CompletionResponse
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for CompletionResponse
impl Debug for CompletionResponse
Source§impl Default for CompletionResponse
impl Default for CompletionResponse
Source§fn default() -> CompletionResponse
fn default() -> CompletionResponse
Source§impl<'de> Deserialize<'de> for CompletionResponse
impl<'de> Deserialize<'de> for CompletionResponse
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 CompletionResponse
impl PartialEq for CompletionResponse
Source§impl Serialize for CompletionResponse
impl Serialize for CompletionResponse
impl StructuralPartialEq for CompletionResponse
Auto Trait Implementations§
impl Freeze for CompletionResponse
impl RefUnwindSafe for CompletionResponse
impl Send for CompletionResponse
impl Sync for CompletionResponse
impl Unpin for CompletionResponse
impl UnsafeUnpin for CompletionResponse
impl UnwindSafe for CompletionResponse
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 moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian().impl<T> Scalar for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.