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}