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}