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}