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::v2::schema as 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: &serde_json::Value,
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_json(_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: &serde_json::Value,
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                // The schema enum's inherent `method()` (path syntax prefers
90                // inherent items) covers every variant, including ones this
91                // macro does not list.
92                <$enum>::method(self)
93            }
94
95            fn to_untyped_message(&self) -> Result<UntypedMessage, crate::Error> {
96                UntypedMessage::new(self.method(), self)
97            }
98
99            fn parse_message(
100                method: &str,
101                params: &serde_json::Value,
102            ) -> Result<Self, crate::Error> {
103                match method {
104                    $( $(#[$meta])* $method => crate::util::json_cast_params(params).map(Self::$variant), )*
105                    _ => {
106                        if method.starts_with('_') {
107                            crate::util::json_cast_params(params).map(
108                                |ext_req: v2::ExtRequest| {
109                                    Self::$ext_variant(Box::new(v2::ExtRequest::new(
110                                        method.to_string(),
111                                        ext_req.params,
112                                    )))
113                                },
114                            )
115                        } else {
116                            Err(crate::Error::method_not_found())
117                        }
118                    }
119                }
120            }
121        }
122
123        impl JsonRpcRequest for $enum {
124            type Response = serde_json::Value;
125        }
126    };
127}
128
129macro_rules! impl_v2_jsonrpc_notification_enum {
130    ($enum:ty {
131        $( $(#[$meta:meta])* $variant:ident => $method:literal, )*
132        [ext] $ext_variant:ident,
133    }) => {
134        impl JsonRpcMessage for $enum {
135            fn matches_method(_method: &str) -> bool {
136                true
137            }
138
139            fn method(&self) -> &str {
140                // The schema enum's inherent `method()` (path syntax prefers
141                // inherent items) covers every variant, including ones this
142                // macro does not list.
143                <$enum>::method(self)
144            }
145
146            fn to_untyped_message(&self) -> Result<UntypedMessage, crate::Error> {
147                UntypedMessage::new(self.method(), self)
148            }
149
150            fn parse_message(
151                method: &str,
152                params: &serde_json::Value,
153            ) -> Result<Self, crate::Error> {
154                match method {
155                    $( $(#[$meta])* $method => crate::util::json_cast_params(params).map(Self::$variant), )*
156                    _ => {
157                        if method.starts_with('_') {
158                            crate::util::json_cast_params(params).map(
159                                |ext_notif: v2::ExtNotification| {
160                                    Self::$ext_variant(Box::new(v2::ExtNotification::new(
161                                        method.to_string(),
162                                        ext_notif.params,
163                                    )))
164                                },
165                            )
166                        } else {
167                            Err(crate::Error::method_not_found())
168                        }
169                    }
170                }
171            }
172        }
173
174        impl JsonRpcNotification for $enum {}
175    };
176}
177
178macro_rules! impl_v2_jsonrpc_response_enum {
179    ($enum:ty {
180        $( $(#[$meta:meta])* $variant:ident => $method:literal, )*
181        [ext] $ext_variant:ident,
182    }) => {
183        impl JsonRpcResponse for $enum {
184            fn into_json(
185                self,
186                _method: &str,
187            ) -> Result<serde_json::Value, crate::Error> {
188                serde_json::to_value(self).map_err(crate::Error::into_internal_error)
189            }
190
191            fn from_json(
192                method: &str,
193                value: serde_json::Value,
194            ) -> Result<Self, crate::Error> {
195                match method {
196                    $( $(#[$meta])* $method => crate::util::json_cast(value).map(Self::$variant), )*
197                    _ => {
198                        if method.starts_with('_') {
199                            crate::util::json_cast(value).map(Self::$ext_variant)
200                        } else {
201                            Err(crate::Error::method_not_found())
202                        }
203                    }
204                }
205            }
206        }
207    };
208}
209
210impl_v2_jsonrpc_request!(v2::InitializeRequest, v2::InitializeResponse, "initialize");
211impl_v2_jsonrpc_request!(v2::LoginAuthRequest, v2::LoginAuthResponse, "auth/login");
212impl_v2_jsonrpc_request!(v2::LogoutAuthRequest, v2::LogoutAuthResponse, "auth/logout");
213#[cfg(feature = "unstable_auth_status")]
214impl_v2_jsonrpc_request!(v2::AuthStatusRequest, v2::AuthStatusResponse, "auth/status");
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);
250#[cfg(feature = "unstable_session_archive")]
251impl_v2_jsonrpc_request!(
252    v2::ArchiveSessionRequest,
253    v2::ArchiveSessionResponse,
254    "session/archive"
255);
256#[cfg(feature = "unstable_session_archive")]
257impl_v2_jsonrpc_request!(
258    v2::UnarchiveSessionRequest,
259    v2::UnarchiveSessionResponse,
260    "session/unarchive"
261);
262#[cfg(feature = "unstable_session_status")]
263impl_v2_jsonrpc_request!(
264    v2::SessionStatusRequest,
265    v2::SessionStatusResponse,
266    "session/status"
267);
268#[cfg(feature = "unstable_session_set_title")]
269impl_v2_jsonrpc_request!(
270    v2::SetSessionTitleRequest,
271    v2::SetSessionTitleResponse,
272    "session/set_title"
273);
274impl_v2_jsonrpc_request!(
275    v2::ResumeSessionRequest,
276    v2::ResumeSessionResponse,
277    "session/resume"
278);
279impl_v2_jsonrpc_request!(
280    v2::CloseSessionRequest,
281    v2::CloseSessionResponse,
282    "session/close"
283);
284impl_v2_jsonrpc_request!(
285    v2::SetSessionConfigOptionRequest,
286    v2::SetSessionConfigOptionResponse,
287    "session/set_config_option"
288);
289impl_v2_jsonrpc_request!(
290    v2::CancelToolCallRequest,
291    v2::CancelToolCallResponse,
292    "tool_call/cancel"
293);
294impl_v2_jsonrpc_request!(
295    v2::CancelTerminalRequest,
296    v2::CancelTerminalResponse,
297    "terminal/cancel"
298);
299impl_v2_jsonrpc_request!(v2::PromptRequest, v2::PromptResponse, "session/prompt");
300#[cfg(feature = "unstable_mcp_over_acp")]
301impl_v2_jsonrpc_request!(v2::MessageMcpRequest, v2::MessageMcpResponse, "mcp/message");
302
303impl_v2_jsonrpc_notification!(v2::CancelRequestNotification, "$/cancel_request");
304impl_v2_jsonrpc_notification!(v2::CancelSessionNotification, "session/cancel");
305#[cfg(feature = "unstable_mcp_over_acp")]
306impl_v2_jsonrpc_notification!(v2::MessageMcpNotification, "mcp/message");
307
308impl_v2_jsonrpc_request!(
309    v2::RequestPermissionRequest,
310    v2::RequestPermissionResponse,
311    "session/request_permission"
312);
313impl_v2_jsonrpc_request!(
314    v2::CreateElicitationRequest,
315    v2::CreateElicitationResponse,
316    "elicitation/create"
317);
318
319impl_v2_jsonrpc_notification!(v2::UpdateSessionNotification, "session/update");
320impl_v2_jsonrpc_notification!(v2::CompleteElicitationNotification, "elicitation/complete");
321#[cfg(feature = "unstable_auth_status")]
322impl_v2_jsonrpc_notification!(v2::AuthStatusUpdateNotification, "auth/status_update");
323
324impl_jsonrpc_protocol_level_notification_enum!(v2::ProtocolLevelNotification {
325    CancelRequestNotification => "$/cancel_request",
326});
327
328impl_v2_jsonrpc_request_enum!(v2::ClientRequest {
329    InitializeRequest => "initialize",
330    LoginAuthRequest => "auth/login",
331    LogoutAuthRequest => "auth/logout",
332    #[cfg(feature = "unstable_auth_status")]
333    AuthStatusRequest => "auth/status",
334    #[cfg(feature = "unstable_llm_providers")]
335    ListProvidersRequest => "providers/list",
336    #[cfg(feature = "unstable_llm_providers")]
337    SetProviderRequest => "providers/set",
338    #[cfg(feature = "unstable_llm_providers")]
339    DisableProviderRequest => "providers/disable",
340    NewSessionRequest => "session/new",
341    ListSessionsRequest => "session/list",
342    DeleteSessionRequest => "session/delete",
343    #[cfg(feature = "unstable_session_fork")]
344    ForkSessionRequest => "session/fork",
345    #[cfg(feature = "unstable_session_archive")]
346    ArchiveSessionRequest => "session/archive",
347    #[cfg(feature = "unstable_session_archive")]
348    UnarchiveSessionRequest => "session/unarchive",
349    #[cfg(feature = "unstable_session_status")]
350    SessionStatusRequest => "session/status",
351    #[cfg(feature = "unstable_session_set_title")]
352    SetSessionTitleRequest => "session/set_title",
353    ResumeSessionRequest => "session/resume",
354    CloseSessionRequest => "session/close",
355    CancelToolCallRequest => "tool_call/cancel",
356    CancelTerminalRequest => "terminal/cancel",
357    SetSessionConfigOptionRequest => "session/set_config_option",
358    PromptRequest => "session/prompt",
359    [ext] ExtMethodRequest,
360});
361
362impl_v2_jsonrpc_response_enum!(v2::AgentResponse {
363    InitializeResponse => "initialize",
364    LoginAuthResponse => "auth/login",
365    LogoutAuthResponse => "auth/logout",
366    #[cfg(feature = "unstable_auth_status")]
367    AuthStatusResponse => "auth/status",
368    #[cfg(feature = "unstable_llm_providers")]
369    ListProvidersResponse => "providers/list",
370    #[cfg(feature = "unstable_llm_providers")]
371    SetProviderResponse => "providers/set",
372    #[cfg(feature = "unstable_llm_providers")]
373    DisableProviderResponse => "providers/disable",
374    NewSessionResponse => "session/new",
375    ListSessionsResponse => "session/list",
376    DeleteSessionResponse => "session/delete",
377    #[cfg(feature = "unstable_session_fork")]
378    ForkSessionResponse => "session/fork",
379    #[cfg(feature = "unstable_session_archive")]
380    ArchiveSessionResponse => "session/archive",
381    #[cfg(feature = "unstable_session_archive")]
382    UnarchiveSessionResponse => "session/unarchive",
383    #[cfg(feature = "unstable_session_status")]
384    SessionStatusResponse => "session/status",
385    #[cfg(feature = "unstable_session_set_title")]
386    SetSessionTitleResponse => "session/set_title",
387    ResumeSessionResponse => "session/resume",
388    CloseSessionResponse => "session/close",
389    CancelToolCallResponse => "tool_call/cancel",
390    CancelTerminalResponse => "terminal/cancel",
391    SetSessionConfigOptionResponse => "session/set_config_option",
392    PromptResponse => "session/prompt",
393    [ext] ExtMethodResponse,
394});
395
396impl_v2_jsonrpc_notification_enum!(v2::ClientNotification {
397    CancelSessionNotification => "session/cancel",
398    #[cfg(feature = "unstable_mcp_over_acp")]
399    MessageMcpNotification => "mcp/message",
400    [ext] ExtNotification,
401});
402
403impl_v2_jsonrpc_request_enum!(v2::AgentRequest {
404    RequestPermissionRequest => "session/request_permission",
405    CreateElicitationRequest => "elicitation/create",
406    #[cfg(feature = "unstable_mcp_over_acp")]
407    MessageMcpRequest => "mcp/message",
408    [ext] ExtMethodRequest,
409});
410
411impl_v2_jsonrpc_response_enum!(v2::ClientResponse {
412    RequestPermissionResponse => "session/request_permission",
413    CreateElicitationResponse => "elicitation/create",
414    #[cfg(feature = "unstable_mcp_over_acp")]
415    MessageMcpResponse => "mcp/message",
416    [ext] ExtMethodResponse,
417});
418
419impl_v2_jsonrpc_notification_enum!(v2::AgentNotification {
420    UpdateSessionNotification => "session/update",
421    CompleteElicitationNotification => "elicitation/complete",
422    #[cfg(feature = "unstable_auth_status")]
423    AuthStatusUpdateNotification => "auth/status_update",
424    [ext] ExtNotification,
425});