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")]
10use agent_client_protocol_schema::{SetSessionModelRequest, SetSessionModelResponse};
11use serde_json::value::RawValue;
12
13/// Defines the interface that all ACP-compliant agents must implement.
14///
15/// Agents are programs that use generative AI to autonomously modify code. They handle
16/// requests from clients and execute tasks using language models and tools.
17#[async_trait::async_trait(?Send)]
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 protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
29    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse>;
30
31    /// Authenticates the client using the specified authentication method.
32    ///
33    /// Called when the agent requires authentication before allowing session creation.
34    /// The client provides the authentication method ID that was advertised during initialization.
35    ///
36    /// After successful authentication, the client can proceed to create sessions with
37    /// `new_session` without receiving an `auth_required` error.
38    ///
39    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
40    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse>;
41
42    /// Creates a new conversation session with the agent.
43    ///
44    /// Sessions represent independent conversation contexts with their own history and state.
45    ///
46    /// The agent should:
47    /// - Create a new session context
48    /// - Connect to any specified MCP servers
49    /// - Return a unique session ID for future requests
50    ///
51    /// May return an `auth_required` error if the agent requires authentication.
52    ///
53    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
54    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse>;
55
56    /// Processes a user prompt within a session.
57    ///
58    /// This method handles the whole lifecycle of a prompt:
59    /// - Receives user messages with optional context (files, images, etc.)
60    /// - Processes the prompt using language models
61    /// - Reports language model content and tool calls to the Clients
62    /// - Requests permission to run tools
63    /// - Executes any requested tool calls
64    /// - Returns when the turn is complete with a stop reason
65    ///
66    /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
67    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse>;
68
69    /// Cancels ongoing operations for a session.
70    ///
71    /// This is a notification sent by the client to cancel an ongoing prompt turn.
72    ///
73    /// Upon receiving this notification, the Agent SHOULD:
74    /// - Stop all language model requests as soon as possible
75    /// - Abort all tool call invocations in progress
76    /// - Send any pending `session/update` notifications
77    /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
78    ///
79    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
80    async fn cancel(&self, args: CancelNotification) -> Result<()>;
81
82    /// Loads an existing session to resume a previous conversation.
83    ///
84    /// This method is only available if the agent advertises the `loadSession` capability.
85    ///
86    /// The agent should:
87    /// - Restore the session context and conversation history
88    /// - Connect to the specified MCP servers
89    /// - Stream the entire conversation history back to the client via notifications
90    ///
91    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
92    async fn load_session(&self, _args: LoadSessionRequest) -> Result<LoadSessionResponse> {
93        Err(Error::method_not_found())
94    }
95
96    /// Sets the current mode for a session.
97    ///
98    /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
99    /// that affect system prompts, tool availability, and permission behaviors.
100    ///
101    /// The mode must be one of the modes advertised in `availableModes` during session
102    /// creation or loading. Agents may also change modes autonomously and notify the
103    /// client via `current_mode_update` notifications.
104    ///
105    /// This method can be called at any time during a session, whether the Agent is
106    /// idle or actively generating a response.
107    ///
108    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
109    async fn set_session_mode(
110        &self,
111        _args: SetSessionModeRequest,
112    ) -> Result<SetSessionModeResponse> {
113        Err(Error::method_not_found())
114    }
115
116    /// **UNSTABLE**
117    ///
118    /// This capability is not part of the spec yet, and may be removed or changed at any point.
119    ///
120    /// Select a model for a given session.
121    #[cfg(feature = "unstable")]
122    async fn set_session_model(
123        &self,
124        _args: SetSessionModelRequest,
125    ) -> Result<SetSessionModelResponse> {
126        Err(Error::method_not_found())
127    }
128
129    /// Handles extension method requests from the client.
130    ///
131    /// Extension methods provide a way to add custom functionality while maintaining
132    /// protocol compatibility.
133    ///
134    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
135    async fn ext_method(&self, _args: ExtRequest) -> Result<ExtResponse> {
136        Ok(RawValue::NULL.to_owned().into())
137    }
138
139    /// Handles extension notifications from the client.
140    ///
141    /// Extension notifications provide a way to send one-way messages for custom functionality
142    /// while maintaining protocol compatibility.
143    ///
144    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
145    async fn ext_notification(&self, _args: ExtNotification) -> Result<()> {
146        Ok(())
147    }
148}
149
150#[async_trait::async_trait(?Send)]
151impl<T: Agent> Agent for Rc<T> {
152    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse> {
153        self.as_ref().initialize(args).await
154    }
155    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse> {
156        self.as_ref().authenticate(args).await
157    }
158    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse> {
159        self.as_ref().new_session(args).await
160    }
161    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse> {
162        self.as_ref().load_session(args).await
163    }
164    async fn set_session_mode(
165        &self,
166        args: SetSessionModeRequest,
167    ) -> Result<SetSessionModeResponse> {
168        self.as_ref().set_session_mode(args).await
169    }
170    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse> {
171        self.as_ref().prompt(args).await
172    }
173    async fn cancel(&self, args: CancelNotification) -> Result<()> {
174        self.as_ref().cancel(args).await
175    }
176    #[cfg(feature = "unstable")]
177    async fn set_session_model(
178        &self,
179        args: SetSessionModelRequest,
180    ) -> Result<SetSessionModelResponse> {
181        self.as_ref().set_session_model(args).await
182    }
183    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
184        self.as_ref().ext_method(args).await
185    }
186    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
187        self.as_ref().ext_notification(args).await
188    }
189}
190
191#[async_trait::async_trait(?Send)]
192impl<T: Agent> Agent for Arc<T> {
193    async fn initialize(&self, args: InitializeRequest) -> Result<InitializeResponse> {
194        self.as_ref().initialize(args).await
195    }
196    async fn authenticate(&self, args: AuthenticateRequest) -> Result<AuthenticateResponse> {
197        self.as_ref().authenticate(args).await
198    }
199    async fn new_session(&self, args: NewSessionRequest) -> Result<NewSessionResponse> {
200        self.as_ref().new_session(args).await
201    }
202    async fn load_session(&self, args: LoadSessionRequest) -> Result<LoadSessionResponse> {
203        self.as_ref().load_session(args).await
204    }
205    async fn set_session_mode(
206        &self,
207        args: SetSessionModeRequest,
208    ) -> Result<SetSessionModeResponse> {
209        self.as_ref().set_session_mode(args).await
210    }
211    async fn prompt(&self, args: PromptRequest) -> Result<PromptResponse> {
212        self.as_ref().prompt(args).await
213    }
214    async fn cancel(&self, args: CancelNotification) -> Result<()> {
215        self.as_ref().cancel(args).await
216    }
217    #[cfg(feature = "unstable")]
218    async fn set_session_model(
219        &self,
220        args: SetSessionModelRequest,
221    ) -> Result<SetSessionModelResponse> {
222        self.as_ref().set_session_model(args).await
223    }
224    async fn ext_method(&self, args: ExtRequest) -> Result<ExtResponse> {
225        self.as_ref().ext_method(args).await
226    }
227    async fn ext_notification(&self, args: ExtNotification) -> Result<()> {
228        self.as_ref().ext_notification(args).await
229    }
230}