agent_client_protocol_schema/
content.rs

1//! Content blocks for representing various types of information in the Agent Client Protocol.
2//!
3//! This module defines the core content types used throughout the protocol for communication
4//! between agents and clients. Content blocks provide a flexible, extensible way to represent
5//! text, images, audio, and other resources in prompts, responses, and tool call results.
6//!
7//! The content block structure is designed to be compatible with the Model Context Protocol (MCP),
8//! allowing seamless integration between ACP and MCP-based tools.
9//!
10//! See: [Content](https://agentclientprotocol.com/protocol/content)
11
12use schemars::JsonSchema;
13use serde::{Deserialize, Serialize};
14
15use crate::Meta;
16
17/// Content blocks represent displayable information in the Agent Client Protocol.
18///
19/// They provide a structured way to handle various types of user-facing content—whether
20/// it's text from language models, images for analysis, or embedded resources for context.
21///
22/// Content blocks appear in:
23/// - User prompts sent via `session/prompt`
24/// - Language model output streamed through `session/update` notifications
25/// - Progress updates and results from tool calls
26///
27/// This structure is compatible with the Model Context Protocol (MCP), enabling
28/// agents to seamlessly forward content from MCP tool outputs without transformation.
29///
30/// See protocol docs: [Content](https://agentclientprotocol.com/protocol/content)
31#[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 content. May be plain text or formatted with Markdown.
37    ///
38    /// All agents MUST support text content blocks in prompts.
39    /// Clients SHOULD render this text as Markdown.
40    Text(TextContent),
41    /// Images for visual context or analysis.
42    ///
43    /// Requires the `image` prompt capability when included in prompts.
44    Image(ImageContent),
45    /// Audio data for transcription or analysis.
46    ///
47    /// Requires the `audio` prompt capability when included in prompts.
48    Audio(AudioContent),
49    /// References to resources that the agent can access.
50    ///
51    /// All agents MUST support resource links in prompts.
52    ResourceLink(ResourceLink),
53    /// Complete resource contents embedded directly in the message.
54    ///
55    /// Preferred for including context as it avoids extra round-trips.
56    ///
57    /// Requires the `embeddedContext` prompt capability when included in prompts.
58    Resource(EmbeddedResource),
59}
60
61/// Text provided to or from an LLM.
62#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
69    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
70    /// these keys.
71    ///
72    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
73    #[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: Annotations) -> Self {
88        self.annotations = Some(annotations);
89        self
90    }
91
92    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
93    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
94    /// these keys.
95    ///
96    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
97    #[must_use]
98    pub fn meta(mut self, meta: Meta) -> Self {
99        self.meta = Some(meta);
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/// An image provided to or from an LLM.
111#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
122    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
123    /// these keys.
124    ///
125    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
126    #[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: Annotations) -> Self {
143        self.annotations = Some(annotations);
144        self
145    }
146
147    #[must_use]
148    pub fn uri(mut self, uri: impl Into<String>) -> Self {
149        self.uri = Some(uri.into());
150        self
151    }
152
153    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
154    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
155    /// these keys.
156    ///
157    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
158    #[must_use]
159    pub fn meta(mut self, meta: Meta) -> Self {
160        self.meta = Some(meta);
161        self
162    }
163}
164
165/// Audio provided to or from an LLM.
166#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
175    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
176    /// these keys.
177    ///
178    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
179    #[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: Annotations) -> Self {
195        self.annotations = Some(annotations);
196        self
197    }
198
199    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
200    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
201    /// these keys.
202    ///
203    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
204    #[must_use]
205    pub fn meta(mut self, meta: Meta) -> Self {
206        self.meta = Some(meta);
207        self
208    }
209}
210
211/// The contents of a resource, embedded into a prompt or tool call result.
212#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
219    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
220    /// these keys.
221    ///
222    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
223    #[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: Annotations) -> Self {
239        self.annotations = Some(annotations);
240        self
241    }
242
243    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
244    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
245    /// these keys.
246    ///
247    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
248    #[must_use]
249    pub fn meta(mut self, meta: Meta) -> Self {
250        self.meta = Some(meta);
251        self
252    }
253}
254
255/// Resource content that can be embedded in a message.
256#[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/// Text-based resource contents.
265#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
274    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
275    /// these keys.
276    ///
277    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
278    #[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 Into<String>) -> Self {
294        self.mime_type = Some(mime_type.into());
295        self
296    }
297
298    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
299    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
300    /// these keys.
301    ///
302    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
303    #[must_use]
304    pub fn meta(mut self, meta: Meta) -> Self {
305        self.meta = Some(meta);
306        self
307    }
308}
309
310/// Binary resource contents.
311#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
320    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
321    /// these keys.
322    ///
323    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
324    #[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 Into<String>) -> Self {
340        self.mime_type = Some(mime_type.into());
341        self
342    }
343
344    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
345    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
346    /// these keys.
347    ///
348    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
349    #[must_use]
350    pub fn meta(mut self, meta: Meta) -> Self {
351        self.meta = Some(meta);
352        self
353    }
354}
355
356/// A resource that the server is capable of reading, included in a prompt or tool call result.
357#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
374    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
375    /// these keys.
376    ///
377    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
378    #[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: Annotations) -> Self {
398        self.annotations = Some(annotations);
399        self
400    }
401
402    #[must_use]
403    pub fn description(mut self, description: impl Into<String>) -> Self {
404        self.description = Some(description.into());
405        self
406    }
407
408    #[must_use]
409    pub fn mime_type(mut self, mime_type: impl Into<String>) -> Self {
410        self.mime_type = Some(mime_type.into());
411        self
412    }
413
414    #[must_use]
415    pub fn size(mut self, size: i64) -> Self {
416        self.size = Some(size);
417        self
418    }
419
420    #[must_use]
421    pub fn title(mut self, title: impl Into<String>) -> Self {
422        self.title = Some(title.into());
423        self
424    }
425
426    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
427    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
428    /// these keys.
429    ///
430    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
431    #[must_use]
432    pub fn meta(mut self, meta: Meta) -> Self {
433        self.meta = Some(meta);
434        self
435    }
436}
437
438/// Optional annotations for the client. The client can use annotations to inform how objects are used or displayed
439#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
450    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
451    /// these keys.
452    ///
453    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
454    #[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: Vec<Role>) -> Self {
466        self.audience = Some(audience);
467        self
468    }
469
470    #[must_use]
471    pub fn last_modified(mut self, last_modified: impl Into<String>) -> Self {
472        self.last_modified = Some(last_modified.into());
473        self
474    }
475
476    #[must_use]
477    pub fn priority(mut self, priority: f64) -> Self {
478        self.priority = Some(priority);
479        self
480    }
481
482    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
483    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
484    /// these keys.
485    ///
486    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
487    #[must_use]
488    pub fn meta(mut self, meta: Meta) -> Self {
489        self.meta = Some(meta);
490        self
491    }
492}
493
494/// The sender or recipient of messages and data in a conversation.
495#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
496#[serde(rename_all = "camelCase")]
497#[non_exhaustive]
498pub enum Role {
499    Assistant,
500    User,
501}