use serde::{Deserialize, Serialize};
use crate::ir::content::ContentPart;
use crate::ir::provider_echo::ProviderEchoSnapshot;
use crate::ir::usage::Usage;
use crate::ir::warning::ModelWarning;
use crate::rate_limit::RateLimitSnapshot;
impl ModelResponse {
#[must_use]
pub fn first_text(&self) -> Option<&str> {
self.content.iter().find_map(|part| match part {
ContentPart::Text { text, .. } => Some(text.as_str()),
_ => None,
})
}
#[must_use]
pub fn full_text(&self) -> String {
let mut out = String::new();
for part in &self.content {
if let ContentPart::Text { text, .. } = part {
if !out.is_empty() {
out.push('\n');
}
out.push_str(text);
}
}
out
}
#[must_use]
pub fn tool_uses(&self) -> Vec<ToolUseRef<'_>> {
self.content
.iter()
.filter_map(|part| match part {
ContentPart::ToolUse {
id, name, input, ..
} => Some(ToolUseRef { id, name, input }),
_ => None,
})
.collect()
}
#[must_use]
pub fn has_tool_uses(&self) -> bool {
self.content
.iter()
.any(|part| matches!(part, ContentPart::ToolUse { .. }))
}
}
#[derive(Clone, Copy, Debug)]
pub struct ToolUseRef<'a> {
pub id: &'a str,
pub name: &'a str,
pub input: &'a serde_json::Value,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct ModelResponse {
pub id: String,
pub model: String,
pub stop_reason: StopReason,
pub content: Vec<ContentPart>,
pub usage: Usage,
#[serde(default)]
pub rate_limit: Option<RateLimitSnapshot>,
#[serde(default)]
pub warnings: Vec<ModelWarning>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub provider_echoes: Vec<ProviderEchoSnapshot>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
#[non_exhaustive]
pub enum RefusalReason {
Safety,
Recitation,
Guardrail,
ProviderFailure,
Other {
raw: String,
},
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
#[non_exhaustive]
pub enum StopReason {
EndTurn,
MaxTokens,
StopSequence {
sequence: String,
},
ToolUse,
Refusal {
reason: RefusalReason,
},
Other {
raw: String,
},
}