1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9#[serde(untagged)]
10pub enum UserInput {
11 Text(String),
13 Parts(Vec<ContentPart>),
15}
16
17impl From<String> for UserInput {
18 fn from(value: String) -> Self {
19 Self::Text(value)
20 }
21}
22
23impl From<&str> for UserInput {
24 fn from(value: &str) -> Self {
25 Self::Text(value.to_string())
26 }
27}
28
29impl From<Vec<ContentPart>> for UserInput {
30 fn from(value: Vec<ContentPart>) -> Self {
31 Self::Parts(value)
32 }
33}
34
35impl From<String> for ContentPart {
36 fn from(value: String) -> Self {
37 Self::Text(TextPart { text: value })
38 }
39}
40
41impl From<&str> for ContentPart {
42 fn from(value: &str) -> Self {
43 Self::Text(TextPart {
44 text: value.to_string(),
45 })
46 }
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
55#[serde(tag = "type", rename_all = "snake_case")]
56#[non_exhaustive]
57pub enum ContentPart {
58 Text(TextPart),
60 Think(ThinkPart),
62 #[serde(rename = "image_url")]
64 ImageUrl(ImageUrlPart),
65 #[serde(rename = "audio_url")]
67 AudioUrl(AudioUrlPart),
68 #[serde(rename = "video_url")]
70 VideoUrl(VideoUrlPart),
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
75pub struct TextPart {
76 pub text: String,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
82pub struct ThinkPart {
83 pub think: String,
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub encrypted: Option<String>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
92pub struct ImageUrlPart {
93 pub image_url: MediaUrl,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
99pub struct AudioUrlPart {
100 pub audio_url: MediaUrl,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
106pub struct VideoUrlPart {
107 pub video_url: MediaUrl,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
113pub struct MediaUrl {
114 pub url: String,
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub id: Option<String>,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
130pub struct DisplayBlock {
131 #[serde(rename = "type")]
133 pub block_type: DisplayBlockType,
134 #[serde(skip_serializing_if = "Option::is_none")]
136 pub text: Option<String>,
137 #[serde(skip_serializing_if = "Option::is_none")]
139 pub path: Option<String>,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub old_text: Option<String>,
143 #[serde(skip_serializing_if = "Option::is_none")]
145 pub new_text: Option<String>,
146 #[serde(skip_serializing_if = "Option::is_none", default)]
149 pub is_summary: Option<bool>,
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub items: Option<Vec<TodoDisplayItem>>,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub language: Option<String>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub command: Option<String>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub data: Option<serde_json::Value>,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
166#[serde(rename_all = "snake_case")]
167#[non_exhaustive]
168pub enum DisplayBlockType {
169 Brief,
171 Diff,
173 Todo,
175 Shell,
177 #[serde(rename = "unknown")]
179 Unknown,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
184pub struct TodoDisplayItem {
185 pub title: String,
187 pub status: TodoStatus,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
193#[serde(rename_all = "snake_case")]
194#[non_exhaustive]
195pub enum TodoStatus {
196 Pending,
198 InProgress,
200 Done,
202}
203
204impl DisplayBlock {
209 pub fn brief(text: impl Into<String>) -> Self {
211 Self {
212 block_type: DisplayBlockType::Brief,
213 text: Some(text.into()),
214 path: None,
215 old_text: None,
216 new_text: None,
217 is_summary: None,
218 items: None,
219 language: None,
220 command: None,
221 data: None,
222 }
223 }
224
225 pub fn diff(
227 path: impl Into<String>,
228 old_text: impl Into<String>,
229 new_text: impl Into<String>,
230 ) -> Self {
231 Self {
232 block_type: DisplayBlockType::Diff,
233 text: None,
234 path: Some(path.into()),
235 old_text: Some(old_text.into()),
236 new_text: Some(new_text.into()),
237 is_summary: None,
238 items: None,
239 language: None,
240 command: None,
241 data: None,
242 }
243 }
244
245 #[must_use]
247 pub const fn todo(items: Vec<TodoDisplayItem>) -> Self {
248 Self {
249 block_type: DisplayBlockType::Todo,
250 text: None,
251 path: None,
252 old_text: None,
253 new_text: None,
254 is_summary: None,
255 items: Some(items),
256 language: None,
257 command: None,
258 data: None,
259 }
260 }
261
262 pub fn shell(command: impl Into<String>, language: impl Into<String>) -> Self {
264 Self {
265 block_type: DisplayBlockType::Shell,
266 text: None,
267 path: None,
268 old_text: None,
269 new_text: None,
270 is_summary: None,
271 items: None,
272 language: Some(language.into()),
273 command: Some(command.into()),
274 data: None,
275 }
276 }
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
285pub struct ToolReturnValue {
286 pub is_error: bool,
288 pub output: ToolOutput,
290 pub message: String,
292 pub display: Vec<DisplayBlock>,
294 #[serde(skip_serializing_if = "Option::is_none")]
296 pub extras: Option<serde_json::Value>,
297}
298
299impl ToolReturnValue {
300 pub fn new(message: impl Into<String>) -> Self {
302 Self {
303 is_error: false,
304 output: ToolOutput::Text(String::new()),
305 message: message.into(),
306 display: vec![],
307 extras: None,
308 }
309 }
310
311 #[must_use]
313 pub const fn with_error(mut self) -> Self {
314 self.is_error = true;
315 self
316 }
317
318 #[must_use]
320 pub fn with_output(mut self, output: impl Into<ToolOutput>) -> Self {
321 self.output = output.into();
322 self
323 }
324
325 #[must_use]
327 pub fn with_display(mut self, block: DisplayBlock) -> Self {
328 self.display.push(block);
329 self
330 }
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
335#[serde(untagged)]
336pub enum ToolOutput {
337 Text(String),
339 Parts(Vec<ContentPart>),
341}
342
343impl From<String> for ToolOutput {
344 fn from(value: String) -> Self {
345 Self::Text(value)
346 }
347}
348
349impl From<&str> for ToolOutput {
350 fn from(value: &str) -> Self {
351 Self::Text(value.to_string())
352 }
353}
354
355impl From<Vec<ContentPart>> for ToolOutput {
356 fn from(value: Vec<ContentPart>) -> Self {
357 Self::Parts(value)
358 }
359}