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