agent_client_protocol/agent.rs
1//! Methods and notifications the agent handles/receives.
2//!
3//! This module defines the Agent trait and all associated types for implementing
4//! an AI coding agent that follows the Agent Client Protocol (ACP).
5
6use std::{path::PathBuf, sync::Arc};
7
8use anyhow::Result;
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11
12use crate::{ClientCapabilities, ContentBlock, Error, ProtocolVersion, SessionId};
13
14/// Defines the interface that all ACP-compliant agents must implement.
15///
16/// Agents are programs that use generative AI to autonomously modify code. They handle
17/// requests from clients and execute tasks using language models and tools.
18pub trait Agent {
19 /// Establishes the connection with a client and negotiates protocol capabilities.
20 ///
21 /// This method is called once at the beginning of the connection to:
22 /// - Negotiate the protocol version to use
23 /// - Exchange capability information between client and agent
24 /// - Determine available authentication methods
25 ///
26 /// The agent should respond with its supported protocol version and capabilities.
27 ///
28 /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
29 fn initialize(
30 &self,
31 arguments: InitializeRequest,
32 ) -> impl Future<Output = Result<InitializeResponse, Error>>;
33
34 /// Authenticates the client using the specified authentication method.
35 ///
36 /// Called when the agent requires authentication before allowing session creation.
37 /// The client provides the authentication method ID that was advertised during initialization.
38 ///
39 /// After successful authentication, the client can proceed to create sessions with
40 /// `new_session` without receiving an `auth_required` error.
41 ///
42 /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
43 fn authenticate(
44 &self,
45 arguments: AuthenticateRequest,
46 ) -> impl Future<Output = Result<(), Error>>;
47
48 /// Creates a new conversation session with the agent.
49 ///
50 /// Sessions represent independent conversation contexts with their own history and state.
51 ///
52 /// The agent should:
53 /// - Create a new session context
54 /// - Connect to any specified MCP servers
55 /// - Return a unique session ID for future requests
56 ///
57 /// May return an `auth_required` error if the agent requires authentication.
58 ///
59 /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
60 fn new_session(
61 &self,
62 arguments: NewSessionRequest,
63 ) -> impl Future<Output = Result<NewSessionResponse, Error>>;
64
65 /// Loads an existing session to resume a previous conversation.
66 ///
67 /// This method is only available if the agent advertises the `loadSession` capability.
68 ///
69 /// The agent should:
70 /// - Restore the session context and conversation history
71 /// - Connect to the specified MCP servers
72 /// - Stream the entire conversation history back to the client via notifications
73 ///
74 /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
75 fn load_session(
76 &self,
77 arguments: LoadSessionRequest,
78 ) -> impl Future<Output = Result<(), Error>>;
79
80 /// Processes a user prompt within a session.
81 ///
82 /// This method handles the whole lifecycle of a prompt:
83 /// - Receives user messages with optional context (files, images, etc.)
84 /// - Processes the prompt using language models
85 /// - Reports language model content and tool calls to the Clients
86 /// - Requests permission to run tools
87 /// - Executes any requested tool calls
88 /// - Returns when the turn is complete with a stop reason
89 ///
90 /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
91 fn prompt(
92 &self,
93 arguments: PromptRequest,
94 ) -> impl Future<Output = Result<PromptResponse, Error>>;
95
96 /// Cancels ongoing operations for a session.
97 ///
98 /// This is a notification sent by the client to cancel an ongoing prompt turn.
99 ///
100 /// Upon receiving this notification, the Agent SHOULD:
101 /// - Stop all language model requests as soon as possible
102 /// - Abort all tool call invocations in progress
103 /// - Send any pending `session/update` notifications
104 /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
105 ///
106 /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
107 fn cancel(&self, args: CancelNotification) -> impl Future<Output = Result<(), Error>>;
108}
109
110// Initialize
111
112/// Request parameters for the initialize method.
113///
114/// Sent by the client to establish connection and negotiate capabilities.
115///
116/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
117#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
118#[schemars(extend("x-side" = "agent", "x-method" = "initialize"))]
119#[serde(rename_all = "camelCase")]
120pub struct InitializeRequest {
121 /// The latest protocol version supported by the client.
122 pub protocol_version: ProtocolVersion,
123 /// Capabilities supported by the client.
124 #[serde(default)]
125 pub client_capabilities: ClientCapabilities,
126}
127
128/// Response from the initialize method.
129///
130/// Contains the negotiated protocol version and agent capabilities.
131///
132/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
133#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
134#[schemars(extend("x-side" = "agent", "x-method" = "initialize"))]
135#[serde(rename_all = "camelCase")]
136pub struct InitializeResponse {
137 /// The protocol version the client specified if supported by the agent,
138 /// or the latest protocol version supported by the agent.
139 ///
140 /// The client should disconnect, if it doesn't support this version.
141 pub protocol_version: ProtocolVersion,
142 /// Capabilities supported by the agent.
143 #[serde(default)]
144 pub agent_capabilities: AgentCapabilities,
145 /// Authentication methods supported by the agent.
146 #[serde(default)]
147 pub auth_methods: Vec<AuthMethod>,
148}
149
150// Authentication
151
152/// Request parameters for the authenticate method.
153///
154/// Specifies which authentication method to use.
155#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
156#[schemars(extend("x-side" = "agent", "x-method" = "authenticate"))]
157#[serde(rename_all = "camelCase")]
158pub struct AuthenticateRequest {
159 /// The ID of the authentication method to use.
160 /// Must be one of the methods advertised in the initialize response.
161 pub method_id: AuthMethodId,
162}
163
164/// Unique identifier for an authentication method.
165#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
166#[serde(transparent)]
167pub struct AuthMethodId(pub Arc<str>);
168
169/// Describes an available authentication method.
170#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
171#[serde(rename_all = "camelCase")]
172pub struct AuthMethod {
173 /// Unique identifier for this authentication method.
174 pub id: AuthMethodId,
175 /// Human-readable name of the authentication method.
176 pub name: String,
177 /// Optional description providing more details about this authentication method.
178 pub description: Option<String>,
179}
180
181// New session
182
183/// Request parameters for creating a new session.
184///
185/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
186#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
187#[schemars(extend("x-side" = "agent", "x-method" = "session/new"))]
188#[serde(rename_all = "camelCase")]
189pub struct NewSessionRequest {
190 /// The working directory for this session. Must be an absolute path.
191 pub cwd: PathBuf,
192 /// List of MCP (Model Context Protocol) servers the agent should connect to.
193 pub mcp_servers: Vec<McpServer>,
194}
195
196/// Response from creating a new session.
197///
198/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
199#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
200#[schemars(extend("x-side" = "agent", "x-method" = "session/new"))]
201#[serde(rename_all = "camelCase")]
202pub struct NewSessionResponse {
203 /// Unique identifier for the created session.
204 ///
205 /// Used in all subsequent requests for this conversation.
206 pub session_id: SessionId,
207}
208
209// Load session
210
211/// Request parameters for loading an existing session.
212///
213/// Only available if the agent supports the `loadSession` capability.
214///
215/// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
216#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
217#[schemars(extend("x-side" = "agent", "x-method" = "session/load"))]
218#[serde(rename_all = "camelCase")]
219pub struct LoadSessionRequest {
220 /// List of MCP servers to connect to for this session.
221 pub mcp_servers: Vec<McpServer>,
222 /// The working directory for this session.
223 pub cwd: PathBuf,
224 /// The ID of the session to load.
225 pub session_id: SessionId,
226}
227
228// MCP
229
230/// Configuration for connecting to an MCP (Model Context Protocol) server.
231///
232/// MCP servers provide tools and context that the agent can use when
233/// processing prompts.
234///
235/// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)
236#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
237#[serde(rename_all = "camelCase")]
238pub struct McpServer {
239 /// Human-readable name identifying this MCP server.
240 pub name: String,
241 /// Path to the MCP server executable.
242 pub command: PathBuf,
243 /// Command-line arguments to pass to the MCP server.
244 pub args: Vec<String>,
245 /// Environment variables to set when launching the MCP server.
246 pub env: Vec<EnvVariable>,
247}
248
249/// An environment variable to set when launching an MCP server.
250#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
251#[serde(rename_all = "camelCase")]
252pub struct EnvVariable {
253 /// The name of the environment variable.
254 pub name: String,
255 /// The value to set for the environment variable.
256 pub value: String,
257}
258
259// Prompt
260
261/// Request parameters for sending a user prompt to the agent.
262///
263/// Contains the user's message and any additional context.
264///
265/// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message)
266#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
267#[schemars(extend("x-side" = "agent", "x-method" = "session/prompt"))]
268#[serde(rename_all = "camelCase")]
269pub struct PromptRequest {
270 /// The ID of the session to send this user message to
271 pub session_id: SessionId,
272 /// The blocks of content that compose the user's message.
273 ///
274 /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
275 /// while other variants are optionally enabled via [`PromptCapabilities`].
276 ///
277 /// The Client MUST adapt its interface according to [`PromptCapabilities`].
278 ///
279 /// The client MAY include referenced pieces of context as either
280 /// [`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].
281 ///
282 /// When available, [`ContentBlock::Resource`] is preferred
283 /// as it avoids extra round-trips and allows the message to include
284 /// pieces of context from sources the agent may not have access to.
285 pub prompt: Vec<ContentBlock>,
286}
287
288/// Response from processing a user prompt.
289///
290/// See protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion)
291#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
292#[schemars(extend("x-side" = "agent", "x-method" = "session/prompt"))]
293#[serde(rename_all = "camelCase")]
294pub struct PromptResponse {
295 /// Indicates why the agent stopped processing the turn.
296 pub stop_reason: StopReason,
297}
298
299/// Reasons why an agent stops processing a prompt turn.
300///
301/// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)
302#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
303#[serde(rename_all = "snake_case")]
304pub enum StopReason {
305 /// The turn ended successfully.
306 EndTurn,
307 /// The turn ended because the agent reached the maximum number of tokens.
308 MaxTokens,
309 /// The turn ended because the agent reached the maximum number of allowed
310 /// agent requests between user turns.
311 MaxTurnRequests,
312 /// The turn ended because the agent refused to continue. The user prompt
313 /// and everything that comes after it won't be included in the next
314 /// prompt, so this should be reflected in the UI.
315 Refusal,
316 /// The turn was cancelled by the client via `session/cancel`.
317 ///
318 /// This stop reason MUST be returned when the client sends a `session/cancel`
319 /// notification, even if the cancellation causes exceptions in underlying operations.
320 /// Agents should catch these exceptions and return this semantically meaningful
321 /// response to confirm successful cancellation.
322 Cancelled,
323}
324
325// Capabilities
326
327/// Capabilities supported by the agent.
328///
329/// Advertised during initialization to inform the client about
330/// available features and content types.
331///
332/// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)
333#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
334#[serde(rename_all = "camelCase")]
335pub struct AgentCapabilities {
336 /// Whether the agent supports `session/load`.
337 #[serde(default)]
338 pub load_session: bool,
339 /// Prompt capabilities supported by the agent.
340 #[serde(default)]
341 pub prompt_capabilities: PromptCapabilities,
342}
343
344/// Prompt capabilities supported by the agent in `session/prompt` requests.
345///
346/// Baseline agent functionality requires support for [`ContentBlock::Text`]
347/// and [`ContentBlock::ResourceLink`] in prompt requests.
348///
349/// Other variants must be explicitly opted in to.
350/// Capabilities for different types of content in prompt requests.
351///
352/// Indicates which content types beyond the baseline (text and resource links)
353/// the agent can process.
354///
355/// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)
356#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
357#[serde(rename_all = "camelCase")]
358pub struct PromptCapabilities {
359 /// Agent supports [`ContentBlock::Image`].
360 #[serde(default)]
361 pub image: bool,
362 /// Agent supports [`ContentBlock::Audio`].
363 #[serde(default)]
364 pub audio: bool,
365 /// Agent supports embedded context in `session/prompt` requests.
366 ///
367 /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
368 /// in prompt requests for pieces of context that are referenced in the message.
369 #[serde(default)]
370 pub embedded_context: bool,
371}
372
373// Method schema
374
375/// Names of all methods that agents handle.
376///
377/// Provides a centralized definition of method names used in the protocol.
378#[derive(Debug, Clone, Serialize, Deserialize)]
379pub struct AgentMethodNames {
380 /// Method for initializing the connection.
381 pub initialize: &'static str,
382 /// Method for authenticating with the agent.
383 pub authenticate: &'static str,
384 /// Method for creating a new session.
385 pub session_new: &'static str,
386 /// Method for loading an existing session.
387 pub session_load: &'static str,
388 /// Method for sending a prompt to the agent.
389 pub session_prompt: &'static str,
390 /// Notification for cancelling operations.
391 pub session_cancel: &'static str,
392}
393
394/// Constant containing all agent method names.
395pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
396 initialize: INITIALIZE_METHOD_NAME,
397 authenticate: AUTHENTICATE_METHOD_NAME,
398 session_new: SESSION_NEW_METHOD_NAME,
399 session_load: SESSION_LOAD_METHOD_NAME,
400 session_prompt: SESSION_PROMPT_METHOD_NAME,
401 session_cancel: SESSION_CANCEL_METHOD_NAME,
402};
403
404/// Method name for the initialize request.
405pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
406/// Method name for the authenticate request.
407pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
408/// Method name for creating a new session.
409pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
410/// Method name for loading an existing session.
411pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
412/// Method name for sending a prompt.
413pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
414/// Method name for the cancel notification.
415pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
416
417/// All possible requests that a client can send to an agent.
418///
419/// This enum is used internally for routing RPC requests. You typically won't need
420/// to use this directly - instead, use the methods on the [`Agent`] trait.
421///
422/// This enum encompasses all method calls from client to agent.
423#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
424#[serde(untagged)]
425#[schemars(extend("x-docs-ignore" = true))]
426pub enum ClientRequest {
427 InitializeRequest(InitializeRequest),
428 AuthenticateRequest(AuthenticateRequest),
429 NewSessionRequest(NewSessionRequest),
430 LoadSessionRequest(LoadSessionRequest),
431 PromptRequest(PromptRequest),
432}
433
434/// All possible responses that an agent can send to a client.
435///
436/// This enum is used internally for routing RPC responses. You typically won't need
437/// to use this directly - the responses are handled automatically by the connection.
438///
439/// These are responses to the corresponding ClientRequest variants.
440#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
441#[serde(untagged)]
442#[schemars(extend("x-docs-ignore" = true))]
443pub enum AgentResponse {
444 InitializeResponse(InitializeResponse),
445 AuthenticateResponse,
446 NewSessionResponse(NewSessionResponse),
447 LoadSessionResponse,
448 PromptResponse(PromptResponse),
449}
450
451/// All possible notifications that a client can send to an agent.
452///
453/// This enum is used internally for routing RPC notifications. You typically won't need
454/// to use this directly - use the notification methods on the [`Agent`] trait instead.
455///
456/// Notifications do not expect a response.
457#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
458#[serde(untagged)]
459#[schemars(extend("x-docs-ignore" = true))]
460pub enum ClientNotification {
461 CancelNotification(CancelNotification),
462}
463
464/// Notification to cancel ongoing operations for a session.
465///
466/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
467#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
468#[schemars(extend("x-side" = "agent", "x-method" = "session/cancel"))]
469#[serde(rename_all = "camelCase")]
470pub struct CancelNotification {
471 /// The ID of the session to cancel operations for.
472 pub session_id: SessionId,
473}