ferrin_spec/language_model/
result.rs1use chrono::DateTime;
4use chrono::Utc;
5use serde::Deserialize;
6use serde::Serialize;
7
8use super::content::Content;
9use super::finish_reason::FinishReason;
10use super::stream_part::StreamPart;
11use super::usage::Usage;
12use crate::dynamic::BoxStream;
13use crate::json::JsonValue;
14use crate::shared::Headers;
15use crate::shared::ModelId;
16use crate::shared::ProviderMetadata;
17use crate::shared::Warning;
18
19#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
21pub struct RequestMetadata {
22 #[serde(default, skip_serializing_if = "Option::is_none")]
24 pub body: Option<JsonValue>,
25}
26
27impl RequestMetadata {
28 #[must_use]
30 pub fn with_body(body: JsonValue) -> Self {
31 Self { body: Some(body) }
32 }
33}
34
35#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
40pub struct ResponseMetadata {
41 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub id: Option<String>,
44 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub timestamp: Option<DateTime<Utc>>,
47 #[serde(default, skip_serializing_if = "Option::is_none")]
49 pub model_id: Option<ModelId>,
50 #[serde(default, skip_serializing_if = "Option::is_none")]
52 pub headers: Option<Headers>,
53 #[serde(default, skip_serializing_if = "Option::is_none")]
55 pub body: Option<JsonValue>,
56}
57
58impl ResponseMetadata {
59 #[must_use]
61 pub fn with_headers(headers: Headers) -> Self {
62 Self {
63 headers: Some(headers),
64 ..Self::default()
65 }
66 }
67
68 #[must_use]
71 pub fn new(timestamp: DateTime<Utc>, model_id: impl Into<ModelId>) -> Self {
72 Self {
73 timestamp: Some(timestamp),
74 model_id: Some(model_id.into()),
75 ..Self::default()
76 }
77 }
78
79 pub fn merge(&mut self, other: ResponseMetadata) {
81 if other.id.is_some() {
82 self.id = other.id;
83 }
84 if other.timestamp.is_some() {
85 self.timestamp = other.timestamp;
86 }
87 if other.model_id.is_some() {
88 self.model_id = other.model_id;
89 }
90 if other.headers.is_some() {
91 self.headers = other.headers;
92 }
93 if other.body.is_some() {
94 self.body = other.body;
95 }
96 }
97}
98
99#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
101pub struct GenerateResult {
102 pub content: Vec<Content>,
104 pub finish_reason: FinishReason,
106 #[serde(default)]
108 pub usage: Usage,
109 #[serde(default, skip_serializing_if = "Option::is_none")]
111 pub provider_metadata: Option<ProviderMetadata>,
112 #[serde(default)]
114 pub request: RequestMetadata,
115 #[serde(default)]
117 pub response: ResponseMetadata,
118 #[serde(default)]
120 pub warnings: Vec<Warning>,
121}
122
123impl GenerateResult {
124 #[must_use]
126 pub fn new(content: Vec<Content>, finish_reason: FinishReason) -> Self {
127 Self {
128 content,
129 finish_reason,
130 usage: Usage::default(),
131 provider_metadata: None,
132 request: RequestMetadata::default(),
133 response: ResponseMetadata::default(),
134 warnings: Vec::new(),
135 }
136 }
137
138 #[must_use]
140 pub fn text(&self) -> String {
141 self.content.iter().filter_map(Content::as_text).collect()
142 }
143}
144
145pub struct StreamResult {
147 pub stream: BoxStream<'static, StreamPart>,
149 pub request: RequestMetadata,
151 pub response: ResponseMetadata,
153}
154
155impl StreamResult {
156 #[must_use]
158 pub fn new(stream: BoxStream<'static, StreamPart>) -> Self {
159 Self {
160 stream,
161 request: RequestMetadata::default(),
162 response: ResponseMetadata::default(),
163 }
164 }
165}
166
167impl std::fmt::Debug for StreamResult {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 f.debug_struct("StreamResult")
170 .field("stream", &"<stream>")
171 .field("request", &self.request)
172 .field("response", &self.response)
173 .finish()
174 }
175}