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