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