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