agent_client_protocol/
agent.rs

1use std::{rc::Rc, sync::Arc};
2
3use serde_json::value::RawValue;
4
5use agent_client_protocol_schema::{
6    AuthenticateRequest, AuthenticateResponse, CancelNotification, Error, ExtNotification,
7    ExtRequest, ExtResponse, InitializeRequest, InitializeResponse, LoadSessionRequest,
8    LoadSessionResponse, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse,
9    SetSessionModeRequest, SetSessionModeResponse,
10};
11#[cfg(feature = "unstable")]
12use agent_client_protocol_schema::{SetSessionModelRequest, SetSessionModelResponse};
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.
18#[async_trait::async_trait(?Send)]
19pub trait Agent {
20    /// Establishes the connection with a client and negotiates protocol capabilities.
21    ///
22    /// This method is called once at the beginning of the connection to:
23    /// - Negotiate the protocol version to use
24    /// - Exchange capability information between client and agent
25    /// - Determine available authentication methods
26    ///
27    /// The agent should respond with its supported protocol version and capabilities.
28    ///
29    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
30    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error>;
31
32    /// Authenticates the client using the specified authentication method.
33    ///
34    /// Called when the agent requires authentication before allowing session creation.
35    /// The client provides the authentication method ID that was advertised during initialization.
36    ///
37    /// After successful authentication, the client can proceed to create sessions with
38    /// `new_session` without receiving an `auth_required` error.
39    ///
40    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
41    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error>;
42
43    /// Creates a new conversation session with the agent.
44    ///
45    /// Sessions represent independent conversation contexts with their own history and state.
46    ///
47    /// The agent should:
48    /// - Create a new session context
49    /// - Connect to any specified MCP servers
50    /// - Return a unique session ID for future requests
51    ///
52    /// May return an `auth_required` error if the agent requires authentication.
53    ///
54    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
55    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error>;
56
57    /// Processes a user prompt within a session.
58    ///
59    /// This method handles the whole lifecycle of a prompt:
60    /// - Receives user messages with optional context (files, images, etc.)
61    /// - Processes the prompt using language models
62    /// - Reports language model content and tool calls to the Clients
63    /// - Requests permission to run tools
64    /// - Executes any requested tool calls
65    /// - Returns when the turn is complete with a stop reason
66    ///
67    /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
68    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error>;
69
70    /// Cancels ongoing operations for a session.
71    ///
72    /// This is a notification sent by the client to cancel an ongoing prompt turn.
73    ///
74    /// Upon receiving this notification, the Agent SHOULD:
75    /// - Stop all language model requests as soon as possible
76    /// - Abort all tool call invocations in progress
77    /// - Send any pending `session/update` notifications
78    /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
79    ///
80    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
81    async fn cancel(&self, args: CancelNotification) -> Result<(), Error>;
82
83    /// Loads an existing session to resume a previous conversation.
84    ///
85    /// This method is only available if the agent advertises the `loadSession` capability.
86    ///
87    /// The agent should:
88    /// - Restore the session context and conversation history
89    /// - Connect to the specified MCP servers
90    /// - Stream the entire conversation history back to the client via notifications
91    ///
92    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
93    async fn load_session(&self, _args: LoadSessionRequest) -> Result<LoadSessionResponse, Error> {
94        Err(Error::method_not_found())
95    }
96
97    /// Sets the current mode for a session.
98    ///
99    /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
100    /// that affect system prompts, tool availability, and permission behaviors.
101    ///
102    /// The mode must be one of the modes advertised in `availableModes` during session
103    /// creation or loading. Agents may also change modes autonomously and notify the
104    /// client via `current_mode_update` notifications.
105    ///
106    /// This method can be called at any time during a session, whether the Agent is
107    /// idle or actively generating a response.
108    ///
109    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
110    async fn set_session_mode(
111        &self,
112        _args: SetSessionModeRequest,
113    ) -> Result<SetSessionModeResponse, Error> {
114        Err(Error::method_not_found())
115    }
116
117    /// **UNSTABLE**
118    ///
119    /// This capability is not part of the spec yet, and may be removed or changed at any point.
120    ///
121    /// Select a model for a given session.
122    #[cfg(feature = "unstable")]
123    async fn set_session_model(
124        &self,
125        _args: SetSessionModelRequest,
126    ) -> Result<SetSessionModelResponse, Error> {
127        Err(Error::method_not_found())
128    }
129
130    /// Handles extension method requests from the client.
131    ///
132    /// Extension methods provide a way to add custom functionality while maintaining
133    /// protocol compatibility.
134    ///
135    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
136    async fn ext_method(&self, _args: ExtRequest) -> Result<ExtResponse, Error> {
137        Ok(RawValue::NULL.to_owned().into())
138    }
139
140    /// Handles extension notifications from the client.
141    ///
142    /// Extension notifications provide a way to send one-way messages for custom functionality
143    /// while maintaining protocol compatibility.
144    ///
145    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
146    async fn ext_notification(&self, _args: ExtNotification) -> Result<(), Error> {
147        Ok(())
148    }
149}
150
151#[async_trait::async_trait(?Send)]
152impl<T: Agent> Agent for Rc<T> {
153    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error> {
154        self.as_ref().initialize(args).await
155    }
156    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error> {
157        self.as_ref().authenticate(args).await
158    }
159    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error> {
160        self.as_ref().new_session(args).await
161    }
162    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse, Error> {
163        self.as_ref().load_session(args).await
164    }
165    async fn set_session_mode(
166        &self,
167        args: SetSessionModeRequest,
168    ) -> Result<SetSessionModeResponse, Error> {
169        self.as_ref().set_session_mode(args).await
170    }
171    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error> {
172        self.as_ref().prompt(args).await
173    }
174    async fn cancel(&self, args: CancelNotification) -> Result<(), Error> {
175        self.as_ref().cancel(args).await
176    }
177    #[cfg(feature = "unstable")]
178    async fn set_session_model(
179        &self,
180        args: SetSessionModelRequest,
181    ) -> Result<SetSessionModelResponse, Error> {
182        self.as_ref().set_session_model(args).await
183    }
184    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error> {
185        self.as_ref().ext_method(args).await
186    }
187    async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error> {
188        self.as_ref().ext_notification(args).await
189    }
190}
191
192#[async_trait::async_trait(?Send)]
193impl<T: Agent> Agent for Arc<T> {
194    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse, Error> {
195        self.as_ref().initialize(args).await
196    }
197    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse, Error> {
198        self.as_ref().authenticate(args).await
199    }
200    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse, Error> {
201        self.as_ref().new_session(args).await
202    }
203    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse, Error> {
204        self.as_ref().load_session(args).await
205    }
206    async fn set_session_mode(
207        &self,
208        args: SetSessionModeRequest,
209    ) -> Result<SetSessionModeResponse, Error> {
210        self.as_ref().set_session_mode(args).await
211    }
212    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse, Error> {
213        self.as_ref().prompt(args).await
214    }
215    async fn cancel(&self, args: CancelNotification) -> Result<(), Error> {
216        self.as_ref().cancel(args).await
217    }
218    #[cfg(feature = "unstable")]
219    async fn set_session_model(
220        &self,
221        args: SetSessionModelRequest,
222    ) -> Result<SetSessionModelResponse, Error> {
223        self.as_ref().set_session_model(args).await
224    }
225    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse, Error> {
226        self.as_ref().ext_method(args).await
227    }
228    async fn ext_notification(&self, args: ExtNotification) -> Result<(), Error> {
229        self.as_ref().ext_notification(args).await
230    }
231}