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
15/// Content blocks represent displayable information in the Agent Client Protocol.
16///
17/// They provide a structured way to handle various types of user-facing content—whether
18/// it's text from language models, images for analysis, or embedded resources for context.
19///
20/// Content blocks appear in:
21/// - User prompts sent via `session/prompt`
22/// - Language model output streamed through `session/update` notifications
23/// - Progress updates and results from tool calls
24///
25/// This structure is compatible with the Model Context Protocol (MCP), enabling
26/// agents to seamlessly forward content from MCP tool outputs without transformation.
27///
28/// See protocol docs: [Content](https://agentclientprotocol.com/protocol/content)
29#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
30#[serde(tag = "type", rename_all = "snake_case")]
31#[schemars(extend("discriminator" = {"propertyName": "type"}))]
32pub enum ContentBlock {
33    /// Text content. May be plain text or formatted with Markdown.
34    ///
35    /// All agents MUST support text content blocks in prompts.
36    /// Clients SHOULD render this text as Markdown.
37    Text(TextContent),
38    /// Images for visual context or analysis.
39    ///
40    /// Requires the `image` prompt capability when included in prompts.
41    Image(ImageContent),
42    /// Audio data for transcription or analysis.
43    ///
44    /// Requires the `audio` prompt capability when included in prompts.
45    Audio(AudioContent),
46    /// References to resources that the agent can access.
47    ///
48    /// All agents MUST support resource links in prompts.
49    ResourceLink(ResourceLink),
50    /// Complete resource contents embedded directly in the message.
51    ///
52    /// Preferred for including context as it avoids extra round-trips.
53    ///
54    /// Requires the `embeddedContext` prompt capability when included in prompts.
55    Resource(EmbeddedResource),
56}
57
58/// Text provided to or from an LLM.
59#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
60#[schemars(inline)]
61pub struct TextContent {
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub annotations: Option<Annotations>,
64    pub text: String,
65    /// Extension point for implementations
66    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
67    pub meta: Option<serde_json::Value>,
68}
69
70impl<T: Into<String>> From<T> for ContentBlock {
71    fn from(value: T) -> Self {
72        Self::Text(TextContent {
73            annotations: None,
74            text: value.into(),
75            meta: None,
76        })
77    }
78}
79
80/// An image provided to or from an LLM.
81#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
82#[schemars(inline)]
83pub struct ImageContent {
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub annotations: Option<Annotations>,
86    pub data: String,
87    #[serde(rename = "mimeType")]
88    pub mime_type: String,
89    #[serde(default, skip_serializing_if = "Option::is_none")]
90    pub uri: Option<String>,
91    /// Extension point for implementations
92    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
93    pub meta: Option<serde_json::Value>,
94}
95
96/// Audio provided to or from an LLM.
97#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
98#[schemars(inline)]
99pub struct AudioContent {
100    #[serde(default, skip_serializing_if = "Option::is_none")]
101    pub annotations: Option<Annotations>,
102    pub data: String,
103    #[serde(rename = "mimeType")]
104    pub mime_type: String,
105    /// Extension point for implementations
106    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
107    pub meta: Option<serde_json::Value>,
108}
109
110/// The contents of a resource, embedded into a prompt or tool call result.
111#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
112#[schemars(inline)]
113pub struct EmbeddedResource {
114    #[serde(default, skip_serializing_if = "Option::is_none")]
115    pub annotations: Option<Annotations>,
116    pub resource: EmbeddedResourceResource,
117    /// Extension point for implementations
118    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
119    pub meta: Option<serde_json::Value>,
120}
121
122/// Resource content that can be embedded in a message.
123#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
124#[serde(untagged)]
125pub enum EmbeddedResourceResource {
126    TextResourceContents(TextResourceContents),
127    BlobResourceContents(BlobResourceContents),
128}
129
130/// Text-based resource contents.
131#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
132pub struct TextResourceContents {
133    #[serde(rename = "mimeType", default, skip_serializing_if = "Option::is_none")]
134    pub mime_type: Option<String>,
135    pub text: String,
136    pub uri: String,
137    /// Extension point for implementations
138    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
139    pub meta: Option<serde_json::Value>,
140}
141
142/// Binary resource contents.
143#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
144pub struct BlobResourceContents {
145    pub blob: String,
146    #[serde(rename = "mimeType", default, skip_serializing_if = "Option::is_none")]
147    pub mime_type: Option<String>,
148    pub uri: String,
149    /// Extension point for implementations
150    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
151    pub meta: Option<serde_json::Value>,
152}
153
154/// A resource that the server is capable of reading, included in a prompt or tool call result.
155#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
156#[schemars(inline)]
157pub struct ResourceLink {
158    #[serde(default, skip_serializing_if = "Option::is_none")]
159    pub annotations: Option<Annotations>,
160    #[serde(default, skip_serializing_if = "Option::is_none")]
161    pub description: Option<String>,
162    #[serde(rename = "mimeType", default, skip_serializing_if = "Option::is_none")]
163    pub mime_type: Option<String>,
164    pub name: String,
165    #[serde(default, skip_serializing_if = "Option::is_none")]
166    pub size: Option<i64>,
167    #[serde(default, skip_serializing_if = "Option::is_none")]
168    pub title: Option<String>,
169    pub uri: String,
170    /// Extension point for implementations
171    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
172    pub meta: Option<serde_json::Value>,
173}
174
175/// Optional annotations for the client. The client can use annotations to inform how objects are used or displayed
176#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
177pub struct Annotations {
178    #[serde(default, skip_serializing_if = "Option::is_none")]
179    pub audience: Option<Vec<Role>>,
180    #[serde(
181        rename = "lastModified",
182        default,
183        skip_serializing_if = "Option::is_none"
184    )]
185    pub last_modified: Option<String>,
186    #[serde(default, skip_serializing_if = "Option::is_none")]
187    pub priority: Option<f64>,
188    /// Extension point for implementations
189    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
190    pub meta: Option<serde_json::Value>,
191}
192
193/// The sender or recipient of messages and data in a conversation.
194#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
195pub enum Role {
196    #[serde(rename = "assistant")]
197    Assistant,
198    #[serde(rename = "user")]
199    User,
200}