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 pub fn new(text: impl Into<String>) -> Self {
79 Self {
80 annotations: None,
81 text: text.into(),
82 meta: None,
83 }
84 }
85
86 #[must_use]
87 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
88 self.annotations = annotations.into_option();
89 self
90 }
91
92 #[must_use]
98 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
99 self.meta = meta.into_option();
100 self
101 }
102}
103
104impl<T: Into<String>> From<T> for ContentBlock {
105 fn from(value: T) -> Self {
106 Self::Text(TextContent::new(value))
107 }
108}
109
110#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
112#[serde(rename_all = "camelCase")]
113#[non_exhaustive]
114pub struct ImageContent {
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub annotations: Option<Annotations>,
117 pub data: String,
118 pub mime_type: String,
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub uri: Option<String>,
121 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
127 pub meta: Option<Meta>,
128}
129
130impl ImageContent {
131 pub fn new(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
132 Self {
133 annotations: None,
134 data: data.into(),
135 mime_type: mime_type.into(),
136 uri: None,
137 meta: None,
138 }
139 }
140
141 #[must_use]
142 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
143 self.annotations = annotations.into_option();
144 self
145 }
146
147 #[must_use]
148 pub fn uri(mut self, uri: impl IntoOption<String>) -> Self {
149 self.uri = uri.into_option();
150 self
151 }
152
153 #[must_use]
159 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
160 self.meta = meta.into_option();
161 self
162 }
163}
164
165#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
167#[serde(rename_all = "camelCase")]
168#[non_exhaustive]
169pub struct AudioContent {
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub annotations: Option<Annotations>,
172 pub data: String,
173 pub mime_type: String,
174 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
180 pub meta: Option<Meta>,
181}
182
183impl AudioContent {
184 pub fn new(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
185 Self {
186 annotations: None,
187 data: data.into(),
188 mime_type: mime_type.into(),
189 meta: None,
190 }
191 }
192
193 #[must_use]
194 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
195 self.annotations = annotations.into_option();
196 self
197 }
198
199 #[must_use]
205 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
206 self.meta = meta.into_option();
207 self
208 }
209}
210
211#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
213#[non_exhaustive]
214pub struct EmbeddedResource {
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub annotations: Option<Annotations>,
217 pub resource: EmbeddedResourceResource,
218 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
224 pub meta: Option<Meta>,
225}
226
227impl EmbeddedResource {
228 #[must_use]
229 pub fn new(resource: EmbeddedResourceResource) -> Self {
230 Self {
231 annotations: None,
232 resource,
233 meta: None,
234 }
235 }
236
237 #[must_use]
238 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
239 self.annotations = annotations.into_option();
240 self
241 }
242
243 #[must_use]
249 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
250 self.meta = meta.into_option();
251 self
252 }
253}
254
255#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
257#[serde(untagged)]
258#[non_exhaustive]
259pub enum EmbeddedResourceResource {
260 TextResourceContents(TextResourceContents),
261 BlobResourceContents(BlobResourceContents),
262}
263
264#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
266#[serde(rename_all = "camelCase")]
267#[non_exhaustive]
268pub struct TextResourceContents {
269 #[serde(skip_serializing_if = "Option::is_none")]
270 pub mime_type: Option<String>,
271 pub text: String,
272 pub uri: String,
273 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
279 pub meta: Option<Meta>,
280}
281
282impl TextResourceContents {
283 pub fn new(text: impl Into<String>, uri: impl Into<String>) -> Self {
284 Self {
285 mime_type: None,
286 text: text.into(),
287 uri: uri.into(),
288 meta: None,
289 }
290 }
291
292 #[must_use]
293 pub fn mime_type(mut self, mime_type: impl IntoOption<String>) -> Self {
294 self.mime_type = mime_type.into_option();
295 self
296 }
297
298 #[must_use]
304 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
305 self.meta = meta.into_option();
306 self
307 }
308}
309
310#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
312#[serde(rename_all = "camelCase")]
313#[non_exhaustive]
314pub struct BlobResourceContents {
315 pub blob: String,
316 #[serde(skip_serializing_if = "Option::is_none")]
317 pub mime_type: Option<String>,
318 pub uri: String,
319 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
325 pub meta: Option<Meta>,
326}
327
328impl BlobResourceContents {
329 pub fn new(blob: impl Into<String>, uri: impl Into<String>) -> Self {
330 Self {
331 blob: blob.into(),
332 mime_type: None,
333 uri: uri.into(),
334 meta: None,
335 }
336 }
337
338 #[must_use]
339 pub fn mime_type(mut self, mime_type: impl IntoOption<String>) -> Self {
340 self.mime_type = mime_type.into_option();
341 self
342 }
343
344 #[must_use]
350 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
351 self.meta = meta.into_option();
352 self
353 }
354}
355
356#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
358#[serde(rename_all = "camelCase")]
359#[non_exhaustive]
360pub struct ResourceLink {
361 #[serde(skip_serializing_if = "Option::is_none")]
362 pub annotations: Option<Annotations>,
363 #[serde(skip_serializing_if = "Option::is_none")]
364 pub description: Option<String>,
365 #[serde(skip_serializing_if = "Option::is_none")]
366 pub mime_type: Option<String>,
367 pub name: String,
368 #[serde(skip_serializing_if = "Option::is_none")]
369 pub size: Option<i64>,
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub title: Option<String>,
372 pub uri: String,
373 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
379 pub meta: Option<Meta>,
380}
381
382impl ResourceLink {
383 pub fn new(name: impl Into<String>, uri: impl Into<String>) -> Self {
384 Self {
385 annotations: None,
386 description: None,
387 mime_type: None,
388 name: name.into(),
389 size: None,
390 title: None,
391 uri: uri.into(),
392 meta: None,
393 }
394 }
395
396 #[must_use]
397 pub fn annotations(mut self, annotations: impl IntoOption<Annotations>) -> Self {
398 self.annotations = annotations.into_option();
399 self
400 }
401
402 #[must_use]
403 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
404 self.description = description.into_option();
405 self
406 }
407
408 #[must_use]
409 pub fn mime_type(mut self, mime_type: impl IntoOption<String>) -> Self {
410 self.mime_type = mime_type.into_option();
411 self
412 }
413
414 #[must_use]
415 pub fn size(mut self, size: impl IntoOption<i64>) -> Self {
416 self.size = size.into_option();
417 self
418 }
419
420 #[must_use]
421 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
422 self.title = title.into_option();
423 self
424 }
425
426 #[must_use]
432 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
433 self.meta = meta.into_option();
434 self
435 }
436}
437
438#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, Default)]
440#[serde(rename_all = "camelCase")]
441#[non_exhaustive]
442pub struct Annotations {
443 #[serde(skip_serializing_if = "Option::is_none")]
444 pub audience: Option<Vec<Role>>,
445 #[serde(skip_serializing_if = "Option::is_none")]
446 pub last_modified: Option<String>,
447 #[serde(skip_serializing_if = "Option::is_none")]
448 pub priority: Option<f64>,
449 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
455 pub meta: Option<Meta>,
456}
457
458impl Annotations {
459 #[must_use]
460 pub fn new() -> Self {
461 Self::default()
462 }
463
464 #[must_use]
465 pub fn audience(mut self, audience: impl IntoOption<Vec<Role>>) -> Self {
466 self.audience = audience.into_option();
467 self
468 }
469
470 #[must_use]
471 pub fn last_modified(mut self, last_modified: impl IntoOption<String>) -> Self {
472 self.last_modified = last_modified.into_option();
473 self
474 }
475
476 #[must_use]
477 pub fn priority(mut self, priority: impl IntoOption<f64>) -> Self {
478 self.priority = priority.into_option();
479 self
480 }
481
482 #[must_use]
488 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
489 self.meta = meta.into_option();
490 self
491 }
492}
493
494#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
496#[serde(rename_all = "camelCase")]
497#[non_exhaustive]
498pub enum Role {
499 Assistant,
500 User,
501}