1use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
7
8#[cfg(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};
19#[cfg(feature = "unstable_auth_methods")]
20use crate::DefaultTrueOnError;
21use crate::{IntoOption, ProtocolVersion, SkipListener};
22
23#[cfg(feature = "unstable_mcp_over_acp")]
24use super::mcp::{
25 MCP_MESSAGE_METHOD_NAME, MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
26};
27
28#[cfg(feature = "unstable_nes")]
29use super::{
30 AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
31 DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
32 DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
33 StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
34};
35
36#[cfg(feature = "unstable_nes")]
37use super::{
38 DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
39 DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
40 NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
41 NES_SUGGEST_METHOD_NAME,
42};
43
44#[serde_as]
52#[skip_serializing_none]
53#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
54#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
55#[serde(rename_all = "camelCase")]
56#[non_exhaustive]
57pub struct InitializeRequest {
58 pub protocol_version: ProtocolVersion,
60 pub info: Implementation,
62 #[serde_as(deserialize_as = "DefaultOnError")]
64 #[schemars(extend("x-deserialize-default-on-error" = true))]
65 #[serde(default)]
66 pub capabilities: ClientCapabilities,
67 #[serde_as(deserialize_as = "DefaultOnError")]
73 #[schemars(extend("x-deserialize-default-on-error" = true))]
74 #[serde(default)]
75 #[serde(rename = "_meta")]
76 pub meta: Option<Meta>,
77}
78
79impl InitializeRequest {
80 #[must_use]
82 pub fn new(protocol_version: ProtocolVersion, info: Implementation) -> Self {
83 Self {
84 protocol_version,
85 capabilities: ClientCapabilities::default(),
86 info,
87 meta: None,
88 }
89 }
90
91 #[must_use]
93 pub fn capabilities(mut self, capabilities: ClientCapabilities) -> Self {
94 self.capabilities = capabilities;
95 self
96 }
97
98 #[must_use]
104 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
105 self.meta = meta.into_option();
106 self
107 }
108}
109
110#[serde_as]
116#[skip_serializing_none]
117#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
118#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
119#[serde(rename_all = "camelCase")]
120#[non_exhaustive]
121pub struct InitializeResponse {
122 pub protocol_version: ProtocolVersion,
127 pub info: Implementation,
129 #[serde_as(deserialize_as = "DefaultOnError")]
131 #[schemars(extend("x-deserialize-default-on-error" = true))]
132 #[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")]
145 #[schemars(extend("x-deserialize-default-on-error" = true))]
146 #[serde(default)]
147 #[serde(rename = "_meta")]
148 pub meta: Option<Meta>,
149}
150
151impl InitializeResponse {
152 #[must_use]
154 pub fn new(protocol_version: ProtocolVersion, info: Implementation) -> Self {
155 Self {
156 protocol_version,
157 capabilities: AgentCapabilities::default(),
158 auth_methods: vec![],
159 info,
160 meta: None,
161 }
162 }
163
164 #[must_use]
166 pub fn capabilities(mut self, capabilities: AgentCapabilities) -> Self {
167 self.capabilities = capabilities;
168 self
169 }
170
171 #[must_use]
173 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
174 self.auth_methods = auth_methods;
175 self
176 }
177
178 #[must_use]
184 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
185 self.meta = meta.into_option();
186 self
187 }
188}
189
190#[serde_as]
194#[skip_serializing_none]
195#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
196#[serde(rename_all = "camelCase")]
197#[non_exhaustive]
198pub struct Implementation {
199 pub name: String,
202 #[serde_as(deserialize_as = "DefaultOnError")]
207 #[schemars(extend("x-deserialize-default-on-error" = true))]
208 #[serde(default)]
209 pub title: Option<String>,
210 pub version: String,
213 #[serde_as(deserialize_as = "DefaultOnError")]
219 #[schemars(extend("x-deserialize-default-on-error" = true))]
220 #[serde(default)]
221 #[serde(rename = "_meta")]
222 pub meta: Option<Meta>,
223}
224
225impl Implementation {
226 #[must_use]
228 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
229 Self {
230 name: name.into(),
231 title: None,
232 version: version.into(),
233 meta: None,
234 }
235 }
236
237 #[must_use]
242 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
243 self.title = title.into_option();
244 self
245 }
246
247 #[must_use]
253 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
254 self.meta = meta.into_option();
255 self
256 }
257}
258
259#[serde_as]
265#[skip_serializing_none]
266#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
267#[schemars(extend("x-side" = "agent", "x-method" = AUTH_LOGIN_METHOD_NAME))]
268#[serde(rename_all = "camelCase")]
269#[non_exhaustive]
270pub struct LoginAuthRequest {
271 pub method_id: AuthMethodId,
274 #[serde_as(deserialize_as = "DefaultOnError")]
280 #[schemars(extend("x-deserialize-default-on-error" = true))]
281 #[serde(default)]
282 #[serde(rename = "_meta")]
283 pub meta: Option<Meta>,
284}
285
286impl LoginAuthRequest {
287 #[must_use]
289 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
290 Self {
291 method_id: method_id.into(),
292 meta: None,
293 }
294 }
295
296 #[must_use]
302 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
303 self.meta = meta.into_option();
304 self
305 }
306}
307
308#[serde_as]
310#[skip_serializing_none]
311#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
312#[schemars(extend("x-side" = "agent", "x-method" = AUTH_LOGIN_METHOD_NAME))]
313#[serde(rename_all = "camelCase")]
314#[non_exhaustive]
315pub struct LoginAuthResponse {
316 #[serde_as(deserialize_as = "DefaultOnError")]
322 #[schemars(extend("x-deserialize-default-on-error" = true))]
323 #[serde(default)]
324 #[serde(rename = "_meta")]
325 pub meta: Option<Meta>,
326}
327
328impl LoginAuthResponse {
329 #[must_use]
331 pub fn new() -> Self {
332 Self::default()
333 }
334
335 #[must_use]
341 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
342 self.meta = meta.into_option();
343 self
344 }
345}
346
347#[serde_as]
353#[skip_serializing_none]
354#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
355#[schemars(extend("x-side" = "agent", "x-method" = AUTH_LOGOUT_METHOD_NAME))]
356#[serde(rename_all = "camelCase")]
357#[non_exhaustive]
358pub struct LogoutAuthRequest {
359 #[serde_as(deserialize_as = "DefaultOnError")]
365 #[schemars(extend("x-deserialize-default-on-error" = true))]
366 #[serde(default)]
367 #[serde(rename = "_meta")]
368 pub meta: Option<Meta>,
369}
370
371impl LogoutAuthRequest {
372 #[must_use]
374 pub fn new() -> Self {
375 Self::default()
376 }
377
378 #[must_use]
384 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
385 self.meta = meta.into_option();
386 self
387 }
388}
389
390#[serde_as]
392#[skip_serializing_none]
393#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
394#[schemars(extend("x-side" = "agent", "x-method" = AUTH_LOGOUT_METHOD_NAME))]
395#[serde(rename_all = "camelCase")]
396#[non_exhaustive]
397pub struct LogoutAuthResponse {
398 #[serde_as(deserialize_as = "DefaultOnError")]
404 #[schemars(extend("x-deserialize-default-on-error" = true))]
405 #[serde(default)]
406 #[serde(rename = "_meta")]
407 pub meta: Option<Meta>,
408}
409
410impl LogoutAuthResponse {
411 #[must_use]
413 pub fn new() -> Self {
414 Self::default()
415 }
416
417 #[must_use]
423 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
424 self.meta = meta.into_option();
425 self
426 }
427}
428
429#[serde_as]
431#[skip_serializing_none]
432#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
433#[serde(rename_all = "camelCase")]
434#[non_exhaustive]
435pub struct AgentAuthCapabilities {
436 #[serde_as(deserialize_as = "DefaultOnError")]
442 #[schemars(extend("x-deserialize-default-on-error" = true))]
443 #[serde(default)]
444 #[serde(rename = "_meta")]
445 pub meta: Option<Meta>,
446}
447
448impl AgentAuthCapabilities {
449 #[must_use]
451 pub fn new() -> Self {
452 Self::default()
453 }
454
455 #[must_use]
461 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
462 self.meta = meta.into_option();
463 self
464 }
465}
466
467#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
469#[serde(transparent)]
470#[from(Arc<str>, String, &'static str)]
471#[non_exhaustive]
472pub struct AuthMethodId(pub Arc<str>);
473
474impl AuthMethodId {
475 #[must_use]
477 pub fn new(id: impl Into<Arc<str>>) -> Self {
478 Self(id.into())
479 }
480}
481
482#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
486#[serde(tag = "type", rename_all = "snake_case")]
487#[non_exhaustive]
488pub enum AuthMethod {
489 #[cfg(feature = "unstable_auth_methods")]
495 EnvVar(AuthMethodEnvVar),
496 #[cfg(feature = "unstable_auth_methods")]
502 Terminal(AuthMethodTerminal),
503 Agent(AuthMethodAgent),
507 #[serde(untagged)]
517 Other(OtherAuthMethod),
518}
519
520impl AuthMethod {
521 #[must_use]
523 pub fn id(&self) -> &AuthMethodId {
524 match self {
525 Self::Agent(a) => &a.id,
526 Self::Other(a) => &a.id,
527 #[cfg(feature = "unstable_auth_methods")]
528 Self::EnvVar(e) => &e.id,
529 #[cfg(feature = "unstable_auth_methods")]
530 Self::Terminal(t) => &t.id,
531 }
532 }
533
534 #[must_use]
536 pub fn name(&self) -> &str {
537 match self {
538 Self::Agent(a) => &a.name,
539 Self::Other(a) => &a.name,
540 #[cfg(feature = "unstable_auth_methods")]
541 Self::EnvVar(e) => &e.name,
542 #[cfg(feature = "unstable_auth_methods")]
543 Self::Terminal(t) => &t.name,
544 }
545 }
546
547 #[must_use]
549 pub fn description(&self) -> Option<&str> {
550 match self {
551 Self::Agent(a) => a.description.as_deref(),
552 Self::Other(a) => a.description.as_deref(),
553 #[cfg(feature = "unstable_auth_methods")]
554 Self::EnvVar(e) => e.description.as_deref(),
555 #[cfg(feature = "unstable_auth_methods")]
556 Self::Terminal(t) => t.description.as_deref(),
557 }
558 }
559
560 #[must_use]
566 pub fn meta(&self) -> Option<&Meta> {
567 match self {
568 Self::Agent(a) => a.meta.as_ref(),
569 Self::Other(a) => a.meta.as_ref(),
570 #[cfg(feature = "unstable_auth_methods")]
571 Self::EnvVar(e) => e.meta.as_ref(),
572 #[cfg(feature = "unstable_auth_methods")]
573 Self::Terminal(t) => t.meta.as_ref(),
574 }
575 }
576}
577
578#[serde_as]
580#[skip_serializing_none]
581#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
582#[schemars(inline)]
583#[schemars(transform = other_auth_method_schema)]
584#[serde(rename_all = "camelCase")]
585#[non_exhaustive]
586pub struct OtherAuthMethod {
587 #[serde(rename = "type")]
593 pub type_: String,
594 pub id: AuthMethodId,
596 pub name: String,
598 #[serde_as(deserialize_as = "DefaultOnError")]
600 #[schemars(extend("x-deserialize-default-on-error" = true))]
601 #[serde(default)]
602 pub description: Option<String>,
603 #[serde_as(deserialize_as = "DefaultOnError")]
609 #[schemars(extend("x-deserialize-default-on-error" = true))]
610 #[serde(default)]
611 #[serde(rename = "_meta")]
612 pub meta: Option<Meta>,
613 #[serde(flatten)]
615 pub fields: BTreeMap<String, serde_json::Value>,
616}
617
618impl OtherAuthMethod {
619 #[must_use]
621 pub fn new(
622 type_: impl Into<String>,
623 id: impl Into<AuthMethodId>,
624 name: impl Into<String>,
625 mut fields: BTreeMap<String, serde_json::Value>,
626 ) -> Self {
627 fields.remove("type");
628 fields.remove("id");
629 fields.remove("name");
630 fields.remove("description");
631 fields.remove("_meta");
632 Self {
633 type_: type_.into(),
634 id: id.into(),
635 name: name.into(),
636 description: None,
637 meta: None,
638 fields,
639 }
640 }
641
642 #[must_use]
644 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
645 self.description = description.into_option();
646 self
647 }
648
649 #[must_use]
655 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
656 self.meta = meta.into_option();
657 self
658 }
659}
660
661impl<'de> Deserialize<'de> for OtherAuthMethod {
662 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
663 where
664 D: serde::Deserializer<'de>,
665 {
666 #[derive(Deserialize)]
667 #[serde(rename_all = "camelCase")]
668 struct RawOtherAuthMethod {
669 #[serde(rename = "type")]
670 type_: String,
671 id: AuthMethodId,
672 name: String,
673 description: Option<String>,
674 #[serde(rename = "_meta")]
675 meta: Option<Meta>,
676 #[serde(flatten)]
677 fields: BTreeMap<String, serde_json::Value>,
678 }
679
680 let raw = RawOtherAuthMethod::deserialize(deserializer)?;
681 if is_known_auth_method_type(&raw.type_) {
682 return Err(serde::de::Error::custom(format!(
683 "known authentication method `{}` did not match its schema",
684 raw.type_
685 )));
686 }
687
688 Ok(Self {
689 type_: raw.type_,
690 id: raw.id,
691 name: raw.name,
692 description: raw.description,
693 meta: raw.meta,
694 fields: raw.fields,
695 })
696 }
697}
698
699fn is_known_auth_method_type(type_: &str) -> bool {
700 match type_ {
701 "agent" => true,
702 #[cfg(feature = "unstable_auth_methods")]
703 "env_var" | "terminal" => true,
704 _ => false,
705 }
706}
707
708fn other_auth_method_schema(schema: &mut Schema) {
709 super::schema_util::reject_known_string_discriminators(
710 schema,
711 "type",
712 &[
713 "agent",
714 #[cfg(feature = "unstable_auth_methods")]
715 "env_var",
716 #[cfg(feature = "unstable_auth_methods")]
717 "terminal",
718 ],
719 );
720}
721
722#[serde_as]
726#[skip_serializing_none]
727#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
728#[serde(rename_all = "camelCase")]
729#[non_exhaustive]
730pub struct AuthMethodAgent {
731 pub id: AuthMethodId,
733 pub name: String,
735 #[serde_as(deserialize_as = "DefaultOnError")]
737 #[schemars(extend("x-deserialize-default-on-error" = true))]
738 #[serde(default)]
739 pub description: Option<String>,
740 #[serde_as(deserialize_as = "DefaultOnError")]
746 #[schemars(extend("x-deserialize-default-on-error" = true))]
747 #[serde(default)]
748 #[serde(rename = "_meta")]
749 pub meta: Option<Meta>,
750}
751
752impl AuthMethodAgent {
753 #[must_use]
755 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
756 Self {
757 id: id.into(),
758 name: name.into(),
759 description: None,
760 meta: None,
761 }
762 }
763
764 #[must_use]
766 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
767 self.description = description.into_option();
768 self
769 }
770
771 #[must_use]
777 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
778 self.meta = meta.into_option();
779 self
780 }
781}
782
783#[cfg(feature = "unstable_auth_methods")]
791#[serde_as]
792#[skip_serializing_none]
793#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
794#[serde(rename_all = "camelCase")]
795#[non_exhaustive]
796pub struct AuthMethodEnvVar {
797 pub id: AuthMethodId,
799 pub name: String,
801 #[serde_as(deserialize_as = "DefaultOnError")]
803 #[schemars(extend("x-deserialize-default-on-error" = true))]
804 #[serde(default)]
805 pub description: Option<String>,
806 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
808 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
809 pub vars: Vec<AuthEnvVar>,
810 #[serde_as(deserialize_as = "DefaultOnError")]
812 #[schemars(extend("x-deserialize-default-on-error" = true))]
813 #[serde(default)]
814 pub link: Option<String>,
815 #[serde_as(deserialize_as = "DefaultOnError")]
821 #[schemars(extend("x-deserialize-default-on-error" = true))]
822 #[serde(default)]
823 #[serde(rename = "_meta")]
824 pub meta: Option<Meta>,
825}
826
827#[cfg(feature = "unstable_auth_methods")]
828impl AuthMethodEnvVar {
829 #[must_use]
831 pub fn new(
832 id: impl Into<AuthMethodId>,
833 name: impl Into<String>,
834 vars: Vec<AuthEnvVar>,
835 ) -> Self {
836 Self {
837 id: id.into(),
838 name: name.into(),
839 description: None,
840 vars,
841 link: None,
842 meta: None,
843 }
844 }
845
846 #[must_use]
848 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
849 self.link = link.into_option();
850 self
851 }
852
853 #[must_use]
855 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
856 self.description = description.into_option();
857 self
858 }
859
860 #[must_use]
866 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
867 self.meta = meta.into_option();
868 self
869 }
870}
871
872#[cfg(feature = "unstable_auth_methods")]
878#[serde_as]
879#[skip_serializing_none]
880#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
881#[serde(rename_all = "camelCase")]
882#[non_exhaustive]
883pub struct AuthEnvVar {
884 pub name: String,
886 #[serde_as(deserialize_as = "DefaultOnError")]
888 #[schemars(extend("x-deserialize-default-on-error" = true))]
889 #[serde(default)]
890 pub label: Option<String>,
891 #[serde_as(deserialize_as = "DefaultTrueOnError")]
896 #[schemars(extend("x-deserialize-default-on-error" = true))]
897 #[serde(default = "default_true", skip_serializing_if = "is_true")]
898 #[schemars(extend("default" = true))]
899 pub secret: bool,
900 #[serde_as(deserialize_as = "DefaultOnError")]
904 #[schemars(extend("x-deserialize-default-on-error" = true))]
905 #[serde(default, skip_serializing_if = "is_false")]
906 #[schemars(extend("default" = false))]
907 pub optional: bool,
908 #[serde_as(deserialize_as = "DefaultOnError")]
914 #[schemars(extend("x-deserialize-default-on-error" = true))]
915 #[serde(default)]
916 #[serde(rename = "_meta")]
917 pub meta: Option<Meta>,
918}
919
920#[cfg(feature = "unstable_auth_methods")]
921fn default_true() -> bool {
922 true
923}
924
925#[cfg(feature = "unstable_auth_methods")]
926#[expect(clippy::trivially_copy_pass_by_ref)]
927fn is_true(v: &bool) -> bool {
928 *v
929}
930
931#[cfg(feature = "unstable_auth_methods")]
932#[expect(clippy::trivially_copy_pass_by_ref)]
933fn is_false(v: &bool) -> bool {
934 !*v
935}
936
937#[cfg(feature = "unstable_auth_methods")]
938impl AuthEnvVar {
939 #[must_use]
941 pub fn new(name: impl Into<String>) -> Self {
942 Self {
943 name: name.into(),
944 label: None,
945 secret: true,
946 optional: false,
947 meta: None,
948 }
949 }
950
951 #[must_use]
953 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
954 self.label = label.into_option();
955 self
956 }
957
958 #[must_use]
961 pub fn secret(mut self, secret: bool) -> Self {
962 self.secret = secret;
963 self
964 }
965
966 #[must_use]
968 pub fn optional(mut self, optional: bool) -> Self {
969 self.optional = optional;
970 self
971 }
972
973 #[must_use]
979 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
980 self.meta = meta.into_option();
981 self
982 }
983}
984
985#[cfg(feature = "unstable_auth_methods")]
993#[serde_as]
994#[skip_serializing_none]
995#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
996#[serde(rename_all = "camelCase")]
997#[non_exhaustive]
998pub struct AuthMethodTerminal {
999 pub id: AuthMethodId,
1001 pub name: String,
1003 #[serde_as(deserialize_as = "DefaultOnError")]
1005 #[schemars(extend("x-deserialize-default-on-error" = true))]
1006 #[serde(default)]
1007 pub description: Option<String>,
1008 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1010 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1011 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1012 pub args: Vec<String>,
1013 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1015 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1016 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1017 pub env: Vec<EnvVariable>,
1018 #[serde_as(deserialize_as = "DefaultOnError")]
1024 #[schemars(extend("x-deserialize-default-on-error" = true))]
1025 #[serde(default)]
1026 #[serde(rename = "_meta")]
1027 pub meta: Option<Meta>,
1028}
1029
1030#[cfg(feature = "unstable_auth_methods")]
1031impl AuthMethodTerminal {
1032 #[must_use]
1034 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
1035 Self {
1036 id: id.into(),
1037 name: name.into(),
1038 description: None,
1039 args: Vec::new(),
1040 env: Vec::new(),
1041 meta: None,
1042 }
1043 }
1044
1045 #[must_use]
1047 pub fn args(mut self, args: Vec<String>) -> Self {
1048 self.args = args;
1049 self
1050 }
1051
1052 #[must_use]
1054 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
1055 self.env = env;
1056 self
1057 }
1058
1059 #[must_use]
1061 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1062 self.description = description.into_option();
1063 self
1064 }
1065
1066 #[must_use]
1072 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1073 self.meta = meta.into_option();
1074 self
1075 }
1076}
1077
1078#[serde_as]
1084#[skip_serializing_none]
1085#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1086#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1087#[serde(rename_all = "camelCase")]
1088#[non_exhaustive]
1089pub struct NewSessionRequest {
1090 pub cwd: PathBuf,
1092 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1098 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1099 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1100 pub additional_directories: Vec<PathBuf>,
1101 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1103 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1104 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1105 pub mcp_servers: Vec<McpServer>,
1106 #[serde_as(deserialize_as = "DefaultOnError")]
1112 #[schemars(extend("x-deserialize-default-on-error" = true))]
1113 #[serde(default)]
1114 #[serde(rename = "_meta")]
1115 pub meta: Option<Meta>,
1116}
1117
1118impl NewSessionRequest {
1119 #[must_use]
1121 pub fn new(cwd: impl Into<PathBuf>) -> Self {
1122 Self {
1123 cwd: cwd.into(),
1124 additional_directories: vec![],
1125 mcp_servers: vec![],
1126 meta: None,
1127 }
1128 }
1129
1130 #[must_use]
1132 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1133 self.additional_directories = additional_directories;
1134 self
1135 }
1136
1137 #[must_use]
1139 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1140 self.mcp_servers = mcp_servers;
1141 self
1142 }
1143
1144 #[must_use]
1150 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1151 self.meta = meta.into_option();
1152 self
1153 }
1154}
1155
1156#[serde_as]
1160#[skip_serializing_none]
1161#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1162#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1163#[serde(rename_all = "camelCase")]
1164#[non_exhaustive]
1165pub struct NewSessionResponse {
1166 pub session_id: SessionId,
1170 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1172 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1173 #[serde(default)]
1174 pub config_options: Option<Vec<SessionConfigOption>>,
1175 #[serde_as(deserialize_as = "DefaultOnError")]
1181 #[schemars(extend("x-deserialize-default-on-error" = true))]
1182 #[serde(default)]
1183 #[serde(rename = "_meta")]
1184 pub meta: Option<Meta>,
1185}
1186
1187impl NewSessionResponse {
1188 #[must_use]
1190 pub fn new(session_id: impl Into<SessionId>) -> Self {
1191 Self {
1192 session_id: session_id.into(),
1193 config_options: None,
1194 meta: None,
1195 }
1196 }
1197
1198 #[must_use]
1200 pub fn config_options(
1201 mut self,
1202 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1203 ) -> Self {
1204 self.config_options = config_options.into_option();
1205 self
1206 }
1207
1208 #[must_use]
1214 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1215 self.meta = meta.into_option();
1216 self
1217 }
1218}
1219
1220#[serde_as]
1228#[skip_serializing_none]
1229#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1230#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1231#[serde(rename_all = "camelCase")]
1232#[non_exhaustive]
1233pub struct LoadSessionRequest {
1234 pub session_id: SessionId,
1236 pub cwd: PathBuf,
1238 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1245 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1246 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1247 pub additional_directories: Vec<PathBuf>,
1248 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1250 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1251 pub mcp_servers: Vec<McpServer>,
1252 #[serde_as(deserialize_as = "DefaultOnError")]
1258 #[schemars(extend("x-deserialize-default-on-error" = true))]
1259 #[serde(default)]
1260 #[serde(rename = "_meta")]
1261 pub meta: Option<Meta>,
1262}
1263
1264impl LoadSessionRequest {
1265 #[must_use]
1267 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1268 Self {
1269 mcp_servers: vec![],
1270 cwd: cwd.into(),
1271 additional_directories: vec![],
1272 session_id: session_id.into(),
1273 meta: None,
1274 }
1275 }
1276
1277 #[must_use]
1279 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1280 self.additional_directories = additional_directories;
1281 self
1282 }
1283
1284 #[must_use]
1286 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1287 self.mcp_servers = mcp_servers;
1288 self
1289 }
1290
1291 #[must_use]
1297 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1298 self.meta = meta.into_option();
1299 self
1300 }
1301}
1302
1303#[serde_as]
1305#[skip_serializing_none]
1306#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1307#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1308#[serde(rename_all = "camelCase")]
1309#[non_exhaustive]
1310pub struct LoadSessionResponse {
1311 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1313 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1314 #[serde(default)]
1315 pub config_options: Option<Vec<SessionConfigOption>>,
1316 #[serde_as(deserialize_as = "DefaultOnError")]
1322 #[schemars(extend("x-deserialize-default-on-error" = true))]
1323 #[serde(default)]
1324 #[serde(rename = "_meta")]
1325 pub meta: Option<Meta>,
1326}
1327
1328impl LoadSessionResponse {
1329 #[must_use]
1331 pub fn new() -> Self {
1332 Self::default()
1333 }
1334
1335 #[must_use]
1337 pub fn config_options(
1338 mut self,
1339 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1340 ) -> Self {
1341 self.config_options = config_options.into_option();
1342 self
1343 }
1344
1345 #[must_use]
1351 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1352 self.meta = meta.into_option();
1353 self
1354 }
1355}
1356
1357#[cfg(feature = "unstable_session_fork")]
1370#[serde_as]
1371#[skip_serializing_none]
1372#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1373#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1374#[serde(rename_all = "camelCase")]
1375#[non_exhaustive]
1376pub struct ForkSessionRequest {
1377 pub session_id: SessionId,
1379 pub cwd: PathBuf,
1381 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1387 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1388 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1389 pub additional_directories: Vec<PathBuf>,
1390 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1392 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1393 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1394 pub mcp_servers: Vec<McpServer>,
1395 #[serde_as(deserialize_as = "DefaultOnError")]
1401 #[schemars(extend("x-deserialize-default-on-error" = true))]
1402 #[serde(default)]
1403 #[serde(rename = "_meta")]
1404 pub meta: Option<Meta>,
1405}
1406
1407#[cfg(feature = "unstable_session_fork")]
1408impl ForkSessionRequest {
1409 #[must_use]
1411 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1412 Self {
1413 session_id: session_id.into(),
1414 cwd: cwd.into(),
1415 additional_directories: vec![],
1416 mcp_servers: vec![],
1417 meta: None,
1418 }
1419 }
1420
1421 #[must_use]
1423 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1424 self.additional_directories = additional_directories;
1425 self
1426 }
1427
1428 #[must_use]
1430 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1431 self.mcp_servers = mcp_servers;
1432 self
1433 }
1434
1435 #[must_use]
1441 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1442 self.meta = meta.into_option();
1443 self
1444 }
1445}
1446
1447#[cfg(feature = "unstable_session_fork")]
1453#[serde_as]
1454#[skip_serializing_none]
1455#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1456#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1457#[serde(rename_all = "camelCase")]
1458#[non_exhaustive]
1459pub struct ForkSessionResponse {
1460 pub session_id: SessionId,
1462 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1464 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1465 #[serde(default)]
1466 pub config_options: Option<Vec<SessionConfigOption>>,
1467 #[serde_as(deserialize_as = "DefaultOnError")]
1473 #[schemars(extend("x-deserialize-default-on-error" = true))]
1474 #[serde(default)]
1475 #[serde(rename = "_meta")]
1476 pub meta: Option<Meta>,
1477}
1478
1479#[cfg(feature = "unstable_session_fork")]
1480impl ForkSessionResponse {
1481 #[must_use]
1483 pub fn new(session_id: impl Into<SessionId>) -> Self {
1484 Self {
1485 session_id: session_id.into(),
1486 config_options: None,
1487 meta: None,
1488 }
1489 }
1490
1491 #[must_use]
1493 pub fn config_options(
1494 mut self,
1495 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1496 ) -> Self {
1497 self.config_options = config_options.into_option();
1498 self
1499 }
1500
1501 #[must_use]
1507 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1508 self.meta = meta.into_option();
1509 self
1510 }
1511}
1512
1513#[serde_as]
1522#[skip_serializing_none]
1523#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1524#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1525#[serde(rename_all = "camelCase")]
1526#[non_exhaustive]
1527pub struct ResumeSessionRequest {
1528 pub session_id: SessionId,
1530 pub cwd: PathBuf,
1532 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1539 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1540 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1541 pub additional_directories: Vec<PathBuf>,
1542 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1544 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1545 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1546 pub mcp_servers: Vec<McpServer>,
1547 #[serde_as(deserialize_as = "DefaultOnError")]
1553 #[schemars(extend("x-deserialize-default-on-error" = true))]
1554 #[serde(default)]
1555 #[serde(rename = "_meta")]
1556 pub meta: Option<Meta>,
1557}
1558
1559impl ResumeSessionRequest {
1560 #[must_use]
1562 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1563 Self {
1564 session_id: session_id.into(),
1565 cwd: cwd.into(),
1566 additional_directories: vec![],
1567 mcp_servers: vec![],
1568 meta: None,
1569 }
1570 }
1571
1572 #[must_use]
1574 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1575 self.additional_directories = additional_directories;
1576 self
1577 }
1578
1579 #[must_use]
1581 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1582 self.mcp_servers = mcp_servers;
1583 self
1584 }
1585
1586 #[must_use]
1592 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1593 self.meta = meta.into_option();
1594 self
1595 }
1596}
1597
1598#[serde_as]
1600#[skip_serializing_none]
1601#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1602#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1603#[serde(rename_all = "camelCase")]
1604#[non_exhaustive]
1605pub struct ResumeSessionResponse {
1606 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1608 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1609 #[serde(default)]
1610 pub config_options: Option<Vec<SessionConfigOption>>,
1611 #[serde_as(deserialize_as = "DefaultOnError")]
1617 #[schemars(extend("x-deserialize-default-on-error" = true))]
1618 #[serde(default)]
1619 #[serde(rename = "_meta")]
1620 pub meta: Option<Meta>,
1621}
1622
1623impl ResumeSessionResponse {
1624 #[must_use]
1626 pub fn new() -> Self {
1627 Self::default()
1628 }
1629
1630 #[must_use]
1632 pub fn config_options(
1633 mut self,
1634 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1635 ) -> Self {
1636 self.config_options = config_options.into_option();
1637 self
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#[serde_as]
1662#[skip_serializing_none]
1663#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1664#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1665#[serde(rename_all = "camelCase")]
1666#[non_exhaustive]
1667pub struct CloseSessionRequest {
1668 pub session_id: SessionId,
1670 #[serde_as(deserialize_as = "DefaultOnError")]
1676 #[schemars(extend("x-deserialize-default-on-error" = true))]
1677 #[serde(default)]
1678 #[serde(rename = "_meta")]
1679 pub meta: Option<Meta>,
1680}
1681
1682impl CloseSessionRequest {
1683 #[must_use]
1685 pub fn new(session_id: impl Into<SessionId>) -> Self {
1686 Self {
1687 session_id: session_id.into(),
1688 meta: None,
1689 }
1690 }
1691
1692 #[must_use]
1698 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1699 self.meta = meta.into_option();
1700 self
1701 }
1702}
1703
1704#[serde_as]
1706#[skip_serializing_none]
1707#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1708#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1709#[serde(rename_all = "camelCase")]
1710#[non_exhaustive]
1711pub struct CloseSessionResponse {
1712 #[serde_as(deserialize_as = "DefaultOnError")]
1718 #[schemars(extend("x-deserialize-default-on-error" = true))]
1719 #[serde(default)]
1720 #[serde(rename = "_meta")]
1721 pub meta: Option<Meta>,
1722}
1723
1724impl CloseSessionResponse {
1725 #[must_use]
1727 pub fn new() -> Self {
1728 Self::default()
1729 }
1730
1731 #[must_use]
1737 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1738 self.meta = meta.into_option();
1739 self
1740 }
1741}
1742
1743#[serde_as]
1749#[skip_serializing_none]
1750#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1751#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1752#[serde(rename_all = "camelCase")]
1753#[non_exhaustive]
1754pub struct ListSessionsRequest {
1755 #[serde_as(deserialize_as = "DefaultOnError")]
1757 #[schemars(extend("x-deserialize-default-on-error" = true))]
1758 #[serde(default)]
1759 pub cwd: Option<PathBuf>,
1760 #[serde_as(deserialize_as = "DefaultOnError")]
1762 #[schemars(extend("x-deserialize-default-on-error" = true))]
1763 #[serde(default)]
1764 pub cursor: Option<String>,
1765 #[serde_as(deserialize_as = "DefaultOnError")]
1771 #[schemars(extend("x-deserialize-default-on-error" = true))]
1772 #[serde(default)]
1773 #[serde(rename = "_meta")]
1774 pub meta: Option<Meta>,
1775}
1776
1777impl ListSessionsRequest {
1778 #[must_use]
1780 pub fn new() -> Self {
1781 Self::default()
1782 }
1783
1784 #[must_use]
1786 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1787 self.cwd = cwd.into_option();
1788 self
1789 }
1790
1791 #[must_use]
1793 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1794 self.cursor = cursor.into_option();
1795 self
1796 }
1797
1798 #[must_use]
1804 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1805 self.meta = meta.into_option();
1806 self
1807 }
1808}
1809
1810#[serde_as]
1812#[skip_serializing_none]
1813#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1814#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1815#[serde(rename_all = "camelCase")]
1816#[non_exhaustive]
1817pub struct ListSessionsResponse {
1818 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1820 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1821 pub sessions: Vec<SessionInfo>,
1822 #[serde_as(deserialize_as = "DefaultOnError")]
1825 #[schemars(extend("x-deserialize-default-on-error" = true))]
1826 #[serde(default)]
1827 pub next_cursor: Option<String>,
1828 #[serde_as(deserialize_as = "DefaultOnError")]
1834 #[schemars(extend("x-deserialize-default-on-error" = true))]
1835 #[serde(default)]
1836 #[serde(rename = "_meta")]
1837 pub meta: Option<Meta>,
1838}
1839
1840impl ListSessionsResponse {
1841 #[must_use]
1843 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1844 Self {
1845 sessions,
1846 next_cursor: None,
1847 meta: None,
1848 }
1849 }
1850
1851 #[must_use]
1853 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1854 self.next_cursor = next_cursor.into_option();
1855 self
1856 }
1857
1858 #[must_use]
1864 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1865 self.meta = meta.into_option();
1866 self
1867 }
1868}
1869
1870#[serde_as]
1876#[skip_serializing_none]
1877#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1878#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1879#[serde(rename_all = "camelCase")]
1880#[non_exhaustive]
1881pub struct DeleteSessionRequest {
1882 pub session_id: SessionId,
1884 #[serde_as(deserialize_as = "DefaultOnError")]
1890 #[schemars(extend("x-deserialize-default-on-error" = true))]
1891 #[serde(default)]
1892 #[serde(rename = "_meta")]
1893 pub meta: Option<Meta>,
1894}
1895
1896impl DeleteSessionRequest {
1897 #[must_use]
1899 pub fn new(session_id: impl Into<SessionId>) -> Self {
1900 Self {
1901 session_id: session_id.into(),
1902 meta: None,
1903 }
1904 }
1905
1906 #[must_use]
1912 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1913 self.meta = meta.into_option();
1914 self
1915 }
1916}
1917
1918#[serde_as]
1920#[skip_serializing_none]
1921#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1922#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1923#[serde(rename_all = "camelCase")]
1924#[non_exhaustive]
1925pub struct DeleteSessionResponse {
1926 #[serde_as(deserialize_as = "DefaultOnError")]
1932 #[schemars(extend("x-deserialize-default-on-error" = true))]
1933 #[serde(default)]
1934 #[serde(rename = "_meta")]
1935 pub meta: Option<Meta>,
1936}
1937
1938impl DeleteSessionResponse {
1939 #[must_use]
1941 pub fn new() -> Self {
1942 Self::default()
1943 }
1944
1945 #[must_use]
1951 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1952 self.meta = meta.into_option();
1953 self
1954 }
1955}
1956
1957#[serde_as]
1959#[skip_serializing_none]
1960#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1961#[serde(rename_all = "camelCase")]
1962#[non_exhaustive]
1963pub struct SessionInfo {
1964 pub session_id: SessionId,
1966 pub cwd: PathBuf,
1968 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1974 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1975 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1976 pub additional_directories: Vec<PathBuf>,
1977
1978 #[serde_as(deserialize_as = "DefaultOnError")]
1980 #[schemars(extend("x-deserialize-default-on-error" = true))]
1981 #[serde(default)]
1982 pub title: Option<String>,
1983 #[serde_as(deserialize_as = "DefaultOnError")]
1985 #[schemars(extend("x-deserialize-default-on-error" = true))]
1986 #[serde(default)]
1987 pub updated_at: Option<String>,
1988 #[serde_as(deserialize_as = "DefaultOnError")]
1994 #[schemars(extend("x-deserialize-default-on-error" = true))]
1995 #[serde(default)]
1996 #[serde(rename = "_meta")]
1997 pub meta: Option<Meta>,
1998}
1999
2000impl SessionInfo {
2001 #[must_use]
2003 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
2004 Self {
2005 session_id: session_id.into(),
2006 cwd: cwd.into(),
2007 additional_directories: vec![],
2008 title: None,
2009 updated_at: None,
2010 meta: None,
2011 }
2012 }
2013
2014 #[must_use]
2016 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
2017 self.additional_directories = additional_directories;
2018 self
2019 }
2020
2021 #[must_use]
2023 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
2024 self.title = title.into_option();
2025 self
2026 }
2027
2028 #[must_use]
2030 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
2031 self.updated_at = updated_at.into_option();
2032 self
2033 }
2034
2035 #[must_use]
2041 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2042 self.meta = meta.into_option();
2043 self
2044 }
2045}
2046
2047#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2051#[serde(transparent)]
2052#[from(Arc<str>, String, &'static str)]
2053#[non_exhaustive]
2054pub struct SessionConfigId(pub Arc<str>);
2055
2056impl SessionConfigId {
2057 #[must_use]
2059 pub fn new(id: impl Into<Arc<str>>) -> Self {
2060 Self(id.into())
2061 }
2062}
2063
2064#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2066#[serde(transparent)]
2067#[from(Arc<str>, String, &'static str)]
2068#[non_exhaustive]
2069pub struct SessionConfigValueId(pub Arc<str>);
2070
2071impl SessionConfigValueId {
2072 #[must_use]
2074 pub fn new(id: impl Into<Arc<str>>) -> Self {
2075 Self(id.into())
2076 }
2077}
2078
2079#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2081#[serde(transparent)]
2082#[from(Arc<str>, String, &'static str)]
2083#[non_exhaustive]
2084pub struct SessionConfigGroupId(pub Arc<str>);
2085
2086impl SessionConfigGroupId {
2087 #[must_use]
2089 pub fn new(id: impl Into<Arc<str>>) -> Self {
2090 Self(id.into())
2091 }
2092}
2093
2094#[serde_as]
2096#[skip_serializing_none]
2097#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2098#[serde(rename_all = "camelCase")]
2099#[non_exhaustive]
2100pub struct SessionConfigSelectOption {
2101 pub value: SessionConfigValueId,
2103 pub name: String,
2105 #[serde_as(deserialize_as = "DefaultOnError")]
2107 #[schemars(extend("x-deserialize-default-on-error" = true))]
2108 #[serde(default)]
2109 pub description: Option<String>,
2110 #[serde_as(deserialize_as = "DefaultOnError")]
2116 #[schemars(extend("x-deserialize-default-on-error" = true))]
2117 #[serde(default)]
2118 #[serde(rename = "_meta")]
2119 pub meta: Option<Meta>,
2120}
2121
2122impl SessionConfigSelectOption {
2123 #[must_use]
2125 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2126 Self {
2127 value: value.into(),
2128 name: name.into(),
2129 description: None,
2130 meta: None,
2131 }
2132 }
2133
2134 #[must_use]
2136 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2137 self.description = description.into_option();
2138 self
2139 }
2140
2141 #[must_use]
2147 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2148 self.meta = meta.into_option();
2149 self
2150 }
2151}
2152
2153#[serde_as]
2155#[skip_serializing_none]
2156#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2157#[serde(rename_all = "camelCase")]
2158#[non_exhaustive]
2159pub struct SessionConfigSelectGroup {
2160 pub group: SessionConfigGroupId,
2162 pub name: String,
2164 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2166 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2167 pub options: Vec<SessionConfigSelectOption>,
2168 #[serde_as(deserialize_as = "DefaultOnError")]
2174 #[schemars(extend("x-deserialize-default-on-error" = true))]
2175 #[serde(default)]
2176 #[serde(rename = "_meta")]
2177 pub meta: Option<Meta>,
2178}
2179
2180impl SessionConfigSelectGroup {
2181 #[must_use]
2183 pub fn new(
2184 group: impl Into<SessionConfigGroupId>,
2185 name: impl Into<String>,
2186 options: Vec<SessionConfigSelectOption>,
2187 ) -> Self {
2188 Self {
2189 group: group.into(),
2190 name: name.into(),
2191 options,
2192 meta: None,
2193 }
2194 }
2195
2196 #[must_use]
2202 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2203 self.meta = meta.into_option();
2204 self
2205 }
2206}
2207
2208#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2210#[serde(untagged)]
2211#[non_exhaustive]
2212pub enum SessionConfigSelectOptions {
2213 Ungrouped(Vec<SessionConfigSelectOption>),
2215 Grouped(Vec<SessionConfigSelectGroup>),
2217}
2218
2219impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2220 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2221 SessionConfigSelectOptions::Ungrouped(options)
2222 }
2223}
2224
2225impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2226 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2227 SessionConfigSelectOptions::Grouped(groups)
2228 }
2229}
2230
2231#[skip_serializing_none]
2233#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2234#[serde(rename_all = "camelCase")]
2235#[non_exhaustive]
2236pub struct SessionConfigSelect {
2237 pub current_value: SessionConfigValueId,
2239 pub options: SessionConfigSelectOptions,
2241}
2242
2243impl SessionConfigSelect {
2244 #[must_use]
2246 pub fn new(
2247 current_value: impl Into<SessionConfigValueId>,
2248 options: impl Into<SessionConfigSelectOptions>,
2249 ) -> Self {
2250 Self {
2251 current_value: current_value.into(),
2252 options: options.into(),
2253 }
2254 }
2255}
2256
2257#[cfg(feature = "unstable_boolean_config")]
2263#[skip_serializing_none]
2264#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2265#[serde(rename_all = "camelCase")]
2266#[non_exhaustive]
2267pub struct SessionConfigBoolean {
2268 pub current_value: bool,
2270}
2271
2272#[cfg(feature = "unstable_boolean_config")]
2273impl SessionConfigBoolean {
2274 #[must_use]
2276 pub fn new(current_value: bool) -> Self {
2277 Self { current_value }
2278 }
2279}
2280
2281#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2291#[serde(rename_all = "snake_case")]
2292#[non_exhaustive]
2293pub enum SessionConfigOptionCategory {
2294 Mode,
2296 Model,
2298 ModelConfig,
2300 ThoughtLevel,
2302 #[serde(untagged)]
2308 Other(String),
2309}
2310
2311#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2313#[serde(tag = "type", rename_all = "snake_case")]
2314#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2315#[non_exhaustive]
2316pub enum SessionConfigKind {
2317 Select(SessionConfigSelect),
2319 #[cfg(feature = "unstable_boolean_config")]
2325 Boolean(SessionConfigBoolean),
2326 #[serde(untagged)]
2336 Other(OtherSessionConfigKind),
2337}
2338
2339#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2341#[schemars(inline)]
2342#[schemars(transform = other_session_config_kind_schema)]
2343#[serde(rename_all = "camelCase")]
2344#[non_exhaustive]
2345pub struct OtherSessionConfigKind {
2346 #[serde(rename = "type")]
2352 pub type_: String,
2353 #[serde(flatten)]
2355 pub fields: BTreeMap<String, serde_json::Value>,
2356}
2357
2358impl OtherSessionConfigKind {
2359 #[must_use]
2361 pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2362 fields.remove("type");
2363 fields.remove("_meta");
2364 Self {
2365 type_: type_.into(),
2366 fields,
2367 }
2368 }
2369}
2370
2371impl<'de> Deserialize<'de> for OtherSessionConfigKind {
2372 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2373 where
2374 D: serde::Deserializer<'de>,
2375 {
2376 let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2377 let type_ = fields
2378 .remove("type")
2379 .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2380 let serde_json::Value::String(type_) = type_ else {
2381 return Err(serde::de::Error::custom("`type` must be a string"));
2382 };
2383
2384 if is_known_session_config_kind_type(&type_) {
2385 return Err(serde::de::Error::custom(format!(
2386 "known session configuration option `{type_}` did not match its schema"
2387 )));
2388 }
2389
2390 Ok(Self { type_, fields })
2391 }
2392}
2393
2394fn is_known_session_config_kind_type(type_: &str) -> bool {
2395 match type_ {
2396 "select" => true,
2397 #[cfg(feature = "unstable_boolean_config")]
2398 "boolean" => true,
2399 _ => false,
2400 }
2401}
2402
2403fn other_session_config_kind_schema(schema: &mut Schema) {
2404 super::schema_util::reject_known_string_discriminators(
2405 schema,
2406 "type",
2407 &[
2408 "select",
2409 #[cfg(feature = "unstable_boolean_config")]
2410 "boolean",
2411 ],
2412 );
2413}
2414
2415#[serde_as]
2417#[skip_serializing_none]
2418#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2419#[serde(rename_all = "camelCase")]
2420#[non_exhaustive]
2421pub struct SessionConfigOption {
2422 pub id: SessionConfigId,
2424 pub name: String,
2426 #[serde_as(deserialize_as = "DefaultOnError")]
2428 #[schemars(extend("x-deserialize-default-on-error" = true))]
2429 #[serde(default)]
2430 pub description: Option<String>,
2431 #[serde_as(deserialize_as = "DefaultOnError")]
2433 #[schemars(extend("x-deserialize-default-on-error" = true))]
2434 #[serde(default)]
2435 pub category: Option<SessionConfigOptionCategory>,
2436 #[serde(flatten)]
2438 pub kind: SessionConfigKind,
2439 #[serde_as(deserialize_as = "DefaultOnError")]
2445 #[schemars(extend("x-deserialize-default-on-error" = true))]
2446 #[serde(default)]
2447 #[serde(rename = "_meta")]
2448 pub meta: Option<Meta>,
2449}
2450
2451impl SessionConfigOption {
2452 #[must_use]
2454 pub fn new(
2455 id: impl Into<SessionConfigId>,
2456 name: impl Into<String>,
2457 kind: SessionConfigKind,
2458 ) -> Self {
2459 Self {
2460 id: id.into(),
2461 name: name.into(),
2462 description: None,
2463 category: None,
2464 kind,
2465 meta: None,
2466 }
2467 }
2468
2469 #[must_use]
2471 pub fn select(
2472 id: impl Into<SessionConfigId>,
2473 name: impl Into<String>,
2474 current_value: impl Into<SessionConfigValueId>,
2475 options: impl Into<SessionConfigSelectOptions>,
2476 ) -> Self {
2477 Self::new(
2478 id,
2479 name,
2480 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2481 )
2482 }
2483
2484 #[cfg(feature = "unstable_boolean_config")]
2488 #[must_use]
2489 pub fn boolean(
2490 id: impl Into<SessionConfigId>,
2491 name: impl Into<String>,
2492 current_value: bool,
2493 ) -> Self {
2494 Self::new(
2495 id,
2496 name,
2497 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2498 )
2499 }
2500
2501 #[must_use]
2503 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2504 self.description = description.into_option();
2505 self
2506 }
2507
2508 #[must_use]
2510 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2511 self.category = category.into_option();
2512 self
2513 }
2514
2515 #[must_use]
2521 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2522 self.meta = meta.into_option();
2523 self
2524 }
2525}
2526
2527#[cfg(feature = "unstable_boolean_config")]
2542#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2543#[serde(tag = "type", rename_all = "snake_case")]
2544#[non_exhaustive]
2545pub enum SessionConfigOptionValue {
2546 Boolean {
2548 value: bool,
2550 },
2551 #[serde(untagged)]
2557 ValueId {
2558 value: SessionConfigValueId,
2560 },
2561}
2562
2563#[cfg(feature = "unstable_boolean_config")]
2564impl SessionConfigOptionValue {
2565 #[must_use]
2567 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2568 Self::ValueId { value: id.into() }
2569 }
2570
2571 #[must_use]
2573 pub fn boolean(val: bool) -> Self {
2574 Self::Boolean { value: val }
2575 }
2576
2577 #[must_use]
2580 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2581 match self {
2582 Self::ValueId { value } => Some(value),
2583 _ => None,
2584 }
2585 }
2586
2587 #[must_use]
2589 pub fn as_bool(&self) -> Option<bool> {
2590 match self {
2591 Self::Boolean { value } => Some(*value),
2592 _ => None,
2593 }
2594 }
2595}
2596
2597#[cfg(feature = "unstable_boolean_config")]
2598impl From<SessionConfigValueId> for SessionConfigOptionValue {
2599 fn from(value: SessionConfigValueId) -> Self {
2600 Self::ValueId { value }
2601 }
2602}
2603
2604#[cfg(feature = "unstable_boolean_config")]
2605impl From<bool> for SessionConfigOptionValue {
2606 fn from(value: bool) -> Self {
2607 Self::Boolean { value }
2608 }
2609}
2610
2611#[cfg(feature = "unstable_boolean_config")]
2612impl From<&str> for SessionConfigOptionValue {
2613 fn from(value: &str) -> Self {
2614 Self::ValueId {
2615 value: SessionConfigValueId::new(value),
2616 }
2617 }
2618}
2619
2620#[serde_as]
2622#[skip_serializing_none]
2623#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2624#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2625#[serde(rename_all = "camelCase")]
2626#[non_exhaustive]
2627pub struct SetSessionConfigOptionRequest {
2628 pub session_id: SessionId,
2630 pub config_id: SessionConfigId,
2632 #[cfg(feature = "unstable_boolean_config")]
2637 #[serde(flatten)]
2638 pub value: SessionConfigOptionValue,
2639 #[cfg(not(feature = "unstable_boolean_config"))]
2641 pub value: SessionConfigValueId,
2642 #[serde_as(deserialize_as = "DefaultOnError")]
2648 #[schemars(extend("x-deserialize-default-on-error" = true))]
2649 #[serde(default)]
2650 #[serde(rename = "_meta")]
2651 pub meta: Option<Meta>,
2652}
2653
2654impl SetSessionConfigOptionRequest {
2655 #[cfg(feature = "unstable_boolean_config")]
2657 #[must_use]
2658 pub fn new(
2659 session_id: impl Into<SessionId>,
2660 config_id: impl Into<SessionConfigId>,
2661 value: impl Into<SessionConfigOptionValue>,
2662 ) -> Self {
2663 Self {
2664 session_id: session_id.into(),
2665 config_id: config_id.into(),
2666 value: value.into(),
2667 meta: None,
2668 }
2669 }
2670
2671 #[cfg(not(feature = "unstable_boolean_config"))]
2674 #[must_use]
2675 pub fn new(
2676 session_id: impl Into<SessionId>,
2677 config_id: impl Into<SessionConfigId>,
2678 value: impl Into<SessionConfigValueId>,
2679 ) -> Self {
2680 Self {
2681 session_id: session_id.into(),
2682 config_id: config_id.into(),
2683 value: value.into(),
2684 meta: None,
2685 }
2686 }
2687
2688 #[must_use]
2694 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2695 self.meta = meta.into_option();
2696 self
2697 }
2698}
2699
2700#[serde_as]
2702#[skip_serializing_none]
2703#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2704#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2705#[serde(rename_all = "camelCase")]
2706#[non_exhaustive]
2707pub struct SetSessionConfigOptionResponse {
2708 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2710 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2711 pub config_options: Vec<SessionConfigOption>,
2712 #[serde_as(deserialize_as = "DefaultOnError")]
2718 #[schemars(extend("x-deserialize-default-on-error" = true))]
2719 #[serde(default)]
2720 #[serde(rename = "_meta")]
2721 pub meta: Option<Meta>,
2722}
2723
2724impl SetSessionConfigOptionResponse {
2725 #[must_use]
2727 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2728 Self {
2729 config_options,
2730 meta: None,
2731 }
2732 }
2733
2734 #[must_use]
2740 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2741 self.meta = meta.into_option();
2742 self
2743 }
2744}
2745
2746#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2755#[serde(tag = "type", rename_all = "snake_case")]
2756#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2757#[non_exhaustive]
2758pub enum McpServer {
2759 Http(McpServerHttp),
2763 #[cfg(feature = "unstable_mcp_over_acp")]
2772 Acp(McpServerAcp),
2773 Stdio(McpServerStdio),
2777 #[serde(untagged)]
2787 Other(OtherMcpServer),
2788}
2789
2790#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2792#[schemars(inline)]
2793#[schemars(transform = other_mcp_server_schema)]
2794#[serde(rename_all = "camelCase")]
2795#[non_exhaustive]
2796pub struct OtherMcpServer {
2797 #[serde(rename = "type")]
2803 pub type_: String,
2804 #[serde(flatten)]
2806 pub fields: BTreeMap<String, serde_json::Value>,
2807}
2808
2809impl OtherMcpServer {
2810 #[must_use]
2812 pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2813 fields.remove("type");
2814 Self {
2815 type_: type_.into(),
2816 fields,
2817 }
2818 }
2819}
2820
2821impl<'de> Deserialize<'de> for OtherMcpServer {
2822 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2823 where
2824 D: serde::Deserializer<'de>,
2825 {
2826 let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2827 let type_ = fields
2828 .remove("type")
2829 .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2830 let serde_json::Value::String(type_) = type_ else {
2831 return Err(serde::de::Error::custom("`type` must be a string"));
2832 };
2833
2834 if is_known_mcp_server_type(&type_) {
2835 return Err(serde::de::Error::custom(format!(
2836 "known MCP server transport `{type_}` did not match its schema"
2837 )));
2838 }
2839
2840 Ok(Self { type_, fields })
2841 }
2842}
2843
2844fn is_known_mcp_server_type(type_: &str) -> bool {
2845 match type_ {
2846 "http" | "stdio" => true,
2847 #[cfg(feature = "unstable_mcp_over_acp")]
2848 "acp" => true,
2849 _ => false,
2850 }
2851}
2852
2853fn other_mcp_server_schema(schema: &mut Schema) {
2854 super::schema_util::reject_known_string_discriminators(
2855 schema,
2856 "type",
2857 &[
2858 "http",
2859 "stdio",
2860 #[cfg(feature = "unstable_mcp_over_acp")]
2861 "acp",
2862 ],
2863 );
2864}
2865
2866#[serde_as]
2868#[skip_serializing_none]
2869#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2870#[serde(rename_all = "camelCase")]
2871#[non_exhaustive]
2872pub struct McpServerHttp {
2873 pub name: String,
2875 pub url: String,
2877 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2879 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2880 pub headers: Vec<HttpHeader>,
2881 #[serde_as(deserialize_as = "DefaultOnError")]
2887 #[schemars(extend("x-deserialize-default-on-error" = true))]
2888 #[serde(default)]
2889 #[serde(rename = "_meta")]
2890 pub meta: Option<Meta>,
2891}
2892
2893impl McpServerHttp {
2894 #[must_use]
2896 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2897 Self {
2898 name: name.into(),
2899 url: url.into(),
2900 headers: Vec::new(),
2901 meta: None,
2902 }
2903 }
2904
2905 #[must_use]
2907 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2908 self.headers = headers;
2909 self
2910 }
2911
2912 #[must_use]
2918 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2919 self.meta = meta.into_option();
2920 self
2921 }
2922}
2923
2924#[cfg(feature = "unstable_mcp_over_acp")]
2934#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2935#[serde(transparent)]
2936#[from(Arc<str>, String, &'static str)]
2937#[non_exhaustive]
2938pub struct McpServerAcpId(pub Arc<str>);
2939
2940#[cfg(feature = "unstable_mcp_over_acp")]
2941impl McpServerAcpId {
2942 #[must_use]
2944 pub fn new(id: impl Into<Arc<str>>) -> Self {
2945 Self(id.into())
2946 }
2947}
2948
2949#[serde_as]
2958#[skip_serializing_none]
2959#[cfg(feature = "unstable_mcp_over_acp")]
2960#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2961#[serde(rename_all = "camelCase")]
2962#[non_exhaustive]
2963pub struct McpServerAcp {
2964 pub name: String,
2966 pub id: McpServerAcpId,
2971 #[serde_as(deserialize_as = "DefaultOnError")]
2977 #[schemars(extend("x-deserialize-default-on-error" = true))]
2978 #[serde(default)]
2979 #[serde(rename = "_meta")]
2980 pub meta: Option<Meta>,
2981}
2982
2983#[cfg(feature = "unstable_mcp_over_acp")]
2984impl McpServerAcp {
2985 #[must_use]
2987 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2988 Self {
2989 name: name.into(),
2990 id: id.into(),
2991 meta: None,
2992 }
2993 }
2994
2995 #[must_use]
3001 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3002 self.meta = meta.into_option();
3003 self
3004 }
3005}
3006
3007#[serde_as]
3009#[skip_serializing_none]
3010#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3011#[serde(rename_all = "camelCase")]
3012#[non_exhaustive]
3013pub struct McpServerStdio {
3014 pub name: String,
3016 pub command: PathBuf,
3018 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3020 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3021 pub args: Vec<String>,
3022 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3024 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3025 pub env: Vec<EnvVariable>,
3026 #[serde_as(deserialize_as = "DefaultOnError")]
3032 #[schemars(extend("x-deserialize-default-on-error" = true))]
3033 #[serde(default)]
3034 #[serde(rename = "_meta")]
3035 pub meta: Option<Meta>,
3036}
3037
3038impl McpServerStdio {
3039 #[must_use]
3041 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
3042 Self {
3043 name: name.into(),
3044 command: command.into(),
3045 args: Vec::new(),
3046 env: Vec::new(),
3047 meta: None,
3048 }
3049 }
3050
3051 #[must_use]
3053 pub fn args(mut self, args: Vec<String>) -> Self {
3054 self.args = args;
3055 self
3056 }
3057
3058 #[must_use]
3060 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
3061 self.env = env;
3062 self
3063 }
3064
3065 #[must_use]
3071 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3072 self.meta = meta.into_option();
3073 self
3074 }
3075}
3076
3077#[serde_as]
3079#[skip_serializing_none]
3080#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3081#[serde(rename_all = "camelCase")]
3082#[non_exhaustive]
3083pub struct EnvVariable {
3084 pub name: String,
3086 pub value: String,
3088 #[serde_as(deserialize_as = "DefaultOnError")]
3094 #[schemars(extend("x-deserialize-default-on-error" = true))]
3095 #[serde(default)]
3096 #[serde(rename = "_meta")]
3097 pub meta: Option<Meta>,
3098}
3099
3100impl EnvVariable {
3101 #[must_use]
3103 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3104 Self {
3105 name: name.into(),
3106 value: value.into(),
3107 meta: None,
3108 }
3109 }
3110
3111 #[must_use]
3117 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3118 self.meta = meta.into_option();
3119 self
3120 }
3121}
3122
3123#[serde_as]
3125#[skip_serializing_none]
3126#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3127#[serde(rename_all = "camelCase")]
3128#[non_exhaustive]
3129pub struct HttpHeader {
3130 pub name: String,
3132 pub value: String,
3134 #[serde_as(deserialize_as = "DefaultOnError")]
3140 #[schemars(extend("x-deserialize-default-on-error" = true))]
3141 #[serde(default)]
3142 #[serde(rename = "_meta")]
3143 pub meta: Option<Meta>,
3144}
3145
3146impl HttpHeader {
3147 #[must_use]
3149 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3150 Self {
3151 name: name.into(),
3152 value: value.into(),
3153 meta: None,
3154 }
3155 }
3156
3157 #[must_use]
3163 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3164 self.meta = meta.into_option();
3165 self
3166 }
3167}
3168
3169#[serde_as]
3177#[skip_serializing_none]
3178#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
3179#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3180#[serde(rename_all = "camelCase")]
3181#[non_exhaustive]
3182pub struct PromptRequest {
3183 pub session_id: SessionId,
3185 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3199 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3200 pub prompt: Vec<ContentBlock>,
3201 #[serde_as(deserialize_as = "DefaultOnError")]
3207 #[schemars(extend("x-deserialize-default-on-error" = true))]
3208 #[serde(default)]
3209 #[serde(rename = "_meta")]
3210 pub meta: Option<Meta>,
3211}
3212
3213impl PromptRequest {
3214 #[must_use]
3216 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3217 Self {
3218 session_id: session_id.into(),
3219 prompt,
3220 meta: None,
3221 }
3222 }
3223
3224 #[must_use]
3230 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3231 self.meta = meta.into_option();
3232 self
3233 }
3234}
3235
3236#[serde_as]
3243#[skip_serializing_none]
3244#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3245#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3246#[serde(rename_all = "camelCase")]
3247#[non_exhaustive]
3248pub struct PromptResponse {
3249 #[serde_as(deserialize_as = "DefaultOnError")]
3255 #[schemars(extend("x-deserialize-default-on-error" = true))]
3256 #[serde(default)]
3257 #[serde(rename = "_meta")]
3258 pub meta: Option<Meta>,
3259}
3260
3261impl PromptResponse {
3262 #[must_use]
3264 pub fn new() -> Self {
3265 Self::default()
3266 }
3267
3268 #[must_use]
3274 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3275 self.meta = meta.into_option();
3276 self
3277 }
3278}
3279
3280#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3284#[serde(rename_all = "snake_case")]
3285#[non_exhaustive]
3286pub enum StopReason {
3287 EndTurn,
3289 MaxTokens,
3291 MaxTurnRequests,
3294 Refusal,
3298 Cancelled,
3304 #[serde(untagged)]
3310 Other(String),
3311}
3312
3313#[cfg(feature = "unstable_end_turn_token_usage")]
3319#[serde_as]
3320#[skip_serializing_none]
3321#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3322#[serde(rename_all = "camelCase")]
3323#[non_exhaustive]
3324pub struct Usage {
3325 pub total_tokens: u64,
3327 pub input_tokens: u64,
3329 pub output_tokens: u64,
3331 #[serde_as(deserialize_as = "DefaultOnError")]
3333 #[schemars(extend("x-deserialize-default-on-error" = true))]
3334 #[serde(default)]
3335 pub thought_tokens: Option<u64>,
3336 #[serde_as(deserialize_as = "DefaultOnError")]
3338 #[schemars(extend("x-deserialize-default-on-error" = true))]
3339 #[serde(default)]
3340 pub cached_read_tokens: Option<u64>,
3341 #[serde_as(deserialize_as = "DefaultOnError")]
3343 #[schemars(extend("x-deserialize-default-on-error" = true))]
3344 #[serde(default)]
3345 pub cached_write_tokens: Option<u64>,
3346 #[serde_as(deserialize_as = "DefaultOnError")]
3352 #[schemars(extend("x-deserialize-default-on-error" = true))]
3353 #[serde(default)]
3354 #[serde(rename = "_meta")]
3355 pub meta: Option<Meta>,
3356}
3357
3358#[cfg(feature = "unstable_end_turn_token_usage")]
3359impl Usage {
3360 #[must_use]
3362 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3363 Self {
3364 total_tokens,
3365 input_tokens,
3366 output_tokens,
3367 thought_tokens: None,
3368 cached_read_tokens: None,
3369 cached_write_tokens: None,
3370 meta: None,
3371 }
3372 }
3373
3374 #[must_use]
3376 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3377 self.thought_tokens = thought_tokens.into_option();
3378 self
3379 }
3380
3381 #[must_use]
3383 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3384 self.cached_read_tokens = cached_read_tokens.into_option();
3385 self
3386 }
3387
3388 #[must_use]
3390 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3391 self.cached_write_tokens = cached_write_tokens.into_option();
3392 self
3393 }
3394
3395 #[must_use]
3401 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3402 self.meta = meta.into_option();
3403 self
3404 }
3405}
3406
3407#[cfg(feature = "unstable_llm_providers")]
3420#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3421#[serde(rename_all = "snake_case")]
3422#[non_exhaustive]
3423#[expect(clippy::doc_markdown)]
3424pub enum LlmProtocol {
3425 Anthropic,
3427 #[serde(rename = "openai")]
3429 OpenAi,
3430 Azure,
3432 Vertex,
3434 Bedrock,
3436 #[serde(untagged)]
3442 Other(String),
3443}
3444
3445#[cfg(feature = "unstable_llm_providers")]
3451#[serde_as]
3452#[skip_serializing_none]
3453#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3454#[serde(rename_all = "camelCase")]
3455#[non_exhaustive]
3456pub struct ProviderCurrentConfig {
3457 pub api_type: LlmProtocol,
3459 pub base_url: String,
3461 #[serde_as(deserialize_as = "DefaultOnError")]
3467 #[schemars(extend("x-deserialize-default-on-error" = true))]
3468 #[serde(default)]
3469 #[serde(rename = "_meta")]
3470 pub meta: Option<Meta>,
3471}
3472
3473#[cfg(feature = "unstable_llm_providers")]
3474impl ProviderCurrentConfig {
3475 #[must_use]
3477 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3478 Self {
3479 api_type,
3480 base_url: base_url.into(),
3481 meta: None,
3482 }
3483 }
3484
3485 #[must_use]
3491 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3492 self.meta = meta.into_option();
3493 self
3494 }
3495}
3496
3497#[cfg(feature = "unstable_llm_providers")]
3503#[serde_as]
3504#[skip_serializing_none]
3505#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3506#[serde(rename_all = "camelCase")]
3507#[non_exhaustive]
3508pub struct ProviderInfo {
3509 pub id: String,
3511 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3513 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3514 pub supported: Vec<LlmProtocol>,
3515 pub required: bool,
3518 #[serde_as(deserialize_as = "DefaultOnError")]
3521 #[schemars(extend("x-deserialize-default-on-error" = true))]
3522 #[serde(default)]
3523 pub current: Option<ProviderCurrentConfig>,
3524 #[serde_as(deserialize_as = "DefaultOnError")]
3530 #[schemars(extend("x-deserialize-default-on-error" = true))]
3531 #[serde(default)]
3532 #[serde(rename = "_meta")]
3533 pub meta: Option<Meta>,
3534}
3535
3536#[cfg(feature = "unstable_llm_providers")]
3537impl ProviderInfo {
3538 #[must_use]
3540 pub fn new(
3541 id: impl Into<String>,
3542 supported: Vec<LlmProtocol>,
3543 required: bool,
3544 current: impl IntoOption<ProviderCurrentConfig>,
3545 ) -> Self {
3546 Self {
3547 id: id.into(),
3548 supported,
3549 required,
3550 current: current.into_option(),
3551 meta: None,
3552 }
3553 }
3554
3555 #[must_use]
3561 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3562 self.meta = meta.into_option();
3563 self
3564 }
3565}
3566
3567#[cfg(feature = "unstable_llm_providers")]
3573#[serde_as]
3574#[skip_serializing_none]
3575#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3576#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3577#[serde(rename_all = "camelCase")]
3578#[non_exhaustive]
3579pub struct ListProvidersRequest {
3580 #[serde_as(deserialize_as = "DefaultOnError")]
3586 #[schemars(extend("x-deserialize-default-on-error" = true))]
3587 #[serde(default)]
3588 #[serde(rename = "_meta")]
3589 pub meta: Option<Meta>,
3590}
3591
3592#[cfg(feature = "unstable_llm_providers")]
3593impl ListProvidersRequest {
3594 #[must_use]
3596 pub fn new() -> Self {
3597 Self::default()
3598 }
3599
3600 #[must_use]
3606 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3607 self.meta = meta.into_option();
3608 self
3609 }
3610}
3611
3612#[cfg(feature = "unstable_llm_providers")]
3618#[serde_as]
3619#[skip_serializing_none]
3620#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3621#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3622#[serde(rename_all = "camelCase")]
3623#[non_exhaustive]
3624pub struct ListProvidersResponse {
3625 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3627 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3628 pub providers: Vec<ProviderInfo>,
3629 #[serde_as(deserialize_as = "DefaultOnError")]
3635 #[schemars(extend("x-deserialize-default-on-error" = true))]
3636 #[serde(default)]
3637 #[serde(rename = "_meta")]
3638 pub meta: Option<Meta>,
3639}
3640
3641#[cfg(feature = "unstable_llm_providers")]
3642impl ListProvidersResponse {
3643 #[must_use]
3645 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3646 Self {
3647 providers,
3648 meta: None,
3649 }
3650 }
3651
3652 #[must_use]
3658 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3659 self.meta = meta.into_option();
3660 self
3661 }
3662}
3663
3664#[cfg(feature = "unstable_llm_providers")]
3672#[serde_as]
3673#[skip_serializing_none]
3674#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3675#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3676#[serde(rename_all = "camelCase")]
3677#[non_exhaustive]
3678pub struct SetProviderRequest {
3679 pub id: String,
3681 pub api_type: LlmProtocol,
3683 pub base_url: String,
3685 #[serde_as(deserialize_as = "DefaultOnError")]
3688 #[schemars(extend("x-deserialize-default-on-error" = true))]
3689 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3690 pub headers: HashMap<String, String>,
3691 #[serde_as(deserialize_as = "DefaultOnError")]
3697 #[schemars(extend("x-deserialize-default-on-error" = true))]
3698 #[serde(default)]
3699 #[serde(rename = "_meta")]
3700 pub meta: Option<Meta>,
3701}
3702
3703#[cfg(feature = "unstable_llm_providers")]
3704impl SetProviderRequest {
3705 #[must_use]
3707 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3708 Self {
3709 id: id.into(),
3710 api_type,
3711 base_url: base_url.into(),
3712 headers: HashMap::new(),
3713 meta: None,
3714 }
3715 }
3716
3717 #[must_use]
3720 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3721 self.headers = headers;
3722 self
3723 }
3724
3725 #[must_use]
3731 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3732 self.meta = meta.into_option();
3733 self
3734 }
3735}
3736
3737#[cfg(feature = "unstable_llm_providers")]
3743#[serde_as]
3744#[skip_serializing_none]
3745#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3746#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3747#[serde(rename_all = "camelCase")]
3748#[non_exhaustive]
3749pub struct SetProviderResponse {
3750 #[serde_as(deserialize_as = "DefaultOnError")]
3756 #[schemars(extend("x-deserialize-default-on-error" = true))]
3757 #[serde(default)]
3758 #[serde(rename = "_meta")]
3759 pub meta: Option<Meta>,
3760}
3761
3762#[cfg(feature = "unstable_llm_providers")]
3763impl SetProviderResponse {
3764 #[must_use]
3766 pub fn new() -> Self {
3767 Self::default()
3768 }
3769
3770 #[must_use]
3776 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3777 self.meta = meta.into_option();
3778 self
3779 }
3780}
3781
3782#[cfg(feature = "unstable_llm_providers")]
3788#[serde_as]
3789#[skip_serializing_none]
3790#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3791#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3792#[serde(rename_all = "camelCase")]
3793#[non_exhaustive]
3794pub struct DisableProviderRequest {
3795 pub id: String,
3797 #[serde_as(deserialize_as = "DefaultOnError")]
3803 #[schemars(extend("x-deserialize-default-on-error" = true))]
3804 #[serde(default)]
3805 #[serde(rename = "_meta")]
3806 pub meta: Option<Meta>,
3807}
3808
3809#[cfg(feature = "unstable_llm_providers")]
3810impl DisableProviderRequest {
3811 #[must_use]
3813 pub fn new(id: impl Into<String>) -> Self {
3814 Self {
3815 id: id.into(),
3816 meta: None,
3817 }
3818 }
3819
3820 #[must_use]
3826 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3827 self.meta = meta.into_option();
3828 self
3829 }
3830}
3831
3832#[cfg(feature = "unstable_llm_providers")]
3838#[serde_as]
3839#[skip_serializing_none]
3840#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3841#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3842#[serde(rename_all = "camelCase")]
3843#[non_exhaustive]
3844pub struct DisableProviderResponse {
3845 #[serde_as(deserialize_as = "DefaultOnError")]
3851 #[schemars(extend("x-deserialize-default-on-error" = true))]
3852 #[serde(default)]
3853 #[serde(rename = "_meta")]
3854 pub meta: Option<Meta>,
3855}
3856
3857#[cfg(feature = "unstable_llm_providers")]
3858impl DisableProviderResponse {
3859 #[must_use]
3861 pub fn new() -> Self {
3862 Self::default()
3863 }
3864
3865 #[must_use]
3871 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3872 self.meta = meta.into_option();
3873 self
3874 }
3875}
3876
3877#[serde_as]
3886#[skip_serializing_none]
3887#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3888#[serde(rename_all = "camelCase")]
3889#[non_exhaustive]
3890pub struct AgentCapabilities {
3891 #[serde_as(deserialize_as = "DefaultOnError")]
3898 #[schemars(extend("x-deserialize-default-on-error" = true))]
3899 #[serde(default)]
3900 pub session: Option<SessionCapabilities>,
3901 #[serde_as(deserialize_as = "DefaultOnError")]
3903 #[schemars(extend("x-deserialize-default-on-error" = true))]
3904 #[serde(default)]
3905 pub auth: Option<AgentAuthCapabilities>,
3906 #[cfg(feature = "unstable_llm_providers")]
3914 #[serde_as(deserialize_as = "DefaultOnError")]
3915 #[schemars(extend("x-deserialize-default-on-error" = true))]
3916 #[serde(default)]
3917 pub providers: Option<ProvidersCapabilities>,
3918 #[cfg(feature = "unstable_nes")]
3924 #[serde_as(deserialize_as = "DefaultOnError")]
3925 #[schemars(extend("x-deserialize-default-on-error" = true))]
3926 #[serde(default)]
3927 pub nes: Option<NesCapabilities>,
3928 #[cfg(feature = "unstable_nes")]
3934 #[serde_as(deserialize_as = "DefaultOnError")]
3935 #[schemars(extend("x-deserialize-default-on-error" = true))]
3936 #[serde(default)]
3937 pub position_encoding: Option<PositionEncodingKind>,
3938 #[serde_as(deserialize_as = "DefaultOnError")]
3944 #[schemars(extend("x-deserialize-default-on-error" = true))]
3945 #[serde(default)]
3946 #[serde(rename = "_meta")]
3947 pub meta: Option<Meta>,
3948}
3949
3950impl AgentCapabilities {
3951 #[must_use]
3953 pub fn new() -> Self {
3954 Self::default()
3955 }
3956
3957 #[must_use]
3964 pub fn session(mut self, session: impl IntoOption<SessionCapabilities>) -> Self {
3965 self.session = session.into_option();
3966 self
3967 }
3968
3969 #[must_use]
3971 pub fn auth(mut self, auth: impl IntoOption<AgentAuthCapabilities>) -> Self {
3972 self.auth = auth.into_option();
3973 self
3974 }
3975
3976 #[cfg(feature = "unstable_llm_providers")]
3982 #[must_use]
3983 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3984 self.providers = providers.into_option();
3985 self
3986 }
3987
3988 #[cfg(feature = "unstable_nes")]
3994 #[must_use]
3995 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3996 self.nes = nes.into_option();
3997 self
3998 }
3999
4000 #[cfg(feature = "unstable_nes")]
4004 #[must_use]
4005 pub fn position_encoding(
4006 mut self,
4007 position_encoding: impl IntoOption<PositionEncodingKind>,
4008 ) -> Self {
4009 self.position_encoding = position_encoding.into_option();
4010 self
4011 }
4012
4013 #[must_use]
4019 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4020 self.meta = meta.into_option();
4021 self
4022 }
4023}
4024
4025#[cfg(feature = "unstable_llm_providers")]
4033#[serde_as]
4034#[skip_serializing_none]
4035#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4036#[non_exhaustive]
4037pub struct ProvidersCapabilities {
4038 #[serde_as(deserialize_as = "DefaultOnError")]
4044 #[schemars(extend("x-deserialize-default-on-error" = true))]
4045 #[serde(default)]
4046 #[serde(rename = "_meta")]
4047 pub meta: Option<Meta>,
4048}
4049
4050#[cfg(feature = "unstable_llm_providers")]
4051impl ProvidersCapabilities {
4052 #[must_use]
4054 pub fn new() -> Self {
4055 Self::default()
4056 }
4057
4058 #[must_use]
4064 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4065 self.meta = meta.into_option();
4066 self
4067 }
4068}
4069
4070#[serde_as]
4081#[skip_serializing_none]
4082#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4083#[serde(rename_all = "camelCase")]
4084#[non_exhaustive]
4085pub struct SessionCapabilities {
4086 #[serde_as(deserialize_as = "DefaultOnError")]
4092 #[schemars(extend("x-deserialize-default-on-error" = true))]
4093 #[serde(default)]
4094 pub prompt: Option<PromptCapabilities>,
4095 #[serde_as(deserialize_as = "DefaultOnError")]
4100 #[schemars(extend("x-deserialize-default-on-error" = true))]
4101 #[serde(default)]
4102 pub mcp: Option<McpCapabilities>,
4103 #[serde_as(deserialize_as = "DefaultOnError")]
4108 #[schemars(extend("x-deserialize-default-on-error" = true))]
4109 #[serde(default)]
4110 pub load: Option<SessionLoadCapabilities>,
4111 #[serde_as(deserialize_as = "DefaultOnError")]
4113 #[schemars(extend("x-deserialize-default-on-error" = true))]
4114 #[serde(default)]
4115 pub list: Option<SessionListCapabilities>,
4116 #[serde_as(deserialize_as = "DefaultOnError")]
4121 #[schemars(extend("x-deserialize-default-on-error" = true))]
4122 #[serde(default)]
4123 pub delete: Option<SessionDeleteCapabilities>,
4124 #[serde_as(deserialize_as = "DefaultOnError")]
4130 #[schemars(extend("x-deserialize-default-on-error" = true))]
4131 #[serde(default)]
4132 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
4133 #[cfg(feature = "unstable_session_fork")]
4139 #[serde_as(deserialize_as = "DefaultOnError")]
4140 #[schemars(extend("x-deserialize-default-on-error" = true))]
4141 #[serde(default)]
4142 pub fork: Option<SessionForkCapabilities>,
4143 #[serde_as(deserialize_as = "DefaultOnError")]
4145 #[schemars(extend("x-deserialize-default-on-error" = true))]
4146 #[serde(default)]
4147 pub resume: Option<SessionResumeCapabilities>,
4148 #[serde_as(deserialize_as = "DefaultOnError")]
4150 #[schemars(extend("x-deserialize-default-on-error" = true))]
4151 #[serde(default)]
4152 pub close: Option<SessionCloseCapabilities>,
4153 #[serde_as(deserialize_as = "DefaultOnError")]
4159 #[schemars(extend("x-deserialize-default-on-error" = true))]
4160 #[serde(default)]
4161 #[serde(rename = "_meta")]
4162 pub meta: Option<Meta>,
4163}
4164
4165impl SessionCapabilities {
4166 #[must_use]
4168 pub fn new() -> Self {
4169 Self::default()
4170 }
4171
4172 #[must_use]
4178 pub fn prompt(mut self, prompt: impl IntoOption<PromptCapabilities>) -> Self {
4179 self.prompt = prompt.into_option();
4180 self
4181 }
4182
4183 #[must_use]
4188 pub fn mcp(mut self, mcp: impl IntoOption<McpCapabilities>) -> Self {
4189 self.mcp = mcp.into_option();
4190 self
4191 }
4192
4193 #[must_use]
4198 pub fn load(mut self, load: impl IntoOption<SessionLoadCapabilities>) -> Self {
4199 self.load = load.into_option();
4200 self
4201 }
4202
4203 #[must_use]
4205 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
4206 self.list = list.into_option();
4207 self
4208 }
4209
4210 #[must_use]
4215 pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
4216 self.delete = delete.into_option();
4217 self
4218 }
4219
4220 #[must_use]
4226 pub fn additional_directories(
4227 mut self,
4228 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4229 ) -> Self {
4230 self.additional_directories = additional_directories.into_option();
4231 self
4232 }
4233
4234 #[cfg(feature = "unstable_session_fork")]
4235 #[must_use]
4237 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4238 self.fork = fork.into_option();
4239 self
4240 }
4241
4242 #[must_use]
4244 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4245 self.resume = resume.into_option();
4246 self
4247 }
4248
4249 #[must_use]
4251 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4252 self.close = close.into_option();
4253 self
4254 }
4255
4256 #[must_use]
4262 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4263 self.meta = meta.into_option();
4264 self
4265 }
4266}
4267
4268#[serde_as]
4272#[skip_serializing_none]
4273#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4274#[non_exhaustive]
4275pub struct SessionLoadCapabilities {
4276 #[serde_as(deserialize_as = "DefaultOnError")]
4282 #[schemars(extend("x-deserialize-default-on-error" = true))]
4283 #[serde(default)]
4284 #[serde(rename = "_meta")]
4285 pub meta: Option<Meta>,
4286}
4287
4288impl SessionLoadCapabilities {
4289 #[must_use]
4291 pub fn new() -> Self {
4292 Self::default()
4293 }
4294
4295 #[must_use]
4301 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4302 self.meta = meta.into_option();
4303 self
4304 }
4305}
4306
4307#[serde_as]
4311#[skip_serializing_none]
4312#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4313#[non_exhaustive]
4314pub struct SessionListCapabilities {
4315 #[serde_as(deserialize_as = "DefaultOnError")]
4321 #[schemars(extend("x-deserialize-default-on-error" = true))]
4322 #[serde(default)]
4323 #[serde(rename = "_meta")]
4324 pub meta: Option<Meta>,
4325}
4326
4327impl SessionListCapabilities {
4328 #[must_use]
4330 pub fn new() -> Self {
4331 Self::default()
4332 }
4333
4334 #[must_use]
4340 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4341 self.meta = meta.into_option();
4342 self
4343 }
4344}
4345
4346#[serde_as]
4350#[skip_serializing_none]
4351#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4352#[non_exhaustive]
4353pub struct SessionDeleteCapabilities {
4354 #[serde_as(deserialize_as = "DefaultOnError")]
4360 #[schemars(extend("x-deserialize-default-on-error" = true))]
4361 #[serde(default)]
4362 #[serde(rename = "_meta")]
4363 pub meta: Option<Meta>,
4364}
4365
4366impl SessionDeleteCapabilities {
4367 #[must_use]
4369 pub fn new() -> Self {
4370 Self::default()
4371 }
4372
4373 #[must_use]
4379 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4380 self.meta = meta.into_option();
4381 self
4382 }
4383}
4384
4385#[serde_as]
4392#[skip_serializing_none]
4393#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4394#[non_exhaustive]
4395pub struct SessionAdditionalDirectoriesCapabilities {
4396 #[serde_as(deserialize_as = "DefaultOnError")]
4402 #[schemars(extend("x-deserialize-default-on-error" = true))]
4403 #[serde(default)]
4404 #[serde(rename = "_meta")]
4405 pub meta: Option<Meta>,
4406}
4407
4408impl SessionAdditionalDirectoriesCapabilities {
4409 #[must_use]
4411 pub fn new() -> Self {
4412 Self::default()
4413 }
4414
4415 #[must_use]
4421 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4422 self.meta = meta.into_option();
4423 self
4424 }
4425}
4426
4427#[cfg(feature = "unstable_session_fork")]
4435#[serde_as]
4436#[skip_serializing_none]
4437#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4438#[non_exhaustive]
4439pub struct SessionForkCapabilities {
4440 #[serde_as(deserialize_as = "DefaultOnError")]
4446 #[schemars(extend("x-deserialize-default-on-error" = true))]
4447 #[serde(default)]
4448 #[serde(rename = "_meta")]
4449 pub meta: Option<Meta>,
4450}
4451
4452#[cfg(feature = "unstable_session_fork")]
4453impl SessionForkCapabilities {
4454 #[must_use]
4456 pub fn new() -> Self {
4457 Self::default()
4458 }
4459
4460 #[must_use]
4466 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4467 self.meta = meta.into_option();
4468 self
4469 }
4470}
4471
4472#[serde_as]
4476#[skip_serializing_none]
4477#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4478#[non_exhaustive]
4479pub struct SessionResumeCapabilities {
4480 #[serde_as(deserialize_as = "DefaultOnError")]
4486 #[schemars(extend("x-deserialize-default-on-error" = true))]
4487 #[serde(default)]
4488 #[serde(rename = "_meta")]
4489 pub meta: Option<Meta>,
4490}
4491
4492impl SessionResumeCapabilities {
4493 #[must_use]
4495 pub fn new() -> Self {
4496 Self::default()
4497 }
4498
4499 #[must_use]
4505 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4506 self.meta = meta.into_option();
4507 self
4508 }
4509}
4510
4511#[serde_as]
4515#[skip_serializing_none]
4516#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4517#[non_exhaustive]
4518pub struct SessionCloseCapabilities {
4519 #[serde_as(deserialize_as = "DefaultOnError")]
4525 #[schemars(extend("x-deserialize-default-on-error" = true))]
4526 #[serde(default)]
4527 #[serde(rename = "_meta")]
4528 pub meta: Option<Meta>,
4529}
4530
4531impl SessionCloseCapabilities {
4532 #[must_use]
4534 pub fn new() -> Self {
4535 Self::default()
4536 }
4537
4538 #[must_use]
4544 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4545 self.meta = meta.into_option();
4546 self
4547 }
4548}
4549
4550#[serde_as]
4563#[skip_serializing_none]
4564#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4565#[serde(rename_all = "camelCase")]
4566#[non_exhaustive]
4567pub struct PromptCapabilities {
4568 #[serde_as(deserialize_as = "DefaultOnError")]
4573 #[schemars(extend("x-deserialize-default-on-error" = true))]
4574 #[serde(default)]
4575 pub image: Option<PromptImageCapabilities>,
4576 #[serde_as(deserialize_as = "DefaultOnError")]
4581 #[schemars(extend("x-deserialize-default-on-error" = true))]
4582 #[serde(default)]
4583 pub audio: Option<PromptAudioCapabilities>,
4584 #[serde_as(deserialize_as = "DefaultOnError")]
4592 #[schemars(extend("x-deserialize-default-on-error" = true))]
4593 #[serde(default)]
4594 pub embedded_context: Option<PromptEmbeddedContextCapabilities>,
4595 #[serde_as(deserialize_as = "DefaultOnError")]
4601 #[schemars(extend("x-deserialize-default-on-error" = true))]
4602 #[serde(default)]
4603 #[serde(rename = "_meta")]
4604 pub meta: Option<Meta>,
4605}
4606
4607impl PromptCapabilities {
4608 #[must_use]
4610 pub fn new() -> Self {
4611 Self::default()
4612 }
4613
4614 #[must_use]
4619 pub fn image(mut self, image: impl IntoOption<PromptImageCapabilities>) -> Self {
4620 self.image = image.into_option();
4621 self
4622 }
4623
4624 #[must_use]
4629 pub fn audio(mut self, audio: impl IntoOption<PromptAudioCapabilities>) -> Self {
4630 self.audio = audio.into_option();
4631 self
4632 }
4633
4634 #[must_use]
4642 pub fn embedded_context(
4643 mut self,
4644 embedded_context: impl IntoOption<PromptEmbeddedContextCapabilities>,
4645 ) -> Self {
4646 self.embedded_context = embedded_context.into_option();
4647 self
4648 }
4649
4650 #[must_use]
4656 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4657 self.meta = meta.into_option();
4658 self
4659 }
4660}
4661
4662#[serde_as]
4666#[skip_serializing_none]
4667#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4668#[non_exhaustive]
4669pub struct PromptImageCapabilities {
4670 #[serde_as(deserialize_as = "DefaultOnError")]
4676 #[schemars(extend("x-deserialize-default-on-error" = true))]
4677 #[serde(default)]
4678 #[serde(rename = "_meta")]
4679 pub meta: Option<Meta>,
4680}
4681
4682impl PromptImageCapabilities {
4683 #[must_use]
4685 pub fn new() -> Self {
4686 Self::default()
4687 }
4688
4689 #[must_use]
4695 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4696 self.meta = meta.into_option();
4697 self
4698 }
4699}
4700
4701#[serde_as]
4705#[skip_serializing_none]
4706#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4707#[non_exhaustive]
4708pub struct PromptAudioCapabilities {
4709 #[serde_as(deserialize_as = "DefaultOnError")]
4715 #[schemars(extend("x-deserialize-default-on-error" = true))]
4716 #[serde(default)]
4717 #[serde(rename = "_meta")]
4718 pub meta: Option<Meta>,
4719}
4720
4721impl PromptAudioCapabilities {
4722 #[must_use]
4724 pub fn new() -> Self {
4725 Self::default()
4726 }
4727
4728 #[must_use]
4734 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4735 self.meta = meta.into_option();
4736 self
4737 }
4738}
4739
4740#[serde_as]
4744#[skip_serializing_none]
4745#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4746#[non_exhaustive]
4747pub struct PromptEmbeddedContextCapabilities {
4748 #[serde_as(deserialize_as = "DefaultOnError")]
4754 #[schemars(extend("x-deserialize-default-on-error" = true))]
4755 #[serde(default)]
4756 #[serde(rename = "_meta")]
4757 pub meta: Option<Meta>,
4758}
4759
4760impl PromptEmbeddedContextCapabilities {
4761 #[must_use]
4763 pub fn new() -> Self {
4764 Self::default()
4765 }
4766
4767 #[must_use]
4773 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4774 self.meta = meta.into_option();
4775 self
4776 }
4777}
4778
4779#[serde_as]
4781#[skip_serializing_none]
4782#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4783#[serde(rename_all = "camelCase")]
4784#[non_exhaustive]
4785pub struct McpCapabilities {
4786 #[serde_as(deserialize_as = "DefaultOnError")]
4791 #[schemars(extend("x-deserialize-default-on-error" = true))]
4792 #[serde(default)]
4793 pub stdio: Option<McpStdioCapabilities>,
4794 #[serde_as(deserialize_as = "DefaultOnError")]
4799 #[schemars(extend("x-deserialize-default-on-error" = true))]
4800 #[serde(default)]
4801 pub http: Option<McpHttpCapabilities>,
4802 #[cfg(feature = "unstable_mcp_over_acp")]
4811 #[serde_as(deserialize_as = "DefaultOnError")]
4812 #[schemars(extend("x-deserialize-default-on-error" = true))]
4813 #[serde(default)]
4814 pub acp: Option<McpAcpCapabilities>,
4815 #[serde_as(deserialize_as = "DefaultOnError")]
4821 #[schemars(extend("x-deserialize-default-on-error" = true))]
4822 #[serde(default)]
4823 #[serde(rename = "_meta")]
4824 pub meta: Option<Meta>,
4825}
4826
4827impl McpCapabilities {
4828 #[must_use]
4830 pub fn new() -> Self {
4831 Self::default()
4832 }
4833
4834 #[must_use]
4839 pub fn stdio(mut self, stdio: impl IntoOption<McpStdioCapabilities>) -> Self {
4840 self.stdio = stdio.into_option();
4841 self
4842 }
4843
4844 #[must_use]
4849 pub fn http(mut self, http: impl IntoOption<McpHttpCapabilities>) -> Self {
4850 self.http = http.into_option();
4851 self
4852 }
4853
4854 #[cfg(feature = "unstable_mcp_over_acp")]
4860 #[must_use]
4864 pub fn acp(mut self, acp: impl IntoOption<McpAcpCapabilities>) -> Self {
4865 self.acp = acp.into_option();
4866 self
4867 }
4868
4869 #[must_use]
4875 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4876 self.meta = meta.into_option();
4877 self
4878 }
4879}
4880
4881#[serde_as]
4885#[skip_serializing_none]
4886#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4887#[non_exhaustive]
4888pub struct McpStdioCapabilities {
4889 #[serde_as(deserialize_as = "DefaultOnError")]
4895 #[schemars(extend("x-deserialize-default-on-error" = true))]
4896 #[serde(default)]
4897 #[serde(rename = "_meta")]
4898 pub meta: Option<Meta>,
4899}
4900
4901impl McpStdioCapabilities {
4902 #[must_use]
4904 pub fn new() -> Self {
4905 Self::default()
4906 }
4907
4908 #[must_use]
4914 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4915 self.meta = meta.into_option();
4916 self
4917 }
4918}
4919
4920#[serde_as]
4924#[skip_serializing_none]
4925#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4926#[non_exhaustive]
4927pub struct McpHttpCapabilities {
4928 #[serde_as(deserialize_as = "DefaultOnError")]
4934 #[schemars(extend("x-deserialize-default-on-error" = true))]
4935 #[serde(default)]
4936 #[serde(rename = "_meta")]
4937 pub meta: Option<Meta>,
4938}
4939
4940impl McpHttpCapabilities {
4941 #[must_use]
4943 pub fn new() -> Self {
4944 Self::default()
4945 }
4946
4947 #[must_use]
4953 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4954 self.meta = meta.into_option();
4955 self
4956 }
4957}
4958
4959#[cfg(feature = "unstable_mcp_over_acp")]
4967#[serde_as]
4968#[skip_serializing_none]
4969#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4970#[non_exhaustive]
4971pub struct McpAcpCapabilities {
4972 #[serde_as(deserialize_as = "DefaultOnError")]
4978 #[schemars(extend("x-deserialize-default-on-error" = true))]
4979 #[serde(default)]
4980 #[serde(rename = "_meta")]
4981 pub meta: Option<Meta>,
4982}
4983
4984#[cfg(feature = "unstable_mcp_over_acp")]
4985impl McpAcpCapabilities {
4986 #[must_use]
4988 pub fn new() -> Self {
4989 Self::default()
4990 }
4991
4992 #[must_use]
4998 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4999 self.meta = meta.into_option();
5000 self
5001 }
5002}
5003
5004#[serde_as]
5008#[skip_serializing_none]
5009#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5010#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5011#[serde(rename_all = "camelCase")]
5012#[non_exhaustive]
5013pub struct CancelSessionNotification {
5014 pub session_id: SessionId,
5016 #[serde_as(deserialize_as = "DefaultOnError")]
5022 #[schemars(extend("x-deserialize-default-on-error" = true))]
5023 #[serde(default)]
5024 #[serde(rename = "_meta")]
5025 pub meta: Option<Meta>,
5026}
5027
5028impl CancelSessionNotification {
5029 #[must_use]
5031 pub fn new(session_id: impl Into<SessionId>) -> Self {
5032 Self {
5033 session_id: session_id.into(),
5034 meta: None,
5035 }
5036 }
5037
5038 #[must_use]
5044 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5045 self.meta = meta.into_option();
5046 self
5047 }
5048}
5049
5050#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5056#[non_exhaustive]
5057pub struct AgentMethodNames {
5058 pub initialize: &'static str,
5060 pub auth_login: &'static str,
5062 #[cfg(feature = "unstable_llm_providers")]
5064 pub providers_list: &'static str,
5065 #[cfg(feature = "unstable_llm_providers")]
5067 pub providers_set: &'static str,
5068 #[cfg(feature = "unstable_llm_providers")]
5070 pub providers_disable: &'static str,
5071 pub session_new: &'static str,
5073 pub session_load: &'static str,
5075 pub session_set_config_option: &'static str,
5077 pub session_prompt: &'static str,
5079 pub session_cancel: &'static str,
5081 #[cfg(feature = "unstable_mcp_over_acp")]
5083 pub mcp_message: &'static str,
5084 pub session_list: &'static str,
5086 pub session_delete: &'static str,
5088 #[cfg(feature = "unstable_session_fork")]
5090 pub session_fork: &'static str,
5091 pub session_resume: &'static str,
5093 pub session_close: &'static str,
5095 pub auth_logout: &'static str,
5097 #[cfg(feature = "unstable_nes")]
5099 pub nes_start: &'static str,
5100 #[cfg(feature = "unstable_nes")]
5102 pub nes_suggest: &'static str,
5103 #[cfg(feature = "unstable_nes")]
5105 pub nes_accept: &'static str,
5106 #[cfg(feature = "unstable_nes")]
5108 pub nes_reject: &'static str,
5109 #[cfg(feature = "unstable_nes")]
5111 pub nes_close: &'static str,
5112 #[cfg(feature = "unstable_nes")]
5114 pub document_did_open: &'static str,
5115 #[cfg(feature = "unstable_nes")]
5117 pub document_did_change: &'static str,
5118 #[cfg(feature = "unstable_nes")]
5120 pub document_did_close: &'static str,
5121 #[cfg(feature = "unstable_nes")]
5123 pub document_did_save: &'static str,
5124 #[cfg(feature = "unstable_nes")]
5126 pub document_did_focus: &'static str,
5127}
5128
5129pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
5131 initialize: INITIALIZE_METHOD_NAME,
5132 auth_login: AUTH_LOGIN_METHOD_NAME,
5133 #[cfg(feature = "unstable_llm_providers")]
5134 providers_list: PROVIDERS_LIST_METHOD_NAME,
5135 #[cfg(feature = "unstable_llm_providers")]
5136 providers_set: PROVIDERS_SET_METHOD_NAME,
5137 #[cfg(feature = "unstable_llm_providers")]
5138 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
5139 session_new: SESSION_NEW_METHOD_NAME,
5140 session_load: SESSION_LOAD_METHOD_NAME,
5141 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
5142 session_prompt: SESSION_PROMPT_METHOD_NAME,
5143 session_cancel: SESSION_CANCEL_METHOD_NAME,
5144 #[cfg(feature = "unstable_mcp_over_acp")]
5145 mcp_message: MCP_MESSAGE_METHOD_NAME,
5146 session_list: SESSION_LIST_METHOD_NAME,
5147 session_delete: SESSION_DELETE_METHOD_NAME,
5148 #[cfg(feature = "unstable_session_fork")]
5149 session_fork: SESSION_FORK_METHOD_NAME,
5150 session_resume: SESSION_RESUME_METHOD_NAME,
5151 session_close: SESSION_CLOSE_METHOD_NAME,
5152 auth_logout: AUTH_LOGOUT_METHOD_NAME,
5153 #[cfg(feature = "unstable_nes")]
5154 nes_start: NES_START_METHOD_NAME,
5155 #[cfg(feature = "unstable_nes")]
5156 nes_suggest: NES_SUGGEST_METHOD_NAME,
5157 #[cfg(feature = "unstable_nes")]
5158 nes_accept: NES_ACCEPT_METHOD_NAME,
5159 #[cfg(feature = "unstable_nes")]
5160 nes_reject: NES_REJECT_METHOD_NAME,
5161 #[cfg(feature = "unstable_nes")]
5162 nes_close: NES_CLOSE_METHOD_NAME,
5163 #[cfg(feature = "unstable_nes")]
5164 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
5165 #[cfg(feature = "unstable_nes")]
5166 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
5167 #[cfg(feature = "unstable_nes")]
5168 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
5169 #[cfg(feature = "unstable_nes")]
5170 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
5171 #[cfg(feature = "unstable_nes")]
5172 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
5173};
5174
5175pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
5177pub(crate) const AUTH_LOGIN_METHOD_NAME: &str = "auth/login";
5179#[cfg(feature = "unstable_llm_providers")]
5181pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
5182#[cfg(feature = "unstable_llm_providers")]
5184pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
5185#[cfg(feature = "unstable_llm_providers")]
5187pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
5188pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
5190pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
5192pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
5194pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
5196pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
5198pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
5200pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
5202#[cfg(feature = "unstable_session_fork")]
5204pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
5205pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
5207pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
5209pub(crate) const AUTH_LOGOUT_METHOD_NAME: &str = "auth/logout";
5211
5212#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5219#[serde(untagged)]
5220#[schemars(inline)]
5221#[non_exhaustive]
5222pub enum ClientRequest {
5223 InitializeRequest(Box<InitializeRequest>),
5234 LoginAuthRequest(LoginAuthRequest),
5244 #[cfg(feature = "unstable_llm_providers")]
5250 ListProvidersRequest(ListProvidersRequest),
5251 #[cfg(feature = "unstable_llm_providers")]
5257 SetProviderRequest(Box<SetProviderRequest>),
5258 #[cfg(feature = "unstable_llm_providers")]
5264 DisableProviderRequest(DisableProviderRequest),
5265 LogoutAuthRequest(LogoutAuthRequest),
5270 NewSessionRequest(NewSessionRequest),
5283 LoadSessionRequest(LoadSessionRequest),
5294 ListSessionsRequest(ListSessionsRequest),
5300 DeleteSessionRequest(DeleteSessionRequest),
5304 #[cfg(feature = "unstable_session_fork")]
5305 ForkSessionRequest(ForkSessionRequest),
5317 ResumeSessionRequest(ResumeSessionRequest),
5324 CloseSessionRequest(CloseSessionRequest),
5331 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
5333 PromptRequest(PromptRequest),
5345 #[cfg(feature = "unstable_nes")]
5346 StartNesRequest(Box<StartNesRequest>),
5352 #[cfg(feature = "unstable_nes")]
5353 SuggestNesRequest(Box<SuggestNesRequest>),
5359 #[cfg(feature = "unstable_nes")]
5360 CloseNesRequest(CloseNesRequest),
5369 #[cfg(feature = "unstable_mcp_over_acp")]
5375 MessageMcpRequest(MessageMcpRequest),
5376 ExtMethodRequest(ExtRequest),
5383}
5384
5385impl ClientRequest {
5386 #[must_use]
5388 pub fn method(&self) -> &str {
5389 match self {
5390 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
5391 Self::LoginAuthRequest(_) => AGENT_METHOD_NAMES.auth_login,
5392 #[cfg(feature = "unstable_llm_providers")]
5393 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
5394 #[cfg(feature = "unstable_llm_providers")]
5395 Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
5396 #[cfg(feature = "unstable_llm_providers")]
5397 Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
5398 Self::LogoutAuthRequest(_) => AGENT_METHOD_NAMES.auth_logout,
5399 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
5400 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
5401 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
5402 Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
5403 #[cfg(feature = "unstable_session_fork")]
5404 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
5405 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
5406 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
5407 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
5408 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
5409 #[cfg(feature = "unstable_nes")]
5410 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
5411 #[cfg(feature = "unstable_nes")]
5412 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
5413 #[cfg(feature = "unstable_nes")]
5414 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
5415 #[cfg(feature = "unstable_mcp_over_acp")]
5416 Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
5417 Self::ExtMethodRequest(ext_request) => &ext_request.method,
5418 }
5419 }
5420}
5421
5422#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5429#[serde(untagged)]
5430#[schemars(inline)]
5431#[non_exhaustive]
5432pub enum AgentResponse {
5433 InitializeResponse(Box<InitializeResponse>),
5435 LoginAuthResponse(#[serde(default)] LoginAuthResponse),
5437 #[cfg(feature = "unstable_llm_providers")]
5439 ListProvidersResponse(ListProvidersResponse),
5440 #[cfg(feature = "unstable_llm_providers")]
5442 SetProviderResponse(#[serde(default)] SetProviderResponse),
5443 #[cfg(feature = "unstable_llm_providers")]
5445 DisableProviderResponse(#[serde(default)] DisableProviderResponse),
5446 LogoutAuthResponse(#[serde(default)] LogoutAuthResponse),
5448 NewSessionResponse(NewSessionResponse),
5450 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5452 ListSessionsResponse(ListSessionsResponse),
5454 DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
5456 #[cfg(feature = "unstable_session_fork")]
5458 ForkSessionResponse(ForkSessionResponse),
5459 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5461 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5463 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5465 PromptResponse(PromptResponse),
5467 #[cfg(feature = "unstable_nes")]
5469 StartNesResponse(StartNesResponse),
5470 #[cfg(feature = "unstable_nes")]
5472 SuggestNesResponse(SuggestNesResponse),
5473 #[cfg(feature = "unstable_nes")]
5475 CloseNesResponse(#[serde(default)] CloseNesResponse),
5476 ExtMethodResponse(ExtResponse),
5478 #[cfg(feature = "unstable_mcp_over_acp")]
5480 MessageMcpResponse(MessageMcpResponse),
5481}
5482
5483#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5490#[serde(untagged)]
5491#[schemars(inline)]
5492#[non_exhaustive]
5493pub enum ClientNotification {
5494 CancelSessionNotification(CancelSessionNotification),
5508 #[cfg(feature = "unstable_nes")]
5509 DidOpenDocumentNotification(DidOpenDocumentNotification),
5513 #[cfg(feature = "unstable_nes")]
5514 DidChangeDocumentNotification(DidChangeDocumentNotification),
5518 #[cfg(feature = "unstable_nes")]
5519 DidCloseDocumentNotification(DidCloseDocumentNotification),
5523 #[cfg(feature = "unstable_nes")]
5524 DidSaveDocumentNotification(DidSaveDocumentNotification),
5528 #[cfg(feature = "unstable_nes")]
5529 DidFocusDocumentNotification(Box<DidFocusDocumentNotification>),
5533 #[cfg(feature = "unstable_nes")]
5534 AcceptNesNotification(AcceptNesNotification),
5538 #[cfg(feature = "unstable_nes")]
5539 RejectNesNotification(RejectNesNotification),
5543 #[cfg(feature = "unstable_mcp_over_acp")]
5549 MessageMcpNotification(MessageMcpNotification),
5550 ExtNotification(ExtNotification),
5557}
5558
5559impl ClientNotification {
5560 #[must_use]
5562 pub fn method(&self) -> &str {
5563 match self {
5564 Self::CancelSessionNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5565 #[cfg(feature = "unstable_nes")]
5566 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5567 #[cfg(feature = "unstable_nes")]
5568 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5569 #[cfg(feature = "unstable_nes")]
5570 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5571 #[cfg(feature = "unstable_nes")]
5572 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5573 #[cfg(feature = "unstable_nes")]
5574 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5575 #[cfg(feature = "unstable_nes")]
5576 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5577 #[cfg(feature = "unstable_nes")]
5578 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5579 #[cfg(feature = "unstable_mcp_over_acp")]
5580 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5581 Self::ExtNotification(ext_notification) => &ext_notification.method,
5582 }
5583 }
5584}
5585
5586#[cfg(test)]
5587mod test_serialization {
5588 use super::*;
5589 use serde_json::json;
5590
5591 fn test_meta() -> Meta {
5592 json!({ "source": "test" }).as_object().unwrap().clone()
5593 }
5594
5595 fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
5596 serde_json::to_string(value)
5597 .unwrap()
5598 .matches("\"_meta\"")
5599 .count()
5600 }
5601
5602 #[test]
5603 fn test_initialize_capabilities_default_on_malformed_values() {
5604 let request: InitializeRequest = serde_json::from_value(json!({
5605 "protocolVersion": 2,
5606 "capabilities": false,
5607 "info": {
5608 "name": "client",
5609 "version": "1.0.0"
5610 }
5611 }))
5612 .unwrap();
5613 assert_eq!(request.capabilities, ClientCapabilities::default());
5614
5615 let response: InitializeResponse = serde_json::from_value(json!({
5616 "protocolVersion": 2,
5617 "capabilities": false,
5618 "info": {
5619 "name": "agent",
5620 "version": "1.0.0"
5621 }
5622 }))
5623 .unwrap();
5624 assert_eq!(response.capabilities, AgentCapabilities::default());
5625 }
5626
5627 #[test]
5628 fn test_agent_capabilities_default_on_malformed_values() {
5629 let capabilities: AgentCapabilities = serde_json::from_value(json!({
5630 "session": false,
5631 "auth": false
5632 }))
5633 .unwrap();
5634
5635 assert!(capabilities.session.is_none());
5636 assert_eq!(capabilities.auth, None);
5637 }
5638
5639 #[test]
5640 fn test_mcp_server_stdio_serialization() {
5641 let server = McpServer::Stdio(
5642 McpServerStdio::new("test-server", "/usr/bin/server")
5643 .args(vec!["--port".to_string(), "3000".to_string()])
5644 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5645 );
5646
5647 let json = serde_json::to_value(&server).unwrap();
5648 assert_eq!(
5649 json,
5650 json!({
5651 "type": "stdio",
5652 "name": "test-server",
5653 "command": "/usr/bin/server",
5654 "args": ["--port", "3000"],
5655 "env": [
5656 {
5657 "name": "API_KEY",
5658 "value": "secret123"
5659 }
5660 ]
5661 })
5662 );
5663
5664 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5665 match deserialized {
5666 McpServer::Stdio(McpServerStdio {
5667 name,
5668 command,
5669 args,
5670 env,
5671 meta: _,
5672 }) => {
5673 assert_eq!(name, "test-server");
5674 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5675 assert_eq!(args, vec!["--port", "3000"]);
5676 assert_eq!(env.len(), 1);
5677 assert_eq!(env[0].name, "API_KEY");
5678 assert_eq!(env[0].value, "secret123");
5679 }
5680 _ => panic!("Expected Stdio variant"),
5681 }
5682 }
5683
5684 #[test]
5685 fn test_mcp_server_unknown_transport_serialization() {
5686 let json = json!({
5687 "type": "websocket",
5688 "name": "future-server",
5689 "url": "wss://example.com/mcp",
5690 "protocolVersion": "2026-01-01"
5691 });
5692
5693 let deserialized: McpServer = serde_json::from_value(json.clone()).unwrap();
5694 let McpServer::Other(OtherMcpServer { type_, fields }) = &deserialized else {
5695 panic!("Expected Other variant");
5696 };
5697
5698 assert_eq!(type_, "websocket");
5699 assert_eq!(fields["name"], "future-server");
5700 assert_eq!(fields["url"], "wss://example.com/mcp");
5701 assert_eq!(fields["protocolVersion"], "2026-01-01");
5702 assert_eq!(serde_json::to_value(&deserialized).unwrap(), json);
5703 }
5704
5705 #[test]
5706 fn test_mcp_server_stdio_requires_type() {
5707 let result = serde_json::from_value::<McpServer>(json!({
5708 "name": "test-server",
5709 "command": "/usr/bin/server",
5710 "args": [],
5711 "env": []
5712 }));
5713
5714 assert!(result.is_err());
5715 }
5716
5717 #[test]
5718 fn test_mcp_server_unknown_does_not_hide_malformed_known_transport() {
5719 let result = serde_json::from_value::<McpServer>(json!({
5720 "type": "stdio",
5721 "name": "test-server",
5722 "args": [],
5723 "env": []
5724 }));
5725
5726 assert!(result.is_err());
5727 }
5728
5729 #[test]
5730 fn test_mcp_server_http_serialization() {
5731 let server = McpServer::Http(
5732 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5733 HttpHeader::new("Authorization", "Bearer token123"),
5734 HttpHeader::new("Content-Type", "application/json"),
5735 ]),
5736 );
5737
5738 let json = serde_json::to_value(&server).unwrap();
5739 assert_eq!(
5740 json,
5741 json!({
5742 "type": "http",
5743 "name": "http-server",
5744 "url": "https://api.example.com",
5745 "headers": [
5746 {
5747 "name": "Authorization",
5748 "value": "Bearer token123"
5749 },
5750 {
5751 "name": "Content-Type",
5752 "value": "application/json"
5753 }
5754 ]
5755 })
5756 );
5757
5758 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5759 match deserialized {
5760 McpServer::Http(McpServerHttp {
5761 name,
5762 url,
5763 headers,
5764 meta: _,
5765 }) => {
5766 assert_eq!(name, "http-server");
5767 assert_eq!(url, "https://api.example.com");
5768 assert_eq!(headers.len(), 2);
5769 assert_eq!(headers[0].name, "Authorization");
5770 assert_eq!(headers[0].value, "Bearer token123");
5771 assert_eq!(headers[1].name, "Content-Type");
5772 assert_eq!(headers[1].value, "application/json");
5773 }
5774 _ => panic!("Expected Http variant"),
5775 }
5776 }
5777
5778 #[cfg(feature = "unstable_mcp_over_acp")]
5779 #[test]
5780 fn test_client_mcp_message_method_names() {
5781 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5782
5783 assert_eq!(
5784 ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
5785 .method(),
5786 "mcp/message"
5787 );
5788 assert_eq!(
5789 ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
5790 "conn-1",
5791 "notifications/progress"
5792 ))
5793 .method(),
5794 "mcp/message"
5795 );
5796 }
5797
5798 #[test]
5799 fn test_auth_method_names() {
5800 assert_eq!(AGENT_METHOD_NAMES.auth_login, "auth/login");
5801 assert_eq!(AGENT_METHOD_NAMES.auth_logout, "auth/logout");
5802
5803 assert_eq!(
5804 ClientRequest::LoginAuthRequest(LoginAuthRequest::new("agent-login")).method(),
5805 "auth/login"
5806 );
5807 assert_eq!(
5808 ClientRequest::LogoutAuthRequest(LogoutAuthRequest::new()).method(),
5809 "auth/logout"
5810 );
5811 }
5812
5813 #[test]
5814 fn test_session_config_option_category_known_variants() {
5815 assert_eq!(
5817 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5818 json!("mode")
5819 );
5820 assert_eq!(
5821 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5822 json!("model")
5823 );
5824 assert_eq!(
5825 serde_json::to_value(&SessionConfigOptionCategory::ModelConfig).unwrap(),
5826 json!("model_config")
5827 );
5828 assert_eq!(
5829 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5830 json!("thought_level")
5831 );
5832
5833 assert_eq!(
5835 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5836 SessionConfigOptionCategory::Mode
5837 );
5838 assert_eq!(
5839 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5840 SessionConfigOptionCategory::Model
5841 );
5842 assert_eq!(
5843 serde_json::from_str::<SessionConfigOptionCategory>("\"model_config\"").unwrap(),
5844 SessionConfigOptionCategory::ModelConfig
5845 );
5846 assert_eq!(
5847 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5848 SessionConfigOptionCategory::ThoughtLevel
5849 );
5850 }
5851
5852 #[test]
5853 fn test_session_config_option_category_unknown_variants() {
5854 let unknown: SessionConfigOptionCategory =
5856 serde_json::from_str("\"some_future_category\"").unwrap();
5857 assert_eq!(
5858 unknown,
5859 SessionConfigOptionCategory::Other("some_future_category".to_string())
5860 );
5861
5862 let json = serde_json::to_value(&unknown).unwrap();
5864 assert_eq!(json, json!("some_future_category"));
5865 }
5866
5867 #[test]
5868 fn test_session_config_option_category_custom_categories() {
5869 let custom: SessionConfigOptionCategory =
5871 serde_json::from_str("\"_my_custom_category\"").unwrap();
5872 assert_eq!(
5873 custom,
5874 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5875 );
5876
5877 let json = serde_json::to_value(&custom).unwrap();
5879 assert_eq!(json, json!("_my_custom_category"));
5880
5881 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5883 assert_eq!(
5884 deserialized,
5885 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5886 );
5887 }
5888
5889 #[test]
5890 fn test_auth_method_agent_serialization() {
5891 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5892
5893 let json = serde_json::to_value(&method).unwrap();
5894 assert_eq!(
5895 json,
5896 json!({
5897 "id": "default-auth",
5898 "name": "Default Auth",
5899 "type": "agent"
5900 })
5901 );
5902 assert!(!json.as_object().unwrap().contains_key("description"));
5904
5905 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5906 match deserialized {
5907 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5908 assert_eq!(id.0.as_ref(), "default-auth");
5909 assert_eq!(name, "Default Auth");
5910 }
5911 _ => panic!("Expected Agent variant"),
5912 }
5913 }
5914
5915 #[test]
5916 fn test_auth_method_agent_deserialization() {
5917 let json = json!({
5918 "id": "agent-auth",
5919 "name": "Agent Auth",
5920 "type": "agent"
5921 });
5922
5923 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5924 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5925 }
5926
5927 #[test]
5928 fn test_auth_method_agent_requires_type() {
5929 assert!(
5930 serde_json::from_value::<AuthMethod>(json!({
5931 "id": "agent-auth",
5932 "name": "Agent Auth"
5933 }))
5934 .is_err()
5935 );
5936 }
5937
5938 #[test]
5939 fn test_auth_method_agent_rejects_null_type() {
5940 assert!(
5941 serde_json::from_value::<AuthMethod>(json!({
5942 "id": "agent-auth",
5943 "name": "Agent Auth",
5944 "type": null
5945 }))
5946 .is_err()
5947 );
5948 }
5949
5950 #[test]
5951 fn test_auth_method_unknown_does_not_hide_malformed_agent() {
5952 assert!(
5953 serde_json::from_value::<AuthMethod>(json!({
5954 "id": "agent-auth",
5955 "type": "agent"
5956 }))
5957 .is_err()
5958 );
5959 }
5960
5961 #[test]
5962 fn test_auth_method_unknown_variant_roundtrip() {
5963 let method: AuthMethod = serde_json::from_value(json!({
5964 "id": "oauth",
5965 "name": "OAuth",
5966 "type": "_oauth",
5967 "authorizationUrl": "https://example.com/auth"
5968 }))
5969 .unwrap();
5970
5971 assert_eq!(method.id().0.as_ref(), "oauth");
5972 assert_eq!(method.name(), "OAuth");
5973 let AuthMethod::Other(unknown) = method else {
5974 panic!("expected unknown auth method");
5975 };
5976 assert_eq!(unknown.type_, "_oauth");
5977 assert_eq!(
5978 unknown.fields.get("authorizationUrl"),
5979 Some(&json!("https://example.com/auth"))
5980 );
5981
5982 assert_eq!(
5983 serde_json::to_value(AuthMethod::Other(unknown)).unwrap(),
5984 json!({
5985 "id": "oauth",
5986 "name": "OAuth",
5987 "type": "_oauth",
5988 "authorizationUrl": "https://example.com/auth"
5989 })
5990 );
5991 }
5992
5993 #[cfg(feature = "unstable_auth_methods")]
5994 #[test]
5995 fn test_auth_method_unknown_does_not_hide_malformed_known_variant() {
5996 assert!(
5997 serde_json::from_value::<AuthMethod>(json!({
5998 "id": "api-key",
5999 "name": "API Key",
6000 "type": "env_var"
6001 }))
6002 .is_err()
6003 );
6004 }
6005
6006 #[test]
6007 fn test_session_delete_serialization() {
6008 assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
6009 assert_eq!(
6010 ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
6011 "session/delete"
6012 );
6013 assert_eq!(
6014 serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
6015 json!({
6016 "sessionId": "sess_abc123"
6017 })
6018 );
6019 assert_eq!(
6020 serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
6021 json!({})
6022 );
6023 assert_eq!(
6024 serde_json::to_value(
6025 SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
6026 )
6027 .unwrap(),
6028 json!({
6029 "delete": {}
6030 })
6031 );
6032 }
6033 #[test]
6034 fn test_session_additional_directories_serialization() {
6035 assert_eq!(
6036 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
6037 json!({
6038 "cwd": "/home/user/project",
6039 })
6040 );
6041 assert_eq!(
6042 serde_json::to_value(
6043 NewSessionRequest::new("/home/user/project").additional_directories(vec![
6044 PathBuf::from("/home/user/shared-lib"),
6045 PathBuf::from("/home/user/product-docs"),
6046 ])
6047 )
6048 .unwrap(),
6049 json!({
6050 "cwd": "/home/user/project",
6051 "additionalDirectories": [
6052 "/home/user/shared-lib",
6053 "/home/user/product-docs"
6054 ],
6055 })
6056 );
6057 assert_eq!(
6058 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
6059 json!({
6060 "sessionId": "sess_abc123",
6061 "cwd": "/home/user/project"
6062 })
6063 );
6064 assert_eq!(
6065 serde_json::to_value(
6066 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
6067 PathBuf::from("/home/user/shared-lib"),
6068 PathBuf::from("/home/user/product-docs"),
6069 ])
6070 )
6071 .unwrap(),
6072 json!({
6073 "sessionId": "sess_abc123",
6074 "cwd": "/home/user/project",
6075 "additionalDirectories": [
6076 "/home/user/shared-lib",
6077 "/home/user/product-docs"
6078 ]
6079 })
6080 );
6081 assert_eq!(
6082 serde_json::from_value::<SessionInfo>(json!({
6083 "sessionId": "sess_abc123",
6084 "cwd": "/home/user/project"
6085 }))
6086 .unwrap()
6087 .additional_directories,
6088 Vec::<PathBuf>::new()
6089 );
6090 }
6091 #[test]
6092 fn test_session_load_capabilities_serialization() {
6093 assert_eq!(
6094 serde_json::to_value(SessionCapabilities::new().load(SessionLoadCapabilities::new()))
6095 .unwrap(),
6096 json!({
6097 "load": {}
6098 })
6099 );
6100 }
6101
6102 #[test]
6103 fn test_session_additional_directories_capabilities_serialization() {
6104 assert_eq!(
6105 serde_json::to_value(
6106 SessionCapabilities::new()
6107 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
6108 )
6109 .unwrap(),
6110 json!({
6111 "additionalDirectories": {}
6112 })
6113 );
6114 }
6115
6116 #[cfg(feature = "unstable_auth_methods")]
6117 #[test]
6118 fn test_auth_method_env_var_serialization() {
6119 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
6120 "api-key",
6121 "API Key",
6122 vec![AuthEnvVar::new("API_KEY")],
6123 ));
6124
6125 let json = serde_json::to_value(&method).unwrap();
6126 assert_eq!(
6127 json,
6128 json!({
6129 "id": "api-key",
6130 "name": "API Key",
6131 "type": "env_var",
6132 "vars": [{"name": "API_KEY"}]
6133 })
6134 );
6135 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
6137 assert!(
6138 !json["vars"][0]
6139 .as_object()
6140 .unwrap()
6141 .contains_key("optional")
6142 );
6143
6144 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6145 match deserialized {
6146 AuthMethod::EnvVar(AuthMethodEnvVar {
6147 id,
6148 name: method_name,
6149 vars,
6150 link,
6151 ..
6152 }) => {
6153 assert_eq!(id.0.as_ref(), "api-key");
6154 assert_eq!(method_name, "API Key");
6155 assert_eq!(vars.len(), 1);
6156 assert_eq!(vars[0].name, "API_KEY");
6157 assert!(vars[0].secret);
6158 assert!(!vars[0].optional);
6159 assert!(link.is_none());
6160 }
6161 _ => panic!("Expected EnvVar variant"),
6162 }
6163 }
6164
6165 #[cfg(feature = "unstable_auth_methods")]
6166 #[test]
6167 fn test_auth_method_env_var_with_link_serialization() {
6168 let method = AuthMethod::EnvVar(
6169 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
6170 .link("https://example.com/keys"),
6171 );
6172
6173 let json = serde_json::to_value(&method).unwrap();
6174 assert_eq!(
6175 json,
6176 json!({
6177 "id": "api-key",
6178 "name": "API Key",
6179 "type": "env_var",
6180 "vars": [{"name": "API_KEY"}],
6181 "link": "https://example.com/keys"
6182 })
6183 );
6184
6185 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6186 match deserialized {
6187 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
6188 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
6189 }
6190 _ => panic!("Expected EnvVar variant"),
6191 }
6192 }
6193
6194 #[cfg(feature = "unstable_auth_methods")]
6195 #[test]
6196 fn test_auth_method_env_var_multiple_vars() {
6197 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
6198 "azure-openai",
6199 "Azure OpenAI",
6200 vec![
6201 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
6202 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
6203 .label("Endpoint URL")
6204 .secret(false),
6205 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
6206 .label("API Version")
6207 .secret(false)
6208 .optional(true),
6209 ],
6210 ));
6211
6212 let json = serde_json::to_value(&method).unwrap();
6213 assert_eq!(
6214 json,
6215 json!({
6216 "id": "azure-openai",
6217 "name": "Azure OpenAI",
6218 "type": "env_var",
6219 "vars": [
6220 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
6221 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
6222 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
6223 ]
6224 })
6225 );
6226
6227 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6228 match deserialized {
6229 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
6230 assert_eq!(vars.len(), 3);
6231 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
6233 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
6234 assert!(vars[0].secret);
6235 assert!(!vars[0].optional);
6236 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
6238 assert!(!vars[1].secret);
6239 assert!(!vars[1].optional);
6240 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
6242 assert!(!vars[2].secret);
6243 assert!(vars[2].optional);
6244 }
6245 _ => panic!("Expected EnvVar variant"),
6246 }
6247 }
6248
6249 #[cfg(feature = "unstable_auth_methods")]
6250 #[test]
6251 fn test_auth_method_terminal_serialization() {
6252 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
6253
6254 let json = serde_json::to_value(&method).unwrap();
6255 assert_eq!(
6256 json,
6257 json!({
6258 "id": "tui-auth",
6259 "name": "Terminal Auth",
6260 "type": "terminal"
6261 })
6262 );
6263 assert!(!json.as_object().unwrap().contains_key("args"));
6265 assert!(!json.as_object().unwrap().contains_key("env"));
6266
6267 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6268 match deserialized {
6269 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
6270 assert!(args.is_empty());
6271 assert!(env.is_empty());
6272 }
6273 _ => panic!("Expected Terminal variant"),
6274 }
6275 }
6276
6277 #[cfg(feature = "unstable_auth_methods")]
6278 #[test]
6279 fn test_auth_method_terminal_with_args_and_env_serialization() {
6280 let method = AuthMethod::Terminal(
6281 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
6282 .args(vec!["--interactive".to_string(), "--color".to_string()])
6283 .env(vec![EnvVariable::new("TERM", "xterm-256color")]),
6284 );
6285
6286 let json = serde_json::to_value(&method).unwrap();
6287 assert_eq!(
6288 json,
6289 json!({
6290 "id": "tui-auth",
6291 "name": "Terminal Auth",
6292 "type": "terminal",
6293 "args": ["--interactive", "--color"],
6294 "env": [
6295 {
6296 "name": "TERM",
6297 "value": "xterm-256color"
6298 }
6299 ]
6300 })
6301 );
6302
6303 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6304 match deserialized {
6305 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
6306 assert_eq!(args, vec!["--interactive", "--color"]);
6307 assert_eq!(env.len(), 1);
6308 assert_eq!(env[0].name, "TERM");
6309 assert_eq!(env[0].value, "xterm-256color");
6310 }
6311 _ => panic!("Expected Terminal variant"),
6312 }
6313 }
6314
6315 #[cfg(feature = "unstable_boolean_config")]
6316 #[test]
6317 fn test_session_config_option_value_id_serialize() {
6318 let val = SessionConfigOptionValue::value_id("model-1");
6319 let json = serde_json::to_value(&val).unwrap();
6320 assert_eq!(json, json!({ "value": "model-1" }));
6322 assert!(!json.as_object().unwrap().contains_key("type"));
6323 }
6324
6325 #[cfg(feature = "unstable_boolean_config")]
6326 #[test]
6327 fn test_session_config_option_value_boolean_serialize() {
6328 let val = SessionConfigOptionValue::boolean(true);
6329 let json = serde_json::to_value(&val).unwrap();
6330 assert_eq!(json, json!({ "type": "boolean", "value": true }));
6331 }
6332
6333 #[cfg(feature = "unstable_boolean_config")]
6334 #[test]
6335 fn test_session_config_option_value_deserialize_no_type() {
6336 let json = json!({ "value": "model-1" });
6338 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6339 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
6340 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
6341 }
6342
6343 #[cfg(feature = "unstable_boolean_config")]
6344 #[test]
6345 fn test_session_config_option_value_deserialize_boolean() {
6346 let json = json!({ "type": "boolean", "value": true });
6347 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6348 assert_eq!(val, SessionConfigOptionValue::boolean(true));
6349 assert_eq!(val.as_bool(), Some(true));
6350 }
6351
6352 #[cfg(feature = "unstable_boolean_config")]
6353 #[test]
6354 fn test_session_config_option_value_deserialize_boolean_false() {
6355 let json = json!({ "type": "boolean", "value": false });
6356 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6357 assert_eq!(val, SessionConfigOptionValue::boolean(false));
6358 assert_eq!(val.as_bool(), Some(false));
6359 }
6360
6361 #[cfg(feature = "unstable_boolean_config")]
6362 #[test]
6363 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
6364 let json = json!({ "type": "text", "value": "freeform input" });
6366 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6367 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
6368 }
6369
6370 #[cfg(feature = "unstable_boolean_config")]
6371 #[test]
6372 fn test_session_config_option_value_roundtrip_value_id() {
6373 let original = SessionConfigOptionValue::value_id("option-a");
6374 let json = serde_json::to_value(&original).unwrap();
6375 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6376 assert_eq!(original, roundtripped);
6377 }
6378
6379 #[cfg(feature = "unstable_boolean_config")]
6380 #[test]
6381 fn test_session_config_option_value_roundtrip_boolean() {
6382 let original = SessionConfigOptionValue::boolean(false);
6383 let json = serde_json::to_value(&original).unwrap();
6384 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6385 assert_eq!(original, roundtripped);
6386 }
6387
6388 #[cfg(feature = "unstable_boolean_config")]
6389 #[test]
6390 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
6391 let json = json!({ "type": "boolean", "value": "not a bool" });
6393 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
6394 assert!(result.is_ok());
6396 assert_eq!(
6397 result.unwrap().as_value_id().unwrap().to_string(),
6398 "not a bool"
6399 );
6400 }
6401
6402 #[cfg(feature = "unstable_boolean_config")]
6403 #[test]
6404 fn test_session_config_option_value_from_impls() {
6405 let from_str: SessionConfigOptionValue = "model-1".into();
6406 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
6407
6408 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
6409 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
6410
6411 let from_bool: SessionConfigOptionValue = true.into();
6412 assert_eq!(from_bool.as_bool(), Some(true));
6413 }
6414
6415 #[cfg(feature = "unstable_boolean_config")]
6416 #[test]
6417 fn test_set_session_config_option_request_value_id() {
6418 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
6419 let json = serde_json::to_value(&req).unwrap();
6420 assert_eq!(
6421 json,
6422 json!({
6423 "sessionId": "sess_1",
6424 "configId": "model",
6425 "value": "model-1"
6426 })
6427 );
6428 assert!(!json.as_object().unwrap().contains_key("type"));
6430 }
6431
6432 #[cfg(feature = "unstable_boolean_config")]
6433 #[test]
6434 fn test_set_session_config_option_request_boolean() {
6435 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
6436 let json = serde_json::to_value(&req).unwrap();
6437 assert_eq!(
6438 json,
6439 json!({
6440 "sessionId": "sess_1",
6441 "configId": "brave_mode",
6442 "type": "boolean",
6443 "value": true
6444 })
6445 );
6446 }
6447
6448 #[cfg(feature = "unstable_boolean_config")]
6449 #[test]
6450 fn test_set_session_config_option_request_deserialize_no_type() {
6451 let json = json!({
6453 "sessionId": "sess_1",
6454 "configId": "model",
6455 "value": "model-1"
6456 });
6457 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6458 assert_eq!(req.session_id.to_string(), "sess_1");
6459 assert_eq!(req.config_id.to_string(), "model");
6460 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
6461 }
6462
6463 #[cfg(feature = "unstable_boolean_config")]
6464 #[test]
6465 fn test_set_session_config_option_request_deserialize_boolean() {
6466 let json = json!({
6467 "sessionId": "sess_1",
6468 "configId": "brave_mode",
6469 "type": "boolean",
6470 "value": true
6471 });
6472 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6473 assert_eq!(req.value.as_bool(), Some(true));
6474 }
6475
6476 #[cfg(feature = "unstable_boolean_config")]
6477 #[test]
6478 fn test_set_session_config_option_request_roundtrip_value_id() {
6479 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
6480 let json = serde_json::to_value(&original).unwrap();
6481 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6482 assert_eq!(original, roundtripped);
6483 }
6484
6485 #[cfg(feature = "unstable_boolean_config")]
6486 #[test]
6487 fn test_set_session_config_option_request_roundtrip_boolean() {
6488 let original = SetSessionConfigOptionRequest::new("s", "c", false);
6489 let json = serde_json::to_value(&original).unwrap();
6490 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6491 assert_eq!(original, roundtripped);
6492 }
6493
6494 #[cfg(feature = "unstable_boolean_config")]
6495 #[test]
6496 fn test_session_config_boolean_serialization() {
6497 let cfg = SessionConfigBoolean::new(true);
6498 let json = serde_json::to_value(&cfg).unwrap();
6499 assert_eq!(json, json!({ "currentValue": true }));
6500
6501 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6502 assert!(deserialized.current_value);
6503 }
6504
6505 #[cfg(feature = "unstable_boolean_config")]
6506 #[test]
6507 fn test_session_config_option_boolean_variant() {
6508 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6509 .description("Skip confirmation prompts")
6510 .meta(test_meta());
6511 assert_eq!(serialized_meta_key_count(&opt), 1);
6512
6513 let json = serde_json::to_value(&opt).unwrap();
6514 assert_eq!(
6515 json,
6516 json!({
6517 "id": "brave_mode",
6518 "name": "Brave Mode",
6519 "description": "Skip confirmation prompts",
6520 "type": "boolean",
6521 "currentValue": false,
6522 "_meta": {
6523 "source": "test"
6524 }
6525 })
6526 );
6527
6528 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6529 assert_eq!(deserialized.id.to_string(), "brave_mode");
6530 assert_eq!(deserialized.name, "Brave Mode");
6531 match deserialized.kind {
6532 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6533 _ => panic!("Expected Boolean kind"),
6534 }
6535 }
6536
6537 #[cfg(feature = "unstable_boolean_config")]
6538 #[test]
6539 fn test_session_config_option_select_still_works() {
6540 let opt = SessionConfigOption::select(
6542 "model",
6543 "Model",
6544 "model-1",
6545 vec![
6546 SessionConfigSelectOption::new("model-1", "Model 1"),
6547 SessionConfigSelectOption::new("model-2", "Model 2"),
6548 ],
6549 )
6550 .meta(test_meta());
6551 assert_eq!(serialized_meta_key_count(&opt), 1);
6552
6553 let json = serde_json::to_value(&opt).unwrap();
6554 assert_eq!(json["type"], "select");
6555 assert_eq!(json["currentValue"], "model-1");
6556 assert_eq!(json["options"].as_array().unwrap().len(), 2);
6557 assert_eq!(json["_meta"]["source"], "test");
6558
6559 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6560 match deserialized.kind {
6561 SessionConfigKind::Select(ref s) => {
6562 assert_eq!(s.current_value.to_string(), "model-1");
6563 }
6564 _ => panic!("Expected Select kind"),
6565 }
6566 }
6567
6568 #[test]
6569 fn test_session_config_option_unknown_kind_roundtrip() {
6570 let option: SessionConfigOption = serde_json::from_value(json!({
6571 "id": "verbosity",
6572 "name": "Verbosity",
6573 "type": "_slider",
6574 "currentValue": 3,
6575 "min": 0,
6576 "max": 5,
6577 "_meta": {
6578 "source": "test"
6579 }
6580 }))
6581 .unwrap();
6582
6583 assert_eq!(option.id.to_string(), "verbosity");
6584 assert_eq!(option.meta.as_ref().unwrap()["source"], "test");
6585 let SessionConfigKind::Other(unknown) = &option.kind else {
6586 panic!("expected unknown config kind");
6587 };
6588 assert_eq!(unknown.type_, "_slider");
6589 assert_eq!(unknown.fields.get("currentValue"), Some(&json!(3)));
6590 assert!(!unknown.fields.contains_key("_meta"));
6591 assert_eq!(serialized_meta_key_count(&option), 1);
6592
6593 let json = serde_json::to_value(&option).unwrap();
6594 assert_eq!(json["type"], "_slider");
6595 assert_eq!(json["currentValue"], 3);
6596 assert_eq!(json["min"], 0);
6597 assert_eq!(json["max"], 5);
6598 assert_eq!(json["_meta"]["source"], "test");
6599 }
6600
6601 #[test]
6602 fn test_session_config_option_unknown_kind_does_not_duplicate_flattened_meta() {
6603 let mut fields = std::collections::BTreeMap::new();
6604 fields.insert("currentValue".to_string(), json!(3));
6605 fields.insert("_meta".to_string(), json!({ "inner": "ignored" }));
6606
6607 let option = SessionConfigOption::new(
6608 "verbosity",
6609 "Verbosity",
6610 SessionConfigKind::Other(OtherSessionConfigKind::new("_slider", fields)),
6611 )
6612 .meta(test_meta());
6613
6614 let SessionConfigKind::Other(unknown) = &option.kind else {
6615 panic!("expected unknown config kind");
6616 };
6617 assert!(!unknown.fields.contains_key("_meta"));
6618 assert_eq!(serialized_meta_key_count(&option), 1);
6619
6620 let json = serde_json::to_value(&option).unwrap();
6621 assert_eq!(json["type"], "_slider");
6622 assert_eq!(json["currentValue"], 3);
6623 assert_eq!(json["_meta"]["source"], "test");
6624 }
6625
6626 #[test]
6627 fn test_session_config_option_unknown_does_not_hide_malformed_known_kind() {
6628 assert!(
6629 serde_json::from_value::<SessionConfigOption>(json!({
6630 "id": "model",
6631 "name": "Model",
6632 "type": "select"
6633 }))
6634 .is_err()
6635 );
6636 }
6637
6638 #[cfg(feature = "unstable_llm_providers")]
6639 #[test]
6640 fn test_llm_protocol_known_variants() {
6641 assert_eq!(
6642 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6643 json!("anthropic")
6644 );
6645 assert_eq!(
6646 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6647 json!("openai")
6648 );
6649 assert_eq!(
6650 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6651 json!("azure")
6652 );
6653 assert_eq!(
6654 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6655 json!("vertex")
6656 );
6657 assert_eq!(
6658 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6659 json!("bedrock")
6660 );
6661
6662 assert_eq!(
6663 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6664 LlmProtocol::Anthropic
6665 );
6666 assert_eq!(
6667 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6668 LlmProtocol::OpenAi
6669 );
6670 assert_eq!(
6671 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6672 LlmProtocol::Azure
6673 );
6674 assert_eq!(
6675 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6676 LlmProtocol::Vertex
6677 );
6678 assert_eq!(
6679 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6680 LlmProtocol::Bedrock
6681 );
6682 }
6683
6684 #[cfg(feature = "unstable_llm_providers")]
6685 #[test]
6686 fn test_llm_protocol_unknown_variant() {
6687 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6688 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6689
6690 let json = serde_json::to_value(&unknown).unwrap();
6691 assert_eq!(json, json!("cohere"));
6692 }
6693
6694 #[cfg(feature = "unstable_llm_providers")]
6695 #[test]
6696 fn test_provider_current_config_serialization() {
6697 let config =
6698 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6699
6700 let json = serde_json::to_value(&config).unwrap();
6701 assert_eq!(
6702 json,
6703 json!({
6704 "apiType": "anthropic",
6705 "baseUrl": "https://api.anthropic.com"
6706 })
6707 );
6708
6709 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6710 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6711 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6712 }
6713
6714 #[cfg(feature = "unstable_llm_providers")]
6715 #[test]
6716 fn test_provider_info_with_current_config() {
6717 let info = ProviderInfo::new(
6718 "main",
6719 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6720 true,
6721 Some(ProviderCurrentConfig::new(
6722 LlmProtocol::Anthropic,
6723 "https://api.anthropic.com",
6724 )),
6725 );
6726
6727 let json = serde_json::to_value(&info).unwrap();
6728 assert_eq!(
6729 json,
6730 json!({
6731 "id": "main",
6732 "supported": ["anthropic", "openai"],
6733 "required": true,
6734 "current": {
6735 "apiType": "anthropic",
6736 "baseUrl": "https://api.anthropic.com"
6737 }
6738 })
6739 );
6740
6741 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6742 assert_eq!(deserialized.id, "main");
6743 assert_eq!(deserialized.supported.len(), 2);
6744 assert!(deserialized.required);
6745 assert!(deserialized.current.is_some());
6746 assert_eq!(
6747 deserialized.current.as_ref().unwrap().api_type,
6748 LlmProtocol::Anthropic
6749 );
6750 }
6751
6752 #[cfg(feature = "unstable_llm_providers")]
6753 #[test]
6754 fn test_provider_info_disabled() {
6755 let info = ProviderInfo::new(
6756 "secondary",
6757 vec![LlmProtocol::OpenAi],
6758 false,
6759 None::<ProviderCurrentConfig>,
6760 );
6761
6762 let json = serde_json::to_value(&info).unwrap();
6763 assert_eq!(
6764 json,
6765 json!({
6766 "id": "secondary",
6767 "supported": ["openai"],
6768 "required": false
6769 })
6770 );
6771
6772 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6773 assert_eq!(deserialized.id, "secondary");
6774 assert!(!deserialized.required);
6775 assert!(deserialized.current.is_none());
6776 }
6777
6778 #[cfg(feature = "unstable_llm_providers")]
6779 #[test]
6780 fn test_provider_info_missing_current_defaults_to_none() {
6781 let json = json!({
6783 "id": "main",
6784 "supported": ["anthropic"],
6785 "required": true
6786 });
6787 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6788 assert!(deserialized.current.is_none());
6789 }
6790
6791 #[cfg(feature = "unstable_llm_providers")]
6792 #[test]
6793 fn test_provider_info_explicit_null_current_decodes_to_none() {
6794 let json = json!({
6798 "id": "main",
6799 "supported": ["anthropic"],
6800 "required": true,
6801 "current": null
6802 });
6803 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6804 assert!(deserialized.current.is_none());
6805 }
6806
6807 #[cfg(feature = "unstable_llm_providers")]
6808 #[test]
6809 fn test_list_providers_response_serialization() {
6810 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6811 "main",
6812 vec![LlmProtocol::Anthropic],
6813 true,
6814 Some(ProviderCurrentConfig::new(
6815 LlmProtocol::Anthropic,
6816 "https://api.anthropic.com",
6817 )),
6818 )]);
6819
6820 let json = serde_json::to_value(&response).unwrap();
6821 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6822 assert_eq!(json["providers"][0]["id"], "main");
6823
6824 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6825 assert_eq!(deserialized.providers.len(), 1);
6826 }
6827
6828 #[cfg(feature = "unstable_llm_providers")]
6829 #[test]
6830 fn test_set_provider_request_serialization() {
6831 use std::collections::HashMap;
6832
6833 let mut headers = HashMap::new();
6834 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6835
6836 let request =
6837 SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6838 .headers(headers);
6839
6840 let json = serde_json::to_value(&request).unwrap();
6841 assert_eq!(
6842 json,
6843 json!({
6844 "id": "main",
6845 "apiType": "openai",
6846 "baseUrl": "https://api.openai.com/v1",
6847 "headers": {
6848 "Authorization": "Bearer sk-test"
6849 }
6850 })
6851 );
6852
6853 let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6854 assert_eq!(deserialized.id, "main");
6855 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6856 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6857 assert_eq!(deserialized.headers.len(), 1);
6858 assert_eq!(
6859 deserialized.headers.get("Authorization").unwrap(),
6860 "Bearer sk-test"
6861 );
6862 }
6863
6864 #[cfg(feature = "unstable_llm_providers")]
6865 #[test]
6866 fn test_set_provider_request_omits_empty_headers() {
6867 let request =
6868 SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6869
6870 let json = serde_json::to_value(&request).unwrap();
6871 assert!(!json.as_object().unwrap().contains_key("headers"));
6873 }
6874
6875 #[cfg(feature = "unstable_llm_providers")]
6876 #[test]
6877 fn test_disable_provider_request_serialization() {
6878 let request = DisableProviderRequest::new("secondary");
6879
6880 let json = serde_json::to_value(&request).unwrap();
6881 assert_eq!(json, json!({ "id": "secondary" }));
6882
6883 let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6884 assert_eq!(deserialized.id, "secondary");
6885 }
6886
6887 #[cfg(feature = "unstable_llm_providers")]
6888 #[test]
6889 fn test_providers_capabilities_serialization() {
6890 let caps = ProvidersCapabilities::new();
6891
6892 let json = serde_json::to_value(&caps).unwrap();
6893 assert_eq!(json, json!({}));
6894
6895 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6896 assert!(deserialized.meta.is_none());
6897 }
6898
6899 #[cfg(feature = "unstable_llm_providers")]
6900 #[test]
6901 fn test_agent_capabilities_with_providers() {
6902 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6903
6904 let json = serde_json::to_value(&caps).unwrap();
6905 assert_eq!(json["providers"], json!({}));
6906
6907 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6908 assert!(deserialized.providers.is_some());
6909 }
6910
6911 #[test]
6912 fn test_agent_capabilities_session_is_explicit() {
6913 let json = serde_json::to_value(AgentCapabilities::new()).unwrap();
6914 assert!(json.get("session").is_none());
6915
6916 let caps = AgentCapabilities::new().session(
6917 SessionCapabilities::new()
6918 .prompt(PromptCapabilities::new().image(PromptImageCapabilities::new()))
6919 .mcp(McpCapabilities::new().stdio(McpStdioCapabilities::new()))
6920 .load(SessionLoadCapabilities::new()),
6921 );
6922
6923 assert_eq!(
6924 serde_json::to_value(&caps).unwrap(),
6925 json!({
6926 "session": {
6927 "prompt": {
6928 "image": {}
6929 },
6930 "mcp": {
6931 "stdio": {}
6932 },
6933 "load": {}
6934 }
6935 })
6936 );
6937
6938 let deserialized: AgentCapabilities = serde_json::from_value(json!({
6939 "session": false
6940 }))
6941 .unwrap();
6942 assert!(deserialized.session.is_none());
6943 }
6944
6945 #[test]
6946 fn test_prompt_capabilities_serialize_supported_content_as_objects() {
6947 let caps = PromptCapabilities::new()
6948 .image(PromptImageCapabilities::new())
6949 .audio(PromptAudioCapabilities::new())
6950 .embedded_context(PromptEmbeddedContextCapabilities::new());
6951
6952 assert_eq!(
6953 serde_json::to_value(&caps).unwrap(),
6954 json!({
6955 "image": {},
6956 "audio": {},
6957 "embeddedContext": {}
6958 })
6959 );
6960
6961 let deserialized: PromptCapabilities = serde_json::from_value(json!({
6962 "image": null,
6963 "audio": false,
6964 "embeddedContext": {}
6965 }))
6966 .unwrap();
6967 assert!(deserialized.image.is_none());
6968 assert!(deserialized.audio.is_none());
6969 assert!(deserialized.embedded_context.is_some());
6970 }
6971
6972 #[test]
6973 fn test_mcp_capabilities_serialize_supported_transports_as_objects() {
6974 let caps = McpCapabilities::new()
6975 .stdio(McpStdioCapabilities::new())
6976 .http(McpHttpCapabilities::new());
6977
6978 assert_eq!(
6979 serde_json::to_value(&caps).unwrap(),
6980 json!({
6981 "stdio": {},
6982 "http": {}
6983 })
6984 );
6985
6986 let deserialized: McpCapabilities = serde_json::from_value(json!({
6987 "stdio": null,
6988 "http": false
6989 }))
6990 .unwrap();
6991 assert!(deserialized.stdio.is_none());
6992 assert!(deserialized.http.is_none());
6993 }
6994
6995 #[cfg(feature = "unstable_mcp_over_acp")]
6996 #[test]
6997 fn test_mcp_capabilities_serialize_acp_support_as_object() {
6998 let caps = McpCapabilities::new().acp(McpAcpCapabilities::new());
6999
7000 assert_eq!(
7001 serde_json::to_value(&caps).unwrap(),
7002 json!({
7003 "acp": {}
7004 })
7005 );
7006 }
7007}