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#[cfg(feature = "unstable_mcp_over_acp")]
285impl_v2_jsonrpc_request!(v2::ConnectMcpRequest, v2::ConnectMcpResponse, "mcp/connect");
286#[cfg(feature = "unstable_mcp_over_acp")]
287impl_v2_jsonrpc_request!(
288    v2::DisconnectMcpRequest,
289    v2::DisconnectMcpResponse,
290    "mcp/disconnect"
291);
292
293impl_v2_jsonrpc_notification!(v2::UpdateSessionNotification, "session/update");
294impl_v2_jsonrpc_notification!(v2::CompleteElicitationNotification, "elicitation/complete");
295
296impl_jsonrpc_protocol_level_notification_enum!(v2::ProtocolLevelNotification {
297    CancelRequestNotification => "$/cancel_request",
298});
299
300impl_v2_jsonrpc_request_enum!(v2::ClientRequest {
301    InitializeRequest => "initialize",
302    LoginAuthRequest => "auth/login",
303    LogoutAuthRequest => "auth/logout",
304    #[cfg(feature = "unstable_llm_providers")]
305    ListProvidersRequest => "providers/list",
306    #[cfg(feature = "unstable_llm_providers")]
307    SetProviderRequest => "providers/set",
308    #[cfg(feature = "unstable_llm_providers")]
309    DisableProviderRequest => "providers/disable",
310    NewSessionRequest => "session/new",
311    ListSessionsRequest => "session/list",
312    DeleteSessionRequest => "session/delete",
313    #[cfg(feature = "unstable_session_fork")]
314    ForkSessionRequest => "session/fork",
315    ResumeSessionRequest => "session/resume",
316    CloseSessionRequest => "session/close",
317    SetSessionConfigOptionRequest => "session/set_config_option",
318    PromptRequest => "session/prompt",
319    #[cfg(feature = "unstable_mcp_over_acp")]
320    MessageMcpRequest => "mcp/message",
321    [ext] ExtMethodRequest,
322});
323
324impl_v2_jsonrpc_response_enum!(v2::AgentResponse {
325    InitializeResponse => "initialize",
326    LoginAuthResponse => "auth/login",
327    LogoutAuthResponse => "auth/logout",
328    #[cfg(feature = "unstable_llm_providers")]
329    ListProvidersResponse => "providers/list",
330    #[cfg(feature = "unstable_llm_providers")]
331    SetProviderResponse => "providers/set",
332    #[cfg(feature = "unstable_llm_providers")]
333    DisableProviderResponse => "providers/disable",
334    NewSessionResponse => "session/new",
335    ListSessionsResponse => "session/list",
336    DeleteSessionResponse => "session/delete",
337    #[cfg(feature = "unstable_session_fork")]
338    ForkSessionResponse => "session/fork",
339    ResumeSessionResponse => "session/resume",
340    CloseSessionResponse => "session/close",
341    SetSessionConfigOptionResponse => "session/set_config_option",
342    PromptResponse => "session/prompt",
343    #[cfg(feature = "unstable_mcp_over_acp")]
344    MessageMcpResponse => "mcp/message",
345    [ext] ExtMethodResponse,
346});
347
348impl_v2_jsonrpc_notification_enum!(v2::ClientNotification {
349    CancelSessionNotification => "session/cancel",
350    #[cfg(feature = "unstable_mcp_over_acp")]
351    MessageMcpNotification => "mcp/message",
352    [ext] ExtNotification,
353});
354
355impl_v2_jsonrpc_request_enum!(v2::AgentRequest {
356    RequestPermissionRequest => "session/request_permission",
357    CreateElicitationRequest => "elicitation/create",
358    #[cfg(feature = "unstable_mcp_over_acp")]
359    ConnectMcpRequest => "mcp/connect",
360    #[cfg(feature = "unstable_mcp_over_acp")]
361    MessageMcpRequest => "mcp/message",
362    #[cfg(feature = "unstable_mcp_over_acp")]
363    DisconnectMcpRequest => "mcp/disconnect",
364    [ext] ExtMethodRequest,
365});
366
367impl_v2_jsonrpc_response_enum!(v2::ClientResponse {
368    RequestPermissionResponse => "session/request_permission",
369    CreateElicitationResponse => "elicitation/create",
370    #[cfg(feature = "unstable_mcp_over_acp")]
371    ConnectMcpResponse => "mcp/connect",
372    #[cfg(feature = "unstable_mcp_over_acp")]
373    MessageMcpResponse => "mcp/message",
374    #[cfg(feature = "unstable_mcp_over_acp")]
375    DisconnectMcpResponse => "mcp/disconnect",
376    [ext] ExtMethodResponse,
377});
378
379impl_v2_jsonrpc_notification_enum!(v2::AgentNotification {
380    UpdateSessionNotification => "session/update",
381    CompleteElicitationNotification => "elicitation/complete",
382    #[cfg(feature = "unstable_mcp_over_acp")]
383    MessageMcpNotification => "mcp/message",
384    [ext] ExtNotification,
385});