agent_client_protocol/
agent.rs

1//! Methods and notifications the agent handles/receives.
2//!
3//! This module defines the Agent trait and all associated types for implementing
4//! an AI coding agent that follows the Agent Client Protocol (ACP).
5
6use std::{path::PathBuf, sync::Arc};
7
8use anyhow::Result;
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11
12use crate::{ClientCapabilities, ContentBlock, Error, ProtocolVersion, SessionId};
13
14/// The Agent trait defines the interface that all ACP-compliant agents must implement.
15///
16/// Agents are programs that use generative AI to autonomously modify code. They handle
17/// requests from clients and execute tasks using language models and tools.
18pub trait Agent {
19    /// Establishes the connection with a client and negotiates protocol capabilities.
20    ///
21    /// This method is called once at the beginning of the connection to:
22    /// - Negotiate the protocol version to use
23    /// - Exchange capability information between client and agent
24    /// - Determine available authentication methods
25    ///
26    /// The agent should respond with its supported protocol version and capabilities.
27    ///
28    /// See: <https://agentclientprotocol.com/protocol/initialization>
29    fn initialize(
30        &self,
31        arguments: InitializeRequest,
32    ) -> impl Future<Output = Result<InitializeResponse, Error>>;
33
34    /// Authenticates the client using the specified authentication method.
35    ///
36    /// Called when the agent requires authentication before allowing session creation.
37    /// The client provides the authentication method ID that was advertised during initialization.
38    ///
39    /// After successful authentication, the client can proceed to create sessions with
40    /// `new_session` without receiving an `auth_required` error.
41    ///
42    /// See: <https://agentclientprotocol.com/protocol/initialization>
43    fn authenticate(
44        &self,
45        arguments: AuthenticateRequest,
46    ) -> impl Future<Output = Result<(), Error>>;
47
48    /// Creates a new conversation session with the agent.
49    ///
50    /// Sessions represent independent conversation contexts with their own history and state.
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    /// # Errors
57    ///
58    /// May return an `auth_required` error if the agent requires authentication.
59    ///
60    /// See: <https://agentclientprotocol.com/protocol/session-setup>
61    fn new_session(
62        &self,
63        arguments: NewSessionRequest,
64    ) -> impl Future<Output = Result<NewSessionResponse, Error>>;
65
66    /// Loads an existing session to resume a previous conversation.
67    ///
68    /// This method is only available if the agent advertises the `loadSession` capability.
69    /// The agent should:
70    /// - Restore the session context and conversation history
71    /// - Connect to the specified MCP servers
72    /// - Stream the entire conversation history back to the client via notifications
73    ///
74    /// See: <https://agentclientprotocol.com/protocol/session-setup#loading-sessions>
75    fn load_session(
76        &self,
77        arguments: LoadSessionRequest,
78    ) -> impl Future<Output = Result<(), Error>>;
79
80    /// Processes a user prompt within a session.
81    ///
82    /// This is the core interaction method where the agent:
83    /// - Receives user messages with optional context (files, images, etc.)
84    /// - Processes the prompt using language models
85    /// - Executes any requested tool calls
86    /// - Returns when the turn is complete with a stop reason
87    ///
88    /// See: <https://agentclientprotocol.com/protocol/prompt-turn>
89    fn prompt(
90        &self,
91        arguments: PromptRequest,
92    ) -> impl Future<Output = Result<PromptResponse, Error>>;
93
94    /// Cancels ongoing operations for a session.
95    ///
96    /// This is a notification sent by the client to cancel an ongoing prompt turn.
97    ///
98    /// Upon receiving this notification, the Agent SHOULD:
99    /// - Stop all language model requests as soon as possible
100    /// - Abort all tool call invocations in progress
101    /// - Send any pending `session/update` notifications
102    /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
103    ///
104    /// See: <https://agentclientprotocol.com/protocol/prompt-turn#cancellation>
105    fn cancel(&self, args: CancelNotification) -> impl Future<Output = Result<(), Error>>;
106}
107
108// Initialize
109
110/// Request parameters for the initialize method.
111///
112/// Sent by the client to establish connection and negotiate capabilities.
113///
114/// See: <https://agentclientprotocol.com/protocol/initialization>
115#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
116#[serde(rename_all = "camelCase")]
117pub struct InitializeRequest {
118    /// The latest protocol version supported by the client.
119    pub protocol_version: ProtocolVersion,
120    /// Capabilities supported by the client.
121    #[serde(default)]
122    pub client_capabilities: ClientCapabilities,
123}
124
125/// Response from the initialize method.
126///
127/// Contains the negotiated protocol version and agent capabilities.
128///
129/// See: <https://agentclientprotocol.com/protocol/initialization>
130#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
131#[serde(rename_all = "camelCase")]
132pub struct InitializeResponse {
133    /// The protocol version the client specified if supported by the agent,
134    /// or the latest protocol version supported by the agent.
135    ///
136    /// The client should disconnect, if it doesn't support this version.
137    pub protocol_version: ProtocolVersion,
138    /// Capabilities supported by the agent.
139    #[serde(default)]
140    pub agent_capabilities: AgentCapabilities,
141    /// Authentication methods supported by the agent.
142    #[serde(default)]
143    pub auth_methods: Vec<AuthMethod>,
144}
145
146// Authentication
147
148/// Request parameters for the authenticate method.
149///
150/// Specifies which authentication method to use.
151#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
152#[serde(rename_all = "camelCase")]
153pub struct AuthenticateRequest {
154    /// The ID of the authentication method to use.
155    /// Must be one of the methods advertised in the initialize response.
156    pub method_id: AuthMethodId,
157}
158
159/// Unique identifier for an authentication method.
160#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
161#[serde(transparent)]
162pub struct AuthMethodId(pub Arc<str>);
163
164/// Describes an available authentication method.
165#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
166#[serde(rename_all = "camelCase")]
167pub struct AuthMethod {
168    /// Unique identifier for this authentication method.
169    pub id: AuthMethodId,
170    /// Human-readable name of the authentication method.
171    pub name: String,
172    /// Optional description providing more details about this authentication method.
173    pub description: Option<String>,
174}
175
176// New session
177
178/// Request parameters for creating a new session.
179///
180/// See: <https://agentclientprotocol.com/protocol/session-setup#creating-a-session>
181#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
182#[serde(rename_all = "camelCase")]
183pub struct NewSessionRequest {
184    /// List of MCP (Model Context Protocol) servers the agent should connect to.
185    /// These provide tools and context to the language model.
186    pub mcp_servers: Vec<McpServer>,
187    /// The working directory for this session.
188    /// Must be an absolute path that serves as the context for file operations.
189    pub cwd: PathBuf,
190}
191
192/// Response from creating a new session.
193///
194/// See: <https://agentclientprotocol.com/protocol/session-setup#creating-a-session>
195#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
196#[serde(rename_all = "camelCase")]
197pub struct NewSessionResponse {
198    /// Unique identifier for the created session.
199    /// Used in all subsequent requests for this conversation.
200    pub session_id: SessionId,
201}
202
203// Load session
204
205/// Request parameters for loading an existing session.
206///
207/// Only available if the agent supports the `loadSession` capability.
208///
209/// See: <https://agentclientprotocol.com/protocol/session-setup#loading-sessions>
210#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
211#[serde(rename_all = "camelCase")]
212pub struct LoadSessionRequest {
213    /// List of MCP servers to connect to for this session.
214    pub mcp_servers: Vec<McpServer>,
215    /// The working directory for this session.
216    pub cwd: PathBuf,
217    /// The ID of the session to load.
218    pub session_id: SessionId,
219}
220
221// MCP
222
223/// Configuration for connecting to an MCP (Model Context Protocol) server.
224///
225/// MCP servers provide tools and context that the agent can use when
226/// processing prompts.
227///
228/// See: <https://agentclientprotocol.com/protocol/session-setup#mcp-servers>
229#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
230#[serde(rename_all = "camelCase")]
231pub struct McpServer {
232    /// Human-readable name identifying this MCP server.
233    pub name: String,
234    /// Path to the MCP server executable.
235    pub command: PathBuf,
236    /// Command-line arguments to pass to the MCP server.
237    pub args: Vec<String>,
238    /// Environment variables to set when launching the MCP server.
239    pub env: Vec<EnvVariable>,
240}
241
242/// An environment variable to set when launching an MCP server.
243#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
244#[serde(rename_all = "camelCase")]
245pub struct EnvVariable {
246    /// The name of the environment variable.
247    pub name: String,
248    /// The value to set for the environment variable.
249    pub value: String,
250}
251
252// Prompt
253
254/// Request parameters for sending a user prompt to the agent.
255///
256/// Contains the user's message and any additional context.
257///
258/// See: <https://agentclientprotocol.com/protocol/prompt-turn#1-user-message>
259#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
260#[serde(rename_all = "camelCase")]
261pub struct PromptRequest {
262    /// The ID of the session to send this user message to
263    pub session_id: SessionId,
264    /// The blocks of content that compose the user's message.
265    ///
266    /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
267    /// while other variants are optionally enabled via [`PromptCapabilities`].
268    ///
269    /// The Client MUST adapt its interface according to [`PromptCapabilities`].
270    ///
271    /// ## Context
272    ///
273    /// The client MAY include referenced pieces of context as either
274    /// [`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].
275    ///
276    /// When available, [`ContentBlock::Resource`] is preferred
277    /// as it avoids extra round-trips and allows the message to include
278    /// pieces of context from sources the agent may not have access to.
279    pub prompt: Vec<ContentBlock>,
280}
281
282/// Response from processing a user prompt.
283///
284/// See: <https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion>
285#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
286#[serde(rename_all = "camelCase")]
287pub struct PromptResponse {
288    /// Indicates why the agent stopped processing the turn.
289    pub stop_reason: StopReason,
290}
291
292/// Reasons why an agent stops processing a prompt turn.
293///
294/// See: <https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons>
295#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
296#[serde(rename_all = "snake_case")]
297pub enum StopReason {
298    /// The turn ended successfully.
299    EndTurn,
300    /// The turn ended because the agent reached the maximum number of tokens.
301    MaxTokens,
302    /// The turn ended because the agent reached the maximum number of allowed
303    /// agent requests between user turns.
304    MaxTurnRequests,
305    /// The turn ended because the agent refused to continue. The user prompt
306    /// and everything that comes after it won't be included in the next
307    /// prompt, so this should be reflected in the UI.
308    Refusal,
309    /// The turn was cancelled by the client via `session/cancel`.
310    ///
311    /// This stop reason MUST be returned when the client sends a `session/cancel`
312    /// notification, even if the cancellation causes exceptions in underlying operations.
313    /// Agents should catch these exceptions and return this semantically meaningful
314    /// response to confirm successful cancellation.
315    Cancelled,
316}
317
318// Capabilities
319
320/// Capabilities supported by the agent.
321///
322/// Advertised during initialization to inform the client about
323/// available features and content types.
324///
325/// See: <https://agentclientprotocol.com/protocol/initialization#agent-capabilities>
326#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
327#[serde(rename_all = "camelCase")]
328pub struct AgentCapabilities {
329    /// Whether the agent supports `session/load`.
330    #[serde(default)]
331    pub load_session: bool,
332    /// Prompt capabilities supported by the agent.
333    #[serde(default)]
334    pub prompt_capabilities: PromptCapabilities,
335}
336
337/// Prompt capabilities supported by the agent in `session/prompt` requests.
338///
339/// Baseline agent functionality requires support for [`ContentBlock::Text`]
340/// and [`ContentBlock::ResourceLink`] in prompt requests.
341///
342/// Other variants must be explicitly opted in to.
343/// Capabilities for different types of content in prompt requests.
344///
345/// Indicates which content types beyond the baseline (text and resource links)
346/// the agent can process.
347///
348/// See: <https://agentclientprotocol.com/protocol/initialization#prompt-capabilities>
349#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
350#[serde(rename_all = "camelCase")]
351pub struct PromptCapabilities {
352    /// Agent supports [`ContentBlock::Image`].
353    #[serde(default)]
354    pub image: bool,
355    /// Agent supports [`ContentBlock::Audio`].
356    #[serde(default)]
357    pub audio: bool,
358    /// Agent supports embedded context in `session/prompt` requests.
359    ///
360    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
361    /// in prompt requests for pieces of context that are referenced in the message.
362    #[serde(default)]
363    pub embedded_context: bool,
364}
365
366// Method schema
367
368/// Names of all methods that agents handle.
369///
370/// Provides a centralized definition of method names used in the protocol.
371#[derive(Debug, Clone, Serialize, Deserialize)]
372pub struct AgentMethodNames {
373    /// Method for initializing the connection.
374    pub initialize: &'static str,
375    /// Method for authenticating with the agent.
376    pub authenticate: &'static str,
377    /// Method for creating a new session.
378    pub session_new: &'static str,
379    /// Method for loading an existing session.
380    pub session_load: &'static str,
381    /// Method for sending a prompt to the agent.
382    pub session_prompt: &'static str,
383    /// Notification for cancelling operations.
384    pub session_cancel: &'static str,
385}
386
387/// Constant containing all agent method names.
388pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
389    initialize: INITIALIZE_METHOD_NAME,
390    authenticate: AUTHENTICATE_METHOD_NAME,
391    session_new: SESSION_NEW_METHOD_NAME,
392    session_load: SESSION_LOAD_METHOD_NAME,
393    session_prompt: SESSION_PROMPT_METHOD_NAME,
394    session_cancel: SESSION_CANCEL_METHOD_NAME,
395};
396
397/// Method name for the initialize request.
398pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
399/// Method name for the authenticate request.
400pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
401/// Method name for creating a new session.
402pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
403/// Method name for loading an existing session.
404pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
405/// Method name for sending a prompt.
406pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
407/// Method name for the cancel notification.
408pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
409
410/// All possible requests that a client can send to an agent.
411///
412/// This enum is used internally for routing RPC requests. You typically won't need
413/// to use this directly - instead, use the methods on the [`Agent`] trait.
414///
415/// This enum encompasses all method calls from client to agent.
416#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
417#[serde(untagged)]
418pub enum ClientRequest {
419    InitializeRequest(InitializeRequest),
420    AuthenticateRequest(AuthenticateRequest),
421    NewSessionRequest(NewSessionRequest),
422    LoadSessionRequest(LoadSessionRequest),
423    PromptRequest(PromptRequest),
424}
425
426/// All possible responses that an agent can send to a client.
427///
428/// This enum is used internally for routing RPC responses. You typically won't need
429/// to use this directly - the responses are handled automatically by the connection.
430///
431/// These are responses to the corresponding ClientRequest variants.
432#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
433#[serde(untagged)]
434pub enum AgentResponse {
435    InitializeResponse(InitializeResponse),
436    AuthenticateResponse,
437    NewSessionResponse(NewSessionResponse),
438    LoadSessionResponse,
439    PromptResponse(PromptResponse),
440}
441
442/// All possible notifications that a client can send to an agent.
443///
444/// This enum is used internally for routing RPC notifications. You typically won't need
445/// to use this directly - use the notification methods on the [`Agent`] trait instead.
446///
447/// Notifications do not expect a response.
448#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
449#[serde(untagged)]
450pub enum ClientNotification {
451    CancelNotification(CancelNotification),
452}
453
454/// Notification to cancel ongoing operations for a session.
455///
456/// See: <https://agentclientprotocol.com/protocol/prompt-turn#cancellation>
457#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
458#[serde(rename_all = "camelCase")]
459pub struct CancelNotification {
460    /// The ID of the session to cancel operations for.
461    pub session_id: SessionId,
462}