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
use std::{rc::Rc, sync::Arc};
use agent_client_protocol_schema::{
AuthenticateRequest, AuthenticateResponse, CancelNotification, Error, ExtNotification,
ExtRequest, ExtResponse, InitializeRequest, InitializeResponse, LoadSessionRequest,
LoadSessionResponse, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse,
Result, SetSessionModeRequest, SetSessionModeResponse,
};
#[cfg(feature = "unstable")]
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>;
/// 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")]
async fn set_session_model(
&self,
_args: SetSessionModelRequest,
) -> Result<SetSessionModelResponse> {
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(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
}
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")]
async fn set_session_model(
&self,
args: SetSessionModelRequest,
) -> Result<SetSessionModelResponse> {
self.as_ref().set_session_model(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
}
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")]
async fn set_session_model(
&self,
args: SetSessionModelRequest,
) -> Result<SetSessionModelResponse> {
self.as_ref().set_session_model(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
}
}