agent_client_protocol/
agent.rs

1//! Methods and notifications the agent handles/receives
2
3use std::{path::PathBuf, sync::Arc};
4
5use anyhow::Result;
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9use crate::{ClientCapabilities, ContentBlock, Error, ProtocolVersion, SessionId};
10
11pub trait Agent {
12    fn initialize(
13        &self,
14        arguments: InitializeRequest,
15    ) -> impl Future<Output = Result<InitializeResponse, Error>>;
16
17    fn authenticate(
18        &self,
19        arguments: AuthenticateRequest,
20    ) -> impl Future<Output = Result<(), Error>>;
21
22    fn new_session(
23        &self,
24        arguments: NewSessionRequest,
25    ) -> impl Future<Output = Result<NewSessionResponse, Error>>;
26
27    fn load_session(
28        &self,
29        arguments: LoadSessionRequest,
30    ) -> impl Future<Output = Result<(), Error>>;
31
32    fn prompt(
33        &self,
34        arguments: PromptRequest,
35    ) -> impl Future<Output = Result<PromptResponse, Error>>;
36
37    fn cancel(&self, args: CancelNotification) -> impl Future<Output = Result<(), Error>>;
38}
39
40// Initialize
41
42#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
43#[serde(rename_all = "camelCase")]
44pub struct InitializeRequest {
45    /// The latest protocol version supported by the client.
46    pub protocol_version: ProtocolVersion,
47    /// Capabilities supported by the client.
48    #[serde(default)]
49    pub client_capabilities: ClientCapabilities,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
53#[serde(rename_all = "camelCase")]
54pub struct InitializeResponse {
55    /// The protocol version the client specified if supported by the agent,
56    /// or the latest protocol version supported by the agent.
57    ///
58    /// The client should disconnect, if it doesn't support this version.
59    pub protocol_version: ProtocolVersion,
60    /// Capabilities supported by the agent.
61    #[serde(default)]
62    pub agent_capabilities: AgentCapabilities,
63    /// Authentication methods supported by the agent.
64    #[serde(default)]
65    pub auth_methods: Vec<AuthMethod>,
66}
67
68// Authentication
69
70#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
71#[serde(rename_all = "camelCase")]
72pub struct AuthenticateRequest {
73    pub method_id: AuthMethodId,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
77#[serde(transparent)]
78pub struct AuthMethodId(pub Arc<str>);
79
80#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
81#[serde(rename_all = "camelCase")]
82pub struct AuthMethod {
83    pub id: AuthMethodId,
84    pub name: String,
85    pub description: Option<String>,
86}
87
88// New session
89
90#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
91#[serde(rename_all = "camelCase")]
92pub struct NewSessionRequest {
93    pub mcp_servers: Vec<McpServer>,
94    pub cwd: PathBuf,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
98#[serde(rename_all = "camelCase")]
99pub struct NewSessionResponse {
100    pub session_id: SessionId,
101}
102
103// Load session
104
105#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
106#[serde(rename_all = "camelCase")]
107pub struct LoadSessionRequest {
108    pub mcp_servers: Vec<McpServer>,
109    pub cwd: PathBuf,
110    pub session_id: SessionId,
111}
112
113// MCP
114
115#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
116#[serde(rename_all = "camelCase")]
117pub struct McpServer {
118    pub name: String,
119    pub command: PathBuf,
120    pub args: Vec<String>,
121    pub env: Vec<EnvVariable>,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
125#[serde(rename_all = "camelCase")]
126pub struct EnvVariable {
127    pub name: String,
128    pub value: String,
129}
130
131// Prompt
132
133#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
134#[serde(rename_all = "camelCase")]
135pub struct PromptRequest {
136    /// The ID of the session to send this user message to
137    pub session_id: SessionId,
138    /// The blocks of content that compose the user's message.
139    ///
140    /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
141    /// while other variants are optionally enabled via [`PromptCapabilities`].
142    ///
143    /// The Client MUST adapt its interface according to [`PromptCapabilities`].
144    ///
145    /// ## Context
146    ///
147    /// The client MAY include referenced pieces of context as either
148    /// [`ContentBlock::EmbeddedResource`] or [`ContentBlock::ResourceLink`].
149    ///
150    /// When available, [`ContentBlock::EmbeddedResource`] is preferred
151    /// as it avoids extra round-trips and allows the message to include
152    /// pieces of context from sources the agent may not have access to.
153    pub prompt: Vec<ContentBlock>,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
157#[serde(rename_all = "camelCase")]
158pub struct PromptResponse {
159    pub stop_reason: StopReason,
160}
161
162#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
163#[serde(rename_all = "snake_case")]
164pub enum StopReason {
165    /// The turn ended successfully.
166    EndTurn,
167    /// The turn ended because the agent reached the maximum number of tokens.
168    MaxTokens,
169    /// The turn ended because the agent reached the maximum number of allowed
170    /// agent requests between user turns.
171    MaxTurnRequests,
172    /// The turn ended because the agent refused to continue. The user prompt
173    /// and everything that comes after it won't be included in the next
174    /// prompt, so this should be reflected in the UI.
175    Refusal,
176    /// The turn was canceled by the client.
177    #[serde(alias = "cancelled")]
178    Canceled,
179}
180
181// Capabilities
182
183#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
184#[serde(rename_all = "camelCase")]
185pub struct AgentCapabilities {
186    /// Whether the agent supports `session/load`.
187    #[serde(default)]
188    load_session: bool,
189    /// Prompt capabilities supported by the agent.
190    #[serde(default)]
191    prompt_capabilities: PromptCapabilities,
192}
193
194/// Prompt capabilities supported by the agent in `session/prompt` requests.
195///
196/// Baseline agent functionality requires support for [`ContentBlock::Text`]
197/// and [`ContentBlock::ResourceLink`] in prompt requests.
198///
199/// Other variants must be explicitly opted in to.
200#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
201#[serde(rename_all = "camelCase")]
202pub struct PromptCapabilities {
203    /// Agent supports [`ContentBlock::Image`].
204    #[serde(default)]
205    image: bool,
206    /// Agent supports [`ContentBlock::Audio`].
207    #[serde(default)]
208    audio: bool,
209    /// Agent supports embedded context in `session/prompt` requests.
210    ///
211    /// When enabled, the Client is allowed to include [`ContentBlock::EmbeddedResource`]
212    /// in prompt requests for pieces of context that are referenced in the message.
213    #[serde(default)]
214    embedded_context: bool,
215}
216
217// Method schema
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct AgentMethodNames {
221    pub initialize: &'static str,
222    pub authenticate: &'static str,
223    pub session_new: &'static str,
224    pub session_load: &'static str,
225    pub session_prompt: &'static str,
226    pub session_cancel: &'static str,
227}
228
229pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
230    initialize: INITIALIZE_METHOD_NAME,
231    authenticate: AUTHENTICATE_METHOD_NAME,
232    session_new: SESSION_NEW_METHOD_NAME,
233    session_load: SESSION_LOAD_METHOD_NAME,
234    session_prompt: SESSION_PROMPT_METHOD_NAME,
235    session_cancel: SESSION_CANCEL_METHOD_NAME,
236};
237
238pub const INITIALIZE_METHOD_NAME: &str = "initialize";
239pub const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
240pub const SESSION_NEW_METHOD_NAME: &str = "session/new";
241pub const SESSION_LOAD_METHOD_NAME: &str = "session/load";
242pub const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
243pub const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
244
245/// Requests the client sends to the agent
246#[derive(Debug, Serialize, Deserialize, JsonSchema)]
247#[serde(untagged)]
248pub enum ClientRequest {
249    InitializeRequest(InitializeRequest),
250    AuthenticateRequest(AuthenticateRequest),
251    NewSessionRequest(NewSessionRequest),
252    LoadSessionRequest(LoadSessionRequest),
253    PromptRequest(PromptRequest),
254}
255
256/// Responses the agent sends to the client
257#[derive(Debug, Serialize, Deserialize, JsonSchema)]
258#[serde(untagged)]
259pub enum AgentResponse {
260    InitializeResponse(InitializeResponse),
261    AuthenticateResponse,
262    NewSessionResponse(NewSessionResponse),
263    LoadSessionResponse,
264    PromptResponse(PromptResponse),
265}
266
267/// Notifications the client sends to the agent
268#[derive(Debug, Serialize, Deserialize, JsonSchema)]
269#[serde(untagged)]
270pub enum ClientNotification {
271    CancelNotification(CancelNotification),
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
275#[serde(rename_all = "camelCase")]
276pub struct CancelNotification {
277    pub session_id: SessionId,
278}