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