agent_client_protocol_schema/v1/
proxy.rs1use std::sync::Arc;
7
8use derive_more::From;
9use serde::{Deserialize, Serialize};
10use serde_json::value::RawValue;
11use serde_with::{DefaultOnError, serde_as, skip_serializing_none};
12
13use super::{InitializeRequest, InitializeResponse, Meta};
14use crate::IntoOption;
15
16#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
31#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "proxy", "x-method" = PROXY_INITIALIZE_METHOD_NAME)))]
32#[serde(transparent)]
33#[non_exhaustive]
34pub struct InitializeProxyRequest {
35 pub initialize: InitializeRequest,
37}
38
39impl InitializeProxyRequest {
40 #[must_use]
42 pub fn new(initialize: InitializeRequest) -> Self {
43 Self { initialize }
44 }
45}
46
47impl From<InitializeRequest> for InitializeProxyRequest {
48 fn from(initialize: InitializeRequest) -> Self {
49 Self::new(initialize)
50 }
51}
52
53#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
62#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
63#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "proxy", "x-method" = PROXY_INITIALIZE_METHOD_NAME)))]
64#[serde(transparent)]
65#[non_exhaustive]
66pub struct InitializeProxyResponse {
67 pub initialize: InitializeResponse,
69}
70
71impl InitializeProxyResponse {
72 #[must_use]
74 pub fn new(initialize: InitializeResponse) -> Self {
75 Self { initialize }
76 }
77}
78
79impl From<InitializeResponse> for InitializeProxyResponse {
80 fn from(initialize: InitializeResponse) -> Self {
81 Self::new(initialize)
82 }
83}
84
85#[serde_as]
102#[skip_serializing_none]
103#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
104#[derive(Debug, Clone, Serialize, Deserialize)]
105#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "proxy", "x-method" = PROXY_SUCCESSOR_METHOD_NAME)))]
106#[serde(rename_all = "camelCase")]
107#[non_exhaustive]
108pub struct ProxySuccessorRequest {
109 pub method: Arc<str>,
111 #[cfg_attr(feature = "schemars", schemars(with = "Option<serde_json::Value>"))]
116 #[serde(default)]
117 pub params: Option<Arc<RawValue>>,
118 #[serde_as(deserialize_as = "DefaultOnError")]
127 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
128 #[serde(default)]
129 #[serde(rename = "_meta")]
130 pub meta: Option<Meta>,
131}
132
133impl ProxySuccessorRequest {
134 #[must_use]
136 pub fn new(method: impl Into<Arc<str>>) -> Self {
137 Self {
138 method: method.into(),
139 params: None,
140 meta: None,
141 }
142 }
143
144 #[must_use]
146 pub fn params(mut self, params: impl IntoOption<Arc<RawValue>>) -> Self {
147 self.params = params.into_option();
148 self
149 }
150
151 #[must_use]
157 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
158 self.meta = meta.into_option();
159 self
160 }
161}
162
163#[serde_as]
175#[skip_serializing_none]
176#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
177#[derive(Debug, Clone, Serialize, Deserialize)]
178#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "proxy", "x-method" = PROXY_SUCCESSOR_METHOD_NAME)))]
179#[serde(rename_all = "camelCase")]
180#[non_exhaustive]
181pub struct ProxySuccessorNotification {
182 pub method: Arc<str>,
184 #[cfg_attr(feature = "schemars", schemars(with = "Option<serde_json::Value>"))]
189 #[serde(default)]
190 pub params: Option<Arc<RawValue>>,
191 #[serde_as(deserialize_as = "DefaultOnError")]
200 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
201 #[serde(default)]
202 #[serde(rename = "_meta")]
203 pub meta: Option<Meta>,
204}
205
206impl ProxySuccessorNotification {
207 #[must_use]
209 pub fn new(method: impl Into<Arc<str>>) -> Self {
210 Self {
211 method: method.into(),
212 params: None,
213 meta: None,
214 }
215 }
216
217 #[must_use]
219 pub fn params(mut self, params: impl IntoOption<Arc<RawValue>>) -> Self {
220 self.params = params.into_option();
221 self
222 }
223
224 #[must_use]
230 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
231 self.meta = meta.into_option();
232 self
233 }
234}
235
236#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
242#[derive(Debug, Clone, Serialize, Deserialize, From)]
243#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "proxy", "x-method" = PROXY_SUCCESSOR_METHOD_NAME)))]
244#[serde(transparent)]
245#[non_exhaustive]
246pub struct ProxySuccessorResponse(
247 #[cfg_attr(feature = "schemars", schemars(with = "serde_json::Value"))] pub Arc<RawValue>,
248);
249
250impl ProxySuccessorResponse {
251 #[must_use]
253 pub fn new(result: Arc<RawValue>) -> Self {
254 Self(result)
255 }
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
266#[non_exhaustive]
267pub struct ProxyMethodNames {
268 pub proxy_initialize: &'static str,
270 pub proxy_successor: &'static str,
272}
273
274pub const PROXY_METHOD_NAMES: ProxyMethodNames = ProxyMethodNames {
276 proxy_initialize: PROXY_INITIALIZE_METHOD_NAME,
277 proxy_successor: PROXY_SUCCESSOR_METHOD_NAME,
278};
279
280pub(crate) const PROXY_INITIALIZE_METHOD_NAME: &str = "proxy/initialize";
282pub(crate) const PROXY_SUCCESSOR_METHOD_NAME: &str = "proxy/successor";
284
285#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
294#[derive(Clone, Debug, Serialize, Deserialize)]
295#[allow(clippy::large_enum_variant)]
296#[serde(untagged)]
297#[cfg_attr(feature = "schemars", schemars(inline))]
298#[non_exhaustive]
299pub enum ProxyRequest {
300 InitializeProxyRequest(InitializeProxyRequest),
305 ProxySuccessorRequest(ProxySuccessorRequest),
311}
312
313impl ProxyRequest {
314 #[must_use]
316 pub fn method(&self) -> &str {
317 match self {
318 Self::InitializeProxyRequest(_) => PROXY_METHOD_NAMES.proxy_initialize,
319 Self::ProxySuccessorRequest(_) => PROXY_METHOD_NAMES.proxy_successor,
320 }
321 }
322}
323
324#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
330#[derive(Clone, Debug, Serialize, Deserialize)]
331#[allow(clippy::large_enum_variant)]
332#[serde(untagged)]
333#[cfg_attr(feature = "schemars", schemars(inline))]
334#[non_exhaustive]
335pub enum ProxyResponse {
336 InitializeProxyResponse(InitializeProxyResponse),
338 ProxySuccessorResponse(ProxySuccessorResponse),
340}
341
342#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
348#[derive(Clone, Debug, Serialize, Deserialize)]
349#[serde(untagged)]
350#[cfg_attr(feature = "schemars", schemars(inline))]
351#[non_exhaustive]
352pub enum ProxyNotification {
353 ProxySuccessorNotification(ProxySuccessorNotification),
358}
359
360impl ProxyNotification {
361 #[must_use]
363 pub fn method(&self) -> &str {
364 match self {
365 Self::ProxySuccessorNotification(_) => PROXY_METHOD_NAMES.proxy_successor,
366 }
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use serde_json::json;
373
374 use super::*;
375 use crate::ProtocolVersion;
376
377 fn raw(value: &serde_json::Value) -> Arc<RawValue> {
378 RawValue::from_string(value.to_string()).unwrap().into()
379 }
380
381 #[test]
382 fn test_initialize_proxy_request_matches_initialize_params() {
383 let request = InitializeProxyRequest::new(InitializeRequest::new(ProtocolVersion::V1));
384 let value = serde_json::to_value(&request).unwrap();
385 assert_eq!(value, serde_json::to_value(&request.initialize).unwrap());
386 assert_eq!(
387 ProxyRequest::InitializeProxyRequest(request).method(),
388 "proxy/initialize"
389 );
390 let response = InitializeProxyResponse::new(InitializeResponse::new(ProtocolVersion::V1));
391 assert_eq!(
392 serde_json::to_value(&response).unwrap(),
393 serde_json::to_value(&response.initialize).unwrap()
394 );
395 let parsed: InitializeProxyRequest = serde_json::from_value(value).unwrap();
396 assert_eq!(parsed.initialize.protocol_version, ProtocolVersion::V1);
397 }
398
399 #[test]
400 fn test_proxy_successor_round_trip() {
401 let request = ProxySuccessorRequest::new("session/prompt")
402 .params(raw(
403 &json!({"sessionId": "sess_abc123", "_meta": {"inner": true}}),
404 ))
405 .meta(json!({"outer": true}).as_object().cloned());
406 let value = serde_json::to_value(&request).unwrap();
407 assert_eq!(
408 value,
409 json!({
410 "method": "session/prompt",
411 "params": {"sessionId": "sess_abc123", "_meta": {"inner": true}},
412 "_meta": {"outer": true}
413 })
414 );
415 assert_eq!(
416 ProxyRequest::ProxySuccessorRequest(request).method(),
417 "proxy/successor"
418 );
419
420 for params in [
421 json!({"method": "session/cancel"}),
422 json!({"method": "session/cancel", "params": null}),
423 ] {
424 let notification: ProxySuccessorNotification = serde_json::from_value(params).unwrap();
425 assert_eq!(&*notification.method, "session/cancel");
426 assert!(notification.params.is_none());
427 }
428 assert!(
429 serde_json::from_value::<ProxySuccessorNotification>(json!({"params": {}})).is_err()
430 );
431
432 let response = ProxySuccessorResponse::new(raw(&json!({"stopReason": "end_turn"})));
433 assert_eq!(
434 serde_json::to_value(&response).unwrap(),
435 json!({"stopReason": "end_turn"})
436 );
437 }
438}