Skip to main content

agent_client_protocol/schema/
v2_impls.rs

1//! JSON-RPC trait implementations for the experimental schema v2 namespace.
2
3use crate::schema::v2;
4use crate::{JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, UntypedMessage};
5
6macro_rules! impl_v2_jsonrpc_request {
7    ($req:ty, $resp:ty, $method:literal) => {
8        impl JsonRpcMessage for $req {
9            fn matches_method(method: &str) -> bool {
10                method == $method
11            }
12
13            fn method(&self) -> &str {
14                $method
15            }
16
17            fn to_untyped_message(&self) -> Result<UntypedMessage, crate::Error> {
18                UntypedMessage::new($method, self)
19            }
20
21            fn parse_message(
22                method: &str,
23                params: &impl serde::Serialize,
24            ) -> Result<Self, crate::Error> {
25                if method != $method {
26                    return Err(crate::Error::method_not_found());
27                }
28                crate::util::json_cast_params(params)
29            }
30        }
31
32        impl JsonRpcRequest for $req {
33            type Response = $resp;
34        }
35
36        impl JsonRpcResponse for $resp {
37            fn into_json(self, _method: &str) -> Result<serde_json::Value, crate::Error> {
38                serde_json::to_value(self).map_err(crate::Error::into_internal_error)
39            }
40
41            fn from_value(_method: &str, value: serde_json::Value) -> Result<Self, crate::Error> {
42                crate::util::json_cast(value)
43            }
44        }
45    };
46}
47
48macro_rules! impl_v2_jsonrpc_notification {
49    ($notif:ty, $method:literal) => {
50        impl JsonRpcMessage for $notif {
51            fn matches_method(method: &str) -> bool {
52                method == $method
53            }
54
55            fn method(&self) -> &str {
56                $method
57            }
58
59            fn to_untyped_message(&self) -> Result<UntypedMessage, crate::Error> {
60                UntypedMessage::new($method, self)
61            }
62
63            fn parse_message(
64                method: &str,
65                params: &impl serde::Serialize,
66            ) -> Result<Self, crate::Error> {
67                if method != $method {
68                    return Err(crate::Error::method_not_found());
69                }
70                crate::util::json_cast_params(params)
71            }
72        }
73
74        impl JsonRpcNotification for $notif {}
75    };
76}
77
78macro_rules! impl_v2_jsonrpc_request_enum {
79    ($enum:ty {
80        $( $(#[$meta:meta])* $variant:ident => $method:literal, )*
81        [ext] $ext_variant:ident,
82    }) => {
83        impl JsonRpcMessage for $enum {
84            fn matches_method(_method: &str) -> bool {
85                true
86            }
87
88            fn method(&self) -> &str {
89                match self {
90                    $( $(#[$meta])* Self::$variant(_) => $method, )*
91                    Self::$ext_variant(ext) => &ext.method,
92                    _ => "_unknown",
93                }
94            }
95
96            fn to_untyped_message(&self) -> Result<UntypedMessage, crate::Error> {
97                UntypedMessage::new(self.method(), self)
98            }
99
100            fn parse_message(
101                method: &str,
102                params: &impl serde::Serialize,
103            ) -> Result<Self, crate::Error> {
104                match method {
105                    $( $(#[$meta])* $method => crate::util::json_cast_params(params).map(Self::$variant), )*
106                    _ => {
107                        if method.starts_with('_') {
108                            crate::util::json_cast_params(params).map(
109                                |ext_req: v2::ExtRequest| {
110                                    Self::$ext_variant(v2::ExtRequest::new(
111                                        method.to_string(),
112                                        ext_req.params,
113                                    ))
114                                },
115                            )
116                        } else {
117                            Err(crate::Error::method_not_found())
118                        }
119                    }
120                }
121            }
122        }
123
124        impl JsonRpcRequest for $enum {
125            type Response = serde_json::Value;
126        }
127    };
128}
129
130macro_rules! impl_v2_jsonrpc_notification_enum {
131    ($enum:ty {
132        $( $(#[$meta:meta])* $variant:ident => $method:literal, )*
133        [ext] $ext_variant:ident,
134    }) => {
135        impl JsonRpcMessage for $enum {
136            fn matches_method(_method: &str) -> bool {
137                true
138            }
139
140            fn method(&self) -> &str {
141                match self {
142                    $( $(#[$meta])* Self::$variant(_) => $method, )*
143                    Self::$ext_variant(ext) => &ext.method,
144                    _ => "_unknown",
145                }
146            }
147
148            fn to_untyped_message(&self) -> Result<UntypedMessage, crate::Error> {
149                UntypedMessage::new(self.method(), self)
150            }
151
152            fn parse_message(
153                method: &str,
154                params: &impl serde::Serialize,
155            ) -> Result<Self, crate::Error> {
156                match method {
157                    $( $(#[$meta])* $method => crate::util::json_cast_params(params).map(Self::$variant), )*
158                    _ => {
159                        if method.starts_with('_') {
160                            crate::util::json_cast_params(params).map(
161                                |ext_notif: v2::ExtNotification| {
162                                    Self::$ext_variant(v2::ExtNotification::new(
163                                        method.to_string(),
164                                        ext_notif.params,
165                                    ))
166                                },
167                            )
168                        } else {
169                            Err(crate::Error::method_not_found())
170                        }
171                    }
172                }
173            }
174        }
175
176        impl JsonRpcNotification for $enum {}
177    };
178}
179
180macro_rules! impl_v2_jsonrpc_response_enum {
181    ($enum:ty {
182        $( $(#[$meta:meta])* $variant:ident => $method:literal, )*
183        [ext] $ext_variant:ident,
184    }) => {
185        impl JsonRpcResponse for $enum {
186            fn into_json(
187                self,
188                _method: &str,
189            ) -> Result<serde_json::Value, crate::Error> {
190                serde_json::to_value(self).map_err(crate::Error::into_internal_error)
191            }
192
193            fn from_value(
194                method: &str,
195                value: serde_json::Value,
196            ) -> Result<Self, crate::Error> {
197                match method {
198                    $( $(#[$meta])* $method => crate::util::json_cast(value).map(Self::$variant), )*
199                    _ => {
200                        if method.starts_with('_') {
201                            crate::util::json_cast(value).map(Self::$ext_variant)
202                        } else {
203                            Err(crate::Error::method_not_found())
204                        }
205                    }
206                }
207            }
208        }
209    };
210}
211
212impl_v2_jsonrpc_request!(v2::InitializeRequest, v2::InitializeResponse, "initialize");
213impl_v2_jsonrpc_request!(
214    v2::AuthenticateRequest,
215    v2::AuthenticateResponse,
216    "authenticate"
217);
218impl_v2_jsonrpc_request!(v2::LogoutRequest, v2::LogoutResponse, "logout");
219impl_v2_jsonrpc_request!(v2::NewSessionRequest, v2::NewSessionResponse, "session/new");
220impl_v2_jsonrpc_request!(
221    v2::LoadSessionRequest,
222    v2::LoadSessionResponse,
223    "session/load"
224);
225impl_v2_jsonrpc_request!(
226    v2::ListSessionsRequest,
227    v2::ListSessionsResponse,
228    "session/list"
229);
230impl_v2_jsonrpc_request!(
231    v2::DeleteSessionRequest,
232    v2::DeleteSessionResponse,
233    "session/delete"
234);
235#[cfg(feature = "unstable_session_fork")]
236impl_v2_jsonrpc_request!(
237    v2::ForkSessionRequest,
238    v2::ForkSessionResponse,
239    "session/fork"
240);
241impl_v2_jsonrpc_request!(
242    v2::ResumeSessionRequest,
243    v2::ResumeSessionResponse,
244    "session/resume"
245);
246impl_v2_jsonrpc_request!(
247    v2::CloseSessionRequest,
248    v2::CloseSessionResponse,
249    "session/close"
250);
251impl_v2_jsonrpc_request!(
252    v2::SetSessionConfigOptionRequest,
253    v2::SetSessionConfigOptionResponse,
254    "session/set_config_option"
255);
256impl_v2_jsonrpc_request!(v2::PromptRequest, v2::PromptResponse, "session/prompt");
257#[cfg(feature = "unstable_mcp_over_acp")]
258impl_v2_jsonrpc_request!(v2::MessageMcpRequest, v2::MessageMcpResponse, "mcp/message");
259
260#[cfg(feature = "unstable_cancel_request")]
261impl_v2_jsonrpc_notification!(v2::CancelRequestNotification, "$/cancel_request");
262impl_v2_jsonrpc_notification!(v2::CancelNotification, "session/cancel");
263#[cfg(feature = "unstable_mcp_over_acp")]
264impl_v2_jsonrpc_notification!(v2::MessageMcpNotification, "mcp/message");
265
266impl_v2_jsonrpc_request!(
267    v2::RequestPermissionRequest,
268    v2::RequestPermissionResponse,
269    "session/request_permission"
270);
271#[cfg(feature = "unstable_elicitation")]
272impl_v2_jsonrpc_request!(
273    v2::CreateElicitationRequest,
274    v2::CreateElicitationResponse,
275    "elicitation/create"
276);
277#[cfg(feature = "unstable_mcp_over_acp")]
278impl_v2_jsonrpc_request!(v2::ConnectMcpRequest, v2::ConnectMcpResponse, "mcp/connect");
279#[cfg(feature = "unstable_mcp_over_acp")]
280impl_v2_jsonrpc_request!(
281    v2::DisconnectMcpRequest,
282    v2::DisconnectMcpResponse,
283    "mcp/disconnect"
284);
285
286impl_v2_jsonrpc_notification!(v2::SessionNotification, "session/update");
287#[cfg(feature = "unstable_elicitation")]
288impl_v2_jsonrpc_notification!(v2::CompleteElicitationNotification, "elicitation/complete");
289
290#[cfg(feature = "unstable_cancel_request")]
291impl_jsonrpc_protocol_level_notification_enum!(v2::ProtocolLevelNotification {
292    CancelRequestNotification => "$/cancel_request",
293});
294
295impl_v2_jsonrpc_request_enum!(v2::ClientRequest {
296    InitializeRequest => "initialize",
297    AuthenticateRequest => "authenticate",
298    LogoutRequest => "logout",
299    NewSessionRequest => "session/new",
300    LoadSessionRequest => "session/load",
301    ListSessionsRequest => "session/list",
302    DeleteSessionRequest => "session/delete",
303    #[cfg(feature = "unstable_session_fork")]
304    ForkSessionRequest => "session/fork",
305    ResumeSessionRequest => "session/resume",
306    CloseSessionRequest => "session/close",
307    SetSessionConfigOptionRequest => "session/set_config_option",
308    PromptRequest => "session/prompt",
309    #[cfg(feature = "unstable_mcp_over_acp")]
310    MessageMcpRequest => "mcp/message",
311    [ext] ExtMethodRequest,
312});
313
314impl_v2_jsonrpc_response_enum!(v2::AgentResponse {
315    InitializeResponse => "initialize",
316    AuthenticateResponse => "authenticate",
317    LogoutResponse => "logout",
318    NewSessionResponse => "session/new",
319    LoadSessionResponse => "session/load",
320    ListSessionsResponse => "session/list",
321    DeleteSessionResponse => "session/delete",
322    #[cfg(feature = "unstable_session_fork")]
323    ForkSessionResponse => "session/fork",
324    ResumeSessionResponse => "session/resume",
325    CloseSessionResponse => "session/close",
326    SetSessionConfigOptionResponse => "session/set_config_option",
327    PromptResponse => "session/prompt",
328    #[cfg(feature = "unstable_mcp_over_acp")]
329    MessageMcpResponse => "mcp/message",
330    [ext] ExtMethodResponse,
331});
332
333impl_v2_jsonrpc_notification_enum!(v2::ClientNotification {
334    CancelNotification => "session/cancel",
335    #[cfg(feature = "unstable_mcp_over_acp")]
336    MessageMcpNotification => "mcp/message",
337    [ext] ExtNotification,
338});
339
340impl_v2_jsonrpc_request_enum!(v2::AgentRequest {
341    RequestPermissionRequest => "session/request_permission",
342    #[cfg(feature = "unstable_elicitation")]
343    CreateElicitationRequest => "elicitation/create",
344    #[cfg(feature = "unstable_mcp_over_acp")]
345    ConnectMcpRequest => "mcp/connect",
346    #[cfg(feature = "unstable_mcp_over_acp")]
347    MessageMcpRequest => "mcp/message",
348    #[cfg(feature = "unstable_mcp_over_acp")]
349    DisconnectMcpRequest => "mcp/disconnect",
350    [ext] ExtMethodRequest,
351});
352
353impl_v2_jsonrpc_response_enum!(v2::ClientResponse {
354    RequestPermissionResponse => "session/request_permission",
355    #[cfg(feature = "unstable_elicitation")]
356    CreateElicitationResponse => "elicitation/create",
357    #[cfg(feature = "unstable_mcp_over_acp")]
358    ConnectMcpResponse => "mcp/connect",
359    #[cfg(feature = "unstable_mcp_over_acp")]
360    MessageMcpResponse => "mcp/message",
361    #[cfg(feature = "unstable_mcp_over_acp")]
362    DisconnectMcpResponse => "mcp/disconnect",
363    [ext] ExtMethodResponse,
364});
365
366impl_v2_jsonrpc_notification_enum!(v2::AgentNotification {
367    SessionNotification => "session/update",
368    #[cfg(feature = "unstable_elicitation")]
369    CompleteElicitationNotification => "elicitation/complete",
370    #[cfg(feature = "unstable_mcp_over_acp")]
371    MessageMcpNotification => "mcp/message",
372    [ext] ExtNotification,
373});