Skip to main content

ferrin_core/generate_text/
result.rs

1//! The result of `generate_text`.
2
3use ferrin_message::Message;
4use ferrin_spec::FinishReason;
5use ferrin_spec::ProviderMetadata;
6use ferrin_spec::Usage;
7use ferrin_spec::Warning;
8
9use super::StepResult;
10
11/// Result of a completed generation loop.
12#[derive(Debug, Clone, PartialEq)]
13pub struct GenerateTextResult<O> {
14    /// All steps in order (at least one).
15    pub steps: Vec<StepResult>,
16    /// Usage summed over all steps.
17    pub total_usage: Usage,
18    /// The structured output (`()` when none was requested).
19    pub output: O,
20}
21
22impl<O> GenerateTextResult<O> {
23    /// The final step.
24    ///
25    /// # Panics
26    ///
27    /// Never: the loop always records at least one step.
28    #[must_use]
29    pub fn last_step(&self) -> &StepResult {
30        #[allow(clippy::expect_used, reason = "the loop records at least one step")]
31        self.steps.last().expect("at least one step")
32    }
33
34    /// Text of the final step.
35    #[must_use]
36    pub fn text(&self) -> String {
37        self.last_step().text()
38    }
39
40    /// Reasoning text of the final step.
41    #[must_use]
42    pub fn reasoning_text(&self) -> Option<String> {
43        self.last_step().reasoning_text()
44    }
45
46    /// Finish reason of the final step.
47    #[must_use]
48    pub fn finish_reason(&self) -> &FinishReason {
49        &self.last_step().finish_reason
50    }
51
52    /// Usage of the final step.
53    #[must_use]
54    pub fn usage(&self) -> &Usage {
55        &self.last_step().usage
56    }
57
58    /// Provider metadata of the final step.
59    #[must_use]
60    pub fn provider_metadata(&self) -> Option<&ProviderMetadata> {
61        self.last_step().provider_metadata.as_ref()
62    }
63
64    /// Warnings of the final step.
65    #[must_use]
66    pub fn warnings(&self) -> &[Warning] {
67        &self.last_step().warnings
68    }
69
70    /// Messages of all steps, ready to append to the conversation history.
71    #[must_use]
72    pub fn response_messages(&self) -> Vec<Message> {
73        self.steps
74            .iter()
75            .flat_map(|step| step.response.messages.iter().cloned())
76            .collect()
77    }
78
79    /// Maps the output.
80    pub fn map_output<P>(self, f: impl FnOnce(O) -> P) -> GenerateTextResult<P> {
81        GenerateTextResult {
82            steps: self.steps,
83            total_usage: self.total_usage,
84            output: f(self.output),
85        }
86    }
87}