Skip to main content

agent_client_protocol/
agent.rs

1use std::{rc::Rc, sync::Arc};
2
3use agent_client_protocol_schema::{
4    AuthenticateRequest, AuthenticateResponse, CancelNotification, Error, ExtNotification,
5    ExtRequest, ExtResponse, InitializeRequest, InitializeResponse, ListSessionsRequest,
6    ListSessionsResponse, LoadSessionRequest, LoadSessionResponse, NewSessionRequest,
7    NewSessionResponse, PromptRequest, PromptResponse, Result, SetSessionConfigOptionRequest,
8    SetSessionConfigOptionResponse, SetSessionModeRequest, SetSessionModeResponse,
9};
10#[cfg(feature = "unstable_session_fork")]
11use agent_client_protocol_schema::{ForkSessionRequest, ForkSessionResponse};
12#[cfg(feature = "unstable_session_resume")]
13use agent_client_protocol_schema::{ResumeSessionRequest, ResumeSessionResponse};
14#[cfg(feature = "unstable_session_model")]
15use agent_client_protocol_schema::{SetSessionModelRequest, SetSessionModelResponse};
16use serde_json::value::RawValue;
17
18/// Defines the interface that all ACP-compliant agents must implement.
19///
20/// Agents are programs that use generative AI to autonomously modify code. They handle
21/// requests from clients and execute tasks using language models and tools.
22#[async_trait::async_trait(?Send)]
23pub trait Agent {
24    /// Establishes the connection with a client and negotiates protocol capabilities.
25    ///
26    /// This method is called once at the beginning of the connection to:
27    /// - Negotiate the protocol version to use
28    /// - Exchange capability information between client and agent
29    /// - Determine available authentication methods
30    ///
31    /// The agent should respond with its supported protocol version and capabilities.
32    ///
33    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
34    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse>;
35
36    /// Authenticates the client using the specified authentication method.
37    ///
38    /// Called when the agent requires authentication before allowing session creation.
39    /// The client provides the authentication method ID that was advertised during initialization.
40    ///
41    /// After successful authentication, the client can proceed to create sessions with
42    /// `new_session` without receiving an `auth_required` error.
43    ///
44    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
45    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse>;
46
47    /// Creates a new conversation session with the agent.
48    ///
49    /// Sessions represent independent conversation contexts with their own history and state.
50    ///
51    /// The agent should:
52    /// - Create a new session context
53    /// - Connect to any specified MCP servers
54    /// - Return a unique session ID for future requests
55    ///
56    /// May return an `auth_required` error if the agent requires authentication.
57    ///
58    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
59    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse>;
60
61    /// Processes a user prompt within a session.
62    ///
63    /// This method handles the whole lifecycle of a prompt:
64    /// - Receives user messages with optional context (files, images, etc.)
65    /// - Processes the prompt using language models
66    /// - Reports language model content and tool calls to the Clients
67    /// - Requests permission to run tools
68    /// - Executes any requested tool calls
69    /// - Returns when the turn is complete with a stop reason
70    ///
71    /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
72    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse>;
73
74    /// Cancels ongoing operations for a session.
75    ///
76    /// This is a notification sent by the client to cancel an ongoing prompt turn.
77    ///
78    /// Upon receiving this notification, the Agent SHOULD:
79    /// - Stop all language model requests as soon as possible
80    /// - Abort all tool call invocations in progress
81    /// - Send any pending `session/update` notifications
82    /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
83    ///
84    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
85    async fn cancel(&self, args: CancelNotification) -> Result<()>;
86
87    /// Loads an existing session to resume a previous conversation.
88    ///
89    /// This method is only available if the agent advertises the `loadSession` capability.
90    ///
91    /// The agent should:
92    /// - Restore the session context and conversation history
93    /// - Connect to the specified MCP servers
94    /// - Stream the entire conversation history back to the client via notifications
95    ///
96    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
97    async fn load_session(&self, _args: LoadSessionRequest) -> Result<LoadSessionResponse> {
98        Err(Error::method_not_found())
99    }
100
101    /// Sets the current mode for a session.
102    ///
103    /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
104    /// that affect system prompts, tool availability, and permission behaviors.
105    ///
106    /// The mode must be one of the modes advertised in `availableModes` during session
107    /// creation or loading. Agents may also change modes autonomously and notify the
108    /// client via `current_mode_update` notifications.
109    ///
110    /// This method can be called at any time during a session, whether the Agent is
111    /// idle or actively generating a response.
112    ///
113    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
114    async fn set_session_mode(
115        &self,
116        _args: SetSessionModeRequest,
117    ) -> Result<SetSessionModeResponse> {
118        Err(Error::method_not_found())
119    }
120
121    /// **UNSTABLE**
122    ///
123    /// This capability is not part of the spec yet, and may be removed or changed at any point.
124    ///
125    /// Select a model for a given session.
126    #[cfg(feature = "unstable_session_model")]
127    async fn set_session_model(
128        &self,
129        _args: SetSessionModelRequest,
130    ) -> Result<SetSessionModelResponse> {
131        Err(Error::method_not_found())
132    }
133
134    /// Sets the current value for a session configuration option.
135    ///
136    /// Configuration options allow agents to expose arbitrary selectors (like model choice,
137    /// reasoning level, etc.) that clients can display and modify.
138    ///
139    /// The response returns the full list of configuration options with their current values,
140    /// as changing one option may affect others.
141    async fn set_session_config_option(
142        &self,
143        _args: SetSessionConfigOptionRequest,
144    ) -> Result<SetSessionConfigOptionResponse> {
145        Err(Error::method_not_found())
146    }
147
148    /// **UNSTABLE**
149    ///
150    /// This capability is not part of the spec yet, and may be removed or changed at any point.
151    ///
152    /// Lists existing sessions known to the agent.
153    ///
154    /// Only available if the Agent supports the `sessionCapabilities.list` capability.
155    async fn list_sessions(&self, _args: ListSessionsRequest) -> Result<ListSessionsResponse> {
156        Err(Error::method_not_found())
157    }
158
159    /// **UNSTABLE**
160    ///
161    /// This capability is not part of the spec yet, and may be removed or changed at any point.
162    ///
163    /// Forks an existing session, creating a new session with the same conversation history.
164    ///
165    /// Only available if the Agent supports the `sessionCapabilities.fork` capability.
166    #[cfg(feature = "unstable_session_fork")]
167    async fn fork_session(&self, _args: ForkSessionRequest) -> Result<ForkSessionResponse> {
168        Err(Error::method_not_found())
169    }
170
171    /// **UNSTABLE**
172    ///
173    /// This capability is not part of the spec yet, and may be removed or changed at any point.
174    ///
175    /// Resumes an existing session without replaying message history.
176    ///
177    /// This is similar to `load_session`, except it does not return previous messages.
178    /// Useful for agents that support continuing conversations but don't store full history.
179    ///
180    /// Only available if the Agent supports the `sessionCapabilities.resume` capability.
181    #[cfg(feature = "unstable_session_resume")]
182    async fn resume_session(&self, _args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
183        Err(Error::method_not_found())
184    }
185
186    /// Handles extension method requests from the client.
187    ///
188    /// Extension methods provide a way to add custom functionality while maintaining
189    /// protocol compatibility.
190    ///
191    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
192    async fn ext_method(&self, _args: ExtRequest) -> Result<ExtResponse> {
193        Ok(ExtResponse::new(RawValue::NULL.to_owned().into()))
194    }
195
196    /// Handles extension notifications from the client.
197    ///
198    /// Extension notifications provide a way to send one-way messages for custom functionality
199    /// while maintaining protocol compatibility.
200    ///
201    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
202    async fn ext_notification(&self, _args: ExtNotification) -> Result<()> {
203        Ok(())
204    }
205}
206
207#[async_trait::async_trait(?Send)]
208impl<T: Agent> Agent for Rc<T> {
209    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse> {
210        self.as_ref().initialize(args).await
211    }
212    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse> {
213        self.as_ref().authenticate(args).await
214    }
215    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse> {
216        self.as_ref().new_session(args).await
217    }
218    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse> {
219        self.as_ref().load_session(args).await
220    }
221    async fn set_session_mode(
222        &self,
223        args: SetSessionModeRequest,
224    ) -> Result<SetSessionModeResponse> {
225        self.as_ref().set_session_mode(args).await
226    }
227    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse> {
228        self.as_ref().prompt(args).await
229    }
230    async fn cancel(&self, args: CancelNotification) -> Result<()> {
231        self.as_ref().cancel(args).await
232    }
233    #[cfg(feature = "unstable_session_model")]
234    async fn set_session_model(
235        &self,
236        args: SetSessionModelRequest,
237    ) -> Result<SetSessionModelResponse> {
238        self.as_ref().set_session_model(args).await
239    }
240    async fn set_session_config_option(
241        &self,
242        args: SetSessionConfigOptionRequest,
243    ) -> Result<SetSessionConfigOptionResponse> {
244        self.as_ref().set_session_config_option(args).await
245    }
246
247    async fn list_sessions(&self, args: ListSessionsRequest) -> Result<ListSessionsResponse> {
248        self.as_ref().list_sessions(args).await
249    }
250    #[cfg(feature = "unstable_session_fork")]
251    async fn fork_session(&self, args: ForkSessionRequest) -> Result<ForkSessionResponse> {
252        self.as_ref().fork_session(args).await
253    }
254    #[cfg(feature = "unstable_session_resume")]
255    async fn resume_session(&self, args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
256        self.as_ref().resume_session(args).await
257    }
258    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
259        self.as_ref().ext_method(args).await
260    }
261    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
262        self.as_ref().ext_notification(args).await
263    }
264}
265
266#[async_trait::async_trait(?Send)]
267impl<T: Agent> Agent for Arc<T> {
268    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse> {
269        self.as_ref().initialize(args).await
270    }
271    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse> {
272        self.as_ref().authenticate(args).await
273    }
274    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse> {
275        self.as_ref().new_session(args).await
276    }
277    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse> {
278        self.as_ref().load_session(args).await
279    }
280    async fn set_session_mode(
281        &self,
282        args: SetSessionModeRequest,
283    ) -> Result<SetSessionModeResponse> {
284        self.as_ref().set_session_mode(args).await
285    }
286    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse> {
287        self.as_ref().prompt(args).await
288    }
289    async fn cancel(&self, args: CancelNotification) -> Result<()> {
290        self.as_ref().cancel(args).await
291    }
292    #[cfg(feature = "unstable_session_model")]
293    async fn set_session_model(
294        &self,
295        args: SetSessionModelRequest,
296    ) -> Result<SetSessionModelResponse> {
297        self.as_ref().set_session_model(args).await
298    }
299    async fn set_session_config_option(
300        &self,
301        args: SetSessionConfigOptionRequest,
302    ) -> Result<SetSessionConfigOptionResponse> {
303        self.as_ref().set_session_config_option(args).await
304    }
305    async fn list_sessions(&self, args: ListSessionsRequest) -> Result<ListSessionsResponse> {
306        self.as_ref().list_sessions(args).await
307    }
308    #[cfg(feature = "unstable_session_fork")]
309    async fn fork_session(&self, args: ForkSessionRequest) -> Result<ForkSessionResponse> {
310        self.as_ref().fork_session(args).await
311    }
312    #[cfg(feature = "unstable_session_resume")]
313    async fn resume_session(&self, args: ResumeSessionRequest) -> Result<ResumeSessionResponse> {
314        self.as_ref().resume_session(args).await
315    }
316    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
317        self.as_ref().ext_method(args).await
318    }
319    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
320        self.as_ref().ext_notification(args).await
321    }
322}