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}