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