1use schemars::JsonSchema;
13use serde::{Deserialize, Serialize};
14
15use crate::{IntoOption, Meta};
16
17#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
32#[serde(tag = "type", rename_all = "snake_case")]
33#[schemars(extend("discriminator" = {"propertyName": "type"}))]
34#[non_exhaustive]
35pub enum ContentBlock {
36 Text(TextContent),
41 Image(ImageContent),
45 Audio(AudioContent),
49 ResourceLink(ResourceLink),
53 Resource(EmbeddedResource),
59}
60
61#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
63#[non_exhaustive]
64pub struct TextContent {
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub annotations: Option<Annotations>,
67 pub text: String,
68 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
74 pub meta: Option<Meta>,
75}
76
77impl TextContent {
78 #[must_use]
79 pub fn new(text: impl Into<String>) -> Self {
80 Self {
81 annotations: None,
82 text: text.into(),
83 meta: None,
84 }
85 }
86
87 #[must_use]
88 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
89 self.annotations = annotations.into_option();
90 self
91 }
92
93 #[must_use]
99 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
100 self.meta = meta.into_option();
101 self
102 }
103}
104
105impl<T: Into<String>> From<T> for ContentBlock {
106 fn from(value: T) -> Self {
107 Self::Text(TextContent::new(value))
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
113#[serde(rename_all = "camelCase")]
114#[non_exhaustive]
115pub struct ImageContent {
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub annotations: Option<Annotations>,
118 pub data: String,
119 pub mime_type: String,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub uri: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
128 pub meta: Option<Meta>,
129}
130
131impl ImageContent {
132 #[must_use]
133 pub fn new(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
134 Self {
135 annotations: None,
136 data: data.into(),
137 mime_type: mime_type.into(),
138 uri: None,
139 meta: None,
140 }
141 }
142
143 #[must_use]
144 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
145 self.annotations = annotations.into_option();
146 self
147 }
148
149 #[must_use]
150 pub fn uri(mut self, uri: impl IntoOption<String>) -> Self {
151 self.uri = uri.into_option();
152 self
153 }
154
155 #[must_use]
161 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
162 self.meta = meta.into_option();
163 self
164 }
165}
166
167#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
169#[serde(rename_all = "camelCase")]
170#[non_exhaustive]
171pub struct AudioContent {
172 #[serde(skip_serializing_if = "Option::is_none")]
173 pub annotations: Option<Annotations>,
174 pub data: String,
175 pub mime_type: String,
176 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
182 pub meta: Option<Meta>,
183}
184
185impl AudioContent {
186 #[must_use]
187 pub fn new(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
188 Self {
189 annotations: None,
190 data: data.into(),
191 mime_type: mime_type.into(),
192 meta: None,
193 }
194 }
195
196 #[must_use]
197 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
198 self.annotations = annotations.into_option();
199 self
200 }
201
202 #[must_use]
208 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
209 self.meta = meta.into_option();
210 self
211 }
212}
213
214#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
216#[non_exhaustive]
217pub struct EmbeddedResource {
218 #[serde(skip_serializing_if = "Option::is_none")]
219 pub annotations: Option<Annotations>,
220 pub resource: EmbeddedResourceResource,
221 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
227 pub meta: Option<Meta>,
228}
229
230impl EmbeddedResource {
231 #[must_use]
232 pub fn new(resource: EmbeddedResourceResource) -> Self {
233 Self {
234 annotations: None,
235 resource,
236 meta: None,
237 }
238 }
239
240 #[must_use]
241 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
242 self.annotations = annotations.into_option();
243 self
244 }
245
246 #[must_use]
252 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
253 self.meta = meta.into_option();
254 self
255 }
256}
257
258#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
260#[serde(untagged)]
261#[non_exhaustive]
262pub enum EmbeddedResourceResource {
263 TextResourceContents(TextResourceContents),
264 BlobResourceContents(BlobResourceContents),
265}
266
267#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
269#[serde(rename_all = "camelCase")]
270#[non_exhaustive]
271pub struct TextResourceContents {
272 #[serde(skip_serializing_if = "Option::is_none")]
273 pub mime_type: Option<String>,
274 pub text: String,
275 pub uri: String,
276 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
282 pub meta: Option<Meta>,
283}
284
285impl TextResourceContents {
286 #[must_use]
287 pub fn new(text: impl Into<String>, uri: impl Into<String>) -> Self {
288 Self {
289 mime_type: None,
290 text: text.into(),
291 uri: uri.into(),
292 meta: None,
293 }
294 }
295
296 #[must_use]
297 pub fn mime_type(mut self, mime_type: impl IntoOption<String>) -> Self {
298 self.mime_type = mime_type.into_option();
299 self
300 }
301
302 #[must_use]
308 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
309 self.meta = meta.into_option();
310 self
311 }
312}
313
314#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
316#[serde(rename_all = "camelCase")]
317#[non_exhaustive]
318pub struct BlobResourceContents {
319 pub blob: String,
320 #[serde(skip_serializing_if = "Option::is_none")]
321 pub mime_type: Option<String>,
322 pub uri: String,
323 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
329 pub meta: Option<Meta>,
330}
331
332impl BlobResourceContents {
333 #[must_use]
334 pub fn new(blob: impl Into<String>, uri: impl Into<String>) -> Self {
335 Self {
336 blob: blob.into(),
337 mime_type: None,
338 uri: uri.into(),
339 meta: None,
340 }
341 }
342
343 #[must_use]
344 pub fn mime_type(mut self, mime_type: impl IntoOption<String>) -> Self {
345 self.mime_type = mime_type.into_option();
346 self
347 }
348
349 #[must_use]
355 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
356 self.meta = meta.into_option();
357 self
358 }
359}
360
361#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
363#[serde(rename_all = "camelCase")]
364#[non_exhaustive]
365pub struct ResourceLink {
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub annotations: Option<Annotations>,
368 #[serde(skip_serializing_if = "Option::is_none")]
369 pub description: Option<String>,
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub mime_type: Option<String>,
372 pub name: String,
373 #[serde(skip_serializing_if = "Option::is_none")]
374 pub size: Option<i64>,
375 #[serde(skip_serializing_if = "Option::is_none")]
376 pub title: Option<String>,
377 pub uri: String,
378 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
384 pub meta: Option<Meta>,
385}
386
387impl ResourceLink {
388 #[must_use]
389 pub fn new(name: impl Into<String>, uri: impl Into<String>) -> Self {
390 Self {
391 annotations: None,
392 description: None,
393 mime_type: None,
394 name: name.into(),
395 size: None,
396 title: None,
397 uri: uri.into(),
398 meta: None,
399 }
400 }
401
402 #[must_use]
403 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
404 self.annotations = annotations.into_option();
405 self
406 }
407
408 #[must_use]
409 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
410 self.description = description.into_option();
411 self
412 }
413
414 #[must_use]
415 pub fn mime_type(mut self, mime_type: impl IntoOption<String>) -> Self {
416 self.mime_type = mime_type.into_option();
417 self
418 }
419
420 #[must_use]
421 pub fn size(mut self, size: impl IntoOption<i64>) -> Self {
422 self.size = size.into_option();
423 self
424 }
425
426 #[must_use]
427 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
428 self.title = title.into_option();
429 self
430 }
431
432 #[must_use]
438 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
439 self.meta = meta.into_option();
440 self
441 }
442}
443
444#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, Default)]
446#[serde(rename_all = "camelCase")]
447#[non_exhaustive]
448pub struct Annotations {
449 #[serde(skip_serializing_if = "Option::is_none")]
450 pub audience: Option<Vec<Role>>,
451 #[serde(skip_serializing_if = "Option::is_none")]
452 pub last_modified: Option<String>,
453 #[serde(skip_serializing_if = "Option::is_none")]
454 pub priority: Option<f64>,
455 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
461 pub meta: Option<Meta>,
462}
463
464impl Annotations {
465 #[must_use]
466 pub fn new() -> Self {
467 Self::default()
468 }
469
470 #[must_use]
471 pub fn audience(mut self, audience: impl IntoOption<Vec<Role>>) -> Self {
472 self.audience = audience.into_option();
473 self
474 }
475
476 #[must_use]
477 pub fn last_modified(mut self, last_modified: impl IntoOption<String>) -> Self {
478 self.last_modified = last_modified.into_option();
479 self
480 }
481
482 #[must_use]
483 pub fn priority(mut self, priority: impl IntoOption<f64>) -> Self {
484 self.priority = priority.into_option();
485 self
486 }
487
488 #[must_use]
494 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
495 self.meta = meta.into_option();
496 self
497 }
498}
499
500#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
502#[serde(rename_all = "camelCase")]
503#[non_exhaustive]
504pub enum Role {
505 Assistant,
506 User,
507}