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