use ferrin_message::Message;
use ferrin_spec::FinishReason;
use ferrin_spec::ProviderMetadata;
use ferrin_spec::Usage;
use ferrin_spec::Warning;
use ferrin_spec::language_model::Source;
use super::GeneratedFile;
use super::ParsedToolCall;
use super::StepContent;
use super::StepRequest;
use super::StepResponse;
use super::ToolResult;
use super::StepResult;
#[derive(Debug, Clone, PartialEq)]
pub struct GenerateTextResult<O> {
pub steps: Vec<StepResult>,
pub total_usage: Usage,
pub output: O,
}
impl<O> GenerateTextResult<O> {
#[must_use]
pub fn last_step(&self) -> &StepResult {
#[allow(clippy::expect_used, reason = "the loop records at least one step")]
self.steps.last().expect("at least one step")
}
#[must_use]
pub fn text(&self) -> String {
self.last_step().text()
}
#[must_use]
pub fn reasoning_text(&self) -> Option<String> {
self.last_step().reasoning_text()
}
#[must_use]
pub fn finish_reason(&self) -> &FinishReason {
&self.last_step().finish_reason
}
#[must_use]
pub fn usage(&self) -> &Usage {
&self.total_usage
}
#[must_use]
pub fn provider_metadata(&self) -> Option<&ProviderMetadata> {
self.last_step().provider_metadata.as_ref()
}
#[must_use]
pub fn warnings(&self) -> Vec<&Warning> {
self.steps.iter().flat_map(|step| &step.warnings).collect()
}
pub fn content(&self) -> impl Iterator<Item = &StepContent> {
self.steps.iter().flat_map(|step| &step.content)
}
pub fn files(&self) -> impl Iterator<Item = &GeneratedFile> {
self.steps.iter().flat_map(StepResult::files)
}
pub fn sources(&self) -> impl Iterator<Item = &Source> {
self.steps.iter().flat_map(StepResult::sources)
}
pub fn tool_calls(&self) -> impl Iterator<Item = &ParsedToolCall> {
self.steps.iter().flat_map(StepResult::tool_calls)
}
pub fn static_tool_calls(&self) -> impl Iterator<Item = &ParsedToolCall> {
self.tool_calls().filter(|call| !call.dynamic)
}
pub fn dynamic_tool_calls(&self) -> impl Iterator<Item = &ParsedToolCall> {
self.tool_calls().filter(|call| call.dynamic)
}
pub fn tool_results(&self) -> impl Iterator<Item = &ToolResult> {
self.steps.iter().flat_map(StepResult::tool_results)
}
pub fn static_tool_results(&self) -> impl Iterator<Item = &ToolResult> {
self.tool_results().filter(|result| !result.dynamic)
}
pub fn dynamic_tool_results(&self) -> impl Iterator<Item = &ToolResult> {
self.tool_results().filter(|result| result.dynamic)
}
#[must_use]
pub fn final_step(&self) -> &StepResult {
self.last_step()
}
#[must_use]
pub fn raw_finish_reason(&self) -> Option<&str> {
self.finish_reason().raw.as_deref()
}
#[must_use]
pub fn request(&self) -> &StepRequest {
&self.last_step().request
}
#[must_use]
pub fn response(&self) -> &StepResponse {
&self.last_step().response
}
#[must_use]
pub fn response_messages(&self) -> Vec<Message> {
self.steps
.iter()
.flat_map(|step| step.response.messages.iter().cloned())
.collect()
}
pub fn map_output<P>(self, f: impl FnOnce(O) -> P) -> GenerateTextResult<P> {
GenerateTextResult {
steps: self.steps,
total_usage: self.total_usage,
output: f(self.output),
}
}
}