1use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
7
8#[cfg(any(feature = "unstable_auth_methods", feature = "unstable_llm_providers"))]
9use std::collections::HashMap;
10
11use derive_more::{Display, From};
12use schemars::{JsonSchema, Schema};
13use serde::{Deserialize, Serialize};
14use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
15
16use super::{
17 ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, Meta, SessionId,
18};
19use crate::{IntoOption, ProtocolVersion, SkipListener};
20
21#[cfg(feature = "unstable_mcp_over_acp")]
22use super::mcp::{
23 MCP_MESSAGE_METHOD_NAME, MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
24};
25
26#[cfg(feature = "unstable_nes")]
27use super::{
28 AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
29 DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
30 DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
31 StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
32};
33
34#[cfg(feature = "unstable_nes")]
35use super::{
36 DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
37 DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
38 NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
39 NES_SUGGEST_METHOD_NAME,
40};
41
42#[serde_as]
50#[skip_serializing_none]
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
52#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
53#[serde(rename_all = "camelCase")]
54#[non_exhaustive]
55pub struct InitializeRequest {
56 pub protocol_version: ProtocolVersion,
58 #[serde(default)]
60 pub capabilities: ClientCapabilities,
61 #[serde_as(deserialize_as = "DefaultOnError")]
65 #[schemars(extend("x-deserialize-default-on-error" = true))]
66 #[serde(default)]
67 pub client_info: Option<Implementation>,
68 #[serde(rename = "_meta")]
74 pub meta: Option<Meta>,
75}
76
77impl InitializeRequest {
78 #[must_use]
79 pub fn new(protocol_version: ProtocolVersion) -> Self {
80 Self {
81 protocol_version,
82 capabilities: ClientCapabilities::default(),
83 client_info: None,
84 meta: None,
85 }
86 }
87
88 #[must_use]
90 pub fn capabilities(mut self, capabilities: ClientCapabilities) -> Self {
91 self.capabilities = capabilities;
92 self
93 }
94
95 #[must_use]
97 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
98 self.client_info = client_info.into_option();
99 self
100 }
101
102 #[must_use]
108 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
109 self.meta = meta.into_option();
110 self
111 }
112}
113
114#[serde_as]
120#[skip_serializing_none]
121#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
122#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
123#[serde(rename_all = "camelCase")]
124#[non_exhaustive]
125pub struct InitializeResponse {
126 pub protocol_version: ProtocolVersion,
131 #[serde(default)]
133 pub capabilities: AgentCapabilities,
134 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
136 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
137 #[serde(default)]
138 pub auth_methods: Vec<AuthMethod>,
139 #[serde_as(deserialize_as = "DefaultOnError")]
143 #[schemars(extend("x-deserialize-default-on-error" = true))]
144 #[serde(default)]
145 pub agent_info: Option<Implementation>,
146 #[serde(rename = "_meta")]
152 pub meta: Option<Meta>,
153}
154
155impl InitializeResponse {
156 #[must_use]
157 pub fn new(protocol_version: ProtocolVersion) -> Self {
158 Self {
159 protocol_version,
160 capabilities: AgentCapabilities::default(),
161 auth_methods: vec![],
162 agent_info: None,
163 meta: None,
164 }
165 }
166
167 #[must_use]
169 pub fn capabilities(mut self, capabilities: AgentCapabilities) -> Self {
170 self.capabilities = capabilities;
171 self
172 }
173
174 #[must_use]
176 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
177 self.auth_methods = auth_methods;
178 self
179 }
180
181 #[must_use]
183 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
184 self.agent_info = agent_info.into_option();
185 self
186 }
187
188 #[must_use]
194 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
195 self.meta = meta.into_option();
196 self
197 }
198}
199
200#[skip_serializing_none]
204#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
205#[serde(rename_all = "camelCase")]
206#[non_exhaustive]
207pub struct Implementation {
208 pub name: String,
211 pub title: Option<String>,
216 pub version: String,
219 #[serde(rename = "_meta")]
225 pub meta: Option<Meta>,
226}
227
228impl Implementation {
229 #[must_use]
230 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
231 Self {
232 name: name.into(),
233 title: None,
234 version: version.into(),
235 meta: None,
236 }
237 }
238
239 #[must_use]
244 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
245 self.title = title.into_option();
246 self
247 }
248
249 #[must_use]
255 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
256 self.meta = meta.into_option();
257 self
258 }
259}
260
261#[skip_serializing_none]
267#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
268#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
269#[serde(rename_all = "camelCase")]
270#[non_exhaustive]
271pub struct AuthenticateRequest {
272 pub method_id: AuthMethodId,
275 #[serde(rename = "_meta")]
281 pub meta: Option<Meta>,
282}
283
284impl AuthenticateRequest {
285 #[must_use]
286 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
287 Self {
288 method_id: method_id.into(),
289 meta: None,
290 }
291 }
292
293 #[must_use]
299 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
300 self.meta = meta.into_option();
301 self
302 }
303}
304
305#[skip_serializing_none]
307#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
308#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
309#[serde(rename_all = "camelCase")]
310#[non_exhaustive]
311pub struct AuthenticateResponse {
312 #[serde(rename = "_meta")]
318 pub meta: Option<Meta>,
319}
320
321impl AuthenticateResponse {
322 #[must_use]
323 pub fn new() -> Self {
324 Self::default()
325 }
326
327 #[must_use]
333 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
334 self.meta = meta.into_option();
335 self
336 }
337}
338
339#[skip_serializing_none]
345#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
346#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
347#[serde(rename_all = "camelCase")]
348#[non_exhaustive]
349pub struct LogoutRequest {
350 #[serde(rename = "_meta")]
356 pub meta: Option<Meta>,
357}
358
359impl LogoutRequest {
360 #[must_use]
361 pub fn new() -> Self {
362 Self::default()
363 }
364
365 #[must_use]
371 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
372 self.meta = meta.into_option();
373 self
374 }
375}
376
377#[skip_serializing_none]
379#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
380#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
381#[serde(rename_all = "camelCase")]
382#[non_exhaustive]
383pub struct LogoutResponse {
384 #[serde(rename = "_meta")]
390 pub meta: Option<Meta>,
391}
392
393impl LogoutResponse {
394 #[must_use]
395 pub fn new() -> Self {
396 Self::default()
397 }
398
399 #[must_use]
405 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
406 self.meta = meta.into_option();
407 self
408 }
409}
410
411#[serde_as]
413#[skip_serializing_none]
414#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
415#[serde(rename_all = "camelCase")]
416#[non_exhaustive]
417pub struct AgentAuthCapabilities {
418 #[serde_as(deserialize_as = "DefaultOnError")]
422 #[schemars(extend("x-deserialize-default-on-error" = true))]
423 #[serde(default)]
424 pub logout: Option<LogoutCapabilities>,
425 #[serde(rename = "_meta")]
431 pub meta: Option<Meta>,
432}
433
434impl AgentAuthCapabilities {
435 #[must_use]
436 pub fn new() -> Self {
437 Self::default()
438 }
439
440 #[must_use]
442 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
443 self.logout = logout.into_option();
444 self
445 }
446
447 #[must_use]
453 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
454 self.meta = meta.into_option();
455 self
456 }
457}
458
459#[skip_serializing_none]
463#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
464#[non_exhaustive]
465pub struct LogoutCapabilities {
466 #[serde(rename = "_meta")]
472 pub meta: Option<Meta>,
473}
474
475impl LogoutCapabilities {
476 #[must_use]
477 pub fn new() -> Self {
478 Self::default()
479 }
480
481 #[must_use]
487 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
488 self.meta = meta.into_option();
489 self
490 }
491}
492
493#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
494#[serde(transparent)]
495#[from(Arc<str>, String, &'static str)]
496#[non_exhaustive]
497pub struct AuthMethodId(pub Arc<str>);
498
499impl AuthMethodId {
500 #[must_use]
501 pub fn new(id: impl Into<Arc<str>>) -> Self {
502 Self(id.into())
503 }
504}
505
506#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
510#[serde(tag = "type", rename_all = "snake_case")]
511#[non_exhaustive]
512pub enum AuthMethod {
513 #[cfg(feature = "unstable_auth_methods")]
519 EnvVar(AuthMethodEnvVar),
520 #[cfg(feature = "unstable_auth_methods")]
526 Terminal(AuthMethodTerminal),
527 Agent(AuthMethodAgent),
531 #[serde(untagged)]
541 Other(OtherAuthMethod),
542}
543
544impl AuthMethod {
545 #[must_use]
547 pub fn id(&self) -> &AuthMethodId {
548 match self {
549 Self::Agent(a) => &a.id,
550 Self::Other(a) => &a.id,
551 #[cfg(feature = "unstable_auth_methods")]
552 Self::EnvVar(e) => &e.id,
553 #[cfg(feature = "unstable_auth_methods")]
554 Self::Terminal(t) => &t.id,
555 }
556 }
557
558 #[must_use]
560 pub fn name(&self) -> &str {
561 match self {
562 Self::Agent(a) => &a.name,
563 Self::Other(a) => &a.name,
564 #[cfg(feature = "unstable_auth_methods")]
565 Self::EnvVar(e) => &e.name,
566 #[cfg(feature = "unstable_auth_methods")]
567 Self::Terminal(t) => &t.name,
568 }
569 }
570
571 #[must_use]
573 pub fn description(&self) -> Option<&str> {
574 match self {
575 Self::Agent(a) => a.description.as_deref(),
576 Self::Other(a) => a.description.as_deref(),
577 #[cfg(feature = "unstable_auth_methods")]
578 Self::EnvVar(e) => e.description.as_deref(),
579 #[cfg(feature = "unstable_auth_methods")]
580 Self::Terminal(t) => t.description.as_deref(),
581 }
582 }
583
584 #[must_use]
590 pub fn meta(&self) -> Option<&Meta> {
591 match self {
592 Self::Agent(a) => a.meta.as_ref(),
593 Self::Other(a) => a.meta.as_ref(),
594 #[cfg(feature = "unstable_auth_methods")]
595 Self::EnvVar(e) => e.meta.as_ref(),
596 #[cfg(feature = "unstable_auth_methods")]
597 Self::Terminal(t) => t.meta.as_ref(),
598 }
599 }
600}
601
602#[skip_serializing_none]
604#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
605#[schemars(inline)]
606#[schemars(transform = other_auth_method_schema)]
607#[serde(rename_all = "camelCase")]
608#[non_exhaustive]
609pub struct OtherAuthMethod {
610 #[serde(rename = "type")]
616 pub type_: String,
617 pub id: AuthMethodId,
619 pub name: String,
621 pub description: Option<String>,
623 #[serde(rename = "_meta")]
629 pub meta: Option<Meta>,
630 #[serde(flatten)]
632 pub fields: BTreeMap<String, serde_json::Value>,
633}
634
635impl OtherAuthMethod {
636 #[must_use]
637 pub fn new(
638 type_: impl Into<String>,
639 id: impl Into<AuthMethodId>,
640 name: impl Into<String>,
641 mut fields: BTreeMap<String, serde_json::Value>,
642 ) -> Self {
643 fields.remove("type");
644 fields.remove("id");
645 fields.remove("name");
646 fields.remove("description");
647 fields.remove("_meta");
648 Self {
649 type_: type_.into(),
650 id: id.into(),
651 name: name.into(),
652 description: None,
653 meta: None,
654 fields,
655 }
656 }
657
658 #[must_use]
660 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
661 self.description = description.into_option();
662 self
663 }
664
665 #[must_use]
671 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
672 self.meta = meta.into_option();
673 self
674 }
675}
676
677impl<'de> Deserialize<'de> for OtherAuthMethod {
678 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
679 where
680 D: serde::Deserializer<'de>,
681 {
682 #[derive(Deserialize)]
683 #[serde(rename_all = "camelCase")]
684 struct RawOtherAuthMethod {
685 #[serde(rename = "type")]
686 type_: String,
687 id: AuthMethodId,
688 name: String,
689 description: Option<String>,
690 #[serde(rename = "_meta")]
691 meta: Option<Meta>,
692 #[serde(flatten)]
693 fields: BTreeMap<String, serde_json::Value>,
694 }
695
696 let raw = RawOtherAuthMethod::deserialize(deserializer)?;
697 if is_known_auth_method_type(&raw.type_) {
698 return Err(serde::de::Error::custom(format!(
699 "known authentication method `{}` did not match its schema",
700 raw.type_
701 )));
702 }
703
704 Ok(Self {
705 type_: raw.type_,
706 id: raw.id,
707 name: raw.name,
708 description: raw.description,
709 meta: raw.meta,
710 fields: raw.fields,
711 })
712 }
713}
714
715fn is_known_auth_method_type(type_: &str) -> bool {
716 match type_ {
717 "agent" => true,
718 #[cfg(feature = "unstable_auth_methods")]
719 "env_var" | "terminal" => true,
720 _ => false,
721 }
722}
723
724fn other_auth_method_schema(schema: &mut Schema) {
725 super::schema_util::reject_known_string_discriminators(
726 schema,
727 "type",
728 &[
729 "agent",
730 #[cfg(feature = "unstable_auth_methods")]
731 "env_var",
732 #[cfg(feature = "unstable_auth_methods")]
733 "terminal",
734 ],
735 );
736}
737
738#[skip_serializing_none]
742#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
743#[serde(rename_all = "camelCase")]
744#[non_exhaustive]
745pub struct AuthMethodAgent {
746 pub id: AuthMethodId,
748 pub name: String,
750 pub description: Option<String>,
752 #[serde(rename = "_meta")]
758 pub meta: Option<Meta>,
759}
760
761impl AuthMethodAgent {
762 #[must_use]
763 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
764 Self {
765 id: id.into(),
766 name: name.into(),
767 description: None,
768 meta: None,
769 }
770 }
771
772 #[must_use]
774 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
775 self.description = description.into_option();
776 self
777 }
778
779 #[must_use]
785 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
786 self.meta = meta.into_option();
787 self
788 }
789}
790
791#[cfg(feature = "unstable_auth_methods")]
799#[skip_serializing_none]
800#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
801#[serde(rename_all = "camelCase")]
802#[non_exhaustive]
803pub struct AuthMethodEnvVar {
804 pub id: AuthMethodId,
806 pub name: String,
808 pub description: Option<String>,
810 pub vars: Vec<AuthEnvVar>,
812 pub link: Option<String>,
814 #[serde(rename = "_meta")]
820 pub meta: Option<Meta>,
821}
822
823#[cfg(feature = "unstable_auth_methods")]
824impl AuthMethodEnvVar {
825 #[must_use]
826 pub fn new(
827 id: impl Into<AuthMethodId>,
828 name: impl Into<String>,
829 vars: Vec<AuthEnvVar>,
830 ) -> Self {
831 Self {
832 id: id.into(),
833 name: name.into(),
834 description: None,
835 vars,
836 link: None,
837 meta: None,
838 }
839 }
840
841 #[must_use]
843 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
844 self.link = link.into_option();
845 self
846 }
847
848 #[must_use]
850 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
851 self.description = description.into_option();
852 self
853 }
854
855 #[must_use]
861 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
862 self.meta = meta.into_option();
863 self
864 }
865}
866
867#[cfg(feature = "unstable_auth_methods")]
873#[skip_serializing_none]
874#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
875#[serde(rename_all = "camelCase")]
876#[non_exhaustive]
877pub struct AuthEnvVar {
878 pub name: String,
880 pub label: Option<String>,
882 #[serde(default = "default_true", skip_serializing_if = "is_true")]
887 #[schemars(extend("default" = true))]
888 pub secret: bool,
889 #[serde(default, skip_serializing_if = "is_false")]
893 #[schemars(extend("default" = false))]
894 pub optional: bool,
895 #[serde(rename = "_meta")]
901 pub meta: Option<Meta>,
902}
903
904#[cfg(feature = "unstable_auth_methods")]
905fn default_true() -> bool {
906 true
907}
908
909#[cfg(feature = "unstable_auth_methods")]
910#[expect(clippy::trivially_copy_pass_by_ref)]
911fn is_true(v: &bool) -> bool {
912 *v
913}
914
915#[cfg(feature = "unstable_auth_methods")]
916#[expect(clippy::trivially_copy_pass_by_ref)]
917fn is_false(v: &bool) -> bool {
918 !*v
919}
920
921#[cfg(feature = "unstable_auth_methods")]
922impl AuthEnvVar {
923 #[must_use]
925 pub fn new(name: impl Into<String>) -> Self {
926 Self {
927 name: name.into(),
928 label: None,
929 secret: true,
930 optional: false,
931 meta: None,
932 }
933 }
934
935 #[must_use]
937 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
938 self.label = label.into_option();
939 self
940 }
941
942 #[must_use]
945 pub fn secret(mut self, secret: bool) -> Self {
946 self.secret = secret;
947 self
948 }
949
950 #[must_use]
952 pub fn optional(mut self, optional: bool) -> Self {
953 self.optional = optional;
954 self
955 }
956
957 #[must_use]
963 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
964 self.meta = meta.into_option();
965 self
966 }
967}
968
969#[cfg(feature = "unstable_auth_methods")]
977#[skip_serializing_none]
978#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
979#[serde(rename_all = "camelCase")]
980#[non_exhaustive]
981pub struct AuthMethodTerminal {
982 pub id: AuthMethodId,
984 pub name: String,
986 pub description: Option<String>,
988 #[serde(default, skip_serializing_if = "Vec::is_empty")]
990 pub args: Vec<String>,
991 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
993 pub env: HashMap<String, String>,
994 #[serde(rename = "_meta")]
1000 pub meta: Option<Meta>,
1001}
1002
1003#[cfg(feature = "unstable_auth_methods")]
1004impl AuthMethodTerminal {
1005 #[must_use]
1006 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
1007 Self {
1008 id: id.into(),
1009 name: name.into(),
1010 description: None,
1011 args: Vec::new(),
1012 env: HashMap::new(),
1013 meta: None,
1014 }
1015 }
1016
1017 #[must_use]
1019 pub fn args(mut self, args: Vec<String>) -> Self {
1020 self.args = args;
1021 self
1022 }
1023
1024 #[must_use]
1026 pub fn env(mut self, env: HashMap<String, String>) -> Self {
1027 self.env = env;
1028 self
1029 }
1030
1031 #[must_use]
1033 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1034 self.description = description.into_option();
1035 self
1036 }
1037
1038 #[must_use]
1044 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1045 self.meta = meta.into_option();
1046 self
1047 }
1048}
1049
1050#[skip_serializing_none]
1056#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1057#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1058#[serde(rename_all = "camelCase")]
1059#[non_exhaustive]
1060pub struct NewSessionRequest {
1061 pub cwd: PathBuf,
1063 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1069 pub additional_directories: Vec<PathBuf>,
1070 pub mcp_servers: Vec<McpServer>,
1072 #[serde(rename = "_meta")]
1078 pub meta: Option<Meta>,
1079}
1080
1081impl NewSessionRequest {
1082 #[must_use]
1083 pub fn new(cwd: impl Into<PathBuf>) -> Self {
1084 Self {
1085 cwd: cwd.into(),
1086 additional_directories: vec![],
1087 mcp_servers: vec![],
1088 meta: None,
1089 }
1090 }
1091
1092 #[must_use]
1094 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1095 self.additional_directories = additional_directories;
1096 self
1097 }
1098
1099 #[must_use]
1101 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1102 self.mcp_servers = mcp_servers;
1103 self
1104 }
1105
1106 #[must_use]
1112 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1113 self.meta = meta.into_option();
1114 self
1115 }
1116}
1117
1118#[serde_as]
1122#[skip_serializing_none]
1123#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1124#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1125#[serde(rename_all = "camelCase")]
1126#[non_exhaustive]
1127pub struct NewSessionResponse {
1128 pub session_id: SessionId,
1132 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1134 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1135 #[serde(default)]
1136 pub config_options: Option<Vec<SessionConfigOption>>,
1137 #[serde(rename = "_meta")]
1143 pub meta: Option<Meta>,
1144}
1145
1146impl NewSessionResponse {
1147 #[must_use]
1148 pub fn new(session_id: impl Into<SessionId>) -> Self {
1149 Self {
1150 session_id: session_id.into(),
1151 config_options: None,
1152 meta: None,
1153 }
1154 }
1155
1156 #[must_use]
1158 pub fn config_options(
1159 mut self,
1160 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1161 ) -> Self {
1162 self.config_options = config_options.into_option();
1163 self
1164 }
1165
1166 #[must_use]
1172 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1173 self.meta = meta.into_option();
1174 self
1175 }
1176}
1177
1178#[skip_serializing_none]
1186#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1187#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1188#[serde(rename_all = "camelCase")]
1189#[non_exhaustive]
1190pub struct LoadSessionRequest {
1191 pub mcp_servers: Vec<McpServer>,
1193 pub cwd: PathBuf,
1195 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1202 pub additional_directories: Vec<PathBuf>,
1203 pub session_id: SessionId,
1205 #[serde(rename = "_meta")]
1211 pub meta: Option<Meta>,
1212}
1213
1214impl LoadSessionRequest {
1215 #[must_use]
1216 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1217 Self {
1218 mcp_servers: vec![],
1219 cwd: cwd.into(),
1220 additional_directories: vec![],
1221 session_id: session_id.into(),
1222 meta: None,
1223 }
1224 }
1225
1226 #[must_use]
1228 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1229 self.additional_directories = additional_directories;
1230 self
1231 }
1232
1233 #[must_use]
1235 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1236 self.mcp_servers = mcp_servers;
1237 self
1238 }
1239
1240 #[must_use]
1246 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1247 self.meta = meta.into_option();
1248 self
1249 }
1250}
1251
1252#[serde_as]
1254#[skip_serializing_none]
1255#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1256#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1257#[serde(rename_all = "camelCase")]
1258#[non_exhaustive]
1259pub struct LoadSessionResponse {
1260 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1262 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1263 #[serde(default)]
1264 pub config_options: Option<Vec<SessionConfigOption>>,
1265 #[serde(rename = "_meta")]
1271 pub meta: Option<Meta>,
1272}
1273
1274impl LoadSessionResponse {
1275 #[must_use]
1276 pub fn new() -> Self {
1277 Self::default()
1278 }
1279
1280 #[must_use]
1282 pub fn config_options(
1283 mut self,
1284 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1285 ) -> Self {
1286 self.config_options = config_options.into_option();
1287 self
1288 }
1289
1290 #[must_use]
1296 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1297 self.meta = meta.into_option();
1298 self
1299 }
1300}
1301
1302#[cfg(feature = "unstable_session_fork")]
1315#[skip_serializing_none]
1316#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1317#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1318#[serde(rename_all = "camelCase")]
1319#[non_exhaustive]
1320pub struct ForkSessionRequest {
1321 pub session_id: SessionId,
1323 pub cwd: PathBuf,
1325 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1331 pub additional_directories: Vec<PathBuf>,
1332 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1334 pub mcp_servers: Vec<McpServer>,
1335 #[serde(rename = "_meta")]
1341 pub meta: Option<Meta>,
1342}
1343
1344#[cfg(feature = "unstable_session_fork")]
1345impl ForkSessionRequest {
1346 #[must_use]
1347 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1348 Self {
1349 session_id: session_id.into(),
1350 cwd: cwd.into(),
1351 additional_directories: vec![],
1352 mcp_servers: vec![],
1353 meta: None,
1354 }
1355 }
1356
1357 #[must_use]
1359 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1360 self.additional_directories = additional_directories;
1361 self
1362 }
1363
1364 #[must_use]
1366 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1367 self.mcp_servers = mcp_servers;
1368 self
1369 }
1370
1371 #[must_use]
1377 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1378 self.meta = meta.into_option();
1379 self
1380 }
1381}
1382
1383#[cfg(feature = "unstable_session_fork")]
1389#[serde_as]
1390#[skip_serializing_none]
1391#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1392#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1393#[serde(rename_all = "camelCase")]
1394#[non_exhaustive]
1395pub struct ForkSessionResponse {
1396 pub session_id: SessionId,
1398 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1400 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1401 #[serde(default)]
1402 pub config_options: Option<Vec<SessionConfigOption>>,
1403 #[serde(rename = "_meta")]
1409 pub meta: Option<Meta>,
1410}
1411
1412#[cfg(feature = "unstable_session_fork")]
1413impl ForkSessionResponse {
1414 #[must_use]
1415 pub fn new(session_id: impl Into<SessionId>) -> Self {
1416 Self {
1417 session_id: session_id.into(),
1418 config_options: None,
1419 meta: None,
1420 }
1421 }
1422
1423 #[must_use]
1425 pub fn config_options(
1426 mut self,
1427 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1428 ) -> Self {
1429 self.config_options = config_options.into_option();
1430 self
1431 }
1432
1433 #[must_use]
1439 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1440 self.meta = meta.into_option();
1441 self
1442 }
1443}
1444
1445#[skip_serializing_none]
1454#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1455#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1456#[serde(rename_all = "camelCase")]
1457#[non_exhaustive]
1458pub struct ResumeSessionRequest {
1459 pub session_id: SessionId,
1461 pub cwd: PathBuf,
1463 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1470 pub additional_directories: Vec<PathBuf>,
1471 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1473 pub mcp_servers: Vec<McpServer>,
1474 #[serde(rename = "_meta")]
1480 pub meta: Option<Meta>,
1481}
1482
1483impl ResumeSessionRequest {
1484 #[must_use]
1485 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1486 Self {
1487 session_id: session_id.into(),
1488 cwd: cwd.into(),
1489 additional_directories: vec![],
1490 mcp_servers: vec![],
1491 meta: None,
1492 }
1493 }
1494
1495 #[must_use]
1497 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1498 self.additional_directories = additional_directories;
1499 self
1500 }
1501
1502 #[must_use]
1504 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1505 self.mcp_servers = mcp_servers;
1506 self
1507 }
1508
1509 #[must_use]
1515 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1516 self.meta = meta.into_option();
1517 self
1518 }
1519}
1520
1521#[serde_as]
1523#[skip_serializing_none]
1524#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1525#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1526#[serde(rename_all = "camelCase")]
1527#[non_exhaustive]
1528pub struct ResumeSessionResponse {
1529 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1531 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1532 #[serde(default)]
1533 pub config_options: Option<Vec<SessionConfigOption>>,
1534 #[serde(rename = "_meta")]
1540 pub meta: Option<Meta>,
1541}
1542
1543impl ResumeSessionResponse {
1544 #[must_use]
1545 pub fn new() -> Self {
1546 Self::default()
1547 }
1548
1549 #[must_use]
1551 pub fn config_options(
1552 mut self,
1553 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1554 ) -> Self {
1555 self.config_options = config_options.into_option();
1556 self
1557 }
1558
1559 #[must_use]
1565 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1566 self.meta = meta.into_option();
1567 self
1568 }
1569}
1570
1571#[skip_serializing_none]
1581#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1582#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1583#[serde(rename_all = "camelCase")]
1584#[non_exhaustive]
1585pub struct CloseSessionRequest {
1586 pub session_id: SessionId,
1588 #[serde(rename = "_meta")]
1594 pub meta: Option<Meta>,
1595}
1596
1597impl CloseSessionRequest {
1598 #[must_use]
1599 pub fn new(session_id: impl Into<SessionId>) -> Self {
1600 Self {
1601 session_id: session_id.into(),
1602 meta: None,
1603 }
1604 }
1605
1606 #[must_use]
1612 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1613 self.meta = meta.into_option();
1614 self
1615 }
1616}
1617
1618#[skip_serializing_none]
1620#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1621#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1622#[serde(rename_all = "camelCase")]
1623#[non_exhaustive]
1624pub struct CloseSessionResponse {
1625 #[serde(rename = "_meta")]
1631 pub meta: Option<Meta>,
1632}
1633
1634impl CloseSessionResponse {
1635 #[must_use]
1636 pub fn new() -> Self {
1637 Self::default()
1638 }
1639
1640 #[must_use]
1646 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1647 self.meta = meta.into_option();
1648 self
1649 }
1650}
1651
1652#[skip_serializing_none]
1658#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1659#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1660#[serde(rename_all = "camelCase")]
1661#[non_exhaustive]
1662pub struct ListSessionsRequest {
1663 pub cwd: Option<PathBuf>,
1665 pub cursor: Option<String>,
1667 #[serde(rename = "_meta")]
1673 pub meta: Option<Meta>,
1674}
1675
1676impl ListSessionsRequest {
1677 #[must_use]
1678 pub fn new() -> Self {
1679 Self::default()
1680 }
1681
1682 #[must_use]
1684 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1685 self.cwd = cwd.into_option();
1686 self
1687 }
1688
1689 #[must_use]
1691 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1692 self.cursor = cursor.into_option();
1693 self
1694 }
1695
1696 #[must_use]
1702 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1703 self.meta = meta.into_option();
1704 self
1705 }
1706}
1707
1708#[serde_as]
1710#[skip_serializing_none]
1711#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1712#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1713#[serde(rename_all = "camelCase")]
1714#[non_exhaustive]
1715pub struct ListSessionsResponse {
1716 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1718 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1719 pub sessions: Vec<SessionInfo>,
1720 pub next_cursor: Option<String>,
1723 #[serde(rename = "_meta")]
1729 pub meta: Option<Meta>,
1730}
1731
1732impl ListSessionsResponse {
1733 #[must_use]
1734 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1735 Self {
1736 sessions,
1737 next_cursor: None,
1738 meta: None,
1739 }
1740 }
1741
1742 #[must_use]
1743 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1744 self.next_cursor = next_cursor.into_option();
1745 self
1746 }
1747
1748 #[must_use]
1754 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1755 self.meta = meta.into_option();
1756 self
1757 }
1758}
1759
1760#[skip_serializing_none]
1766#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1767#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1768#[serde(rename_all = "camelCase")]
1769#[non_exhaustive]
1770pub struct DeleteSessionRequest {
1771 pub session_id: SessionId,
1773 #[serde(rename = "_meta")]
1779 pub meta: Option<Meta>,
1780}
1781
1782impl DeleteSessionRequest {
1783 #[must_use]
1784 pub fn new(session_id: impl Into<SessionId>) -> Self {
1785 Self {
1786 session_id: session_id.into(),
1787 meta: None,
1788 }
1789 }
1790
1791 #[must_use]
1797 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1798 self.meta = meta.into_option();
1799 self
1800 }
1801}
1802
1803#[skip_serializing_none]
1805#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1806#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1807#[serde(rename_all = "camelCase")]
1808#[non_exhaustive]
1809pub struct DeleteSessionResponse {
1810 #[serde(rename = "_meta")]
1816 pub meta: Option<Meta>,
1817}
1818
1819impl DeleteSessionResponse {
1820 #[must_use]
1821 pub fn new() -> Self {
1822 Self::default()
1823 }
1824
1825 #[must_use]
1831 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1832 self.meta = meta.into_option();
1833 self
1834 }
1835}
1836
1837#[serde_as]
1839#[skip_serializing_none]
1840#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1841#[serde(rename_all = "camelCase")]
1842#[non_exhaustive]
1843pub struct SessionInfo {
1844 pub session_id: SessionId,
1846 pub cwd: PathBuf,
1848 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1854 pub additional_directories: Vec<PathBuf>,
1855
1856 #[serde_as(deserialize_as = "DefaultOnError")]
1858 #[schemars(extend("x-deserialize-default-on-error" = true))]
1859 #[serde(default)]
1860 pub title: Option<String>,
1861 #[serde_as(deserialize_as = "DefaultOnError")]
1863 #[schemars(extend("x-deserialize-default-on-error" = true))]
1864 #[serde(default)]
1865 pub updated_at: Option<String>,
1866 #[serde(rename = "_meta")]
1872 pub meta: Option<Meta>,
1873}
1874
1875impl SessionInfo {
1876 #[must_use]
1877 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1878 Self {
1879 session_id: session_id.into(),
1880 cwd: cwd.into(),
1881 additional_directories: vec![],
1882 title: None,
1883 updated_at: None,
1884 meta: None,
1885 }
1886 }
1887
1888 #[must_use]
1890 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1891 self.additional_directories = additional_directories;
1892 self
1893 }
1894
1895 #[must_use]
1897 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1898 self.title = title.into_option();
1899 self
1900 }
1901
1902 #[must_use]
1904 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1905 self.updated_at = updated_at.into_option();
1906 self
1907 }
1908
1909 #[must_use]
1915 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1916 self.meta = meta.into_option();
1917 self
1918 }
1919}
1920
1921#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1925#[serde(transparent)]
1926#[from(Arc<str>, String, &'static str)]
1927#[non_exhaustive]
1928pub struct SessionConfigId(pub Arc<str>);
1929
1930impl SessionConfigId {
1931 #[must_use]
1932 pub fn new(id: impl Into<Arc<str>>) -> Self {
1933 Self(id.into())
1934 }
1935}
1936
1937#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1939#[serde(transparent)]
1940#[from(Arc<str>, String, &'static str)]
1941#[non_exhaustive]
1942pub struct SessionConfigValueId(pub Arc<str>);
1943
1944impl SessionConfigValueId {
1945 #[must_use]
1946 pub fn new(id: impl Into<Arc<str>>) -> Self {
1947 Self(id.into())
1948 }
1949}
1950
1951#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1953#[serde(transparent)]
1954#[from(Arc<str>, String, &'static str)]
1955#[non_exhaustive]
1956pub struct SessionConfigGroupId(pub Arc<str>);
1957
1958impl SessionConfigGroupId {
1959 #[must_use]
1960 pub fn new(id: impl Into<Arc<str>>) -> Self {
1961 Self(id.into())
1962 }
1963}
1964
1965#[skip_serializing_none]
1967#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1968#[serde(rename_all = "camelCase")]
1969#[non_exhaustive]
1970pub struct SessionConfigSelectOption {
1971 pub value: SessionConfigValueId,
1973 pub name: String,
1975 #[serde(default)]
1977 pub description: Option<String>,
1978 #[serde(rename = "_meta")]
1984 pub meta: Option<Meta>,
1985}
1986
1987impl SessionConfigSelectOption {
1988 #[must_use]
1989 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
1990 Self {
1991 value: value.into(),
1992 name: name.into(),
1993 description: None,
1994 meta: None,
1995 }
1996 }
1997
1998 #[must_use]
1999 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2000 self.description = description.into_option();
2001 self
2002 }
2003
2004 #[must_use]
2010 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2011 self.meta = meta.into_option();
2012 self
2013 }
2014}
2015
2016#[skip_serializing_none]
2018#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2019#[serde(rename_all = "camelCase")]
2020#[non_exhaustive]
2021pub struct SessionConfigSelectGroup {
2022 pub group: SessionConfigGroupId,
2024 pub name: String,
2026 pub options: Vec<SessionConfigSelectOption>,
2028 #[serde(rename = "_meta")]
2034 pub meta: Option<Meta>,
2035}
2036
2037impl SessionConfigSelectGroup {
2038 #[must_use]
2039 pub fn new(
2040 group: impl Into<SessionConfigGroupId>,
2041 name: impl Into<String>,
2042 options: Vec<SessionConfigSelectOption>,
2043 ) -> Self {
2044 Self {
2045 group: group.into(),
2046 name: name.into(),
2047 options,
2048 meta: None,
2049 }
2050 }
2051
2052 #[must_use]
2058 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2059 self.meta = meta.into_option();
2060 self
2061 }
2062}
2063
2064#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2066#[serde(untagged)]
2067#[non_exhaustive]
2068pub enum SessionConfigSelectOptions {
2069 Ungrouped(Vec<SessionConfigSelectOption>),
2071 Grouped(Vec<SessionConfigSelectGroup>),
2073}
2074
2075impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2076 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2077 SessionConfigSelectOptions::Ungrouped(options)
2078 }
2079}
2080
2081impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2082 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2083 SessionConfigSelectOptions::Grouped(groups)
2084 }
2085}
2086
2087#[skip_serializing_none]
2089#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2090#[serde(rename_all = "camelCase")]
2091#[non_exhaustive]
2092pub struct SessionConfigSelect {
2093 pub current_value: SessionConfigValueId,
2095 pub options: SessionConfigSelectOptions,
2097}
2098
2099impl SessionConfigSelect {
2100 #[must_use]
2101 pub fn new(
2102 current_value: impl Into<SessionConfigValueId>,
2103 options: impl Into<SessionConfigSelectOptions>,
2104 ) -> Self {
2105 Self {
2106 current_value: current_value.into(),
2107 options: options.into(),
2108 }
2109 }
2110}
2111
2112#[cfg(feature = "unstable_boolean_config")]
2118#[skip_serializing_none]
2119#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2120#[serde(rename_all = "camelCase")]
2121#[non_exhaustive]
2122pub struct SessionConfigBoolean {
2123 pub current_value: bool,
2125}
2126
2127#[cfg(feature = "unstable_boolean_config")]
2128impl SessionConfigBoolean {
2129 #[must_use]
2130 pub fn new(current_value: bool) -> Self {
2131 Self { current_value }
2132 }
2133}
2134
2135#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2145#[serde(rename_all = "snake_case")]
2146#[non_exhaustive]
2147pub enum SessionConfigOptionCategory {
2148 Mode,
2150 Model,
2152 ThoughtLevel,
2154 #[serde(untagged)]
2160 Other(String),
2161}
2162
2163#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2165#[serde(tag = "type", rename_all = "snake_case")]
2166#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2167#[non_exhaustive]
2168pub enum SessionConfigKind {
2169 Select(SessionConfigSelect),
2171 #[cfg(feature = "unstable_boolean_config")]
2177 Boolean(SessionConfigBoolean),
2178 #[serde(untagged)]
2188 Other(OtherSessionConfigKind),
2189}
2190
2191#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2193#[schemars(inline)]
2194#[schemars(transform = other_session_config_kind_schema)]
2195#[serde(rename_all = "camelCase")]
2196#[non_exhaustive]
2197pub struct OtherSessionConfigKind {
2198 #[serde(rename = "type")]
2204 pub type_: String,
2205 #[serde(flatten)]
2207 pub fields: BTreeMap<String, serde_json::Value>,
2208}
2209
2210impl OtherSessionConfigKind {
2211 #[must_use]
2212 pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2213 fields.remove("type");
2214 fields.remove("_meta");
2215 Self {
2216 type_: type_.into(),
2217 fields,
2218 }
2219 }
2220}
2221
2222impl<'de> Deserialize<'de> for OtherSessionConfigKind {
2223 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2224 where
2225 D: serde::Deserializer<'de>,
2226 {
2227 let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2228 let type_ = fields
2229 .remove("type")
2230 .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2231 let serde_json::Value::String(type_) = type_ else {
2232 return Err(serde::de::Error::custom("`type` must be a string"));
2233 };
2234
2235 if is_known_session_config_kind_type(&type_) {
2236 return Err(serde::de::Error::custom(format!(
2237 "known session configuration option `{type_}` did not match its schema"
2238 )));
2239 }
2240
2241 Ok(Self { type_, fields })
2242 }
2243}
2244
2245fn is_known_session_config_kind_type(type_: &str) -> bool {
2246 match type_ {
2247 "select" => true,
2248 #[cfg(feature = "unstable_boolean_config")]
2249 "boolean" => true,
2250 _ => false,
2251 }
2252}
2253
2254fn other_session_config_kind_schema(schema: &mut Schema) {
2255 super::schema_util::reject_known_string_discriminators(
2256 schema,
2257 "type",
2258 &[
2259 "select",
2260 #[cfg(feature = "unstable_boolean_config")]
2261 "boolean",
2262 ],
2263 );
2264}
2265
2266#[serde_as]
2268#[skip_serializing_none]
2269#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2270#[serde(rename_all = "camelCase")]
2271#[non_exhaustive]
2272pub struct SessionConfigOption {
2273 pub id: SessionConfigId,
2275 pub name: String,
2277 #[serde(default)]
2279 pub description: Option<String>,
2280 #[serde_as(deserialize_as = "DefaultOnError")]
2282 #[schemars(extend("x-deserialize-default-on-error" = true))]
2283 #[serde(default)]
2284 pub category: Option<SessionConfigOptionCategory>,
2285 #[serde(flatten)]
2287 pub kind: SessionConfigKind,
2288 #[serde(rename = "_meta")]
2294 pub meta: Option<Meta>,
2295}
2296
2297impl SessionConfigOption {
2298 #[must_use]
2299 pub fn new(
2300 id: impl Into<SessionConfigId>,
2301 name: impl Into<String>,
2302 kind: SessionConfigKind,
2303 ) -> Self {
2304 Self {
2305 id: id.into(),
2306 name: name.into(),
2307 description: None,
2308 category: None,
2309 kind,
2310 meta: None,
2311 }
2312 }
2313
2314 #[must_use]
2315 pub fn select(
2316 id: impl Into<SessionConfigId>,
2317 name: impl Into<String>,
2318 current_value: impl Into<SessionConfigValueId>,
2319 options: impl Into<SessionConfigSelectOptions>,
2320 ) -> Self {
2321 Self::new(
2322 id,
2323 name,
2324 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2325 )
2326 }
2327
2328 #[cfg(feature = "unstable_boolean_config")]
2332 #[must_use]
2333 pub fn boolean(
2334 id: impl Into<SessionConfigId>,
2335 name: impl Into<String>,
2336 current_value: bool,
2337 ) -> Self {
2338 Self::new(
2339 id,
2340 name,
2341 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2342 )
2343 }
2344
2345 #[must_use]
2346 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2347 self.description = description.into_option();
2348 self
2349 }
2350
2351 #[must_use]
2352 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2353 self.category = category.into_option();
2354 self
2355 }
2356
2357 #[must_use]
2363 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2364 self.meta = meta.into_option();
2365 self
2366 }
2367}
2368
2369#[cfg(feature = "unstable_boolean_config")]
2384#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2385#[serde(tag = "type", rename_all = "snake_case")]
2386#[non_exhaustive]
2387pub enum SessionConfigOptionValue {
2388 Boolean {
2390 value: bool,
2392 },
2393 #[serde(untagged)]
2399 ValueId {
2400 value: SessionConfigValueId,
2402 },
2403}
2404
2405#[cfg(feature = "unstable_boolean_config")]
2406impl SessionConfigOptionValue {
2407 #[must_use]
2409 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2410 Self::ValueId { value: id.into() }
2411 }
2412
2413 #[must_use]
2415 pub fn boolean(val: bool) -> Self {
2416 Self::Boolean { value: val }
2417 }
2418
2419 #[must_use]
2422 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2423 match self {
2424 Self::ValueId { value } => Some(value),
2425 _ => None,
2426 }
2427 }
2428
2429 #[must_use]
2431 pub fn as_bool(&self) -> Option<bool> {
2432 match self {
2433 Self::Boolean { value } => Some(*value),
2434 _ => None,
2435 }
2436 }
2437}
2438
2439#[cfg(feature = "unstable_boolean_config")]
2440impl From<SessionConfigValueId> for SessionConfigOptionValue {
2441 fn from(value: SessionConfigValueId) -> Self {
2442 Self::ValueId { value }
2443 }
2444}
2445
2446#[cfg(feature = "unstable_boolean_config")]
2447impl From<bool> for SessionConfigOptionValue {
2448 fn from(value: bool) -> Self {
2449 Self::Boolean { value }
2450 }
2451}
2452
2453#[cfg(feature = "unstable_boolean_config")]
2454impl From<&str> for SessionConfigOptionValue {
2455 fn from(value: &str) -> Self {
2456 Self::ValueId {
2457 value: SessionConfigValueId::new(value),
2458 }
2459 }
2460}
2461
2462#[skip_serializing_none]
2464#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2465#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2466#[serde(rename_all = "camelCase")]
2467#[non_exhaustive]
2468pub struct SetSessionConfigOptionRequest {
2469 pub session_id: SessionId,
2471 pub config_id: SessionConfigId,
2473 #[cfg(feature = "unstable_boolean_config")]
2478 #[serde(flatten)]
2479 pub value: SessionConfigOptionValue,
2480 #[cfg(not(feature = "unstable_boolean_config"))]
2482 pub value: SessionConfigValueId,
2483 #[serde(rename = "_meta")]
2489 pub meta: Option<Meta>,
2490}
2491
2492impl SetSessionConfigOptionRequest {
2493 #[cfg(feature = "unstable_boolean_config")]
2494 #[must_use]
2495 pub fn new(
2496 session_id: impl Into<SessionId>,
2497 config_id: impl Into<SessionConfigId>,
2498 value: impl Into<SessionConfigOptionValue>,
2499 ) -> Self {
2500 Self {
2501 session_id: session_id.into(),
2502 config_id: config_id.into(),
2503 value: value.into(),
2504 meta: None,
2505 }
2506 }
2507
2508 #[cfg(not(feature = "unstable_boolean_config"))]
2509 #[must_use]
2510 pub fn new(
2511 session_id: impl Into<SessionId>,
2512 config_id: impl Into<SessionConfigId>,
2513 value: impl Into<SessionConfigValueId>,
2514 ) -> Self {
2515 Self {
2516 session_id: session_id.into(),
2517 config_id: config_id.into(),
2518 value: value.into(),
2519 meta: None,
2520 }
2521 }
2522
2523 #[must_use]
2529 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2530 self.meta = meta.into_option();
2531 self
2532 }
2533}
2534
2535#[serde_as]
2537#[skip_serializing_none]
2538#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2539#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2540#[serde(rename_all = "camelCase")]
2541#[non_exhaustive]
2542pub struct SetSessionConfigOptionResponse {
2543 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2545 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2546 pub config_options: Vec<SessionConfigOption>,
2547 #[serde(rename = "_meta")]
2553 pub meta: Option<Meta>,
2554}
2555
2556impl SetSessionConfigOptionResponse {
2557 #[must_use]
2558 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2559 Self {
2560 config_options,
2561 meta: None,
2562 }
2563 }
2564
2565 #[must_use]
2571 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2572 self.meta = meta.into_option();
2573 self
2574 }
2575}
2576
2577#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2586#[serde(tag = "type", rename_all = "snake_case")]
2587#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2588#[non_exhaustive]
2589pub enum McpServer {
2590 Http(McpServerHttp),
2594 #[cfg(feature = "unstable_mcp_over_acp")]
2603 Acp(McpServerAcp),
2604 Stdio(McpServerStdio),
2608 #[serde(untagged)]
2618 Other(OtherMcpServer),
2619}
2620
2621#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2623#[schemars(inline)]
2624#[schemars(transform = other_mcp_server_schema)]
2625#[serde(rename_all = "camelCase")]
2626#[non_exhaustive]
2627pub struct OtherMcpServer {
2628 #[serde(rename = "type")]
2634 pub type_: String,
2635 #[serde(flatten)]
2637 pub fields: BTreeMap<String, serde_json::Value>,
2638}
2639
2640impl OtherMcpServer {
2641 #[must_use]
2642 pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2643 fields.remove("type");
2644 Self {
2645 type_: type_.into(),
2646 fields,
2647 }
2648 }
2649}
2650
2651impl<'de> Deserialize<'de> for OtherMcpServer {
2652 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2653 where
2654 D: serde::Deserializer<'de>,
2655 {
2656 let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2657 let type_ = fields
2658 .remove("type")
2659 .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2660 let serde_json::Value::String(type_) = type_ else {
2661 return Err(serde::de::Error::custom("`type` must be a string"));
2662 };
2663
2664 if is_known_mcp_server_type(&type_) {
2665 return Err(serde::de::Error::custom(format!(
2666 "known MCP server transport `{type_}` did not match its schema"
2667 )));
2668 }
2669
2670 Ok(Self { type_, fields })
2671 }
2672}
2673
2674fn is_known_mcp_server_type(type_: &str) -> bool {
2675 match type_ {
2676 "http" | "stdio" => true,
2677 #[cfg(feature = "unstable_mcp_over_acp")]
2678 "acp" => true,
2679 _ => false,
2680 }
2681}
2682
2683fn other_mcp_server_schema(schema: &mut Schema) {
2684 super::schema_util::reject_known_string_discriminators(
2685 schema,
2686 "type",
2687 &[
2688 "http",
2689 "stdio",
2690 #[cfg(feature = "unstable_mcp_over_acp")]
2691 "acp",
2692 ],
2693 );
2694}
2695
2696#[skip_serializing_none]
2698#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2699#[serde(rename_all = "camelCase")]
2700#[non_exhaustive]
2701pub struct McpServerHttp {
2702 pub name: String,
2704 pub url: String,
2706 pub headers: Vec<HttpHeader>,
2708 #[serde(rename = "_meta")]
2714 pub meta: Option<Meta>,
2715}
2716
2717impl McpServerHttp {
2718 #[must_use]
2719 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2720 Self {
2721 name: name.into(),
2722 url: url.into(),
2723 headers: Vec::new(),
2724 meta: None,
2725 }
2726 }
2727
2728 #[must_use]
2730 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2731 self.headers = headers;
2732 self
2733 }
2734
2735 #[must_use]
2741 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2742 self.meta = meta.into_option();
2743 self
2744 }
2745}
2746
2747#[cfg(feature = "unstable_mcp_over_acp")]
2757#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2758#[serde(transparent)]
2759#[from(Arc<str>, String, &'static str)]
2760#[non_exhaustive]
2761pub struct McpServerAcpId(pub Arc<str>);
2762
2763#[cfg(feature = "unstable_mcp_over_acp")]
2764impl McpServerAcpId {
2765 #[must_use]
2766 pub fn new(id: impl Into<Arc<str>>) -> Self {
2767 Self(id.into())
2768 }
2769}
2770
2771#[skip_serializing_none]
2780#[cfg(feature = "unstable_mcp_over_acp")]
2781#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2782#[serde(rename_all = "camelCase")]
2783#[non_exhaustive]
2784pub struct McpServerAcp {
2785 pub name: String,
2787 pub id: McpServerAcpId,
2792 #[serde(rename = "_meta")]
2798 pub meta: Option<Meta>,
2799}
2800
2801#[cfg(feature = "unstable_mcp_over_acp")]
2802impl McpServerAcp {
2803 #[must_use]
2804 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2805 Self {
2806 name: name.into(),
2807 id: id.into(),
2808 meta: None,
2809 }
2810 }
2811
2812 #[must_use]
2818 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2819 self.meta = meta.into_option();
2820 self
2821 }
2822}
2823
2824#[skip_serializing_none]
2826#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2827#[serde(rename_all = "camelCase")]
2828#[non_exhaustive]
2829pub struct McpServerStdio {
2830 pub name: String,
2832 pub command: PathBuf,
2834 pub args: Vec<String>,
2836 pub env: Vec<EnvVariable>,
2838 #[serde(rename = "_meta")]
2844 pub meta: Option<Meta>,
2845}
2846
2847impl McpServerStdio {
2848 #[must_use]
2849 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2850 Self {
2851 name: name.into(),
2852 command: command.into(),
2853 args: Vec::new(),
2854 env: Vec::new(),
2855 meta: None,
2856 }
2857 }
2858
2859 #[must_use]
2861 pub fn args(mut self, args: Vec<String>) -> Self {
2862 self.args = args;
2863 self
2864 }
2865
2866 #[must_use]
2868 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2869 self.env = env;
2870 self
2871 }
2872
2873 #[must_use]
2879 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2880 self.meta = meta.into_option();
2881 self
2882 }
2883}
2884
2885#[skip_serializing_none]
2887#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2888#[serde(rename_all = "camelCase")]
2889#[non_exhaustive]
2890pub struct EnvVariable {
2891 pub name: String,
2893 pub value: String,
2895 #[serde(rename = "_meta")]
2901 pub meta: Option<Meta>,
2902}
2903
2904impl EnvVariable {
2905 #[must_use]
2906 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2907 Self {
2908 name: name.into(),
2909 value: value.into(),
2910 meta: None,
2911 }
2912 }
2913
2914 #[must_use]
2920 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2921 self.meta = meta.into_option();
2922 self
2923 }
2924}
2925
2926#[skip_serializing_none]
2928#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2929#[serde(rename_all = "camelCase")]
2930#[non_exhaustive]
2931pub struct HttpHeader {
2932 pub name: String,
2934 pub value: String,
2936 #[serde(rename = "_meta")]
2942 pub meta: Option<Meta>,
2943}
2944
2945impl HttpHeader {
2946 #[must_use]
2947 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2948 Self {
2949 name: name.into(),
2950 value: value.into(),
2951 meta: None,
2952 }
2953 }
2954
2955 #[must_use]
2961 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2962 self.meta = meta.into_option();
2963 self
2964 }
2965}
2966
2967#[skip_serializing_none]
2975#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
2976#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2977#[serde(rename_all = "camelCase")]
2978#[non_exhaustive]
2979pub struct PromptRequest {
2980 pub session_id: SessionId,
2982 pub prompt: Vec<ContentBlock>,
2996 #[serde(rename = "_meta")]
3002 pub meta: Option<Meta>,
3003}
3004
3005impl PromptRequest {
3006 #[must_use]
3007 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3008 Self {
3009 session_id: session_id.into(),
3010 prompt,
3011 meta: None,
3012 }
3013 }
3014
3015 #[must_use]
3021 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3022 self.meta = meta.into_option();
3023 self
3024 }
3025}
3026
3027#[serde_as]
3031#[skip_serializing_none]
3032#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3033#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3034#[serde(rename_all = "camelCase")]
3035#[non_exhaustive]
3036pub struct PromptResponse {
3037 pub stop_reason: StopReason,
3039 #[cfg(feature = "unstable_end_turn_token_usage")]
3045 #[serde_as(deserialize_as = "DefaultOnError")]
3046 #[schemars(extend("x-deserialize-default-on-error" = true))]
3047 #[serde(default)]
3048 pub usage: Option<Usage>,
3049 #[serde(rename = "_meta")]
3055 pub meta: Option<Meta>,
3056}
3057
3058impl PromptResponse {
3059 #[must_use]
3060 pub fn new(stop_reason: StopReason) -> Self {
3061 Self {
3062 stop_reason,
3063 #[cfg(feature = "unstable_end_turn_token_usage")]
3064 usage: None,
3065 meta: None,
3066 }
3067 }
3068
3069 #[cfg(feature = "unstable_end_turn_token_usage")]
3075 #[must_use]
3076 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3077 self.usage = usage.into_option();
3078 self
3079 }
3080
3081 #[must_use]
3087 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3088 self.meta = meta.into_option();
3089 self
3090 }
3091}
3092
3093#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3097#[serde(rename_all = "snake_case")]
3098#[non_exhaustive]
3099pub enum StopReason {
3100 EndTurn,
3102 MaxTokens,
3104 MaxTurnRequests,
3107 Refusal,
3111 Cancelled,
3118 #[serde(untagged)]
3124 Other(String),
3125}
3126
3127#[cfg(feature = "unstable_end_turn_token_usage")]
3133#[skip_serializing_none]
3134#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3135#[serde(rename_all = "camelCase")]
3136#[non_exhaustive]
3137pub struct Usage {
3138 pub total_tokens: u64,
3140 pub input_tokens: u64,
3142 pub output_tokens: u64,
3144 pub thought_tokens: Option<u64>,
3146 pub cached_read_tokens: Option<u64>,
3148 pub cached_write_tokens: Option<u64>,
3150 #[serde(rename = "_meta")]
3156 pub meta: Option<Meta>,
3157}
3158
3159#[cfg(feature = "unstable_end_turn_token_usage")]
3160impl Usage {
3161 #[must_use]
3162 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3163 Self {
3164 total_tokens,
3165 input_tokens,
3166 output_tokens,
3167 thought_tokens: None,
3168 cached_read_tokens: None,
3169 cached_write_tokens: None,
3170 meta: None,
3171 }
3172 }
3173
3174 #[must_use]
3176 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3177 self.thought_tokens = thought_tokens.into_option();
3178 self
3179 }
3180
3181 #[must_use]
3183 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3184 self.cached_read_tokens = cached_read_tokens.into_option();
3185 self
3186 }
3187
3188 #[must_use]
3190 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3191 self.cached_write_tokens = cached_write_tokens.into_option();
3192 self
3193 }
3194
3195 #[must_use]
3201 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3202 self.meta = meta.into_option();
3203 self
3204 }
3205}
3206
3207#[cfg(feature = "unstable_llm_providers")]
3220#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3221#[serde(rename_all = "snake_case")]
3222#[non_exhaustive]
3223#[expect(clippy::doc_markdown)]
3224pub enum LlmProtocol {
3225 Anthropic,
3227 #[serde(rename = "openai")]
3229 OpenAi,
3230 Azure,
3232 Vertex,
3234 Bedrock,
3236 #[serde(untagged)]
3242 Other(String),
3243}
3244
3245#[cfg(feature = "unstable_llm_providers")]
3251#[skip_serializing_none]
3252#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3253#[serde(rename_all = "camelCase")]
3254#[non_exhaustive]
3255pub struct ProviderCurrentConfig {
3256 pub api_type: LlmProtocol,
3258 pub base_url: String,
3260 #[serde(rename = "_meta")]
3266 pub meta: Option<Meta>,
3267}
3268
3269#[cfg(feature = "unstable_llm_providers")]
3270impl ProviderCurrentConfig {
3271 #[must_use]
3272 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3273 Self {
3274 api_type,
3275 base_url: base_url.into(),
3276 meta: None,
3277 }
3278 }
3279
3280 #[must_use]
3286 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3287 self.meta = meta.into_option();
3288 self
3289 }
3290}
3291
3292#[cfg(feature = "unstable_llm_providers")]
3298#[serde_as]
3299#[skip_serializing_none]
3300#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3301#[serde(rename_all = "camelCase")]
3302#[non_exhaustive]
3303pub struct ProviderInfo {
3304 pub id: String,
3306 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3308 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3309 pub supported: Vec<LlmProtocol>,
3310 pub required: bool,
3313 pub current: Option<ProviderCurrentConfig>,
3316 #[serde(rename = "_meta")]
3322 pub meta: Option<Meta>,
3323}
3324
3325#[cfg(feature = "unstable_llm_providers")]
3326impl ProviderInfo {
3327 #[must_use]
3328 pub fn new(
3329 id: impl Into<String>,
3330 supported: Vec<LlmProtocol>,
3331 required: bool,
3332 current: impl IntoOption<ProviderCurrentConfig>,
3333 ) -> Self {
3334 Self {
3335 id: id.into(),
3336 supported,
3337 required,
3338 current: current.into_option(),
3339 meta: None,
3340 }
3341 }
3342
3343 #[must_use]
3349 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3350 self.meta = meta.into_option();
3351 self
3352 }
3353}
3354
3355#[cfg(feature = "unstable_llm_providers")]
3361#[skip_serializing_none]
3362#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3363#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3364#[serde(rename_all = "camelCase")]
3365#[non_exhaustive]
3366pub struct ListProvidersRequest {
3367 #[serde(rename = "_meta")]
3373 pub meta: Option<Meta>,
3374}
3375
3376#[cfg(feature = "unstable_llm_providers")]
3377impl ListProvidersRequest {
3378 #[must_use]
3379 pub fn new() -> Self {
3380 Self::default()
3381 }
3382
3383 #[must_use]
3389 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3390 self.meta = meta.into_option();
3391 self
3392 }
3393}
3394
3395#[cfg(feature = "unstable_llm_providers")]
3401#[serde_as]
3402#[skip_serializing_none]
3403#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3404#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3405#[serde(rename_all = "camelCase")]
3406#[non_exhaustive]
3407pub struct ListProvidersResponse {
3408 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3410 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3411 pub providers: Vec<ProviderInfo>,
3412 #[serde(rename = "_meta")]
3418 pub meta: Option<Meta>,
3419}
3420
3421#[cfg(feature = "unstable_llm_providers")]
3422impl ListProvidersResponse {
3423 #[must_use]
3424 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3425 Self {
3426 providers,
3427 meta: None,
3428 }
3429 }
3430
3431 #[must_use]
3437 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3438 self.meta = meta.into_option();
3439 self
3440 }
3441}
3442
3443#[cfg(feature = "unstable_llm_providers")]
3451#[skip_serializing_none]
3452#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3453#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3454#[serde(rename_all = "camelCase")]
3455#[non_exhaustive]
3456pub struct SetProviderRequest {
3457 pub id: String,
3459 pub api_type: LlmProtocol,
3461 pub base_url: String,
3463 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3466 pub headers: HashMap<String, String>,
3467 #[serde(rename = "_meta")]
3473 pub meta: Option<Meta>,
3474}
3475
3476#[cfg(feature = "unstable_llm_providers")]
3477impl SetProviderRequest {
3478 #[must_use]
3479 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3480 Self {
3481 id: id.into(),
3482 api_type,
3483 base_url: base_url.into(),
3484 headers: HashMap::new(),
3485 meta: None,
3486 }
3487 }
3488
3489 #[must_use]
3492 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3493 self.headers = headers;
3494 self
3495 }
3496
3497 #[must_use]
3503 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3504 self.meta = meta.into_option();
3505 self
3506 }
3507}
3508
3509#[cfg(feature = "unstable_llm_providers")]
3515#[skip_serializing_none]
3516#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3517#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3518#[serde(rename_all = "camelCase")]
3519#[non_exhaustive]
3520pub struct SetProviderResponse {
3521 #[serde(rename = "_meta")]
3527 pub meta: Option<Meta>,
3528}
3529
3530#[cfg(feature = "unstable_llm_providers")]
3531impl SetProviderResponse {
3532 #[must_use]
3533 pub fn new() -> Self {
3534 Self::default()
3535 }
3536
3537 #[must_use]
3543 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3544 self.meta = meta.into_option();
3545 self
3546 }
3547}
3548
3549#[cfg(feature = "unstable_llm_providers")]
3555#[skip_serializing_none]
3556#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3557#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3558#[serde(rename_all = "camelCase")]
3559#[non_exhaustive]
3560pub struct DisableProviderRequest {
3561 pub id: String,
3563 #[serde(rename = "_meta")]
3569 pub meta: Option<Meta>,
3570}
3571
3572#[cfg(feature = "unstable_llm_providers")]
3573impl DisableProviderRequest {
3574 #[must_use]
3575 pub fn new(id: impl Into<String>) -> Self {
3576 Self {
3577 id: id.into(),
3578 meta: None,
3579 }
3580 }
3581
3582 #[must_use]
3588 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3589 self.meta = meta.into_option();
3590 self
3591 }
3592}
3593
3594#[cfg(feature = "unstable_llm_providers")]
3600#[skip_serializing_none]
3601#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3602#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3603#[serde(rename_all = "camelCase")]
3604#[non_exhaustive]
3605pub struct DisableProviderResponse {
3606 #[serde(rename = "_meta")]
3612 pub meta: Option<Meta>,
3613}
3614
3615#[cfg(feature = "unstable_llm_providers")]
3616impl DisableProviderResponse {
3617 #[must_use]
3618 pub fn new() -> Self {
3619 Self::default()
3620 }
3621
3622 #[must_use]
3628 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3629 self.meta = meta.into_option();
3630 self
3631 }
3632}
3633
3634#[serde_as]
3643#[skip_serializing_none]
3644#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3645#[serde(rename_all = "camelCase")]
3646#[non_exhaustive]
3647pub struct AgentCapabilities {
3648 #[serde_as(deserialize_as = "DefaultOnError")]
3655 #[schemars(extend("x-deserialize-default-on-error" = true))]
3656 #[serde(default)]
3657 pub session: Option<SessionCapabilities>,
3658 #[serde(default)]
3660 pub auth: AgentAuthCapabilities,
3661 #[cfg(feature = "unstable_llm_providers")]
3669 #[serde_as(deserialize_as = "DefaultOnError")]
3670 #[schemars(extend("x-deserialize-default-on-error" = true))]
3671 #[serde(default)]
3672 pub providers: Option<ProvidersCapabilities>,
3673 #[cfg(feature = "unstable_nes")]
3679 #[serde_as(deserialize_as = "DefaultOnError")]
3680 #[schemars(extend("x-deserialize-default-on-error" = true))]
3681 #[serde(default)]
3682 pub nes: Option<NesCapabilities>,
3683 #[cfg(feature = "unstable_nes")]
3689 #[serde_as(deserialize_as = "DefaultOnError")]
3690 #[schemars(extend("x-deserialize-default-on-error" = true))]
3691 #[serde(default)]
3692 pub position_encoding: Option<PositionEncodingKind>,
3693 #[serde(rename = "_meta")]
3699 pub meta: Option<Meta>,
3700}
3701
3702impl AgentCapabilities {
3703 #[must_use]
3704 pub fn new() -> Self {
3705 Self::default()
3706 }
3707
3708 #[must_use]
3715 pub fn session(mut self, session: impl IntoOption<SessionCapabilities>) -> Self {
3716 self.session = session.into_option();
3717 self
3718 }
3719
3720 #[must_use]
3722 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3723 self.auth = auth;
3724 self
3725 }
3726
3727 #[cfg(feature = "unstable_llm_providers")]
3733 #[must_use]
3734 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3735 self.providers = providers.into_option();
3736 self
3737 }
3738
3739 #[cfg(feature = "unstable_nes")]
3745 #[must_use]
3746 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3747 self.nes = nes.into_option();
3748 self
3749 }
3750
3751 #[cfg(feature = "unstable_nes")]
3755 #[must_use]
3756 pub fn position_encoding(
3757 mut self,
3758 position_encoding: impl IntoOption<PositionEncodingKind>,
3759 ) -> Self {
3760 self.position_encoding = position_encoding.into_option();
3761 self
3762 }
3763
3764 #[must_use]
3770 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3771 self.meta = meta.into_option();
3772 self
3773 }
3774}
3775
3776#[cfg(feature = "unstable_llm_providers")]
3784#[skip_serializing_none]
3785#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3786#[non_exhaustive]
3787pub struct ProvidersCapabilities {
3788 #[serde(rename = "_meta")]
3794 pub meta: Option<Meta>,
3795}
3796
3797#[cfg(feature = "unstable_llm_providers")]
3798impl ProvidersCapabilities {
3799 #[must_use]
3800 pub fn new() -> Self {
3801 Self::default()
3802 }
3803
3804 #[must_use]
3810 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3811 self.meta = meta.into_option();
3812 self
3813 }
3814}
3815
3816#[serde_as]
3827#[skip_serializing_none]
3828#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3829#[serde(rename_all = "camelCase")]
3830#[non_exhaustive]
3831pub struct SessionCapabilities {
3832 #[serde_as(deserialize_as = "DefaultOnError")]
3838 #[schemars(extend("x-deserialize-default-on-error" = true))]
3839 #[serde(default)]
3840 pub prompt: Option<PromptCapabilities>,
3841 #[serde_as(deserialize_as = "DefaultOnError")]
3846 #[schemars(extend("x-deserialize-default-on-error" = true))]
3847 #[serde(default)]
3848 pub mcp: Option<McpCapabilities>,
3849 #[serde_as(deserialize_as = "DefaultOnError")]
3854 #[schemars(extend("x-deserialize-default-on-error" = true))]
3855 #[serde(default)]
3856 pub load: Option<SessionLoadCapabilities>,
3857 #[serde_as(deserialize_as = "DefaultOnError")]
3859 #[schemars(extend("x-deserialize-default-on-error" = true))]
3860 #[serde(default)]
3861 pub list: Option<SessionListCapabilities>,
3862 #[serde_as(deserialize_as = "DefaultOnError")]
3867 #[schemars(extend("x-deserialize-default-on-error" = true))]
3868 #[serde(default)]
3869 pub delete: Option<SessionDeleteCapabilities>,
3870 #[serde_as(deserialize_as = "DefaultOnError")]
3876 #[schemars(extend("x-deserialize-default-on-error" = true))]
3877 #[serde(default)]
3878 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
3879 #[cfg(feature = "unstable_session_fork")]
3885 #[serde_as(deserialize_as = "DefaultOnError")]
3886 #[schemars(extend("x-deserialize-default-on-error" = true))]
3887 #[serde(default)]
3888 pub fork: Option<SessionForkCapabilities>,
3889 #[serde_as(deserialize_as = "DefaultOnError")]
3891 #[schemars(extend("x-deserialize-default-on-error" = true))]
3892 #[serde(default)]
3893 pub resume: Option<SessionResumeCapabilities>,
3894 #[serde_as(deserialize_as = "DefaultOnError")]
3896 #[schemars(extend("x-deserialize-default-on-error" = true))]
3897 #[serde(default)]
3898 pub close: Option<SessionCloseCapabilities>,
3899 #[serde(rename = "_meta")]
3905 pub meta: Option<Meta>,
3906}
3907
3908impl SessionCapabilities {
3909 #[must_use]
3910 pub fn new() -> Self {
3911 Self::default()
3912 }
3913
3914 #[must_use]
3920 pub fn prompt(mut self, prompt: impl IntoOption<PromptCapabilities>) -> Self {
3921 self.prompt = prompt.into_option();
3922 self
3923 }
3924
3925 #[must_use]
3930 pub fn mcp(mut self, mcp: impl IntoOption<McpCapabilities>) -> Self {
3931 self.mcp = mcp.into_option();
3932 self
3933 }
3934
3935 #[must_use]
3940 pub fn load(mut self, load: impl IntoOption<SessionLoadCapabilities>) -> Self {
3941 self.load = load.into_option();
3942 self
3943 }
3944
3945 #[must_use]
3947 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3948 self.list = list.into_option();
3949 self
3950 }
3951
3952 #[must_use]
3957 pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
3958 self.delete = delete.into_option();
3959 self
3960 }
3961
3962 #[must_use]
3968 pub fn additional_directories(
3969 mut self,
3970 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
3971 ) -> Self {
3972 self.additional_directories = additional_directories.into_option();
3973 self
3974 }
3975
3976 #[cfg(feature = "unstable_session_fork")]
3977 #[must_use]
3979 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
3980 self.fork = fork.into_option();
3981 self
3982 }
3983
3984 #[must_use]
3986 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
3987 self.resume = resume.into_option();
3988 self
3989 }
3990
3991 #[must_use]
3993 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
3994 self.close = close.into_option();
3995 self
3996 }
3997
3998 #[must_use]
4004 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4005 self.meta = meta.into_option();
4006 self
4007 }
4008}
4009
4010#[skip_serializing_none]
4014#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4015#[non_exhaustive]
4016pub struct SessionLoadCapabilities {
4017 #[serde(rename = "_meta")]
4023 pub meta: Option<Meta>,
4024}
4025
4026impl SessionLoadCapabilities {
4027 #[must_use]
4028 pub fn new() -> Self {
4029 Self::default()
4030 }
4031
4032 #[must_use]
4038 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4039 self.meta = meta.into_option();
4040 self
4041 }
4042}
4043
4044#[skip_serializing_none]
4048#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4049#[non_exhaustive]
4050pub struct SessionListCapabilities {
4051 #[serde(rename = "_meta")]
4057 pub meta: Option<Meta>,
4058}
4059
4060impl SessionListCapabilities {
4061 #[must_use]
4062 pub fn new() -> Self {
4063 Self::default()
4064 }
4065
4066 #[must_use]
4072 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4073 self.meta = meta.into_option();
4074 self
4075 }
4076}
4077
4078#[skip_serializing_none]
4082#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4083#[non_exhaustive]
4084pub struct SessionDeleteCapabilities {
4085 #[serde(rename = "_meta")]
4091 pub meta: Option<Meta>,
4092}
4093
4094impl SessionDeleteCapabilities {
4095 #[must_use]
4096 pub fn new() -> Self {
4097 Self::default()
4098 }
4099
4100 #[must_use]
4106 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4107 self.meta = meta.into_option();
4108 self
4109 }
4110}
4111
4112#[skip_serializing_none]
4119#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4120#[non_exhaustive]
4121pub struct SessionAdditionalDirectoriesCapabilities {
4122 #[serde(rename = "_meta")]
4128 pub meta: Option<Meta>,
4129}
4130
4131impl SessionAdditionalDirectoriesCapabilities {
4132 #[must_use]
4133 pub fn new() -> Self {
4134 Self::default()
4135 }
4136
4137 #[must_use]
4143 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4144 self.meta = meta.into_option();
4145 self
4146 }
4147}
4148
4149#[cfg(feature = "unstable_session_fork")]
4157#[skip_serializing_none]
4158#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4159#[non_exhaustive]
4160pub struct SessionForkCapabilities {
4161 #[serde(rename = "_meta")]
4167 pub meta: Option<Meta>,
4168}
4169
4170#[cfg(feature = "unstable_session_fork")]
4171impl SessionForkCapabilities {
4172 #[must_use]
4173 pub fn new() -> Self {
4174 Self::default()
4175 }
4176
4177 #[must_use]
4183 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4184 self.meta = meta.into_option();
4185 self
4186 }
4187}
4188
4189#[skip_serializing_none]
4193#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4194#[non_exhaustive]
4195pub struct SessionResumeCapabilities {
4196 #[serde(rename = "_meta")]
4202 pub meta: Option<Meta>,
4203}
4204
4205impl SessionResumeCapabilities {
4206 #[must_use]
4207 pub fn new() -> Self {
4208 Self::default()
4209 }
4210
4211 #[must_use]
4217 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4218 self.meta = meta.into_option();
4219 self
4220 }
4221}
4222
4223#[skip_serializing_none]
4227#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4228#[non_exhaustive]
4229pub struct SessionCloseCapabilities {
4230 #[serde(rename = "_meta")]
4236 pub meta: Option<Meta>,
4237}
4238
4239impl SessionCloseCapabilities {
4240 #[must_use]
4241 pub fn new() -> Self {
4242 Self::default()
4243 }
4244
4245 #[must_use]
4251 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4252 self.meta = meta.into_option();
4253 self
4254 }
4255}
4256
4257#[serde_as]
4270#[skip_serializing_none]
4271#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4272#[serde(rename_all = "camelCase")]
4273#[non_exhaustive]
4274pub struct PromptCapabilities {
4275 #[serde_as(deserialize_as = "DefaultOnError")]
4280 #[schemars(extend("x-deserialize-default-on-error" = true))]
4281 #[serde(default)]
4282 pub image: Option<PromptImageCapabilities>,
4283 #[serde_as(deserialize_as = "DefaultOnError")]
4288 #[schemars(extend("x-deserialize-default-on-error" = true))]
4289 #[serde(default)]
4290 pub audio: Option<PromptAudioCapabilities>,
4291 #[serde_as(deserialize_as = "DefaultOnError")]
4299 #[schemars(extend("x-deserialize-default-on-error" = true))]
4300 #[serde(default)]
4301 pub embedded_context: Option<PromptEmbeddedContextCapabilities>,
4302 #[serde(rename = "_meta")]
4308 pub meta: Option<Meta>,
4309}
4310
4311impl PromptCapabilities {
4312 #[must_use]
4313 pub fn new() -> Self {
4314 Self::default()
4315 }
4316
4317 #[must_use]
4322 pub fn image(mut self, image: impl IntoOption<PromptImageCapabilities>) -> Self {
4323 self.image = image.into_option();
4324 self
4325 }
4326
4327 #[must_use]
4332 pub fn audio(mut self, audio: impl IntoOption<PromptAudioCapabilities>) -> Self {
4333 self.audio = audio.into_option();
4334 self
4335 }
4336
4337 #[must_use]
4345 pub fn embedded_context(
4346 mut self,
4347 embedded_context: impl IntoOption<PromptEmbeddedContextCapabilities>,
4348 ) -> Self {
4349 self.embedded_context = embedded_context.into_option();
4350 self
4351 }
4352
4353 #[must_use]
4359 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4360 self.meta = meta.into_option();
4361 self
4362 }
4363}
4364
4365#[skip_serializing_none]
4369#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4370#[non_exhaustive]
4371pub struct PromptImageCapabilities {
4372 #[serde(rename = "_meta")]
4378 pub meta: Option<Meta>,
4379}
4380
4381impl PromptImageCapabilities {
4382 #[must_use]
4383 pub fn new() -> Self {
4384 Self::default()
4385 }
4386
4387 #[must_use]
4393 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4394 self.meta = meta.into_option();
4395 self
4396 }
4397}
4398
4399#[skip_serializing_none]
4403#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4404#[non_exhaustive]
4405pub struct PromptAudioCapabilities {
4406 #[serde(rename = "_meta")]
4412 pub meta: Option<Meta>,
4413}
4414
4415impl PromptAudioCapabilities {
4416 #[must_use]
4417 pub fn new() -> Self {
4418 Self::default()
4419 }
4420
4421 #[must_use]
4427 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4428 self.meta = meta.into_option();
4429 self
4430 }
4431}
4432
4433#[skip_serializing_none]
4437#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4438#[non_exhaustive]
4439pub struct PromptEmbeddedContextCapabilities {
4440 #[serde(rename = "_meta")]
4446 pub meta: Option<Meta>,
4447}
4448
4449impl PromptEmbeddedContextCapabilities {
4450 #[must_use]
4451 pub fn new() -> Self {
4452 Self::default()
4453 }
4454
4455 #[must_use]
4461 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4462 self.meta = meta.into_option();
4463 self
4464 }
4465}
4466
4467#[serde_as]
4469#[skip_serializing_none]
4470#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4471#[serde(rename_all = "camelCase")]
4472#[non_exhaustive]
4473pub struct McpCapabilities {
4474 #[serde_as(deserialize_as = "DefaultOnError")]
4479 #[schemars(extend("x-deserialize-default-on-error" = true))]
4480 #[serde(default)]
4481 pub stdio: Option<McpStdioCapabilities>,
4482 #[serde_as(deserialize_as = "DefaultOnError")]
4487 #[schemars(extend("x-deserialize-default-on-error" = true))]
4488 #[serde(default)]
4489 pub http: Option<McpHttpCapabilities>,
4490 #[cfg(feature = "unstable_mcp_over_acp")]
4496 #[serde_as(deserialize_as = "DefaultOnError")]
4500 #[schemars(extend("x-deserialize-default-on-error" = true))]
4501 #[serde(default)]
4502 pub acp: Option<McpAcpCapabilities>,
4503 #[serde(rename = "_meta")]
4509 pub meta: Option<Meta>,
4510}
4511
4512impl McpCapabilities {
4513 #[must_use]
4514 pub fn new() -> Self {
4515 Self::default()
4516 }
4517
4518 #[must_use]
4523 pub fn stdio(mut self, stdio: impl IntoOption<McpStdioCapabilities>) -> Self {
4524 self.stdio = stdio.into_option();
4525 self
4526 }
4527
4528 #[must_use]
4533 pub fn http(mut self, http: impl IntoOption<McpHttpCapabilities>) -> Self {
4534 self.http = http.into_option();
4535 self
4536 }
4537
4538 #[cfg(feature = "unstable_mcp_over_acp")]
4544 #[must_use]
4548 pub fn acp(mut self, acp: impl IntoOption<McpAcpCapabilities>) -> Self {
4549 self.acp = acp.into_option();
4550 self
4551 }
4552
4553 #[must_use]
4559 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4560 self.meta = meta.into_option();
4561 self
4562 }
4563}
4564
4565#[skip_serializing_none]
4569#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4570#[non_exhaustive]
4571pub struct McpStdioCapabilities {
4572 #[serde(rename = "_meta")]
4578 pub meta: Option<Meta>,
4579}
4580
4581impl McpStdioCapabilities {
4582 #[must_use]
4583 pub fn new() -> Self {
4584 Self::default()
4585 }
4586
4587 #[must_use]
4593 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4594 self.meta = meta.into_option();
4595 self
4596 }
4597}
4598
4599#[skip_serializing_none]
4603#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4604#[non_exhaustive]
4605pub struct McpHttpCapabilities {
4606 #[serde(rename = "_meta")]
4612 pub meta: Option<Meta>,
4613}
4614
4615impl McpHttpCapabilities {
4616 #[must_use]
4617 pub fn new() -> Self {
4618 Self::default()
4619 }
4620
4621 #[must_use]
4627 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4628 self.meta = meta.into_option();
4629 self
4630 }
4631}
4632
4633#[cfg(feature = "unstable_mcp_over_acp")]
4641#[skip_serializing_none]
4642#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4643#[non_exhaustive]
4644pub struct McpAcpCapabilities {
4645 #[serde(rename = "_meta")]
4651 pub meta: Option<Meta>,
4652}
4653
4654#[cfg(feature = "unstable_mcp_over_acp")]
4655impl McpAcpCapabilities {
4656 #[must_use]
4657 pub fn new() -> Self {
4658 Self::default()
4659 }
4660
4661 #[must_use]
4667 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4668 self.meta = meta.into_option();
4669 self
4670 }
4671}
4672
4673#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4679#[non_exhaustive]
4680pub struct AgentMethodNames {
4681 pub initialize: &'static str,
4683 pub authenticate: &'static str,
4685 #[cfg(feature = "unstable_llm_providers")]
4687 pub providers_list: &'static str,
4688 #[cfg(feature = "unstable_llm_providers")]
4690 pub providers_set: &'static str,
4691 #[cfg(feature = "unstable_llm_providers")]
4693 pub providers_disable: &'static str,
4694 pub session_new: &'static str,
4696 pub session_load: &'static str,
4698 pub session_set_config_option: &'static str,
4700 pub session_prompt: &'static str,
4702 pub session_cancel: &'static str,
4704 #[cfg(feature = "unstable_mcp_over_acp")]
4706 pub mcp_message: &'static str,
4707 pub session_list: &'static str,
4709 pub session_delete: &'static str,
4711 #[cfg(feature = "unstable_session_fork")]
4713 pub session_fork: &'static str,
4714 pub session_resume: &'static str,
4716 pub session_close: &'static str,
4718 pub logout: &'static str,
4720 #[cfg(feature = "unstable_nes")]
4722 pub nes_start: &'static str,
4723 #[cfg(feature = "unstable_nes")]
4725 pub nes_suggest: &'static str,
4726 #[cfg(feature = "unstable_nes")]
4728 pub nes_accept: &'static str,
4729 #[cfg(feature = "unstable_nes")]
4731 pub nes_reject: &'static str,
4732 #[cfg(feature = "unstable_nes")]
4734 pub nes_close: &'static str,
4735 #[cfg(feature = "unstable_nes")]
4737 pub document_did_open: &'static str,
4738 #[cfg(feature = "unstable_nes")]
4740 pub document_did_change: &'static str,
4741 #[cfg(feature = "unstable_nes")]
4743 pub document_did_close: &'static str,
4744 #[cfg(feature = "unstable_nes")]
4746 pub document_did_save: &'static str,
4747 #[cfg(feature = "unstable_nes")]
4749 pub document_did_focus: &'static str,
4750}
4751
4752pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4754 initialize: INITIALIZE_METHOD_NAME,
4755 authenticate: AUTHENTICATE_METHOD_NAME,
4756 #[cfg(feature = "unstable_llm_providers")]
4757 providers_list: PROVIDERS_LIST_METHOD_NAME,
4758 #[cfg(feature = "unstable_llm_providers")]
4759 providers_set: PROVIDERS_SET_METHOD_NAME,
4760 #[cfg(feature = "unstable_llm_providers")]
4761 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4762 session_new: SESSION_NEW_METHOD_NAME,
4763 session_load: SESSION_LOAD_METHOD_NAME,
4764 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4765 session_prompt: SESSION_PROMPT_METHOD_NAME,
4766 session_cancel: SESSION_CANCEL_METHOD_NAME,
4767 #[cfg(feature = "unstable_mcp_over_acp")]
4768 mcp_message: MCP_MESSAGE_METHOD_NAME,
4769 session_list: SESSION_LIST_METHOD_NAME,
4770 session_delete: SESSION_DELETE_METHOD_NAME,
4771 #[cfg(feature = "unstable_session_fork")]
4772 session_fork: SESSION_FORK_METHOD_NAME,
4773 session_resume: SESSION_RESUME_METHOD_NAME,
4774 session_close: SESSION_CLOSE_METHOD_NAME,
4775 logout: LOGOUT_METHOD_NAME,
4776 #[cfg(feature = "unstable_nes")]
4777 nes_start: NES_START_METHOD_NAME,
4778 #[cfg(feature = "unstable_nes")]
4779 nes_suggest: NES_SUGGEST_METHOD_NAME,
4780 #[cfg(feature = "unstable_nes")]
4781 nes_accept: NES_ACCEPT_METHOD_NAME,
4782 #[cfg(feature = "unstable_nes")]
4783 nes_reject: NES_REJECT_METHOD_NAME,
4784 #[cfg(feature = "unstable_nes")]
4785 nes_close: NES_CLOSE_METHOD_NAME,
4786 #[cfg(feature = "unstable_nes")]
4787 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4788 #[cfg(feature = "unstable_nes")]
4789 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4790 #[cfg(feature = "unstable_nes")]
4791 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4792 #[cfg(feature = "unstable_nes")]
4793 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4794 #[cfg(feature = "unstable_nes")]
4795 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4796};
4797
4798pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4800pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4802#[cfg(feature = "unstable_llm_providers")]
4804pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4805#[cfg(feature = "unstable_llm_providers")]
4807pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4808#[cfg(feature = "unstable_llm_providers")]
4810pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4811pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4813pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4815pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4817pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4819pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4821pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4823pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
4825#[cfg(feature = "unstable_session_fork")]
4827pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4828pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4830pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4832pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4834
4835#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4842#[serde(untagged)]
4843#[schemars(inline)]
4844#[non_exhaustive]
4845pub enum ClientRequest {
4846 InitializeRequest(Box<InitializeRequest>),
4857 AuthenticateRequest(AuthenticateRequest),
4867 #[cfg(feature = "unstable_llm_providers")]
4873 ListProvidersRequest(ListProvidersRequest),
4874 #[cfg(feature = "unstable_llm_providers")]
4880 SetProviderRequest(Box<SetProviderRequest>),
4881 #[cfg(feature = "unstable_llm_providers")]
4887 DisableProviderRequest(DisableProviderRequest),
4888 LogoutRequest(LogoutRequest),
4893 NewSessionRequest(NewSessionRequest),
4906 LoadSessionRequest(LoadSessionRequest),
4917 ListSessionsRequest(ListSessionsRequest),
4923 DeleteSessionRequest(DeleteSessionRequest),
4927 #[cfg(feature = "unstable_session_fork")]
4928 ForkSessionRequest(ForkSessionRequest),
4940 ResumeSessionRequest(ResumeSessionRequest),
4947 CloseSessionRequest(CloseSessionRequest),
4954 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4956 PromptRequest(PromptRequest),
4968 #[cfg(feature = "unstable_nes")]
4969 StartNesRequest(Box<StartNesRequest>),
4975 #[cfg(feature = "unstable_nes")]
4976 SuggestNesRequest(Box<SuggestNesRequest>),
4982 #[cfg(feature = "unstable_nes")]
4983 CloseNesRequest(CloseNesRequest),
4992 #[cfg(feature = "unstable_mcp_over_acp")]
4998 MessageMcpRequest(MessageMcpRequest),
4999 ExtMethodRequest(ExtRequest),
5006}
5007
5008impl ClientRequest {
5009 #[must_use]
5011 pub fn method(&self) -> &str {
5012 match self {
5013 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
5014 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
5015 #[cfg(feature = "unstable_llm_providers")]
5016 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
5017 #[cfg(feature = "unstable_llm_providers")]
5018 Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
5019 #[cfg(feature = "unstable_llm_providers")]
5020 Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
5021 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
5022 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
5023 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
5024 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
5025 Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
5026 #[cfg(feature = "unstable_session_fork")]
5027 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
5028 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
5029 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
5030 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
5031 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
5032 #[cfg(feature = "unstable_nes")]
5033 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
5034 #[cfg(feature = "unstable_nes")]
5035 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
5036 #[cfg(feature = "unstable_nes")]
5037 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
5038 #[cfg(feature = "unstable_mcp_over_acp")]
5039 Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
5040 Self::ExtMethodRequest(ext_request) => &ext_request.method,
5041 }
5042 }
5043}
5044
5045#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5052#[serde(untagged)]
5053#[schemars(inline)]
5054#[non_exhaustive]
5055pub enum AgentResponse {
5056 InitializeResponse(Box<InitializeResponse>),
5057 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
5058 #[cfg(feature = "unstable_llm_providers")]
5059 ListProvidersResponse(ListProvidersResponse),
5060 #[cfg(feature = "unstable_llm_providers")]
5061 SetProviderResponse(#[serde(default)] SetProviderResponse),
5062 #[cfg(feature = "unstable_llm_providers")]
5063 DisableProviderResponse(#[serde(default)] DisableProviderResponse),
5064 LogoutResponse(#[serde(default)] LogoutResponse),
5065 NewSessionResponse(NewSessionResponse),
5066 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5067 ListSessionsResponse(ListSessionsResponse),
5068 DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
5069 #[cfg(feature = "unstable_session_fork")]
5070 ForkSessionResponse(ForkSessionResponse),
5071 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5072 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5073 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5074 PromptResponse(PromptResponse),
5075 #[cfg(feature = "unstable_nes")]
5076 StartNesResponse(StartNesResponse),
5077 #[cfg(feature = "unstable_nes")]
5078 SuggestNesResponse(SuggestNesResponse),
5079 #[cfg(feature = "unstable_nes")]
5080 CloseNesResponse(#[serde(default)] CloseNesResponse),
5081 ExtMethodResponse(ExtResponse),
5082 #[cfg(feature = "unstable_mcp_over_acp")]
5083 MessageMcpResponse(MessageMcpResponse),
5084}
5085
5086#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5093#[serde(untagged)]
5094#[schemars(inline)]
5095#[non_exhaustive]
5096pub enum ClientNotification {
5097 CancelNotification(CancelNotification),
5109 #[cfg(feature = "unstable_nes")]
5110 DidOpenDocumentNotification(DidOpenDocumentNotification),
5114 #[cfg(feature = "unstable_nes")]
5115 DidChangeDocumentNotification(DidChangeDocumentNotification),
5119 #[cfg(feature = "unstable_nes")]
5120 DidCloseDocumentNotification(DidCloseDocumentNotification),
5124 #[cfg(feature = "unstable_nes")]
5125 DidSaveDocumentNotification(DidSaveDocumentNotification),
5129 #[cfg(feature = "unstable_nes")]
5130 DidFocusDocumentNotification(Box<DidFocusDocumentNotification>),
5134 #[cfg(feature = "unstable_nes")]
5135 AcceptNesNotification(AcceptNesNotification),
5139 #[cfg(feature = "unstable_nes")]
5140 RejectNesNotification(RejectNesNotification),
5144 #[cfg(feature = "unstable_mcp_over_acp")]
5150 MessageMcpNotification(MessageMcpNotification),
5151 ExtNotification(ExtNotification),
5158}
5159
5160impl ClientNotification {
5161 #[must_use]
5163 pub fn method(&self) -> &str {
5164 match self {
5165 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5166 #[cfg(feature = "unstable_nes")]
5167 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5168 #[cfg(feature = "unstable_nes")]
5169 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5170 #[cfg(feature = "unstable_nes")]
5171 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5172 #[cfg(feature = "unstable_nes")]
5173 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5174 #[cfg(feature = "unstable_nes")]
5175 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5176 #[cfg(feature = "unstable_nes")]
5177 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5178 #[cfg(feature = "unstable_nes")]
5179 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5180 #[cfg(feature = "unstable_mcp_over_acp")]
5181 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5182 Self::ExtNotification(ext_notification) => &ext_notification.method,
5183 }
5184 }
5185}
5186
5187#[skip_serializing_none]
5191#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5192#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5193#[serde(rename_all = "camelCase")]
5194#[non_exhaustive]
5195pub struct CancelNotification {
5196 pub session_id: SessionId,
5198 #[serde(rename = "_meta")]
5204 pub meta: Option<Meta>,
5205}
5206
5207impl CancelNotification {
5208 #[must_use]
5209 pub fn new(session_id: impl Into<SessionId>) -> Self {
5210 Self {
5211 session_id: session_id.into(),
5212 meta: None,
5213 }
5214 }
5215
5216 #[must_use]
5222 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5223 self.meta = meta.into_option();
5224 self
5225 }
5226}
5227
5228#[cfg(test)]
5229mod test_serialization {
5230 use super::*;
5231 use serde_json::json;
5232
5233 fn test_meta() -> Meta {
5234 json!({ "source": "test" }).as_object().unwrap().clone()
5235 }
5236
5237 fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
5238 serde_json::to_string(value)
5239 .unwrap()
5240 .matches("\"_meta\"")
5241 .count()
5242 }
5243
5244 #[test]
5245 fn test_mcp_server_stdio_serialization() {
5246 let server = McpServer::Stdio(
5247 McpServerStdio::new("test-server", "/usr/bin/server")
5248 .args(vec!["--port".to_string(), "3000".to_string()])
5249 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5250 );
5251
5252 let json = serde_json::to_value(&server).unwrap();
5253 assert_eq!(
5254 json,
5255 json!({
5256 "type": "stdio",
5257 "name": "test-server",
5258 "command": "/usr/bin/server",
5259 "args": ["--port", "3000"],
5260 "env": [
5261 {
5262 "name": "API_KEY",
5263 "value": "secret123"
5264 }
5265 ]
5266 })
5267 );
5268
5269 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5270 match deserialized {
5271 McpServer::Stdio(McpServerStdio {
5272 name,
5273 command,
5274 args,
5275 env,
5276 meta: _,
5277 }) => {
5278 assert_eq!(name, "test-server");
5279 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5280 assert_eq!(args, vec!["--port", "3000"]);
5281 assert_eq!(env.len(), 1);
5282 assert_eq!(env[0].name, "API_KEY");
5283 assert_eq!(env[0].value, "secret123");
5284 }
5285 _ => panic!("Expected Stdio variant"),
5286 }
5287 }
5288
5289 #[test]
5290 fn test_mcp_server_unknown_transport_serialization() {
5291 let json = json!({
5292 "type": "websocket",
5293 "name": "future-server",
5294 "url": "wss://example.com/mcp",
5295 "protocolVersion": "2026-01-01"
5296 });
5297
5298 let deserialized: McpServer = serde_json::from_value(json.clone()).unwrap();
5299 let McpServer::Other(OtherMcpServer { type_, fields }) = &deserialized else {
5300 panic!("Expected Other variant");
5301 };
5302
5303 assert_eq!(type_, "websocket");
5304 assert_eq!(fields["name"], "future-server");
5305 assert_eq!(fields["url"], "wss://example.com/mcp");
5306 assert_eq!(fields["protocolVersion"], "2026-01-01");
5307 assert_eq!(serde_json::to_value(&deserialized).unwrap(), json);
5308 }
5309
5310 #[test]
5311 fn test_mcp_server_stdio_requires_type() {
5312 let result = serde_json::from_value::<McpServer>(json!({
5313 "name": "test-server",
5314 "command": "/usr/bin/server",
5315 "args": [],
5316 "env": []
5317 }));
5318
5319 assert!(result.is_err());
5320 }
5321
5322 #[test]
5323 fn test_mcp_server_unknown_does_not_hide_malformed_known_transport() {
5324 let result = serde_json::from_value::<McpServer>(json!({
5325 "type": "stdio",
5326 "name": "test-server",
5327 "args": [],
5328 "env": []
5329 }));
5330
5331 assert!(result.is_err());
5332 }
5333
5334 #[test]
5335 fn test_mcp_server_http_serialization() {
5336 let server = McpServer::Http(
5337 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5338 HttpHeader::new("Authorization", "Bearer token123"),
5339 HttpHeader::new("Content-Type", "application/json"),
5340 ]),
5341 );
5342
5343 let json = serde_json::to_value(&server).unwrap();
5344 assert_eq!(
5345 json,
5346 json!({
5347 "type": "http",
5348 "name": "http-server",
5349 "url": "https://api.example.com",
5350 "headers": [
5351 {
5352 "name": "Authorization",
5353 "value": "Bearer token123"
5354 },
5355 {
5356 "name": "Content-Type",
5357 "value": "application/json"
5358 }
5359 ]
5360 })
5361 );
5362
5363 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5364 match deserialized {
5365 McpServer::Http(McpServerHttp {
5366 name,
5367 url,
5368 headers,
5369 meta: _,
5370 }) => {
5371 assert_eq!(name, "http-server");
5372 assert_eq!(url, "https://api.example.com");
5373 assert_eq!(headers.len(), 2);
5374 assert_eq!(headers[0].name, "Authorization");
5375 assert_eq!(headers[0].value, "Bearer token123");
5376 assert_eq!(headers[1].name, "Content-Type");
5377 assert_eq!(headers[1].value, "application/json");
5378 }
5379 _ => panic!("Expected Http variant"),
5380 }
5381 }
5382
5383 #[cfg(feature = "unstable_mcp_over_acp")]
5384 #[test]
5385 fn test_client_mcp_message_method_names() {
5386 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5387
5388 assert_eq!(
5389 ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
5390 .method(),
5391 "mcp/message"
5392 );
5393 assert_eq!(
5394 ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
5395 "conn-1",
5396 "notifications/progress"
5397 ))
5398 .method(),
5399 "mcp/message"
5400 );
5401 }
5402
5403 #[test]
5404 fn test_session_config_option_category_known_variants() {
5405 assert_eq!(
5407 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5408 json!("mode")
5409 );
5410 assert_eq!(
5411 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5412 json!("model")
5413 );
5414 assert_eq!(
5415 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5416 json!("thought_level")
5417 );
5418
5419 assert_eq!(
5421 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5422 SessionConfigOptionCategory::Mode
5423 );
5424 assert_eq!(
5425 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5426 SessionConfigOptionCategory::Model
5427 );
5428 assert_eq!(
5429 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5430 SessionConfigOptionCategory::ThoughtLevel
5431 );
5432 }
5433
5434 #[test]
5435 fn test_session_config_option_category_unknown_variants() {
5436 let unknown: SessionConfigOptionCategory =
5438 serde_json::from_str("\"some_future_category\"").unwrap();
5439 assert_eq!(
5440 unknown,
5441 SessionConfigOptionCategory::Other("some_future_category".to_string())
5442 );
5443
5444 let json = serde_json::to_value(&unknown).unwrap();
5446 assert_eq!(json, json!("some_future_category"));
5447 }
5448
5449 #[test]
5450 fn test_session_config_option_category_custom_categories() {
5451 let custom: SessionConfigOptionCategory =
5453 serde_json::from_str("\"_my_custom_category\"").unwrap();
5454 assert_eq!(
5455 custom,
5456 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5457 );
5458
5459 let json = serde_json::to_value(&custom).unwrap();
5461 assert_eq!(json, json!("_my_custom_category"));
5462
5463 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5465 assert_eq!(
5466 deserialized,
5467 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5468 );
5469 }
5470
5471 #[test]
5472 fn test_auth_method_agent_serialization() {
5473 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5474
5475 let json = serde_json::to_value(&method).unwrap();
5476 assert_eq!(
5477 json,
5478 json!({
5479 "id": "default-auth",
5480 "name": "Default Auth",
5481 "type": "agent"
5482 })
5483 );
5484 assert!(!json.as_object().unwrap().contains_key("description"));
5486
5487 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5488 match deserialized {
5489 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5490 assert_eq!(id.0.as_ref(), "default-auth");
5491 assert_eq!(name, "Default Auth");
5492 }
5493 _ => panic!("Expected Agent variant"),
5494 }
5495 }
5496
5497 #[test]
5498 fn test_auth_method_agent_deserialization() {
5499 let json = json!({
5500 "id": "agent-auth",
5501 "name": "Agent Auth",
5502 "type": "agent"
5503 });
5504
5505 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5506 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5507 }
5508
5509 #[test]
5510 fn test_auth_method_agent_requires_type() {
5511 assert!(
5512 serde_json::from_value::<AuthMethod>(json!({
5513 "id": "agent-auth",
5514 "name": "Agent Auth"
5515 }))
5516 .is_err()
5517 );
5518 }
5519
5520 #[test]
5521 fn test_auth_method_agent_rejects_null_type() {
5522 assert!(
5523 serde_json::from_value::<AuthMethod>(json!({
5524 "id": "agent-auth",
5525 "name": "Agent Auth",
5526 "type": null
5527 }))
5528 .is_err()
5529 );
5530 }
5531
5532 #[test]
5533 fn test_auth_method_unknown_does_not_hide_malformed_agent() {
5534 assert!(
5535 serde_json::from_value::<AuthMethod>(json!({
5536 "id": "agent-auth",
5537 "type": "agent"
5538 }))
5539 .is_err()
5540 );
5541 }
5542
5543 #[test]
5544 fn test_auth_method_unknown_variant_roundtrip() {
5545 let method: AuthMethod = serde_json::from_value(json!({
5546 "id": "oauth",
5547 "name": "OAuth",
5548 "type": "_oauth",
5549 "authorizationUrl": "https://example.com/auth"
5550 }))
5551 .unwrap();
5552
5553 assert_eq!(method.id().0.as_ref(), "oauth");
5554 assert_eq!(method.name(), "OAuth");
5555 let AuthMethod::Other(unknown) = method else {
5556 panic!("expected unknown auth method");
5557 };
5558 assert_eq!(unknown.type_, "_oauth");
5559 assert_eq!(
5560 unknown.fields.get("authorizationUrl"),
5561 Some(&json!("https://example.com/auth"))
5562 );
5563
5564 assert_eq!(
5565 serde_json::to_value(AuthMethod::Other(unknown)).unwrap(),
5566 json!({
5567 "id": "oauth",
5568 "name": "OAuth",
5569 "type": "_oauth",
5570 "authorizationUrl": "https://example.com/auth"
5571 })
5572 );
5573 }
5574
5575 #[cfg(feature = "unstable_auth_methods")]
5576 #[test]
5577 fn test_auth_method_unknown_does_not_hide_malformed_known_variant() {
5578 assert!(
5579 serde_json::from_value::<AuthMethod>(json!({
5580 "id": "api-key",
5581 "name": "API Key",
5582 "type": "env_var"
5583 }))
5584 .is_err()
5585 );
5586 }
5587
5588 #[test]
5589 fn test_session_delete_serialization() {
5590 assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5591 assert_eq!(
5592 ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5593 "session/delete"
5594 );
5595 assert_eq!(
5596 serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5597 json!({
5598 "sessionId": "sess_abc123"
5599 })
5600 );
5601 assert_eq!(
5602 serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5603 json!({})
5604 );
5605 assert_eq!(
5606 serde_json::to_value(
5607 SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5608 )
5609 .unwrap(),
5610 json!({
5611 "delete": {}
5612 })
5613 );
5614 }
5615 #[test]
5616 fn test_session_additional_directories_serialization() {
5617 assert_eq!(
5618 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5619 json!({
5620 "cwd": "/home/user/project",
5621 "mcpServers": []
5622 })
5623 );
5624 assert_eq!(
5625 serde_json::to_value(
5626 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5627 PathBuf::from("/home/user/shared-lib"),
5628 PathBuf::from("/home/user/product-docs"),
5629 ])
5630 )
5631 .unwrap(),
5632 json!({
5633 "cwd": "/home/user/project",
5634 "additionalDirectories": [
5635 "/home/user/shared-lib",
5636 "/home/user/product-docs"
5637 ],
5638 "mcpServers": []
5639 })
5640 );
5641 assert_eq!(
5642 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5643 json!({
5644 "sessionId": "sess_abc123",
5645 "cwd": "/home/user/project"
5646 })
5647 );
5648 assert_eq!(
5649 serde_json::to_value(
5650 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5651 PathBuf::from("/home/user/shared-lib"),
5652 PathBuf::from("/home/user/product-docs"),
5653 ])
5654 )
5655 .unwrap(),
5656 json!({
5657 "sessionId": "sess_abc123",
5658 "cwd": "/home/user/project",
5659 "additionalDirectories": [
5660 "/home/user/shared-lib",
5661 "/home/user/product-docs"
5662 ]
5663 })
5664 );
5665 assert_eq!(
5666 serde_json::from_value::<SessionInfo>(json!({
5667 "sessionId": "sess_abc123",
5668 "cwd": "/home/user/project"
5669 }))
5670 .unwrap()
5671 .additional_directories,
5672 Vec::<PathBuf>::new()
5673 );
5674 }
5675 #[test]
5676 fn test_session_load_capabilities_serialization() {
5677 assert_eq!(
5678 serde_json::to_value(SessionCapabilities::new().load(SessionLoadCapabilities::new()))
5679 .unwrap(),
5680 json!({
5681 "load": {}
5682 })
5683 );
5684 }
5685
5686 #[test]
5687 fn test_session_additional_directories_capabilities_serialization() {
5688 assert_eq!(
5689 serde_json::to_value(
5690 SessionCapabilities::new()
5691 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5692 )
5693 .unwrap(),
5694 json!({
5695 "additionalDirectories": {}
5696 })
5697 );
5698 }
5699
5700 #[cfg(feature = "unstable_auth_methods")]
5701 #[test]
5702 fn test_auth_method_env_var_serialization() {
5703 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5704 "api-key",
5705 "API Key",
5706 vec![AuthEnvVar::new("API_KEY")],
5707 ));
5708
5709 let json = serde_json::to_value(&method).unwrap();
5710 assert_eq!(
5711 json,
5712 json!({
5713 "id": "api-key",
5714 "name": "API Key",
5715 "type": "env_var",
5716 "vars": [{"name": "API_KEY"}]
5717 })
5718 );
5719 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5721 assert!(
5722 !json["vars"][0]
5723 .as_object()
5724 .unwrap()
5725 .contains_key("optional")
5726 );
5727
5728 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5729 match deserialized {
5730 AuthMethod::EnvVar(AuthMethodEnvVar {
5731 id,
5732 name: method_name,
5733 vars,
5734 link,
5735 ..
5736 }) => {
5737 assert_eq!(id.0.as_ref(), "api-key");
5738 assert_eq!(method_name, "API Key");
5739 assert_eq!(vars.len(), 1);
5740 assert_eq!(vars[0].name, "API_KEY");
5741 assert!(vars[0].secret);
5742 assert!(!vars[0].optional);
5743 assert!(link.is_none());
5744 }
5745 _ => panic!("Expected EnvVar variant"),
5746 }
5747 }
5748
5749 #[cfg(feature = "unstable_auth_methods")]
5750 #[test]
5751 fn test_auth_method_env_var_with_link_serialization() {
5752 let method = AuthMethod::EnvVar(
5753 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5754 .link("https://example.com/keys"),
5755 );
5756
5757 let json = serde_json::to_value(&method).unwrap();
5758 assert_eq!(
5759 json,
5760 json!({
5761 "id": "api-key",
5762 "name": "API Key",
5763 "type": "env_var",
5764 "vars": [{"name": "API_KEY"}],
5765 "link": "https://example.com/keys"
5766 })
5767 );
5768
5769 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5770 match deserialized {
5771 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5772 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5773 }
5774 _ => panic!("Expected EnvVar variant"),
5775 }
5776 }
5777
5778 #[cfg(feature = "unstable_auth_methods")]
5779 #[test]
5780 fn test_auth_method_env_var_multiple_vars() {
5781 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5782 "azure-openai",
5783 "Azure OpenAI",
5784 vec![
5785 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5786 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5787 .label("Endpoint URL")
5788 .secret(false),
5789 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5790 .label("API Version")
5791 .secret(false)
5792 .optional(true),
5793 ],
5794 ));
5795
5796 let json = serde_json::to_value(&method).unwrap();
5797 assert_eq!(
5798 json,
5799 json!({
5800 "id": "azure-openai",
5801 "name": "Azure OpenAI",
5802 "type": "env_var",
5803 "vars": [
5804 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5805 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5806 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5807 ]
5808 })
5809 );
5810
5811 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5812 match deserialized {
5813 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5814 assert_eq!(vars.len(), 3);
5815 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5817 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5818 assert!(vars[0].secret);
5819 assert!(!vars[0].optional);
5820 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5822 assert!(!vars[1].secret);
5823 assert!(!vars[1].optional);
5824 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5826 assert!(!vars[2].secret);
5827 assert!(vars[2].optional);
5828 }
5829 _ => panic!("Expected EnvVar variant"),
5830 }
5831 }
5832
5833 #[cfg(feature = "unstable_auth_methods")]
5834 #[test]
5835 fn test_auth_method_terminal_serialization() {
5836 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5837
5838 let json = serde_json::to_value(&method).unwrap();
5839 assert_eq!(
5840 json,
5841 json!({
5842 "id": "tui-auth",
5843 "name": "Terminal Auth",
5844 "type": "terminal"
5845 })
5846 );
5847 assert!(!json.as_object().unwrap().contains_key("args"));
5849 assert!(!json.as_object().unwrap().contains_key("env"));
5850
5851 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5852 match deserialized {
5853 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5854 assert!(args.is_empty());
5855 assert!(env.is_empty());
5856 }
5857 _ => panic!("Expected Terminal variant"),
5858 }
5859 }
5860
5861 #[cfg(feature = "unstable_auth_methods")]
5862 #[test]
5863 fn test_auth_method_terminal_with_args_and_env_serialization() {
5864 use std::collections::HashMap;
5865
5866 let mut env = HashMap::new();
5867 env.insert("TERM".to_string(), "xterm-256color".to_string());
5868
5869 let method = AuthMethod::Terminal(
5870 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5871 .args(vec!["--interactive".to_string(), "--color".to_string()])
5872 .env(env),
5873 );
5874
5875 let json = serde_json::to_value(&method).unwrap();
5876 assert_eq!(
5877 json,
5878 json!({
5879 "id": "tui-auth",
5880 "name": "Terminal Auth",
5881 "type": "terminal",
5882 "args": ["--interactive", "--color"],
5883 "env": {
5884 "TERM": "xterm-256color"
5885 }
5886 })
5887 );
5888
5889 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5890 match deserialized {
5891 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5892 assert_eq!(args, vec!["--interactive", "--color"]);
5893 assert_eq!(env.len(), 1);
5894 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5895 }
5896 _ => panic!("Expected Terminal variant"),
5897 }
5898 }
5899
5900 #[cfg(feature = "unstable_boolean_config")]
5901 #[test]
5902 fn test_session_config_option_value_id_serialize() {
5903 let val = SessionConfigOptionValue::value_id("model-1");
5904 let json = serde_json::to_value(&val).unwrap();
5905 assert_eq!(json, json!({ "value": "model-1" }));
5907 assert!(!json.as_object().unwrap().contains_key("type"));
5908 }
5909
5910 #[cfg(feature = "unstable_boolean_config")]
5911 #[test]
5912 fn test_session_config_option_value_boolean_serialize() {
5913 let val = SessionConfigOptionValue::boolean(true);
5914 let json = serde_json::to_value(&val).unwrap();
5915 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5916 }
5917
5918 #[cfg(feature = "unstable_boolean_config")]
5919 #[test]
5920 fn test_session_config_option_value_deserialize_no_type() {
5921 let json = json!({ "value": "model-1" });
5923 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5924 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5925 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5926 }
5927
5928 #[cfg(feature = "unstable_boolean_config")]
5929 #[test]
5930 fn test_session_config_option_value_deserialize_boolean() {
5931 let json = json!({ "type": "boolean", "value": true });
5932 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5933 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5934 assert_eq!(val.as_bool(), Some(true));
5935 }
5936
5937 #[cfg(feature = "unstable_boolean_config")]
5938 #[test]
5939 fn test_session_config_option_value_deserialize_boolean_false() {
5940 let json = json!({ "type": "boolean", "value": false });
5941 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5942 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5943 assert_eq!(val.as_bool(), Some(false));
5944 }
5945
5946 #[cfg(feature = "unstable_boolean_config")]
5947 #[test]
5948 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5949 let json = json!({ "type": "text", "value": "freeform input" });
5951 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5952 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5953 }
5954
5955 #[cfg(feature = "unstable_boolean_config")]
5956 #[test]
5957 fn test_session_config_option_value_roundtrip_value_id() {
5958 let original = SessionConfigOptionValue::value_id("option-a");
5959 let json = serde_json::to_value(&original).unwrap();
5960 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5961 assert_eq!(original, roundtripped);
5962 }
5963
5964 #[cfg(feature = "unstable_boolean_config")]
5965 #[test]
5966 fn test_session_config_option_value_roundtrip_boolean() {
5967 let original = SessionConfigOptionValue::boolean(false);
5968 let json = serde_json::to_value(&original).unwrap();
5969 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5970 assert_eq!(original, roundtripped);
5971 }
5972
5973 #[cfg(feature = "unstable_boolean_config")]
5974 #[test]
5975 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5976 let json = json!({ "type": "boolean", "value": "not a bool" });
5978 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5979 assert!(result.is_ok());
5981 assert_eq!(
5982 result.unwrap().as_value_id().unwrap().to_string(),
5983 "not a bool"
5984 );
5985 }
5986
5987 #[cfg(feature = "unstable_boolean_config")]
5988 #[test]
5989 fn test_session_config_option_value_from_impls() {
5990 let from_str: SessionConfigOptionValue = "model-1".into();
5991 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5992
5993 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5994 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5995
5996 let from_bool: SessionConfigOptionValue = true.into();
5997 assert_eq!(from_bool.as_bool(), Some(true));
5998 }
5999
6000 #[cfg(feature = "unstable_boolean_config")]
6001 #[test]
6002 fn test_set_session_config_option_request_value_id() {
6003 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
6004 let json = serde_json::to_value(&req).unwrap();
6005 assert_eq!(
6006 json,
6007 json!({
6008 "sessionId": "sess_1",
6009 "configId": "model",
6010 "value": "model-1"
6011 })
6012 );
6013 assert!(!json.as_object().unwrap().contains_key("type"));
6015 }
6016
6017 #[cfg(feature = "unstable_boolean_config")]
6018 #[test]
6019 fn test_set_session_config_option_request_boolean() {
6020 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
6021 let json = serde_json::to_value(&req).unwrap();
6022 assert_eq!(
6023 json,
6024 json!({
6025 "sessionId": "sess_1",
6026 "configId": "brave_mode",
6027 "type": "boolean",
6028 "value": true
6029 })
6030 );
6031 }
6032
6033 #[cfg(feature = "unstable_boolean_config")]
6034 #[test]
6035 fn test_set_session_config_option_request_deserialize_no_type() {
6036 let json = json!({
6038 "sessionId": "sess_1",
6039 "configId": "model",
6040 "value": "model-1"
6041 });
6042 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6043 assert_eq!(req.session_id.to_string(), "sess_1");
6044 assert_eq!(req.config_id.to_string(), "model");
6045 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
6046 }
6047
6048 #[cfg(feature = "unstable_boolean_config")]
6049 #[test]
6050 fn test_set_session_config_option_request_deserialize_boolean() {
6051 let json = json!({
6052 "sessionId": "sess_1",
6053 "configId": "brave_mode",
6054 "type": "boolean",
6055 "value": true
6056 });
6057 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6058 assert_eq!(req.value.as_bool(), Some(true));
6059 }
6060
6061 #[cfg(feature = "unstable_boolean_config")]
6062 #[test]
6063 fn test_set_session_config_option_request_roundtrip_value_id() {
6064 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
6065 let json = serde_json::to_value(&original).unwrap();
6066 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6067 assert_eq!(original, roundtripped);
6068 }
6069
6070 #[cfg(feature = "unstable_boolean_config")]
6071 #[test]
6072 fn test_set_session_config_option_request_roundtrip_boolean() {
6073 let original = SetSessionConfigOptionRequest::new("s", "c", false);
6074 let json = serde_json::to_value(&original).unwrap();
6075 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6076 assert_eq!(original, roundtripped);
6077 }
6078
6079 #[cfg(feature = "unstable_boolean_config")]
6080 #[test]
6081 fn test_session_config_boolean_serialization() {
6082 let cfg = SessionConfigBoolean::new(true);
6083 let json = serde_json::to_value(&cfg).unwrap();
6084 assert_eq!(json, json!({ "currentValue": true }));
6085
6086 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6087 assert!(deserialized.current_value);
6088 }
6089
6090 #[cfg(feature = "unstable_boolean_config")]
6091 #[test]
6092 fn test_session_config_option_boolean_variant() {
6093 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6094 .description("Skip confirmation prompts")
6095 .meta(test_meta());
6096 assert_eq!(serialized_meta_key_count(&opt), 1);
6097
6098 let json = serde_json::to_value(&opt).unwrap();
6099 assert_eq!(
6100 json,
6101 json!({
6102 "id": "brave_mode",
6103 "name": "Brave Mode",
6104 "description": "Skip confirmation prompts",
6105 "type": "boolean",
6106 "currentValue": false,
6107 "_meta": {
6108 "source": "test"
6109 }
6110 })
6111 );
6112
6113 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6114 assert_eq!(deserialized.id.to_string(), "brave_mode");
6115 assert_eq!(deserialized.name, "Brave Mode");
6116 match deserialized.kind {
6117 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6118 _ => panic!("Expected Boolean kind"),
6119 }
6120 }
6121
6122 #[cfg(feature = "unstable_boolean_config")]
6123 #[test]
6124 fn test_session_config_option_select_still_works() {
6125 let opt = SessionConfigOption::select(
6127 "model",
6128 "Model",
6129 "model-1",
6130 vec![
6131 SessionConfigSelectOption::new("model-1", "Model 1"),
6132 SessionConfigSelectOption::new("model-2", "Model 2"),
6133 ],
6134 )
6135 .meta(test_meta());
6136 assert_eq!(serialized_meta_key_count(&opt), 1);
6137
6138 let json = serde_json::to_value(&opt).unwrap();
6139 assert_eq!(json["type"], "select");
6140 assert_eq!(json["currentValue"], "model-1");
6141 assert_eq!(json["options"].as_array().unwrap().len(), 2);
6142 assert_eq!(json["_meta"]["source"], "test");
6143
6144 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6145 match deserialized.kind {
6146 SessionConfigKind::Select(ref s) => {
6147 assert_eq!(s.current_value.to_string(), "model-1");
6148 }
6149 _ => panic!("Expected Select kind"),
6150 }
6151 }
6152
6153 #[test]
6154 fn test_session_config_option_unknown_kind_roundtrip() {
6155 let option: SessionConfigOption = serde_json::from_value(json!({
6156 "id": "verbosity",
6157 "name": "Verbosity",
6158 "type": "_slider",
6159 "currentValue": 3,
6160 "min": 0,
6161 "max": 5,
6162 "_meta": {
6163 "source": "test"
6164 }
6165 }))
6166 .unwrap();
6167
6168 assert_eq!(option.id.to_string(), "verbosity");
6169 assert_eq!(option.meta.as_ref().unwrap()["source"], "test");
6170 let SessionConfigKind::Other(unknown) = &option.kind else {
6171 panic!("expected unknown config kind");
6172 };
6173 assert_eq!(unknown.type_, "_slider");
6174 assert_eq!(unknown.fields.get("currentValue"), Some(&json!(3)));
6175 assert!(!unknown.fields.contains_key("_meta"));
6176 assert_eq!(serialized_meta_key_count(&option), 1);
6177
6178 let json = serde_json::to_value(&option).unwrap();
6179 assert_eq!(json["type"], "_slider");
6180 assert_eq!(json["currentValue"], 3);
6181 assert_eq!(json["min"], 0);
6182 assert_eq!(json["max"], 5);
6183 assert_eq!(json["_meta"]["source"], "test");
6184 }
6185
6186 #[test]
6187 fn test_session_config_option_unknown_kind_does_not_duplicate_flattened_meta() {
6188 let mut fields = std::collections::BTreeMap::new();
6189 fields.insert("currentValue".to_string(), json!(3));
6190 fields.insert("_meta".to_string(), json!({ "inner": "ignored" }));
6191
6192 let option = SessionConfigOption::new(
6193 "verbosity",
6194 "Verbosity",
6195 SessionConfigKind::Other(OtherSessionConfigKind::new("_slider", fields)),
6196 )
6197 .meta(test_meta());
6198
6199 let SessionConfigKind::Other(unknown) = &option.kind else {
6200 panic!("expected unknown config kind");
6201 };
6202 assert!(!unknown.fields.contains_key("_meta"));
6203 assert_eq!(serialized_meta_key_count(&option), 1);
6204
6205 let json = serde_json::to_value(&option).unwrap();
6206 assert_eq!(json["type"], "_slider");
6207 assert_eq!(json["currentValue"], 3);
6208 assert_eq!(json["_meta"]["source"], "test");
6209 }
6210
6211 #[test]
6212 fn test_session_config_option_unknown_does_not_hide_malformed_known_kind() {
6213 assert!(
6214 serde_json::from_value::<SessionConfigOption>(json!({
6215 "id": "model",
6216 "name": "Model",
6217 "type": "select"
6218 }))
6219 .is_err()
6220 );
6221 }
6222
6223 #[cfg(feature = "unstable_llm_providers")]
6224 #[test]
6225 fn test_llm_protocol_known_variants() {
6226 assert_eq!(
6227 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6228 json!("anthropic")
6229 );
6230 assert_eq!(
6231 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6232 json!("openai")
6233 );
6234 assert_eq!(
6235 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6236 json!("azure")
6237 );
6238 assert_eq!(
6239 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6240 json!("vertex")
6241 );
6242 assert_eq!(
6243 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6244 json!("bedrock")
6245 );
6246
6247 assert_eq!(
6248 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6249 LlmProtocol::Anthropic
6250 );
6251 assert_eq!(
6252 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6253 LlmProtocol::OpenAi
6254 );
6255 assert_eq!(
6256 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6257 LlmProtocol::Azure
6258 );
6259 assert_eq!(
6260 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6261 LlmProtocol::Vertex
6262 );
6263 assert_eq!(
6264 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6265 LlmProtocol::Bedrock
6266 );
6267 }
6268
6269 #[cfg(feature = "unstable_llm_providers")]
6270 #[test]
6271 fn test_llm_protocol_unknown_variant() {
6272 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6273 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6274
6275 let json = serde_json::to_value(&unknown).unwrap();
6276 assert_eq!(json, json!("cohere"));
6277 }
6278
6279 #[cfg(feature = "unstable_llm_providers")]
6280 #[test]
6281 fn test_provider_current_config_serialization() {
6282 let config =
6283 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6284
6285 let json = serde_json::to_value(&config).unwrap();
6286 assert_eq!(
6287 json,
6288 json!({
6289 "apiType": "anthropic",
6290 "baseUrl": "https://api.anthropic.com"
6291 })
6292 );
6293
6294 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6295 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6296 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6297 }
6298
6299 #[cfg(feature = "unstable_llm_providers")]
6300 #[test]
6301 fn test_provider_info_with_current_config() {
6302 let info = ProviderInfo::new(
6303 "main",
6304 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6305 true,
6306 Some(ProviderCurrentConfig::new(
6307 LlmProtocol::Anthropic,
6308 "https://api.anthropic.com",
6309 )),
6310 );
6311
6312 let json = serde_json::to_value(&info).unwrap();
6313 assert_eq!(
6314 json,
6315 json!({
6316 "id": "main",
6317 "supported": ["anthropic", "openai"],
6318 "required": true,
6319 "current": {
6320 "apiType": "anthropic",
6321 "baseUrl": "https://api.anthropic.com"
6322 }
6323 })
6324 );
6325
6326 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6327 assert_eq!(deserialized.id, "main");
6328 assert_eq!(deserialized.supported.len(), 2);
6329 assert!(deserialized.required);
6330 assert!(deserialized.current.is_some());
6331 assert_eq!(
6332 deserialized.current.as_ref().unwrap().api_type,
6333 LlmProtocol::Anthropic
6334 );
6335 }
6336
6337 #[cfg(feature = "unstable_llm_providers")]
6338 #[test]
6339 fn test_provider_info_disabled() {
6340 let info = ProviderInfo::new(
6341 "secondary",
6342 vec![LlmProtocol::OpenAi],
6343 false,
6344 None::<ProviderCurrentConfig>,
6345 );
6346
6347 let json = serde_json::to_value(&info).unwrap();
6348 assert_eq!(
6349 json,
6350 json!({
6351 "id": "secondary",
6352 "supported": ["openai"],
6353 "required": false
6354 })
6355 );
6356
6357 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6358 assert_eq!(deserialized.id, "secondary");
6359 assert!(!deserialized.required);
6360 assert!(deserialized.current.is_none());
6361 }
6362
6363 #[cfg(feature = "unstable_llm_providers")]
6364 #[test]
6365 fn test_provider_info_missing_current_defaults_to_none() {
6366 let json = json!({
6368 "id": "main",
6369 "supported": ["anthropic"],
6370 "required": true
6371 });
6372 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6373 assert!(deserialized.current.is_none());
6374 }
6375
6376 #[cfg(feature = "unstable_llm_providers")]
6377 #[test]
6378 fn test_provider_info_explicit_null_current_decodes_to_none() {
6379 let json = json!({
6383 "id": "main",
6384 "supported": ["anthropic"],
6385 "required": true,
6386 "current": null
6387 });
6388 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6389 assert!(deserialized.current.is_none());
6390 }
6391
6392 #[cfg(feature = "unstable_llm_providers")]
6393 #[test]
6394 fn test_list_providers_response_serialization() {
6395 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6396 "main",
6397 vec![LlmProtocol::Anthropic],
6398 true,
6399 Some(ProviderCurrentConfig::new(
6400 LlmProtocol::Anthropic,
6401 "https://api.anthropic.com",
6402 )),
6403 )]);
6404
6405 let json = serde_json::to_value(&response).unwrap();
6406 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6407 assert_eq!(json["providers"][0]["id"], "main");
6408
6409 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6410 assert_eq!(deserialized.providers.len(), 1);
6411 }
6412
6413 #[cfg(feature = "unstable_llm_providers")]
6414 #[test]
6415 fn test_set_provider_request_serialization() {
6416 use std::collections::HashMap;
6417
6418 let mut headers = HashMap::new();
6419 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6420
6421 let request =
6422 SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6423 .headers(headers);
6424
6425 let json = serde_json::to_value(&request).unwrap();
6426 assert_eq!(
6427 json,
6428 json!({
6429 "id": "main",
6430 "apiType": "openai",
6431 "baseUrl": "https://api.openai.com/v1",
6432 "headers": {
6433 "Authorization": "Bearer sk-test"
6434 }
6435 })
6436 );
6437
6438 let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6439 assert_eq!(deserialized.id, "main");
6440 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6441 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6442 assert_eq!(deserialized.headers.len(), 1);
6443 assert_eq!(
6444 deserialized.headers.get("Authorization").unwrap(),
6445 "Bearer sk-test"
6446 );
6447 }
6448
6449 #[cfg(feature = "unstable_llm_providers")]
6450 #[test]
6451 fn test_set_provider_request_omits_empty_headers() {
6452 let request =
6453 SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6454
6455 let json = serde_json::to_value(&request).unwrap();
6456 assert!(!json.as_object().unwrap().contains_key("headers"));
6458 }
6459
6460 #[cfg(feature = "unstable_llm_providers")]
6461 #[test]
6462 fn test_disable_provider_request_serialization() {
6463 let request = DisableProviderRequest::new("secondary");
6464
6465 let json = serde_json::to_value(&request).unwrap();
6466 assert_eq!(json, json!({ "id": "secondary" }));
6467
6468 let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6469 assert_eq!(deserialized.id, "secondary");
6470 }
6471
6472 #[cfg(feature = "unstable_llm_providers")]
6473 #[test]
6474 fn test_providers_capabilities_serialization() {
6475 let caps = ProvidersCapabilities::new();
6476
6477 let json = serde_json::to_value(&caps).unwrap();
6478 assert_eq!(json, json!({}));
6479
6480 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6481 assert!(deserialized.meta.is_none());
6482 }
6483
6484 #[cfg(feature = "unstable_llm_providers")]
6485 #[test]
6486 fn test_agent_capabilities_with_providers() {
6487 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6488
6489 let json = serde_json::to_value(&caps).unwrap();
6490 assert_eq!(json["providers"], json!({}));
6491
6492 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6493 assert!(deserialized.providers.is_some());
6494 }
6495
6496 #[test]
6497 fn test_agent_capabilities_session_is_explicit() {
6498 let json = serde_json::to_value(AgentCapabilities::new()).unwrap();
6499 assert!(json.get("session").is_none());
6500
6501 let caps = AgentCapabilities::new().session(
6502 SessionCapabilities::new()
6503 .prompt(PromptCapabilities::new().image(PromptImageCapabilities::new()))
6504 .mcp(McpCapabilities::new().stdio(McpStdioCapabilities::new()))
6505 .load(SessionLoadCapabilities::new()),
6506 );
6507
6508 assert_eq!(
6509 serde_json::to_value(&caps).unwrap(),
6510 json!({
6511 "auth": {},
6512 "session": {
6513 "prompt": {
6514 "image": {}
6515 },
6516 "mcp": {
6517 "stdio": {}
6518 },
6519 "load": {}
6520 }
6521 })
6522 );
6523
6524 let deserialized: AgentCapabilities = serde_json::from_value(json!({
6525 "session": false
6526 }))
6527 .unwrap();
6528 assert!(deserialized.session.is_none());
6529 }
6530
6531 #[test]
6532 fn test_prompt_capabilities_serialize_supported_content_as_objects() {
6533 let caps = PromptCapabilities::new()
6534 .image(PromptImageCapabilities::new())
6535 .audio(PromptAudioCapabilities::new())
6536 .embedded_context(PromptEmbeddedContextCapabilities::new());
6537
6538 assert_eq!(
6539 serde_json::to_value(&caps).unwrap(),
6540 json!({
6541 "image": {},
6542 "audio": {},
6543 "embeddedContext": {}
6544 })
6545 );
6546
6547 let deserialized: PromptCapabilities = serde_json::from_value(json!({
6548 "image": null,
6549 "audio": false,
6550 "embeddedContext": {}
6551 }))
6552 .unwrap();
6553 assert!(deserialized.image.is_none());
6554 assert!(deserialized.audio.is_none());
6555 assert!(deserialized.embedded_context.is_some());
6556 }
6557
6558 #[test]
6559 fn test_mcp_capabilities_serialize_supported_transports_as_objects() {
6560 let caps = McpCapabilities::new()
6561 .stdio(McpStdioCapabilities::new())
6562 .http(McpHttpCapabilities::new());
6563
6564 assert_eq!(
6565 serde_json::to_value(&caps).unwrap(),
6566 json!({
6567 "stdio": {},
6568 "http": {}
6569 })
6570 );
6571
6572 let deserialized: McpCapabilities = serde_json::from_value(json!({
6573 "stdio": null,
6574 "http": false
6575 }))
6576 .unwrap();
6577 assert!(deserialized.stdio.is_none());
6578 assert!(deserialized.http.is_none());
6579 }
6580
6581 #[cfg(feature = "unstable_mcp_over_acp")]
6582 #[test]
6583 fn test_mcp_capabilities_serialize_acp_support_as_object() {
6584 let caps = McpCapabilities::new().acp(McpAcpCapabilities::new());
6585
6586 assert_eq!(
6587 serde_json::to_value(&caps).unwrap(),
6588 json!({
6589 "acp": {}
6590 })
6591 );
6592 }
6593}