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
260impl_v2_jsonrpc_notification!(v2::CancelNotification, "session/cancel");
261#[cfg(feature = "unstable_mcp_over_acp")]
262impl_v2_jsonrpc_notification!(v2::MessageMcpNotification, "mcp/message");
263
264impl_v2_jsonrpc_request!(
265    v2::RequestPermissionRequest,
266    v2::RequestPermissionResponse,
267    "session/request_permission"
268);
269#[cfg(feature = "unstable_elicitation")]
270impl_v2_jsonrpc_request!(
271    v2::CreateElicitationRequest,
272    v2::CreateElicitationResponse,
273    "elicitation/create"
274);
275#[cfg(feature = "unstable_mcp_over_acp")]
276impl_v2_jsonrpc_request!(v2::ConnectMcpRequest, v2::ConnectMcpResponse, "mcp/connect");
277#[cfg(feature = "unstable_mcp_over_acp")]
278impl_v2_jsonrpc_request!(
279    v2::DisconnectMcpRequest,
280    v2::DisconnectMcpResponse,
281    "mcp/disconnect"
282);
283
284impl_v2_jsonrpc_notification!(v2::SessionNotification, "session/update");
285#[cfg(feature = "unstable_elicitation")]
286impl_v2_jsonrpc_notification!(v2::CompleteElicitationNotification, "elicitation/complete");
287
288impl_v2_jsonrpc_request_enum!(v2::ClientRequest {
289    InitializeRequest => "initialize",
290    AuthenticateRequest => "authenticate",
291    LogoutRequest => "logout",
292    NewSessionRequest => "session/new",
293    LoadSessionRequest => "session/load",
294    ListSessionsRequest => "session/list",
295    DeleteSessionRequest => "session/delete",
296    #[cfg(feature = "unstable_session_fork")]
297    ForkSessionRequest => "session/fork",
298    ResumeSessionRequest => "session/resume",
299    CloseSessionRequest => "session/close",
300    SetSessionConfigOptionRequest => "session/set_config_option",
301    PromptRequest => "session/prompt",
302    #[cfg(feature = "unstable_mcp_over_acp")]
303    MessageMcpRequest => "mcp/message",
304    [ext] ExtMethodRequest,
305});
306
307impl_v2_jsonrpc_response_enum!(v2::AgentResponse {
308    InitializeResponse => "initialize",
309    AuthenticateResponse => "authenticate",
310    LogoutResponse => "logout",
311    NewSessionResponse => "session/new",
312    LoadSessionResponse => "session/load",
313    ListSessionsResponse => "session/list",
314    DeleteSessionResponse => "session/delete",
315    #[cfg(feature = "unstable_session_fork")]
316    ForkSessionResponse => "session/fork",
317    ResumeSessionResponse => "session/resume",
318    CloseSessionResponse => "session/close",
319    SetSessionConfigOptionResponse => "session/set_config_option",
320    PromptResponse => "session/prompt",
321    #[cfg(feature = "unstable_mcp_over_acp")]
322    MessageMcpResponse => "mcp/message",
323    [ext] ExtMethodResponse,
324});
325
326impl_v2_jsonrpc_notification_enum!(v2::ClientNotification {
327    CancelNotification => "session/cancel",
328    #[cfg(feature = "unstable_mcp_over_acp")]
329    MessageMcpNotification => "mcp/message",
330    [ext] ExtNotification,
331});
332
333impl_v2_jsonrpc_request_enum!(v2::AgentRequest {
334    RequestPermissionRequest => "session/request_permission",
335    #[cfg(feature = "unstable_elicitation")]
336    CreateElicitationRequest => "elicitation/create",
337    #[cfg(feature = "unstable_mcp_over_acp")]
338    ConnectMcpRequest => "mcp/connect",
339    #[cfg(feature = "unstable_mcp_over_acp")]
340    MessageMcpRequest => "mcp/message",
341    #[cfg(feature = "unstable_mcp_over_acp")]
342    DisconnectMcpRequest => "mcp/disconnect",
343    [ext] ExtMethodRequest,
344});
345
346impl_v2_jsonrpc_response_enum!(v2::ClientResponse {
347    RequestPermissionResponse => "session/request_permission",
348    #[cfg(feature = "unstable_elicitation")]
349    CreateElicitationResponse => "elicitation/create",
350    #[cfg(feature = "unstable_mcp_over_acp")]
351    ConnectMcpResponse => "mcp/connect",
352    #[cfg(feature = "unstable_mcp_over_acp")]
353    MessageMcpResponse => "mcp/message",
354    #[cfg(feature = "unstable_mcp_over_acp")]
355    DisconnectMcpResponse => "mcp/disconnect",
356    [ext] ExtMethodResponse,
357});
358
359impl_v2_jsonrpc_notification_enum!(v2::AgentNotification {
360    SessionNotification => "session/update",
361    #[cfg(feature = "unstable_elicitation")]
362    CompleteElicitationNotification => "elicitation/complete",
363    #[cfg(feature = "unstable_mcp_over_acp")]
364    MessageMcpNotification => "mcp/message",
365    [ext] ExtNotification,
366});