Skip to main content

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::{IntoOption, 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    #[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
94    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
95    /// these keys.
96    ///
97    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
98    #[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/// An image provided to or from an LLM.
112#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
123    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
124    /// these keys.
125    ///
126    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
127    #[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
156    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
157    /// these keys.
158    ///
159    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
160    #[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/// Audio provided to or from an LLM.
168#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
177    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
178    /// these keys.
179    ///
180    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
181    #[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
203    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
204    /// these keys.
205    ///
206    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
207    #[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/// The contents of a resource, embedded into a prompt or tool call result.
215#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
222    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
223    /// these keys.
224    ///
225    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
226    #[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
247    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
248    /// these keys.
249    ///
250    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
251    #[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/// Resource content that can be embedded in a message.
259#[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/// Text-based resource contents.
268#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
277    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
278    /// these keys.
279    ///
280    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
281    #[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
303    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
304    /// these keys.
305    ///
306    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
307    #[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/// Binary resource contents.
315#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
324    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
325    /// these keys.
326    ///
327    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
328    #[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
350    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
351    /// these keys.
352    ///
353    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
354    #[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/// A resource that the server is capable of reading, included in a prompt or tool call result.
362#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
379    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
380    /// these keys.
381    ///
382    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
383    #[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
433    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
434    /// these keys.
435    ///
436    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
437    #[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/// Optional annotations for the client. The client can use annotations to inform how objects are used or displayed
445#[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
456    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
457    /// these keys.
458    ///
459    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
460    #[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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
489    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
490    /// these keys.
491    ///
492    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
493    #[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/// The sender or recipient of messages and data in a conversation.
501#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
502#[serde(rename_all = "camelCase")]
503#[non_exhaustive]
504pub enum Role {
505    Assistant,
506    User,
507}