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(Box::new(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(Box::new(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!(v2::LoginAuthRequest, v2::LoginAuthResponse, "auth/login");
214impl_v2_jsonrpc_request!(v2::LogoutAuthRequest, v2::LogoutAuthResponse, "auth/logout");
215impl_v2_jsonrpc_request!(v2::NewSessionRequest, v2::NewSessionResponse, "session/new");
216impl_v2_jsonrpc_request!(
217    v2::ListSessionsRequest,
218    v2::ListSessionsResponse,
219    "session/list"
220);
221impl_v2_jsonrpc_request!(
222    v2::DeleteSessionRequest,
223    v2::DeleteSessionResponse,
224    "session/delete"
225);
226#[cfg(feature = "unstable_session_fork")]
227impl_v2_jsonrpc_request!(
228    v2::ForkSessionRequest,
229    v2::ForkSessionResponse,
230    "session/fork"
231);
232impl_v2_jsonrpc_request!(
233    v2::ResumeSessionRequest,
234    v2::ResumeSessionResponse,
235    "session/resume"
236);
237impl_v2_jsonrpc_request!(
238    v2::CloseSessionRequest,
239    v2::CloseSessionResponse,
240    "session/close"
241);
242impl_v2_jsonrpc_request!(
243    v2::SetSessionConfigOptionRequest,
244    v2::SetSessionConfigOptionResponse,
245    "session/set_config_option"
246);
247impl_v2_jsonrpc_request!(v2::PromptRequest, v2::PromptResponse, "session/prompt");
248#[cfg(feature = "unstable_mcp_over_acp")]
249impl_v2_jsonrpc_request!(v2::MessageMcpRequest, v2::MessageMcpResponse, "mcp/message");
250
251impl_v2_jsonrpc_notification!(v2::CancelRequestNotification, "$/cancel_request");
252impl_v2_jsonrpc_notification!(v2::CancelSessionNotification, "session/cancel");
253#[cfg(feature = "unstable_mcp_over_acp")]
254impl_v2_jsonrpc_notification!(v2::MessageMcpNotification, "mcp/message");
255
256impl_v2_jsonrpc_request!(
257    v2::RequestPermissionRequest,
258    v2::RequestPermissionResponse,
259    "session/request_permission"
260);
261#[cfg(feature = "unstable_elicitation")]
262impl_v2_jsonrpc_request!(
263    v2::CreateElicitationRequest,
264    v2::CreateElicitationResponse,
265    "elicitation/create"
266);
267#[cfg(feature = "unstable_mcp_over_acp")]
268impl_v2_jsonrpc_request!(v2::ConnectMcpRequest, v2::ConnectMcpResponse, "mcp/connect");
269#[cfg(feature = "unstable_mcp_over_acp")]
270impl_v2_jsonrpc_request!(
271    v2::DisconnectMcpRequest,
272    v2::DisconnectMcpResponse,
273    "mcp/disconnect"
274);
275
276impl_v2_jsonrpc_notification!(v2::UpdateSessionNotification, "session/update");
277#[cfg(feature = "unstable_elicitation")]
278impl_v2_jsonrpc_notification!(v2::CompleteElicitationNotification, "elicitation/complete");
279
280impl_jsonrpc_protocol_level_notification_enum!(v2::ProtocolLevelNotification {
281    CancelRequestNotification => "$/cancel_request",
282});
283
284impl_v2_jsonrpc_request_enum!(v2::ClientRequest {
285    InitializeRequest => "initialize",
286    LoginAuthRequest => "auth/login",
287    LogoutAuthRequest => "auth/logout",
288    NewSessionRequest => "session/new",
289    ListSessionsRequest => "session/list",
290    DeleteSessionRequest => "session/delete",
291    #[cfg(feature = "unstable_session_fork")]
292    ForkSessionRequest => "session/fork",
293    ResumeSessionRequest => "session/resume",
294    CloseSessionRequest => "session/close",
295    SetSessionConfigOptionRequest => "session/set_config_option",
296    PromptRequest => "session/prompt",
297    #[cfg(feature = "unstable_mcp_over_acp")]
298    MessageMcpRequest => "mcp/message",
299    [ext] ExtMethodRequest,
300});
301
302impl_v2_jsonrpc_response_enum!(v2::AgentResponse {
303    InitializeResponse => "initialize",
304    LoginAuthResponse => "auth/login",
305    LogoutAuthResponse => "auth/logout",
306    NewSessionResponse => "session/new",
307    ListSessionsResponse => "session/list",
308    DeleteSessionResponse => "session/delete",
309    #[cfg(feature = "unstable_session_fork")]
310    ForkSessionResponse => "session/fork",
311    ResumeSessionResponse => "session/resume",
312    CloseSessionResponse => "session/close",
313    SetSessionConfigOptionResponse => "session/set_config_option",
314    PromptResponse => "session/prompt",
315    #[cfg(feature = "unstable_mcp_over_acp")]
316    MessageMcpResponse => "mcp/message",
317    [ext] ExtMethodResponse,
318});
319
320impl_v2_jsonrpc_notification_enum!(v2::ClientNotification {
321    CancelSessionNotification => "session/cancel",
322    #[cfg(feature = "unstable_mcp_over_acp")]
323    MessageMcpNotification => "mcp/message",
324    [ext] ExtNotification,
325});
326
327impl_v2_jsonrpc_request_enum!(v2::AgentRequest {
328    RequestPermissionRequest => "session/request_permission",
329    #[cfg(feature = "unstable_elicitation")]
330    CreateElicitationRequest => "elicitation/create",
331    #[cfg(feature = "unstable_mcp_over_acp")]
332    ConnectMcpRequest => "mcp/connect",
333    #[cfg(feature = "unstable_mcp_over_acp")]
334    MessageMcpRequest => "mcp/message",
335    #[cfg(feature = "unstable_mcp_over_acp")]
336    DisconnectMcpRequest => "mcp/disconnect",
337    [ext] ExtMethodRequest,
338});
339
340impl_v2_jsonrpc_response_enum!(v2::ClientResponse {
341    RequestPermissionResponse => "session/request_permission",
342    #[cfg(feature = "unstable_elicitation")]
343    CreateElicitationResponse => "elicitation/create",
344    #[cfg(feature = "unstable_mcp_over_acp")]
345    ConnectMcpResponse => "mcp/connect",
346    #[cfg(feature = "unstable_mcp_over_acp")]
347    MessageMcpResponse => "mcp/message",
348    #[cfg(feature = "unstable_mcp_over_acp")]
349    DisconnectMcpResponse => "mcp/disconnect",
350    [ext] ExtMethodResponse,
351});
352
353impl_v2_jsonrpc_notification_enum!(v2::AgentNotification {
354    UpdateSessionNotification => "session/update",
355    #[cfg(feature = "unstable_elicitation")]
356    CompleteElicitationNotification => "elicitation/complete",
357    #[cfg(feature = "unstable_mcp_over_acp")]
358    MessageMcpNotification => "mcp/message",
359    [ext] ExtNotification,
360});