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