1use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
7
8#[cfg(any(feature = "unstable_auth_methods", feature = "unstable_llm_providers"))]
9use std::collections::HashMap;
10
11use derive_more::{Display, From};
12use schemars::{JsonSchema, Schema};
13use serde::{Deserialize, Serialize};
14use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
15
16use super::{
17 ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, Meta, SessionId,
18};
19use crate::{IntoOption, MaybeUndefined, ProtocolVersion, SkipListener};
20
21#[cfg(feature = "unstable_mcp_over_acp")]
22use super::mcp::{
23 MCP_MESSAGE_METHOD_NAME, MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
24};
25
26#[cfg(feature = "unstable_nes")]
27use super::{
28 AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
29 DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
30 DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
31 StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
32};
33
34#[cfg(feature = "unstable_nes")]
35use super::{
36 DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
37 DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
38 NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
39 NES_SUGGEST_METHOD_NAME,
40};
41
42#[serde_as]
50#[skip_serializing_none]
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
52#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
53#[serde(rename_all = "camelCase")]
54#[non_exhaustive]
55pub struct InitializeRequest {
56 pub protocol_version: ProtocolVersion,
58 #[serde(default)]
60 pub capabilities: ClientCapabilities,
61 #[serde_as(deserialize_as = "DefaultOnError")]
65 #[schemars(extend("x-deserialize-default-on-error" = true))]
66 #[serde(default)]
67 pub client_info: Option<Implementation>,
68 #[serde(rename = "_meta")]
74 pub meta: Option<Meta>,
75}
76
77impl InitializeRequest {
78 #[must_use]
79 pub fn new(protocol_version: ProtocolVersion) -> Self {
80 Self {
81 protocol_version,
82 capabilities: ClientCapabilities::default(),
83 client_info: None,
84 meta: None,
85 }
86 }
87
88 #[must_use]
90 pub fn capabilities(mut self, capabilities: ClientCapabilities) -> Self {
91 self.capabilities = capabilities;
92 self
93 }
94
95 #[must_use]
97 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
98 self.client_info = client_info.into_option();
99 self
100 }
101
102 #[must_use]
108 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
109 self.meta = meta.into_option();
110 self
111 }
112}
113
114#[serde_as]
120#[skip_serializing_none]
121#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
122#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
123#[serde(rename_all = "camelCase")]
124#[non_exhaustive]
125pub struct InitializeResponse {
126 pub protocol_version: ProtocolVersion,
131 #[serde(default)]
133 pub capabilities: AgentCapabilities,
134 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
136 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
137 #[serde(default)]
138 pub auth_methods: Vec<AuthMethod>,
139 #[serde_as(deserialize_as = "DefaultOnError")]
143 #[schemars(extend("x-deserialize-default-on-error" = true))]
144 #[serde(default)]
145 pub agent_info: Option<Implementation>,
146 #[serde(rename = "_meta")]
152 pub meta: Option<Meta>,
153}
154
155impl InitializeResponse {
156 #[must_use]
157 pub fn new(protocol_version: ProtocolVersion) -> Self {
158 Self {
159 protocol_version,
160 capabilities: AgentCapabilities::default(),
161 auth_methods: vec![],
162 agent_info: None,
163 meta: None,
164 }
165 }
166
167 #[must_use]
169 pub fn capabilities(mut self, capabilities: AgentCapabilities) -> Self {
170 self.capabilities = capabilities;
171 self
172 }
173
174 #[must_use]
176 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
177 self.auth_methods = auth_methods;
178 self
179 }
180
181 #[must_use]
183 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
184 self.agent_info = agent_info.into_option();
185 self
186 }
187
188 #[must_use]
194 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
195 self.meta = meta.into_option();
196 self
197 }
198}
199
200#[skip_serializing_none]
204#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
205#[serde(rename_all = "camelCase")]
206#[non_exhaustive]
207pub struct Implementation {
208 pub name: String,
211 pub title: Option<String>,
216 pub version: String,
219 #[serde(rename = "_meta")]
225 pub meta: Option<Meta>,
226}
227
228impl Implementation {
229 #[must_use]
230 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
231 Self {
232 name: name.into(),
233 title: None,
234 version: version.into(),
235 meta: None,
236 }
237 }
238
239 #[must_use]
244 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
245 self.title = title.into_option();
246 self
247 }
248
249 #[must_use]
255 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
256 self.meta = meta.into_option();
257 self
258 }
259}
260
261#[skip_serializing_none]
267#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
268#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
269#[serde(rename_all = "camelCase")]
270#[non_exhaustive]
271pub struct AuthenticateRequest {
272 pub method_id: AuthMethodId,
275 #[serde(rename = "_meta")]
281 pub meta: Option<Meta>,
282}
283
284impl AuthenticateRequest {
285 #[must_use]
286 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
287 Self {
288 method_id: method_id.into(),
289 meta: None,
290 }
291 }
292
293 #[must_use]
299 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
300 self.meta = meta.into_option();
301 self
302 }
303}
304
305#[skip_serializing_none]
307#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
308#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
309#[serde(rename_all = "camelCase")]
310#[non_exhaustive]
311pub struct AuthenticateResponse {
312 #[serde(rename = "_meta")]
318 pub meta: Option<Meta>,
319}
320
321impl AuthenticateResponse {
322 #[must_use]
323 pub fn new() -> Self {
324 Self::default()
325 }
326
327 #[must_use]
333 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
334 self.meta = meta.into_option();
335 self
336 }
337}
338
339#[skip_serializing_none]
345#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
346#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
347#[serde(rename_all = "camelCase")]
348#[non_exhaustive]
349pub struct LogoutRequest {
350 #[serde(rename = "_meta")]
356 pub meta: Option<Meta>,
357}
358
359impl LogoutRequest {
360 #[must_use]
361 pub fn new() -> Self {
362 Self::default()
363 }
364
365 #[must_use]
371 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
372 self.meta = meta.into_option();
373 self
374 }
375}
376
377#[skip_serializing_none]
379#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
380#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
381#[serde(rename_all = "camelCase")]
382#[non_exhaustive]
383pub struct LogoutResponse {
384 #[serde(rename = "_meta")]
390 pub meta: Option<Meta>,
391}
392
393impl LogoutResponse {
394 #[must_use]
395 pub fn new() -> Self {
396 Self::default()
397 }
398
399 #[must_use]
405 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
406 self.meta = meta.into_option();
407 self
408 }
409}
410
411#[serde_as]
413#[skip_serializing_none]
414#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
415#[serde(rename_all = "camelCase")]
416#[non_exhaustive]
417pub struct AgentAuthCapabilities {
418 #[serde_as(deserialize_as = "DefaultOnError")]
422 #[schemars(extend("x-deserialize-default-on-error" = true))]
423 #[serde(default)]
424 pub logout: Option<LogoutCapabilities>,
425 #[serde(rename = "_meta")]
431 pub meta: Option<Meta>,
432}
433
434impl AgentAuthCapabilities {
435 #[must_use]
436 pub fn new() -> Self {
437 Self::default()
438 }
439
440 #[must_use]
442 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
443 self.logout = logout.into_option();
444 self
445 }
446
447 #[must_use]
453 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
454 self.meta = meta.into_option();
455 self
456 }
457}
458
459#[skip_serializing_none]
463#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
464#[non_exhaustive]
465pub struct LogoutCapabilities {
466 #[serde(rename = "_meta")]
472 pub meta: Option<Meta>,
473}
474
475impl LogoutCapabilities {
476 #[must_use]
477 pub fn new() -> Self {
478 Self::default()
479 }
480
481 #[must_use]
487 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
488 self.meta = meta.into_option();
489 self
490 }
491}
492
493#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
494#[serde(transparent)]
495#[from(Arc<str>, String, &'static str)]
496#[non_exhaustive]
497pub struct AuthMethodId(pub Arc<str>);
498
499impl AuthMethodId {
500 #[must_use]
501 pub fn new(id: impl Into<Arc<str>>) -> Self {
502 Self(id.into())
503 }
504}
505
506#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
511#[serde(tag = "type", rename_all = "snake_case")]
512#[non_exhaustive]
513pub enum AuthMethod {
514 #[cfg(feature = "unstable_auth_methods")]
520 EnvVar(AuthMethodEnvVar),
521 #[cfg(feature = "unstable_auth_methods")]
527 Terminal(AuthMethodTerminal),
528 #[serde(untagged)]
538 Other(OtherAuthMethod),
539 #[serde(untagged)]
543 Agent(AuthMethodAgent),
544}
545
546impl AuthMethod {
547 #[must_use]
549 pub fn id(&self) -> &AuthMethodId {
550 match self {
551 Self::Agent(a) => &a.id,
552 Self::Other(a) => &a.id,
553 #[cfg(feature = "unstable_auth_methods")]
554 Self::EnvVar(e) => &e.id,
555 #[cfg(feature = "unstable_auth_methods")]
556 Self::Terminal(t) => &t.id,
557 }
558 }
559
560 #[must_use]
562 pub fn name(&self) -> &str {
563 match self {
564 Self::Agent(a) => &a.name,
565 Self::Other(a) => &a.name,
566 #[cfg(feature = "unstable_auth_methods")]
567 Self::EnvVar(e) => &e.name,
568 #[cfg(feature = "unstable_auth_methods")]
569 Self::Terminal(t) => &t.name,
570 }
571 }
572
573 #[must_use]
575 pub fn description(&self) -> Option<&str> {
576 match self {
577 Self::Agent(a) => a.description.as_deref(),
578 Self::Other(a) => a.description.as_deref(),
579 #[cfg(feature = "unstable_auth_methods")]
580 Self::EnvVar(e) => e.description.as_deref(),
581 #[cfg(feature = "unstable_auth_methods")]
582 Self::Terminal(t) => t.description.as_deref(),
583 }
584 }
585
586 #[must_use]
592 pub fn meta(&self) -> Option<&Meta> {
593 match self {
594 Self::Agent(a) => a.meta.as_ref(),
595 Self::Other(a) => a.meta.as_ref(),
596 #[cfg(feature = "unstable_auth_methods")]
597 Self::EnvVar(e) => e.meta.as_ref(),
598 #[cfg(feature = "unstable_auth_methods")]
599 Self::Terminal(t) => t.meta.as_ref(),
600 }
601 }
602}
603
604#[skip_serializing_none]
606#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
607#[schemars(inline)]
608#[schemars(transform = other_auth_method_schema)]
609#[serde(rename_all = "camelCase")]
610#[non_exhaustive]
611pub struct OtherAuthMethod {
612 #[serde(rename = "type")]
618 pub type_: String,
619 pub id: AuthMethodId,
621 pub name: String,
623 pub description: Option<String>,
625 #[serde(rename = "_meta")]
631 pub meta: Option<Meta>,
632 #[serde(flatten)]
634 pub fields: BTreeMap<String, serde_json::Value>,
635}
636
637impl OtherAuthMethod {
638 #[must_use]
639 pub fn new(
640 type_: impl Into<String>,
641 id: impl Into<AuthMethodId>,
642 name: impl Into<String>,
643 mut fields: BTreeMap<String, serde_json::Value>,
644 ) -> Self {
645 fields.remove("type");
646 fields.remove("id");
647 fields.remove("name");
648 fields.remove("description");
649 fields.remove("_meta");
650 Self {
651 type_: type_.into(),
652 id: id.into(),
653 name: name.into(),
654 description: None,
655 meta: None,
656 fields,
657 }
658 }
659
660 #[must_use]
662 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
663 self.description = description.into_option();
664 self
665 }
666
667 #[must_use]
673 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
674 self.meta = meta.into_option();
675 self
676 }
677}
678
679impl<'de> Deserialize<'de> for OtherAuthMethod {
680 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
681 where
682 D: serde::Deserializer<'de>,
683 {
684 #[derive(Deserialize)]
685 #[serde(rename_all = "camelCase")]
686 struct RawOtherAuthMethod {
687 #[serde(rename = "type")]
688 type_: String,
689 id: AuthMethodId,
690 name: String,
691 description: Option<String>,
692 #[serde(rename = "_meta")]
693 meta: Option<Meta>,
694 #[serde(flatten)]
695 fields: BTreeMap<String, serde_json::Value>,
696 }
697
698 let raw = RawOtherAuthMethod::deserialize(deserializer)?;
699 if is_known_auth_method_type(&raw.type_) {
700 return Err(serde::de::Error::custom(format!(
701 "known authentication method `{}` did not match its schema",
702 raw.type_
703 )));
704 }
705
706 Ok(Self {
707 type_: raw.type_,
708 id: raw.id,
709 name: raw.name,
710 description: raw.description,
711 meta: raw.meta,
712 fields: raw.fields,
713 })
714 }
715}
716
717fn is_known_auth_method_type(type_: &str) -> bool {
718 match type_ {
719 "agent" => true,
720 #[cfg(feature = "unstable_auth_methods")]
721 "env_var" | "terminal" => true,
722 _ => false,
723 }
724}
725
726fn other_auth_method_schema(schema: &mut Schema) {
727 super::schema_util::reject_known_string_discriminators(
728 schema,
729 "type",
730 &[
731 "agent",
732 #[cfg(feature = "unstable_auth_methods")]
733 "env_var",
734 #[cfg(feature = "unstable_auth_methods")]
735 "terminal",
736 ],
737 );
738}
739
740#[skip_serializing_none]
744#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
745#[schemars(transform = auth_method_agent_schema)]
746#[serde(rename_all = "camelCase")]
747#[non_exhaustive]
748pub struct AuthMethodAgent {
749 pub id: AuthMethodId,
751 pub name: String,
753 pub description: Option<String>,
755 #[serde(rename = "_meta")]
761 pub meta: Option<Meta>,
762}
763
764impl AuthMethodAgent {
765 #[must_use]
766 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
767 Self {
768 id: id.into(),
769 name: name.into(),
770 description: None,
771 meta: None,
772 }
773 }
774
775 #[must_use]
777 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
778 self.description = description.into_option();
779 self
780 }
781
782 #[must_use]
788 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
789 self.meta = meta.into_option();
790 self
791 }
792}
793
794impl<'de> Deserialize<'de> for AuthMethodAgent {
795 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
796 where
797 D: serde::Deserializer<'de>,
798 {
799 #[derive(Deserialize)]
800 #[serde(rename_all = "camelCase")]
801 struct RawAuthMethodAgent {
802 id: AuthMethodId,
803 name: String,
804 description: Option<String>,
805 #[serde(rename = "_meta")]
806 meta: Option<Meta>,
807 #[serde(rename = "type")]
808 #[serde(default)]
809 type_: MaybeUndefined<String>,
810 }
811
812 let raw = RawAuthMethodAgent::deserialize(deserializer)?;
813 match raw.type_.as_opt_deref() {
814 None | Some(Some("agent")) => {}
815 Some(None) => {
816 return Err(serde::de::Error::custom(
817 "default authentication method `type` must be omitted or `agent`",
818 ));
819 }
820 Some(Some(_)) => {
821 return Err(serde::de::Error::custom(
822 "default authentication method cannot include a non-agent `type`",
823 ));
824 }
825 }
826
827 Ok(Self {
828 id: raw.id,
829 name: raw.name,
830 description: raw.description,
831 meta: raw.meta,
832 })
833 }
834}
835
836fn auth_method_agent_schema(schema: &mut Schema) {
837 super::schema_util::reject_string_property_except(schema, "type", "agent");
838}
839
840#[cfg(feature = "unstable_auth_methods")]
848#[skip_serializing_none]
849#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
850#[serde(rename_all = "camelCase")]
851#[non_exhaustive]
852pub struct AuthMethodEnvVar {
853 pub id: AuthMethodId,
855 pub name: String,
857 pub description: Option<String>,
859 pub vars: Vec<AuthEnvVar>,
861 pub link: Option<String>,
863 #[serde(rename = "_meta")]
869 pub meta: Option<Meta>,
870}
871
872#[cfg(feature = "unstable_auth_methods")]
873impl AuthMethodEnvVar {
874 #[must_use]
875 pub fn new(
876 id: impl Into<AuthMethodId>,
877 name: impl Into<String>,
878 vars: Vec<AuthEnvVar>,
879 ) -> Self {
880 Self {
881 id: id.into(),
882 name: name.into(),
883 description: None,
884 vars,
885 link: None,
886 meta: None,
887 }
888 }
889
890 #[must_use]
892 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
893 self.link = link.into_option();
894 self
895 }
896
897 #[must_use]
899 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
900 self.description = description.into_option();
901 self
902 }
903
904 #[must_use]
910 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
911 self.meta = meta.into_option();
912 self
913 }
914}
915
916#[cfg(feature = "unstable_auth_methods")]
922#[skip_serializing_none]
923#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
924#[serde(rename_all = "camelCase")]
925#[non_exhaustive]
926pub struct AuthEnvVar {
927 pub name: String,
929 pub label: Option<String>,
931 #[serde(default = "default_true", skip_serializing_if = "is_true")]
936 #[schemars(extend("default" = true))]
937 pub secret: bool,
938 #[serde(default, skip_serializing_if = "is_false")]
942 #[schemars(extend("default" = false))]
943 pub optional: bool,
944 #[serde(rename = "_meta")]
950 pub meta: Option<Meta>,
951}
952
953#[cfg(feature = "unstable_auth_methods")]
954fn default_true() -> bool {
955 true
956}
957
958#[cfg(feature = "unstable_auth_methods")]
959#[expect(clippy::trivially_copy_pass_by_ref)]
960fn is_true(v: &bool) -> bool {
961 *v
962}
963
964#[cfg(feature = "unstable_auth_methods")]
965#[expect(clippy::trivially_copy_pass_by_ref)]
966fn is_false(v: &bool) -> bool {
967 !*v
968}
969
970#[cfg(feature = "unstable_auth_methods")]
971impl AuthEnvVar {
972 #[must_use]
974 pub fn new(name: impl Into<String>) -> Self {
975 Self {
976 name: name.into(),
977 label: None,
978 secret: true,
979 optional: false,
980 meta: None,
981 }
982 }
983
984 #[must_use]
986 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
987 self.label = label.into_option();
988 self
989 }
990
991 #[must_use]
994 pub fn secret(mut self, secret: bool) -> Self {
995 self.secret = secret;
996 self
997 }
998
999 #[must_use]
1001 pub fn optional(mut self, optional: bool) -> Self {
1002 self.optional = optional;
1003 self
1004 }
1005
1006 #[must_use]
1012 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1013 self.meta = meta.into_option();
1014 self
1015 }
1016}
1017
1018#[cfg(feature = "unstable_auth_methods")]
1026#[skip_serializing_none]
1027#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1028#[serde(rename_all = "camelCase")]
1029#[non_exhaustive]
1030pub struct AuthMethodTerminal {
1031 pub id: AuthMethodId,
1033 pub name: String,
1035 pub description: Option<String>,
1037 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1039 pub args: Vec<String>,
1040 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
1042 pub env: HashMap<String, String>,
1043 #[serde(rename = "_meta")]
1049 pub meta: Option<Meta>,
1050}
1051
1052#[cfg(feature = "unstable_auth_methods")]
1053impl AuthMethodTerminal {
1054 #[must_use]
1055 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
1056 Self {
1057 id: id.into(),
1058 name: name.into(),
1059 description: None,
1060 args: Vec::new(),
1061 env: HashMap::new(),
1062 meta: None,
1063 }
1064 }
1065
1066 #[must_use]
1068 pub fn args(mut self, args: Vec<String>) -> Self {
1069 self.args = args;
1070 self
1071 }
1072
1073 #[must_use]
1075 pub fn env(mut self, env: HashMap<String, String>) -> Self {
1076 self.env = env;
1077 self
1078 }
1079
1080 #[must_use]
1082 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1083 self.description = description.into_option();
1084 self
1085 }
1086
1087 #[must_use]
1093 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1094 self.meta = meta.into_option();
1095 self
1096 }
1097}
1098
1099#[skip_serializing_none]
1105#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1106#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1107#[serde(rename_all = "camelCase")]
1108#[non_exhaustive]
1109pub struct NewSessionRequest {
1110 pub cwd: PathBuf,
1112 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1118 pub additional_directories: Vec<PathBuf>,
1119 pub mcp_servers: Vec<McpServer>,
1121 #[serde(rename = "_meta")]
1127 pub meta: Option<Meta>,
1128}
1129
1130impl NewSessionRequest {
1131 #[must_use]
1132 pub fn new(cwd: impl Into<PathBuf>) -> Self {
1133 Self {
1134 cwd: cwd.into(),
1135 additional_directories: vec![],
1136 mcp_servers: vec![],
1137 meta: None,
1138 }
1139 }
1140
1141 #[must_use]
1143 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1144 self.additional_directories = additional_directories;
1145 self
1146 }
1147
1148 #[must_use]
1150 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1151 self.mcp_servers = mcp_servers;
1152 self
1153 }
1154
1155 #[must_use]
1161 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1162 self.meta = meta.into_option();
1163 self
1164 }
1165}
1166
1167#[serde_as]
1171#[skip_serializing_none]
1172#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1173#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1174#[serde(rename_all = "camelCase")]
1175#[non_exhaustive]
1176pub struct NewSessionResponse {
1177 pub session_id: SessionId,
1181 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1183 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1184 #[serde(default)]
1185 pub config_options: Option<Vec<SessionConfigOption>>,
1186 #[serde(rename = "_meta")]
1192 pub meta: Option<Meta>,
1193}
1194
1195impl NewSessionResponse {
1196 #[must_use]
1197 pub fn new(session_id: impl Into<SessionId>) -> Self {
1198 Self {
1199 session_id: session_id.into(),
1200 config_options: None,
1201 meta: None,
1202 }
1203 }
1204
1205 #[must_use]
1207 pub fn config_options(
1208 mut self,
1209 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1210 ) -> Self {
1211 self.config_options = config_options.into_option();
1212 self
1213 }
1214
1215 #[must_use]
1221 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1222 self.meta = meta.into_option();
1223 self
1224 }
1225}
1226
1227#[skip_serializing_none]
1235#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1236#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1237#[serde(rename_all = "camelCase")]
1238#[non_exhaustive]
1239pub struct LoadSessionRequest {
1240 pub mcp_servers: Vec<McpServer>,
1242 pub cwd: PathBuf,
1244 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1251 pub additional_directories: Vec<PathBuf>,
1252 pub session_id: SessionId,
1254 #[serde(rename = "_meta")]
1260 pub meta: Option<Meta>,
1261}
1262
1263impl LoadSessionRequest {
1264 #[must_use]
1265 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1266 Self {
1267 mcp_servers: vec![],
1268 cwd: cwd.into(),
1269 additional_directories: vec![],
1270 session_id: session_id.into(),
1271 meta: None,
1272 }
1273 }
1274
1275 #[must_use]
1277 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1278 self.additional_directories = additional_directories;
1279 self
1280 }
1281
1282 #[must_use]
1284 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1285 self.mcp_servers = mcp_servers;
1286 self
1287 }
1288
1289 #[must_use]
1295 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1296 self.meta = meta.into_option();
1297 self
1298 }
1299}
1300
1301#[serde_as]
1303#[skip_serializing_none]
1304#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1305#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1306#[serde(rename_all = "camelCase")]
1307#[non_exhaustive]
1308pub struct LoadSessionResponse {
1309 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1311 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1312 #[serde(default)]
1313 pub config_options: Option<Vec<SessionConfigOption>>,
1314 #[serde(rename = "_meta")]
1320 pub meta: Option<Meta>,
1321}
1322
1323impl LoadSessionResponse {
1324 #[must_use]
1325 pub fn new() -> Self {
1326 Self::default()
1327 }
1328
1329 #[must_use]
1331 pub fn config_options(
1332 mut self,
1333 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1334 ) -> Self {
1335 self.config_options = config_options.into_option();
1336 self
1337 }
1338
1339 #[must_use]
1345 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1346 self.meta = meta.into_option();
1347 self
1348 }
1349}
1350
1351#[cfg(feature = "unstable_session_fork")]
1364#[skip_serializing_none]
1365#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1366#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1367#[serde(rename_all = "camelCase")]
1368#[non_exhaustive]
1369pub struct ForkSessionRequest {
1370 pub session_id: SessionId,
1372 pub cwd: PathBuf,
1374 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1380 pub additional_directories: Vec<PathBuf>,
1381 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1383 pub mcp_servers: Vec<McpServer>,
1384 #[serde(rename = "_meta")]
1390 pub meta: Option<Meta>,
1391}
1392
1393#[cfg(feature = "unstable_session_fork")]
1394impl ForkSessionRequest {
1395 #[must_use]
1396 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1397 Self {
1398 session_id: session_id.into(),
1399 cwd: cwd.into(),
1400 additional_directories: vec![],
1401 mcp_servers: vec![],
1402 meta: None,
1403 }
1404 }
1405
1406 #[must_use]
1408 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1409 self.additional_directories = additional_directories;
1410 self
1411 }
1412
1413 #[must_use]
1415 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1416 self.mcp_servers = mcp_servers;
1417 self
1418 }
1419
1420 #[must_use]
1426 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1427 self.meta = meta.into_option();
1428 self
1429 }
1430}
1431
1432#[cfg(feature = "unstable_session_fork")]
1438#[serde_as]
1439#[skip_serializing_none]
1440#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1441#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1442#[serde(rename_all = "camelCase")]
1443#[non_exhaustive]
1444pub struct ForkSessionResponse {
1445 pub session_id: SessionId,
1447 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1449 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1450 #[serde(default)]
1451 pub config_options: Option<Vec<SessionConfigOption>>,
1452 #[serde(rename = "_meta")]
1458 pub meta: Option<Meta>,
1459}
1460
1461#[cfg(feature = "unstable_session_fork")]
1462impl ForkSessionResponse {
1463 #[must_use]
1464 pub fn new(session_id: impl Into<SessionId>) -> Self {
1465 Self {
1466 session_id: session_id.into(),
1467 config_options: None,
1468 meta: None,
1469 }
1470 }
1471
1472 #[must_use]
1474 pub fn config_options(
1475 mut self,
1476 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1477 ) -> Self {
1478 self.config_options = config_options.into_option();
1479 self
1480 }
1481
1482 #[must_use]
1488 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1489 self.meta = meta.into_option();
1490 self
1491 }
1492}
1493
1494#[skip_serializing_none]
1503#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1504#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1505#[serde(rename_all = "camelCase")]
1506#[non_exhaustive]
1507pub struct ResumeSessionRequest {
1508 pub session_id: SessionId,
1510 pub cwd: PathBuf,
1512 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1519 pub additional_directories: Vec<PathBuf>,
1520 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1522 pub mcp_servers: Vec<McpServer>,
1523 #[serde(rename = "_meta")]
1529 pub meta: Option<Meta>,
1530}
1531
1532impl ResumeSessionRequest {
1533 #[must_use]
1534 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1535 Self {
1536 session_id: session_id.into(),
1537 cwd: cwd.into(),
1538 additional_directories: vec![],
1539 mcp_servers: vec![],
1540 meta: None,
1541 }
1542 }
1543
1544 #[must_use]
1546 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1547 self.additional_directories = additional_directories;
1548 self
1549 }
1550
1551 #[must_use]
1553 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1554 self.mcp_servers = mcp_servers;
1555 self
1556 }
1557
1558 #[must_use]
1564 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1565 self.meta = meta.into_option();
1566 self
1567 }
1568}
1569
1570#[serde_as]
1572#[skip_serializing_none]
1573#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1574#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1575#[serde(rename_all = "camelCase")]
1576#[non_exhaustive]
1577pub struct ResumeSessionResponse {
1578 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1580 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1581 #[serde(default)]
1582 pub config_options: Option<Vec<SessionConfigOption>>,
1583 #[serde(rename = "_meta")]
1589 pub meta: Option<Meta>,
1590}
1591
1592impl ResumeSessionResponse {
1593 #[must_use]
1594 pub fn new() -> Self {
1595 Self::default()
1596 }
1597
1598 #[must_use]
1600 pub fn config_options(
1601 mut self,
1602 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1603 ) -> Self {
1604 self.config_options = config_options.into_option();
1605 self
1606 }
1607
1608 #[must_use]
1614 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1615 self.meta = meta.into_option();
1616 self
1617 }
1618}
1619
1620#[skip_serializing_none]
1630#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1631#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1632#[serde(rename_all = "camelCase")]
1633#[non_exhaustive]
1634pub struct CloseSessionRequest {
1635 pub session_id: SessionId,
1637 #[serde(rename = "_meta")]
1643 pub meta: Option<Meta>,
1644}
1645
1646impl CloseSessionRequest {
1647 #[must_use]
1648 pub fn new(session_id: impl Into<SessionId>) -> Self {
1649 Self {
1650 session_id: session_id.into(),
1651 meta: None,
1652 }
1653 }
1654
1655 #[must_use]
1661 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1662 self.meta = meta.into_option();
1663 self
1664 }
1665}
1666
1667#[skip_serializing_none]
1669#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1670#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1671#[serde(rename_all = "camelCase")]
1672#[non_exhaustive]
1673pub struct CloseSessionResponse {
1674 #[serde(rename = "_meta")]
1680 pub meta: Option<Meta>,
1681}
1682
1683impl CloseSessionResponse {
1684 #[must_use]
1685 pub fn new() -> Self {
1686 Self::default()
1687 }
1688
1689 #[must_use]
1695 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1696 self.meta = meta.into_option();
1697 self
1698 }
1699}
1700
1701#[skip_serializing_none]
1707#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1708#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1709#[serde(rename_all = "camelCase")]
1710#[non_exhaustive]
1711pub struct ListSessionsRequest {
1712 pub cwd: Option<PathBuf>,
1714 pub cursor: Option<String>,
1716 #[serde(rename = "_meta")]
1722 pub meta: Option<Meta>,
1723}
1724
1725impl ListSessionsRequest {
1726 #[must_use]
1727 pub fn new() -> Self {
1728 Self::default()
1729 }
1730
1731 #[must_use]
1733 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1734 self.cwd = cwd.into_option();
1735 self
1736 }
1737
1738 #[must_use]
1740 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1741 self.cursor = cursor.into_option();
1742 self
1743 }
1744
1745 #[must_use]
1751 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1752 self.meta = meta.into_option();
1753 self
1754 }
1755}
1756
1757#[serde_as]
1759#[skip_serializing_none]
1760#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1761#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1762#[serde(rename_all = "camelCase")]
1763#[non_exhaustive]
1764pub struct ListSessionsResponse {
1765 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1767 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1768 pub sessions: Vec<SessionInfo>,
1769 pub next_cursor: Option<String>,
1772 #[serde(rename = "_meta")]
1778 pub meta: Option<Meta>,
1779}
1780
1781impl ListSessionsResponse {
1782 #[must_use]
1783 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1784 Self {
1785 sessions,
1786 next_cursor: None,
1787 meta: None,
1788 }
1789 }
1790
1791 #[must_use]
1792 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1793 self.next_cursor = next_cursor.into_option();
1794 self
1795 }
1796
1797 #[must_use]
1803 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1804 self.meta = meta.into_option();
1805 self
1806 }
1807}
1808
1809#[skip_serializing_none]
1815#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1816#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1817#[serde(rename_all = "camelCase")]
1818#[non_exhaustive]
1819pub struct DeleteSessionRequest {
1820 pub session_id: SessionId,
1822 #[serde(rename = "_meta")]
1828 pub meta: Option<Meta>,
1829}
1830
1831impl DeleteSessionRequest {
1832 #[must_use]
1833 pub fn new(session_id: impl Into<SessionId>) -> Self {
1834 Self {
1835 session_id: session_id.into(),
1836 meta: None,
1837 }
1838 }
1839
1840 #[must_use]
1846 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1847 self.meta = meta.into_option();
1848 self
1849 }
1850}
1851
1852#[skip_serializing_none]
1854#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1855#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1856#[serde(rename_all = "camelCase")]
1857#[non_exhaustive]
1858pub struct DeleteSessionResponse {
1859 #[serde(rename = "_meta")]
1865 pub meta: Option<Meta>,
1866}
1867
1868impl DeleteSessionResponse {
1869 #[must_use]
1870 pub fn new() -> Self {
1871 Self::default()
1872 }
1873
1874 #[must_use]
1880 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1881 self.meta = meta.into_option();
1882 self
1883 }
1884}
1885
1886#[serde_as]
1888#[skip_serializing_none]
1889#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1890#[serde(rename_all = "camelCase")]
1891#[non_exhaustive]
1892pub struct SessionInfo {
1893 pub session_id: SessionId,
1895 pub cwd: PathBuf,
1897 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1903 pub additional_directories: Vec<PathBuf>,
1904
1905 #[serde_as(deserialize_as = "DefaultOnError")]
1907 #[schemars(extend("x-deserialize-default-on-error" = true))]
1908 #[serde(default)]
1909 pub title: Option<String>,
1910 #[serde_as(deserialize_as = "DefaultOnError")]
1912 #[schemars(extend("x-deserialize-default-on-error" = true))]
1913 #[serde(default)]
1914 pub updated_at: Option<String>,
1915 #[serde(rename = "_meta")]
1921 pub meta: Option<Meta>,
1922}
1923
1924impl SessionInfo {
1925 #[must_use]
1926 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1927 Self {
1928 session_id: session_id.into(),
1929 cwd: cwd.into(),
1930 additional_directories: vec![],
1931 title: None,
1932 updated_at: None,
1933 meta: None,
1934 }
1935 }
1936
1937 #[must_use]
1939 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1940 self.additional_directories = additional_directories;
1941 self
1942 }
1943
1944 #[must_use]
1946 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1947 self.title = title.into_option();
1948 self
1949 }
1950
1951 #[must_use]
1953 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1954 self.updated_at = updated_at.into_option();
1955 self
1956 }
1957
1958 #[must_use]
1964 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1965 self.meta = meta.into_option();
1966 self
1967 }
1968}
1969
1970#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1974#[serde(transparent)]
1975#[from(Arc<str>, String, &'static str)]
1976#[non_exhaustive]
1977pub struct SessionConfigId(pub Arc<str>);
1978
1979impl SessionConfigId {
1980 #[must_use]
1981 pub fn new(id: impl Into<Arc<str>>) -> Self {
1982 Self(id.into())
1983 }
1984}
1985
1986#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1988#[serde(transparent)]
1989#[from(Arc<str>, String, &'static str)]
1990#[non_exhaustive]
1991pub struct SessionConfigValueId(pub Arc<str>);
1992
1993impl SessionConfigValueId {
1994 #[must_use]
1995 pub fn new(id: impl Into<Arc<str>>) -> Self {
1996 Self(id.into())
1997 }
1998}
1999
2000#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2002#[serde(transparent)]
2003#[from(Arc<str>, String, &'static str)]
2004#[non_exhaustive]
2005pub struct SessionConfigGroupId(pub Arc<str>);
2006
2007impl SessionConfigGroupId {
2008 #[must_use]
2009 pub fn new(id: impl Into<Arc<str>>) -> Self {
2010 Self(id.into())
2011 }
2012}
2013
2014#[skip_serializing_none]
2016#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2017#[serde(rename_all = "camelCase")]
2018#[non_exhaustive]
2019pub struct SessionConfigSelectOption {
2020 pub value: SessionConfigValueId,
2022 pub name: String,
2024 #[serde(default)]
2026 pub description: Option<String>,
2027 #[serde(rename = "_meta")]
2033 pub meta: Option<Meta>,
2034}
2035
2036impl SessionConfigSelectOption {
2037 #[must_use]
2038 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2039 Self {
2040 value: value.into(),
2041 name: name.into(),
2042 description: None,
2043 meta: None,
2044 }
2045 }
2046
2047 #[must_use]
2048 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2049 self.description = description.into_option();
2050 self
2051 }
2052
2053 #[must_use]
2059 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2060 self.meta = meta.into_option();
2061 self
2062 }
2063}
2064
2065#[skip_serializing_none]
2067#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2068#[serde(rename_all = "camelCase")]
2069#[non_exhaustive]
2070pub struct SessionConfigSelectGroup {
2071 pub group: SessionConfigGroupId,
2073 pub name: String,
2075 pub options: Vec<SessionConfigSelectOption>,
2077 #[serde(rename = "_meta")]
2083 pub meta: Option<Meta>,
2084}
2085
2086impl SessionConfigSelectGroup {
2087 #[must_use]
2088 pub fn new(
2089 group: impl Into<SessionConfigGroupId>,
2090 name: impl Into<String>,
2091 options: Vec<SessionConfigSelectOption>,
2092 ) -> Self {
2093 Self {
2094 group: group.into(),
2095 name: name.into(),
2096 options,
2097 meta: None,
2098 }
2099 }
2100
2101 #[must_use]
2107 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2108 self.meta = meta.into_option();
2109 self
2110 }
2111}
2112
2113#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2115#[serde(untagged)]
2116#[non_exhaustive]
2117pub enum SessionConfigSelectOptions {
2118 Ungrouped(Vec<SessionConfigSelectOption>),
2120 Grouped(Vec<SessionConfigSelectGroup>),
2122}
2123
2124impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2125 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2126 SessionConfigSelectOptions::Ungrouped(options)
2127 }
2128}
2129
2130impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2131 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2132 SessionConfigSelectOptions::Grouped(groups)
2133 }
2134}
2135
2136#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2138#[serde(rename_all = "camelCase")]
2139#[non_exhaustive]
2140pub struct SessionConfigSelect {
2141 pub current_value: SessionConfigValueId,
2143 pub options: SessionConfigSelectOptions,
2145}
2146
2147impl SessionConfigSelect {
2148 #[must_use]
2149 pub fn new(
2150 current_value: impl Into<SessionConfigValueId>,
2151 options: impl Into<SessionConfigSelectOptions>,
2152 ) -> Self {
2153 Self {
2154 current_value: current_value.into(),
2155 options: options.into(),
2156 }
2157 }
2158}
2159
2160#[cfg(feature = "unstable_boolean_config")]
2166#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2167#[serde(rename_all = "camelCase")]
2168#[non_exhaustive]
2169pub struct SessionConfigBoolean {
2170 pub current_value: bool,
2172}
2173
2174#[cfg(feature = "unstable_boolean_config")]
2175impl SessionConfigBoolean {
2176 #[must_use]
2177 pub fn new(current_value: bool) -> Self {
2178 Self { current_value }
2179 }
2180}
2181
2182#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2192#[serde(rename_all = "snake_case")]
2193#[non_exhaustive]
2194pub enum SessionConfigOptionCategory {
2195 Mode,
2197 Model,
2199 ThoughtLevel,
2201 #[serde(untagged)]
2207 Other(String),
2208}
2209
2210#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2212#[serde(tag = "type", rename_all = "snake_case")]
2213#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2214#[non_exhaustive]
2215pub enum SessionConfigKind {
2216 Select(SessionConfigSelect),
2218 #[cfg(feature = "unstable_boolean_config")]
2224 Boolean(SessionConfigBoolean),
2225 #[serde(untagged)]
2235 Other(OtherSessionConfigKind),
2236}
2237
2238#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2240#[schemars(inline)]
2241#[schemars(transform = other_session_config_kind_schema)]
2242#[serde(rename_all = "camelCase")]
2243#[non_exhaustive]
2244pub struct OtherSessionConfigKind {
2245 #[serde(rename = "type")]
2251 pub type_: String,
2252 #[serde(flatten)]
2254 pub fields: BTreeMap<String, serde_json::Value>,
2255}
2256
2257impl OtherSessionConfigKind {
2258 #[must_use]
2259 pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2260 fields.remove("type");
2261 Self {
2262 type_: type_.into(),
2263 fields,
2264 }
2265 }
2266}
2267
2268impl<'de> Deserialize<'de> for OtherSessionConfigKind {
2269 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2270 where
2271 D: serde::Deserializer<'de>,
2272 {
2273 let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2274 let type_ = fields
2275 .remove("type")
2276 .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2277 let serde_json::Value::String(type_) = type_ else {
2278 return Err(serde::de::Error::custom("`type` must be a string"));
2279 };
2280
2281 if is_known_session_config_kind_type(&type_) {
2282 return Err(serde::de::Error::custom(format!(
2283 "known session configuration option `{type_}` did not match its schema"
2284 )));
2285 }
2286
2287 Ok(Self { type_, fields })
2288 }
2289}
2290
2291fn is_known_session_config_kind_type(type_: &str) -> bool {
2292 match type_ {
2293 "select" => true,
2294 #[cfg(feature = "unstable_boolean_config")]
2295 "boolean" => true,
2296 _ => false,
2297 }
2298}
2299
2300fn other_session_config_kind_schema(schema: &mut Schema) {
2301 super::schema_util::reject_known_string_discriminators(
2302 schema,
2303 "type",
2304 &[
2305 "select",
2306 #[cfg(feature = "unstable_boolean_config")]
2307 "boolean",
2308 ],
2309 );
2310}
2311
2312#[serde_as]
2314#[skip_serializing_none]
2315#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2316#[serde(rename_all = "camelCase")]
2317#[non_exhaustive]
2318pub struct SessionConfigOption {
2319 pub id: SessionConfigId,
2321 pub name: String,
2323 #[serde(default)]
2325 pub description: Option<String>,
2326 #[serde_as(deserialize_as = "DefaultOnError")]
2328 #[schemars(extend("x-deserialize-default-on-error" = true))]
2329 #[serde(default)]
2330 pub category: Option<SessionConfigOptionCategory>,
2331 #[serde(flatten)]
2333 pub kind: SessionConfigKind,
2334 #[serde(rename = "_meta")]
2340 pub meta: Option<Meta>,
2341}
2342
2343impl SessionConfigOption {
2344 #[must_use]
2345 pub fn new(
2346 id: impl Into<SessionConfigId>,
2347 name: impl Into<String>,
2348 kind: SessionConfigKind,
2349 ) -> Self {
2350 Self {
2351 id: id.into(),
2352 name: name.into(),
2353 description: None,
2354 category: None,
2355 kind,
2356 meta: None,
2357 }
2358 }
2359
2360 #[must_use]
2361 pub fn select(
2362 id: impl Into<SessionConfigId>,
2363 name: impl Into<String>,
2364 current_value: impl Into<SessionConfigValueId>,
2365 options: impl Into<SessionConfigSelectOptions>,
2366 ) -> Self {
2367 Self::new(
2368 id,
2369 name,
2370 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2371 )
2372 }
2373
2374 #[cfg(feature = "unstable_boolean_config")]
2378 #[must_use]
2379 pub fn boolean(
2380 id: impl Into<SessionConfigId>,
2381 name: impl Into<String>,
2382 current_value: bool,
2383 ) -> Self {
2384 Self::new(
2385 id,
2386 name,
2387 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2388 )
2389 }
2390
2391 #[must_use]
2392 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2393 self.description = description.into_option();
2394 self
2395 }
2396
2397 #[must_use]
2398 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2399 self.category = category.into_option();
2400 self
2401 }
2402
2403 #[must_use]
2409 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2410 self.meta = meta.into_option();
2411 self
2412 }
2413}
2414
2415#[cfg(feature = "unstable_boolean_config")]
2430#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2431#[serde(tag = "type", rename_all = "snake_case")]
2432#[non_exhaustive]
2433pub enum SessionConfigOptionValue {
2434 Boolean {
2436 value: bool,
2438 },
2439 #[serde(untagged)]
2445 ValueId {
2446 value: SessionConfigValueId,
2448 },
2449}
2450
2451#[cfg(feature = "unstable_boolean_config")]
2452impl SessionConfigOptionValue {
2453 #[must_use]
2455 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2456 Self::ValueId { value: id.into() }
2457 }
2458
2459 #[must_use]
2461 pub fn boolean(val: bool) -> Self {
2462 Self::Boolean { value: val }
2463 }
2464
2465 #[must_use]
2468 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2469 match self {
2470 Self::ValueId { value } => Some(value),
2471 _ => None,
2472 }
2473 }
2474
2475 #[must_use]
2477 pub fn as_bool(&self) -> Option<bool> {
2478 match self {
2479 Self::Boolean { value } => Some(*value),
2480 _ => None,
2481 }
2482 }
2483}
2484
2485#[cfg(feature = "unstable_boolean_config")]
2486impl From<SessionConfigValueId> for SessionConfigOptionValue {
2487 fn from(value: SessionConfigValueId) -> Self {
2488 Self::ValueId { value }
2489 }
2490}
2491
2492#[cfg(feature = "unstable_boolean_config")]
2493impl From<bool> for SessionConfigOptionValue {
2494 fn from(value: bool) -> Self {
2495 Self::Boolean { value }
2496 }
2497}
2498
2499#[cfg(feature = "unstable_boolean_config")]
2500impl From<&str> for SessionConfigOptionValue {
2501 fn from(value: &str) -> Self {
2502 Self::ValueId {
2503 value: SessionConfigValueId::new(value),
2504 }
2505 }
2506}
2507
2508#[skip_serializing_none]
2510#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2511#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2512#[serde(rename_all = "camelCase")]
2513#[non_exhaustive]
2514pub struct SetSessionConfigOptionRequest {
2515 pub session_id: SessionId,
2517 pub config_id: SessionConfigId,
2519 #[cfg(feature = "unstable_boolean_config")]
2524 #[serde(flatten)]
2525 pub value: SessionConfigOptionValue,
2526 #[cfg(not(feature = "unstable_boolean_config"))]
2528 pub value: SessionConfigValueId,
2529 #[serde(rename = "_meta")]
2535 pub meta: Option<Meta>,
2536}
2537
2538impl SetSessionConfigOptionRequest {
2539 #[cfg(feature = "unstable_boolean_config")]
2540 #[must_use]
2541 pub fn new(
2542 session_id: impl Into<SessionId>,
2543 config_id: impl Into<SessionConfigId>,
2544 value: impl Into<SessionConfigOptionValue>,
2545 ) -> Self {
2546 Self {
2547 session_id: session_id.into(),
2548 config_id: config_id.into(),
2549 value: value.into(),
2550 meta: None,
2551 }
2552 }
2553
2554 #[cfg(not(feature = "unstable_boolean_config"))]
2555 #[must_use]
2556 pub fn new(
2557 session_id: impl Into<SessionId>,
2558 config_id: impl Into<SessionConfigId>,
2559 value: impl Into<SessionConfigValueId>,
2560 ) -> Self {
2561 Self {
2562 session_id: session_id.into(),
2563 config_id: config_id.into(),
2564 value: value.into(),
2565 meta: None,
2566 }
2567 }
2568
2569 #[must_use]
2575 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2576 self.meta = meta.into_option();
2577 self
2578 }
2579}
2580
2581#[serde_as]
2583#[skip_serializing_none]
2584#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2585#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2586#[serde(rename_all = "camelCase")]
2587#[non_exhaustive]
2588pub struct SetSessionConfigOptionResponse {
2589 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2591 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2592 pub config_options: Vec<SessionConfigOption>,
2593 #[serde(rename = "_meta")]
2599 pub meta: Option<Meta>,
2600}
2601
2602impl SetSessionConfigOptionResponse {
2603 #[must_use]
2604 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2605 Self {
2606 config_options,
2607 meta: None,
2608 }
2609 }
2610
2611 #[must_use]
2617 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2618 self.meta = meta.into_option();
2619 self
2620 }
2621}
2622
2623#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2632#[serde(tag = "type", rename_all = "snake_case")]
2633#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2634#[non_exhaustive]
2635pub enum McpServer {
2636 Http(McpServerHttp),
2640 #[cfg(feature = "unstable_mcp_over_acp")]
2649 Acp(McpServerAcp),
2650 Stdio(McpServerStdio),
2654 #[serde(untagged)]
2664 Other(OtherMcpServer),
2665}
2666
2667#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2669#[schemars(inline)]
2670#[schemars(transform = other_mcp_server_schema)]
2671#[serde(rename_all = "camelCase")]
2672#[non_exhaustive]
2673pub struct OtherMcpServer {
2674 #[serde(rename = "type")]
2680 pub type_: String,
2681 #[serde(flatten)]
2683 pub fields: BTreeMap<String, serde_json::Value>,
2684}
2685
2686impl OtherMcpServer {
2687 #[must_use]
2688 pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2689 fields.remove("type");
2690 Self {
2691 type_: type_.into(),
2692 fields,
2693 }
2694 }
2695}
2696
2697impl<'de> Deserialize<'de> for OtherMcpServer {
2698 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2699 where
2700 D: serde::Deserializer<'de>,
2701 {
2702 let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2703 let type_ = fields
2704 .remove("type")
2705 .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2706 let serde_json::Value::String(type_) = type_ else {
2707 return Err(serde::de::Error::custom("`type` must be a string"));
2708 };
2709
2710 if is_known_mcp_server_type(&type_) {
2711 return Err(serde::de::Error::custom(format!(
2712 "known MCP server transport `{type_}` did not match its schema"
2713 )));
2714 }
2715
2716 Ok(Self { type_, fields })
2717 }
2718}
2719
2720fn is_known_mcp_server_type(type_: &str) -> bool {
2721 match type_ {
2722 "http" | "stdio" => true,
2723 #[cfg(feature = "unstable_mcp_over_acp")]
2724 "acp" => true,
2725 _ => false,
2726 }
2727}
2728
2729fn other_mcp_server_schema(schema: &mut Schema) {
2730 super::schema_util::reject_known_string_discriminators(
2731 schema,
2732 "type",
2733 &[
2734 "http",
2735 "stdio",
2736 #[cfg(feature = "unstable_mcp_over_acp")]
2737 "acp",
2738 ],
2739 );
2740}
2741
2742#[skip_serializing_none]
2744#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2745#[serde(rename_all = "camelCase")]
2746#[non_exhaustive]
2747pub struct McpServerHttp {
2748 pub name: String,
2750 pub url: String,
2752 pub headers: Vec<HttpHeader>,
2754 #[serde(rename = "_meta")]
2760 pub meta: Option<Meta>,
2761}
2762
2763impl McpServerHttp {
2764 #[must_use]
2765 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2766 Self {
2767 name: name.into(),
2768 url: url.into(),
2769 headers: Vec::new(),
2770 meta: None,
2771 }
2772 }
2773
2774 #[must_use]
2776 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2777 self.headers = headers;
2778 self
2779 }
2780
2781 #[must_use]
2787 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2788 self.meta = meta.into_option();
2789 self
2790 }
2791}
2792
2793#[cfg(feature = "unstable_mcp_over_acp")]
2803#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2804#[serde(transparent)]
2805#[from(Arc<str>, String, &'static str)]
2806#[non_exhaustive]
2807pub struct McpServerAcpId(pub Arc<str>);
2808
2809#[cfg(feature = "unstable_mcp_over_acp")]
2810impl McpServerAcpId {
2811 #[must_use]
2812 pub fn new(id: impl Into<Arc<str>>) -> Self {
2813 Self(id.into())
2814 }
2815}
2816
2817#[skip_serializing_none]
2826#[cfg(feature = "unstable_mcp_over_acp")]
2827#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2828#[serde(rename_all = "camelCase")]
2829#[non_exhaustive]
2830pub struct McpServerAcp {
2831 pub name: String,
2833 pub id: McpServerAcpId,
2838 #[serde(rename = "_meta")]
2844 pub meta: Option<Meta>,
2845}
2846
2847#[cfg(feature = "unstable_mcp_over_acp")]
2848impl McpServerAcp {
2849 #[must_use]
2850 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2851 Self {
2852 name: name.into(),
2853 id: id.into(),
2854 meta: None,
2855 }
2856 }
2857
2858 #[must_use]
2864 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2865 self.meta = meta.into_option();
2866 self
2867 }
2868}
2869
2870#[skip_serializing_none]
2872#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2873#[serde(rename_all = "camelCase")]
2874#[non_exhaustive]
2875pub struct McpServerStdio {
2876 pub name: String,
2878 pub command: PathBuf,
2880 pub args: Vec<String>,
2882 pub env: Vec<EnvVariable>,
2884 #[serde(rename = "_meta")]
2890 pub meta: Option<Meta>,
2891}
2892
2893impl McpServerStdio {
2894 #[must_use]
2895 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2896 Self {
2897 name: name.into(),
2898 command: command.into(),
2899 args: Vec::new(),
2900 env: Vec::new(),
2901 meta: None,
2902 }
2903 }
2904
2905 #[must_use]
2907 pub fn args(mut self, args: Vec<String>) -> Self {
2908 self.args = args;
2909 self
2910 }
2911
2912 #[must_use]
2914 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2915 self.env = env;
2916 self
2917 }
2918
2919 #[must_use]
2925 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2926 self.meta = meta.into_option();
2927 self
2928 }
2929}
2930
2931#[skip_serializing_none]
2933#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2934#[serde(rename_all = "camelCase")]
2935#[non_exhaustive]
2936pub struct EnvVariable {
2937 pub name: String,
2939 pub value: String,
2941 #[serde(rename = "_meta")]
2947 pub meta: Option<Meta>,
2948}
2949
2950impl EnvVariable {
2951 #[must_use]
2952 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2953 Self {
2954 name: name.into(),
2955 value: value.into(),
2956 meta: None,
2957 }
2958 }
2959
2960 #[must_use]
2966 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2967 self.meta = meta.into_option();
2968 self
2969 }
2970}
2971
2972#[skip_serializing_none]
2974#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2975#[serde(rename_all = "camelCase")]
2976#[non_exhaustive]
2977pub struct HttpHeader {
2978 pub name: String,
2980 pub value: String,
2982 #[serde(rename = "_meta")]
2988 pub meta: Option<Meta>,
2989}
2990
2991impl HttpHeader {
2992 #[must_use]
2993 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2994 Self {
2995 name: name.into(),
2996 value: value.into(),
2997 meta: None,
2998 }
2999 }
3000
3001 #[must_use]
3007 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3008 self.meta = meta.into_option();
3009 self
3010 }
3011}
3012
3013#[skip_serializing_none]
3021#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
3022#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3023#[serde(rename_all = "camelCase")]
3024#[non_exhaustive]
3025pub struct PromptRequest {
3026 pub session_id: SessionId,
3028 pub prompt: Vec<ContentBlock>,
3042 #[serde(rename = "_meta")]
3048 pub meta: Option<Meta>,
3049}
3050
3051impl PromptRequest {
3052 #[must_use]
3053 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3054 Self {
3055 session_id: session_id.into(),
3056 prompt,
3057 meta: None,
3058 }
3059 }
3060
3061 #[must_use]
3067 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3068 self.meta = meta.into_option();
3069 self
3070 }
3071}
3072
3073#[serde_as]
3077#[skip_serializing_none]
3078#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3079#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3080#[serde(rename_all = "camelCase")]
3081#[non_exhaustive]
3082pub struct PromptResponse {
3083 pub stop_reason: StopReason,
3085 #[cfg(feature = "unstable_end_turn_token_usage")]
3091 #[serde_as(deserialize_as = "DefaultOnError")]
3092 #[schemars(extend("x-deserialize-default-on-error" = true))]
3093 #[serde(default)]
3094 pub usage: Option<Usage>,
3095 #[serde(rename = "_meta")]
3101 pub meta: Option<Meta>,
3102}
3103
3104impl PromptResponse {
3105 #[must_use]
3106 pub fn new(stop_reason: StopReason) -> Self {
3107 Self {
3108 stop_reason,
3109 #[cfg(feature = "unstable_end_turn_token_usage")]
3110 usage: None,
3111 meta: None,
3112 }
3113 }
3114
3115 #[cfg(feature = "unstable_end_turn_token_usage")]
3121 #[must_use]
3122 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3123 self.usage = usage.into_option();
3124 self
3125 }
3126
3127 #[must_use]
3133 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3134 self.meta = meta.into_option();
3135 self
3136 }
3137}
3138
3139#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3143#[serde(rename_all = "snake_case")]
3144#[non_exhaustive]
3145pub enum StopReason {
3146 EndTurn,
3148 MaxTokens,
3150 MaxTurnRequests,
3153 Refusal,
3157 Cancelled,
3164 #[serde(untagged)]
3170 Other(String),
3171}
3172
3173#[cfg(feature = "unstable_end_turn_token_usage")]
3179#[skip_serializing_none]
3180#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3181#[serde(rename_all = "camelCase")]
3182#[non_exhaustive]
3183pub struct Usage {
3184 pub total_tokens: u64,
3186 pub input_tokens: u64,
3188 pub output_tokens: u64,
3190 pub thought_tokens: Option<u64>,
3192 pub cached_read_tokens: Option<u64>,
3194 pub cached_write_tokens: Option<u64>,
3196}
3197
3198#[cfg(feature = "unstable_end_turn_token_usage")]
3199impl Usage {
3200 #[must_use]
3201 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3202 Self {
3203 total_tokens,
3204 input_tokens,
3205 output_tokens,
3206 thought_tokens: None,
3207 cached_read_tokens: None,
3208 cached_write_tokens: None,
3209 }
3210 }
3211
3212 #[must_use]
3214 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3215 self.thought_tokens = thought_tokens.into_option();
3216 self
3217 }
3218
3219 #[must_use]
3221 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3222 self.cached_read_tokens = cached_read_tokens.into_option();
3223 self
3224 }
3225
3226 #[must_use]
3228 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3229 self.cached_write_tokens = cached_write_tokens.into_option();
3230 self
3231 }
3232}
3233
3234#[cfg(feature = "unstable_llm_providers")]
3247#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3248#[serde(rename_all = "snake_case")]
3249#[non_exhaustive]
3250#[expect(clippy::doc_markdown)]
3251pub enum LlmProtocol {
3252 Anthropic,
3254 #[serde(rename = "openai")]
3256 OpenAi,
3257 Azure,
3259 Vertex,
3261 Bedrock,
3263 #[serde(untagged)]
3269 Other(String),
3270}
3271
3272#[cfg(feature = "unstable_llm_providers")]
3278#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3279#[serde(rename_all = "camelCase")]
3280#[non_exhaustive]
3281pub struct ProviderCurrentConfig {
3282 pub api_type: LlmProtocol,
3284 pub base_url: String,
3286}
3287
3288#[cfg(feature = "unstable_llm_providers")]
3289impl ProviderCurrentConfig {
3290 #[must_use]
3291 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3292 Self {
3293 api_type,
3294 base_url: base_url.into(),
3295 }
3296 }
3297}
3298
3299#[cfg(feature = "unstable_llm_providers")]
3305#[serde_as]
3306#[skip_serializing_none]
3307#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3308#[serde(rename_all = "camelCase")]
3309#[non_exhaustive]
3310pub struct ProviderInfo {
3311 pub id: String,
3313 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3315 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3316 pub supported: Vec<LlmProtocol>,
3317 pub required: bool,
3320 pub current: Option<ProviderCurrentConfig>,
3323 #[serde(rename = "_meta")]
3329 pub meta: Option<Meta>,
3330}
3331
3332#[cfg(feature = "unstable_llm_providers")]
3333impl ProviderInfo {
3334 #[must_use]
3335 pub fn new(
3336 id: impl Into<String>,
3337 supported: Vec<LlmProtocol>,
3338 required: bool,
3339 current: impl IntoOption<ProviderCurrentConfig>,
3340 ) -> Self {
3341 Self {
3342 id: id.into(),
3343 supported,
3344 required,
3345 current: current.into_option(),
3346 meta: None,
3347 }
3348 }
3349
3350 #[must_use]
3356 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3357 self.meta = meta.into_option();
3358 self
3359 }
3360}
3361
3362#[cfg(feature = "unstable_llm_providers")]
3368#[skip_serializing_none]
3369#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3370#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3371#[serde(rename_all = "camelCase")]
3372#[non_exhaustive]
3373pub struct ListProvidersRequest {
3374 #[serde(rename = "_meta")]
3380 pub meta: Option<Meta>,
3381}
3382
3383#[cfg(feature = "unstable_llm_providers")]
3384impl ListProvidersRequest {
3385 #[must_use]
3386 pub fn new() -> Self {
3387 Self::default()
3388 }
3389
3390 #[must_use]
3396 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3397 self.meta = meta.into_option();
3398 self
3399 }
3400}
3401
3402#[cfg(feature = "unstable_llm_providers")]
3408#[serde_as]
3409#[skip_serializing_none]
3410#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3411#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3412#[serde(rename_all = "camelCase")]
3413#[non_exhaustive]
3414pub struct ListProvidersResponse {
3415 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3417 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3418 pub providers: Vec<ProviderInfo>,
3419 #[serde(rename = "_meta")]
3425 pub meta: Option<Meta>,
3426}
3427
3428#[cfg(feature = "unstable_llm_providers")]
3429impl ListProvidersResponse {
3430 #[must_use]
3431 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3432 Self {
3433 providers,
3434 meta: None,
3435 }
3436 }
3437
3438 #[must_use]
3444 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3445 self.meta = meta.into_option();
3446 self
3447 }
3448}
3449
3450#[cfg(feature = "unstable_llm_providers")]
3458#[skip_serializing_none]
3459#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3460#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3461#[serde(rename_all = "camelCase")]
3462#[non_exhaustive]
3463pub struct SetProviderRequest {
3464 pub id: String,
3466 pub api_type: LlmProtocol,
3468 pub base_url: String,
3470 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3473 pub headers: HashMap<String, String>,
3474 #[serde(rename = "_meta")]
3480 pub meta: Option<Meta>,
3481}
3482
3483#[cfg(feature = "unstable_llm_providers")]
3484impl SetProviderRequest {
3485 #[must_use]
3486 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3487 Self {
3488 id: id.into(),
3489 api_type,
3490 base_url: base_url.into(),
3491 headers: HashMap::new(),
3492 meta: None,
3493 }
3494 }
3495
3496 #[must_use]
3499 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3500 self.headers = headers;
3501 self
3502 }
3503
3504 #[must_use]
3510 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3511 self.meta = meta.into_option();
3512 self
3513 }
3514}
3515
3516#[cfg(feature = "unstable_llm_providers")]
3522#[skip_serializing_none]
3523#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3524#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3525#[serde(rename_all = "camelCase")]
3526#[non_exhaustive]
3527pub struct SetProviderResponse {
3528 #[serde(rename = "_meta")]
3534 pub meta: Option<Meta>,
3535}
3536
3537#[cfg(feature = "unstable_llm_providers")]
3538impl SetProviderResponse {
3539 #[must_use]
3540 pub fn new() -> Self {
3541 Self::default()
3542 }
3543
3544 #[must_use]
3550 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3551 self.meta = meta.into_option();
3552 self
3553 }
3554}
3555
3556#[cfg(feature = "unstable_llm_providers")]
3562#[skip_serializing_none]
3563#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3564#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3565#[serde(rename_all = "camelCase")]
3566#[non_exhaustive]
3567pub struct DisableProviderRequest {
3568 pub id: String,
3570 #[serde(rename = "_meta")]
3576 pub meta: Option<Meta>,
3577}
3578
3579#[cfg(feature = "unstable_llm_providers")]
3580impl DisableProviderRequest {
3581 #[must_use]
3582 pub fn new(id: impl Into<String>) -> Self {
3583 Self {
3584 id: id.into(),
3585 meta: None,
3586 }
3587 }
3588
3589 #[must_use]
3595 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3596 self.meta = meta.into_option();
3597 self
3598 }
3599}
3600
3601#[cfg(feature = "unstable_llm_providers")]
3607#[skip_serializing_none]
3608#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3609#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3610#[serde(rename_all = "camelCase")]
3611#[non_exhaustive]
3612pub struct DisableProviderResponse {
3613 #[serde(rename = "_meta")]
3619 pub meta: Option<Meta>,
3620}
3621
3622#[cfg(feature = "unstable_llm_providers")]
3623impl DisableProviderResponse {
3624 #[must_use]
3625 pub fn new() -> Self {
3626 Self::default()
3627 }
3628
3629 #[must_use]
3635 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3636 self.meta = meta.into_option();
3637 self
3638 }
3639}
3640
3641#[serde_as]
3650#[skip_serializing_none]
3651#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3652#[serde(rename_all = "camelCase")]
3653#[non_exhaustive]
3654pub struct AgentCapabilities {
3655 #[serde(default)]
3657 pub prompt: PromptCapabilities,
3658 #[serde(default)]
3660 pub mcp: McpCapabilities,
3661 #[serde(default)]
3662 pub session: SessionCapabilities,
3663 #[serde(default)]
3665 pub auth: AgentAuthCapabilities,
3666 #[cfg(feature = "unstable_llm_providers")]
3674 #[serde_as(deserialize_as = "DefaultOnError")]
3675 #[schemars(extend("x-deserialize-default-on-error" = true))]
3676 #[serde(default)]
3677 pub providers: Option<ProvidersCapabilities>,
3678 #[cfg(feature = "unstable_nes")]
3684 #[serde_as(deserialize_as = "DefaultOnError")]
3685 #[schemars(extend("x-deserialize-default-on-error" = true))]
3686 #[serde(default)]
3687 pub nes: Option<NesCapabilities>,
3688 #[cfg(feature = "unstable_nes")]
3694 #[serde_as(deserialize_as = "DefaultOnError")]
3695 #[schemars(extend("x-deserialize-default-on-error" = true))]
3696 #[serde(default)]
3697 pub position_encoding: Option<PositionEncodingKind>,
3698 #[serde(rename = "_meta")]
3704 pub meta: Option<Meta>,
3705}
3706
3707impl AgentCapabilities {
3708 #[must_use]
3709 pub fn new() -> Self {
3710 Self::default()
3711 }
3712
3713 #[must_use]
3715 pub fn prompt(mut self, prompt: PromptCapabilities) -> Self {
3716 self.prompt = prompt;
3717 self
3718 }
3719
3720 #[must_use]
3722 pub fn mcp(mut self, mcp: McpCapabilities) -> Self {
3723 self.mcp = mcp;
3724 self
3725 }
3726
3727 #[must_use]
3729 pub fn session(mut self, session: SessionCapabilities) -> Self {
3730 self.session = session;
3731 self
3732 }
3733
3734 #[must_use]
3736 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3737 self.auth = auth;
3738 self
3739 }
3740
3741 #[cfg(feature = "unstable_llm_providers")]
3747 #[must_use]
3748 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3749 self.providers = providers.into_option();
3750 self
3751 }
3752
3753 #[cfg(feature = "unstable_nes")]
3759 #[must_use]
3760 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3761 self.nes = nes.into_option();
3762 self
3763 }
3764
3765 #[cfg(feature = "unstable_nes")]
3769 #[must_use]
3770 pub fn position_encoding(
3771 mut self,
3772 position_encoding: impl IntoOption<PositionEncodingKind>,
3773 ) -> Self {
3774 self.position_encoding = position_encoding.into_option();
3775 self
3776 }
3777
3778 #[must_use]
3784 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3785 self.meta = meta.into_option();
3786 self
3787 }
3788}
3789
3790#[cfg(feature = "unstable_llm_providers")]
3798#[skip_serializing_none]
3799#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3800#[non_exhaustive]
3801pub struct ProvidersCapabilities {
3802 #[serde(rename = "_meta")]
3808 pub meta: Option<Meta>,
3809}
3810
3811#[cfg(feature = "unstable_llm_providers")]
3812impl ProvidersCapabilities {
3813 #[must_use]
3814 pub fn new() -> Self {
3815 Self::default()
3816 }
3817
3818 #[must_use]
3824 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3825 self.meta = meta.into_option();
3826 self
3827 }
3828}
3829
3830#[serde_as]
3838#[skip_serializing_none]
3839#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3840#[serde(rename_all = "camelCase")]
3841#[non_exhaustive]
3842pub struct SessionCapabilities {
3843 #[serde_as(deserialize_as = "DefaultOnError")]
3848 #[schemars(extend("x-deserialize-default-on-error" = true))]
3849 #[serde(default)]
3850 pub load: Option<SessionLoadCapabilities>,
3851 #[serde_as(deserialize_as = "DefaultOnError")]
3853 #[schemars(extend("x-deserialize-default-on-error" = true))]
3854 #[serde(default)]
3855 pub list: Option<SessionListCapabilities>,
3856 #[serde_as(deserialize_as = "DefaultOnError")]
3861 #[schemars(extend("x-deserialize-default-on-error" = true))]
3862 #[serde(default)]
3863 pub delete: Option<SessionDeleteCapabilities>,
3864 #[serde_as(deserialize_as = "DefaultOnError")]
3870 #[schemars(extend("x-deserialize-default-on-error" = true))]
3871 #[serde(default)]
3872 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
3873 #[cfg(feature = "unstable_session_fork")]
3879 #[serde_as(deserialize_as = "DefaultOnError")]
3880 #[schemars(extend("x-deserialize-default-on-error" = true))]
3881 #[serde(default)]
3882 pub fork: Option<SessionForkCapabilities>,
3883 #[serde_as(deserialize_as = "DefaultOnError")]
3885 #[schemars(extend("x-deserialize-default-on-error" = true))]
3886 #[serde(default)]
3887 pub resume: Option<SessionResumeCapabilities>,
3888 #[serde_as(deserialize_as = "DefaultOnError")]
3890 #[schemars(extend("x-deserialize-default-on-error" = true))]
3891 #[serde(default)]
3892 pub close: Option<SessionCloseCapabilities>,
3893 #[serde(rename = "_meta")]
3899 pub meta: Option<Meta>,
3900}
3901
3902impl SessionCapabilities {
3903 #[must_use]
3904 pub fn new() -> Self {
3905 Self::default()
3906 }
3907
3908 #[must_use]
3913 pub fn load(mut self, load: impl IntoOption<SessionLoadCapabilities>) -> Self {
3914 self.load = load.into_option();
3915 self
3916 }
3917
3918 #[must_use]
3920 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3921 self.list = list.into_option();
3922 self
3923 }
3924
3925 #[must_use]
3930 pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
3931 self.delete = delete.into_option();
3932 self
3933 }
3934
3935 #[must_use]
3941 pub fn additional_directories(
3942 mut self,
3943 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
3944 ) -> Self {
3945 self.additional_directories = additional_directories.into_option();
3946 self
3947 }
3948
3949 #[cfg(feature = "unstable_session_fork")]
3950 #[must_use]
3952 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
3953 self.fork = fork.into_option();
3954 self
3955 }
3956
3957 #[must_use]
3959 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
3960 self.resume = resume.into_option();
3961 self
3962 }
3963
3964 #[must_use]
3966 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
3967 self.close = close.into_option();
3968 self
3969 }
3970
3971 #[must_use]
3977 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3978 self.meta = meta.into_option();
3979 self
3980 }
3981}
3982
3983#[skip_serializing_none]
3987#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3988#[non_exhaustive]
3989pub struct SessionLoadCapabilities {
3990 #[serde(rename = "_meta")]
3996 pub meta: Option<Meta>,
3997}
3998
3999impl SessionLoadCapabilities {
4000 #[must_use]
4001 pub fn new() -> Self {
4002 Self::default()
4003 }
4004
4005 #[must_use]
4011 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4012 self.meta = meta.into_option();
4013 self
4014 }
4015}
4016
4017#[skip_serializing_none]
4021#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4022#[non_exhaustive]
4023pub struct SessionListCapabilities {
4024 #[serde(rename = "_meta")]
4030 pub meta: Option<Meta>,
4031}
4032
4033impl SessionListCapabilities {
4034 #[must_use]
4035 pub fn new() -> Self {
4036 Self::default()
4037 }
4038
4039 #[must_use]
4045 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4046 self.meta = meta.into_option();
4047 self
4048 }
4049}
4050
4051#[skip_serializing_none]
4055#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4056#[non_exhaustive]
4057pub struct SessionDeleteCapabilities {
4058 #[serde(rename = "_meta")]
4064 pub meta: Option<Meta>,
4065}
4066
4067impl SessionDeleteCapabilities {
4068 #[must_use]
4069 pub fn new() -> Self {
4070 Self::default()
4071 }
4072
4073 #[must_use]
4079 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4080 self.meta = meta.into_option();
4081 self
4082 }
4083}
4084
4085#[skip_serializing_none]
4092#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4093#[non_exhaustive]
4094pub struct SessionAdditionalDirectoriesCapabilities {
4095 #[serde(rename = "_meta")]
4101 pub meta: Option<Meta>,
4102}
4103
4104impl SessionAdditionalDirectoriesCapabilities {
4105 #[must_use]
4106 pub fn new() -> Self {
4107 Self::default()
4108 }
4109
4110 #[must_use]
4116 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4117 self.meta = meta.into_option();
4118 self
4119 }
4120}
4121
4122#[cfg(feature = "unstable_session_fork")]
4130#[skip_serializing_none]
4131#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4132#[non_exhaustive]
4133pub struct SessionForkCapabilities {
4134 #[serde(rename = "_meta")]
4140 pub meta: Option<Meta>,
4141}
4142
4143#[cfg(feature = "unstable_session_fork")]
4144impl SessionForkCapabilities {
4145 #[must_use]
4146 pub fn new() -> Self {
4147 Self::default()
4148 }
4149
4150 #[must_use]
4156 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4157 self.meta = meta.into_option();
4158 self
4159 }
4160}
4161
4162#[skip_serializing_none]
4166#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4167#[non_exhaustive]
4168pub struct SessionResumeCapabilities {
4169 #[serde(rename = "_meta")]
4175 pub meta: Option<Meta>,
4176}
4177
4178impl SessionResumeCapabilities {
4179 #[must_use]
4180 pub fn new() -> Self {
4181 Self::default()
4182 }
4183
4184 #[must_use]
4190 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4191 self.meta = meta.into_option();
4192 self
4193 }
4194}
4195
4196#[skip_serializing_none]
4200#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4201#[non_exhaustive]
4202pub struct SessionCloseCapabilities {
4203 #[serde(rename = "_meta")]
4209 pub meta: Option<Meta>,
4210}
4211
4212impl SessionCloseCapabilities {
4213 #[must_use]
4214 pub fn new() -> Self {
4215 Self::default()
4216 }
4217
4218 #[must_use]
4224 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4225 self.meta = meta.into_option();
4226 self
4227 }
4228}
4229
4230#[serde_as]
4243#[skip_serializing_none]
4244#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4245#[serde(rename_all = "camelCase")]
4246#[non_exhaustive]
4247pub struct PromptCapabilities {
4248 #[serde_as(deserialize_as = "DefaultOnError")]
4253 #[schemars(extend("x-deserialize-default-on-error" = true))]
4254 #[serde(default)]
4255 pub image: Option<PromptImageCapabilities>,
4256 #[serde_as(deserialize_as = "DefaultOnError")]
4261 #[schemars(extend("x-deserialize-default-on-error" = true))]
4262 #[serde(default)]
4263 pub audio: Option<PromptAudioCapabilities>,
4264 #[serde_as(deserialize_as = "DefaultOnError")]
4272 #[schemars(extend("x-deserialize-default-on-error" = true))]
4273 #[serde(default)]
4274 pub embedded_context: Option<PromptEmbeddedContextCapabilities>,
4275 #[serde(rename = "_meta")]
4281 pub meta: Option<Meta>,
4282}
4283
4284impl PromptCapabilities {
4285 #[must_use]
4286 pub fn new() -> Self {
4287 Self::default()
4288 }
4289
4290 #[must_use]
4295 pub fn image(mut self, image: impl IntoOption<PromptImageCapabilities>) -> Self {
4296 self.image = image.into_option();
4297 self
4298 }
4299
4300 #[must_use]
4305 pub fn audio(mut self, audio: impl IntoOption<PromptAudioCapabilities>) -> Self {
4306 self.audio = audio.into_option();
4307 self
4308 }
4309
4310 #[must_use]
4318 pub fn embedded_context(
4319 mut self,
4320 embedded_context: impl IntoOption<PromptEmbeddedContextCapabilities>,
4321 ) -> Self {
4322 self.embedded_context = embedded_context.into_option();
4323 self
4324 }
4325
4326 #[must_use]
4332 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4333 self.meta = meta.into_option();
4334 self
4335 }
4336}
4337
4338#[skip_serializing_none]
4342#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4343#[non_exhaustive]
4344pub struct PromptImageCapabilities {
4345 #[serde(rename = "_meta")]
4351 pub meta: Option<Meta>,
4352}
4353
4354impl PromptImageCapabilities {
4355 #[must_use]
4356 pub fn new() -> Self {
4357 Self::default()
4358 }
4359
4360 #[must_use]
4366 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4367 self.meta = meta.into_option();
4368 self
4369 }
4370}
4371
4372#[skip_serializing_none]
4376#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4377#[non_exhaustive]
4378pub struct PromptAudioCapabilities {
4379 #[serde(rename = "_meta")]
4385 pub meta: Option<Meta>,
4386}
4387
4388impl PromptAudioCapabilities {
4389 #[must_use]
4390 pub fn new() -> Self {
4391 Self::default()
4392 }
4393
4394 #[must_use]
4400 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4401 self.meta = meta.into_option();
4402 self
4403 }
4404}
4405
4406#[skip_serializing_none]
4410#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4411#[non_exhaustive]
4412pub struct PromptEmbeddedContextCapabilities {
4413 #[serde(rename = "_meta")]
4419 pub meta: Option<Meta>,
4420}
4421
4422impl PromptEmbeddedContextCapabilities {
4423 #[must_use]
4424 pub fn new() -> Self {
4425 Self::default()
4426 }
4427
4428 #[must_use]
4434 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4435 self.meta = meta.into_option();
4436 self
4437 }
4438}
4439
4440#[serde_as]
4442#[skip_serializing_none]
4443#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4444#[serde(rename_all = "camelCase")]
4445#[non_exhaustive]
4446pub struct McpCapabilities {
4447 #[serde_as(deserialize_as = "DefaultOnError")]
4452 #[schemars(extend("x-deserialize-default-on-error" = true))]
4453 #[serde(default)]
4454 pub stdio: Option<McpStdioCapabilities>,
4455 #[serde_as(deserialize_as = "DefaultOnError")]
4460 #[schemars(extend("x-deserialize-default-on-error" = true))]
4461 #[serde(default)]
4462 pub http: Option<McpHttpCapabilities>,
4463 #[cfg(feature = "unstable_mcp_over_acp")]
4469 #[serde_as(deserialize_as = "DefaultOnError")]
4473 #[schemars(extend("x-deserialize-default-on-error" = true))]
4474 #[serde(default)]
4475 pub acp: Option<McpAcpCapabilities>,
4476 #[serde(rename = "_meta")]
4482 pub meta: Option<Meta>,
4483}
4484
4485impl McpCapabilities {
4486 #[must_use]
4487 pub fn new() -> Self {
4488 Self::default()
4489 }
4490
4491 #[must_use]
4496 pub fn stdio(mut self, stdio: impl IntoOption<McpStdioCapabilities>) -> Self {
4497 self.stdio = stdio.into_option();
4498 self
4499 }
4500
4501 #[must_use]
4506 pub fn http(mut self, http: impl IntoOption<McpHttpCapabilities>) -> Self {
4507 self.http = http.into_option();
4508 self
4509 }
4510
4511 #[cfg(feature = "unstable_mcp_over_acp")]
4517 #[must_use]
4521 pub fn acp(mut self, acp: impl IntoOption<McpAcpCapabilities>) -> Self {
4522 self.acp = acp.into_option();
4523 self
4524 }
4525
4526 #[must_use]
4532 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4533 self.meta = meta.into_option();
4534 self
4535 }
4536}
4537
4538#[skip_serializing_none]
4542#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4543#[non_exhaustive]
4544pub struct McpStdioCapabilities {
4545 #[serde(rename = "_meta")]
4551 pub meta: Option<Meta>,
4552}
4553
4554impl McpStdioCapabilities {
4555 #[must_use]
4556 pub fn new() -> Self {
4557 Self::default()
4558 }
4559
4560 #[must_use]
4566 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4567 self.meta = meta.into_option();
4568 self
4569 }
4570}
4571
4572#[skip_serializing_none]
4576#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4577#[non_exhaustive]
4578pub struct McpHttpCapabilities {
4579 #[serde(rename = "_meta")]
4585 pub meta: Option<Meta>,
4586}
4587
4588impl McpHttpCapabilities {
4589 #[must_use]
4590 pub fn new() -> Self {
4591 Self::default()
4592 }
4593
4594 #[must_use]
4600 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4601 self.meta = meta.into_option();
4602 self
4603 }
4604}
4605
4606#[cfg(feature = "unstable_mcp_over_acp")]
4614#[skip_serializing_none]
4615#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4616#[non_exhaustive]
4617pub struct McpAcpCapabilities {
4618 #[serde(rename = "_meta")]
4624 pub meta: Option<Meta>,
4625}
4626
4627#[cfg(feature = "unstable_mcp_over_acp")]
4628impl McpAcpCapabilities {
4629 #[must_use]
4630 pub fn new() -> Self {
4631 Self::default()
4632 }
4633
4634 #[must_use]
4640 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4641 self.meta = meta.into_option();
4642 self
4643 }
4644}
4645
4646#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4652#[non_exhaustive]
4653pub struct AgentMethodNames {
4654 pub initialize: &'static str,
4656 pub authenticate: &'static str,
4658 #[cfg(feature = "unstable_llm_providers")]
4660 pub providers_list: &'static str,
4661 #[cfg(feature = "unstable_llm_providers")]
4663 pub providers_set: &'static str,
4664 #[cfg(feature = "unstable_llm_providers")]
4666 pub providers_disable: &'static str,
4667 pub session_new: &'static str,
4669 pub session_load: &'static str,
4671 pub session_set_config_option: &'static str,
4673 pub session_prompt: &'static str,
4675 pub session_cancel: &'static str,
4677 #[cfg(feature = "unstable_mcp_over_acp")]
4679 pub mcp_message: &'static str,
4680 pub session_list: &'static str,
4682 pub session_delete: &'static str,
4684 #[cfg(feature = "unstable_session_fork")]
4686 pub session_fork: &'static str,
4687 pub session_resume: &'static str,
4689 pub session_close: &'static str,
4691 pub logout: &'static str,
4693 #[cfg(feature = "unstable_nes")]
4695 pub nes_start: &'static str,
4696 #[cfg(feature = "unstable_nes")]
4698 pub nes_suggest: &'static str,
4699 #[cfg(feature = "unstable_nes")]
4701 pub nes_accept: &'static str,
4702 #[cfg(feature = "unstable_nes")]
4704 pub nes_reject: &'static str,
4705 #[cfg(feature = "unstable_nes")]
4707 pub nes_close: &'static str,
4708 #[cfg(feature = "unstable_nes")]
4710 pub document_did_open: &'static str,
4711 #[cfg(feature = "unstable_nes")]
4713 pub document_did_change: &'static str,
4714 #[cfg(feature = "unstable_nes")]
4716 pub document_did_close: &'static str,
4717 #[cfg(feature = "unstable_nes")]
4719 pub document_did_save: &'static str,
4720 #[cfg(feature = "unstable_nes")]
4722 pub document_did_focus: &'static str,
4723}
4724
4725pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4727 initialize: INITIALIZE_METHOD_NAME,
4728 authenticate: AUTHENTICATE_METHOD_NAME,
4729 #[cfg(feature = "unstable_llm_providers")]
4730 providers_list: PROVIDERS_LIST_METHOD_NAME,
4731 #[cfg(feature = "unstable_llm_providers")]
4732 providers_set: PROVIDERS_SET_METHOD_NAME,
4733 #[cfg(feature = "unstable_llm_providers")]
4734 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4735 session_new: SESSION_NEW_METHOD_NAME,
4736 session_load: SESSION_LOAD_METHOD_NAME,
4737 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4738 session_prompt: SESSION_PROMPT_METHOD_NAME,
4739 session_cancel: SESSION_CANCEL_METHOD_NAME,
4740 #[cfg(feature = "unstable_mcp_over_acp")]
4741 mcp_message: MCP_MESSAGE_METHOD_NAME,
4742 session_list: SESSION_LIST_METHOD_NAME,
4743 session_delete: SESSION_DELETE_METHOD_NAME,
4744 #[cfg(feature = "unstable_session_fork")]
4745 session_fork: SESSION_FORK_METHOD_NAME,
4746 session_resume: SESSION_RESUME_METHOD_NAME,
4747 session_close: SESSION_CLOSE_METHOD_NAME,
4748 logout: LOGOUT_METHOD_NAME,
4749 #[cfg(feature = "unstable_nes")]
4750 nes_start: NES_START_METHOD_NAME,
4751 #[cfg(feature = "unstable_nes")]
4752 nes_suggest: NES_SUGGEST_METHOD_NAME,
4753 #[cfg(feature = "unstable_nes")]
4754 nes_accept: NES_ACCEPT_METHOD_NAME,
4755 #[cfg(feature = "unstable_nes")]
4756 nes_reject: NES_REJECT_METHOD_NAME,
4757 #[cfg(feature = "unstable_nes")]
4758 nes_close: NES_CLOSE_METHOD_NAME,
4759 #[cfg(feature = "unstable_nes")]
4760 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4761 #[cfg(feature = "unstable_nes")]
4762 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4763 #[cfg(feature = "unstable_nes")]
4764 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4765 #[cfg(feature = "unstable_nes")]
4766 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4767 #[cfg(feature = "unstable_nes")]
4768 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4769};
4770
4771pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4773pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4775#[cfg(feature = "unstable_llm_providers")]
4777pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4778#[cfg(feature = "unstable_llm_providers")]
4780pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4781#[cfg(feature = "unstable_llm_providers")]
4783pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4784pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4786pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4788pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4790pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4792pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4794pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4796pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
4798#[cfg(feature = "unstable_session_fork")]
4800pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4801pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4803pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4805pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4807
4808#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4815#[serde(untagged)]
4816#[schemars(inline)]
4817#[non_exhaustive]
4818#[allow(clippy::large_enum_variant)]
4819pub enum ClientRequest {
4820 InitializeRequest(InitializeRequest),
4831 AuthenticateRequest(AuthenticateRequest),
4841 #[cfg(feature = "unstable_llm_providers")]
4847 ListProvidersRequest(ListProvidersRequest),
4848 #[cfg(feature = "unstable_llm_providers")]
4854 SetProviderRequest(SetProviderRequest),
4855 #[cfg(feature = "unstable_llm_providers")]
4861 DisableProviderRequest(DisableProviderRequest),
4862 LogoutRequest(LogoutRequest),
4867 NewSessionRequest(NewSessionRequest),
4880 LoadSessionRequest(LoadSessionRequest),
4891 ListSessionsRequest(ListSessionsRequest),
4897 DeleteSessionRequest(DeleteSessionRequest),
4901 #[cfg(feature = "unstable_session_fork")]
4902 ForkSessionRequest(ForkSessionRequest),
4914 ResumeSessionRequest(ResumeSessionRequest),
4921 CloseSessionRequest(CloseSessionRequest),
4928 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4930 PromptRequest(PromptRequest),
4942 #[cfg(feature = "unstable_nes")]
4943 StartNesRequest(StartNesRequest),
4949 #[cfg(feature = "unstable_nes")]
4950 SuggestNesRequest(SuggestNesRequest),
4956 #[cfg(feature = "unstable_nes")]
4957 CloseNesRequest(CloseNesRequest),
4966 #[cfg(feature = "unstable_mcp_over_acp")]
4972 MessageMcpRequest(MessageMcpRequest),
4973 ExtMethodRequest(ExtRequest),
4980}
4981
4982impl ClientRequest {
4983 #[must_use]
4985 pub fn method(&self) -> &str {
4986 match self {
4987 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4988 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4989 #[cfg(feature = "unstable_llm_providers")]
4990 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4991 #[cfg(feature = "unstable_llm_providers")]
4992 Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
4993 #[cfg(feature = "unstable_llm_providers")]
4994 Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4995 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4996 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4997 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4998 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4999 Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
5000 #[cfg(feature = "unstable_session_fork")]
5001 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
5002 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
5003 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
5004 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
5005 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
5006 #[cfg(feature = "unstable_nes")]
5007 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
5008 #[cfg(feature = "unstable_nes")]
5009 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
5010 #[cfg(feature = "unstable_nes")]
5011 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
5012 #[cfg(feature = "unstable_mcp_over_acp")]
5013 Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
5014 Self::ExtMethodRequest(ext_request) => &ext_request.method,
5015 }
5016 }
5017}
5018
5019#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5026#[serde(untagged)]
5027#[schemars(inline)]
5028#[non_exhaustive]
5029#[allow(clippy::large_enum_variant)]
5030pub enum AgentResponse {
5031 InitializeResponse(InitializeResponse),
5032 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
5033 #[cfg(feature = "unstable_llm_providers")]
5034 ListProvidersResponse(ListProvidersResponse),
5035 #[cfg(feature = "unstable_llm_providers")]
5036 SetProviderResponse(#[serde(default)] SetProviderResponse),
5037 #[cfg(feature = "unstable_llm_providers")]
5038 DisableProviderResponse(#[serde(default)] DisableProviderResponse),
5039 LogoutResponse(#[serde(default)] LogoutResponse),
5040 NewSessionResponse(NewSessionResponse),
5041 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5042 ListSessionsResponse(ListSessionsResponse),
5043 DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
5044 #[cfg(feature = "unstable_session_fork")]
5045 ForkSessionResponse(ForkSessionResponse),
5046 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5047 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5048 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5049 PromptResponse(PromptResponse),
5050 #[cfg(feature = "unstable_nes")]
5051 StartNesResponse(StartNesResponse),
5052 #[cfg(feature = "unstable_nes")]
5053 SuggestNesResponse(SuggestNesResponse),
5054 #[cfg(feature = "unstable_nes")]
5055 CloseNesResponse(#[serde(default)] CloseNesResponse),
5056 ExtMethodResponse(ExtResponse),
5057 #[cfg(feature = "unstable_mcp_over_acp")]
5058 MessageMcpResponse(MessageMcpResponse),
5059}
5060
5061#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5068#[serde(untagged)]
5069#[schemars(inline)]
5070#[non_exhaustive]
5071pub enum ClientNotification {
5072 CancelNotification(CancelNotification),
5084 #[cfg(feature = "unstable_nes")]
5085 DidOpenDocumentNotification(DidOpenDocumentNotification),
5089 #[cfg(feature = "unstable_nes")]
5090 DidChangeDocumentNotification(DidChangeDocumentNotification),
5094 #[cfg(feature = "unstable_nes")]
5095 DidCloseDocumentNotification(DidCloseDocumentNotification),
5099 #[cfg(feature = "unstable_nes")]
5100 DidSaveDocumentNotification(DidSaveDocumentNotification),
5104 #[cfg(feature = "unstable_nes")]
5105 DidFocusDocumentNotification(DidFocusDocumentNotification),
5109 #[cfg(feature = "unstable_nes")]
5110 AcceptNesNotification(AcceptNesNotification),
5114 #[cfg(feature = "unstable_nes")]
5115 RejectNesNotification(RejectNesNotification),
5119 #[cfg(feature = "unstable_mcp_over_acp")]
5125 MessageMcpNotification(MessageMcpNotification),
5126 ExtNotification(ExtNotification),
5133}
5134
5135impl ClientNotification {
5136 #[must_use]
5138 pub fn method(&self) -> &str {
5139 match self {
5140 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5141 #[cfg(feature = "unstable_nes")]
5142 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5143 #[cfg(feature = "unstable_nes")]
5144 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5145 #[cfg(feature = "unstable_nes")]
5146 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5147 #[cfg(feature = "unstable_nes")]
5148 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5149 #[cfg(feature = "unstable_nes")]
5150 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5151 #[cfg(feature = "unstable_nes")]
5152 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5153 #[cfg(feature = "unstable_nes")]
5154 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5155 #[cfg(feature = "unstable_mcp_over_acp")]
5156 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5157 Self::ExtNotification(ext_notification) => &ext_notification.method,
5158 }
5159 }
5160}
5161
5162#[skip_serializing_none]
5166#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5167#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5168#[serde(rename_all = "camelCase")]
5169#[non_exhaustive]
5170pub struct CancelNotification {
5171 pub session_id: SessionId,
5173 #[serde(rename = "_meta")]
5179 pub meta: Option<Meta>,
5180}
5181
5182impl CancelNotification {
5183 #[must_use]
5184 pub fn new(session_id: impl Into<SessionId>) -> Self {
5185 Self {
5186 session_id: session_id.into(),
5187 meta: None,
5188 }
5189 }
5190
5191 #[must_use]
5197 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5198 self.meta = meta.into_option();
5199 self
5200 }
5201}
5202
5203#[cfg(test)]
5204mod test_serialization {
5205 use super::*;
5206 use serde_json::json;
5207
5208 #[test]
5209 fn test_mcp_server_stdio_serialization() {
5210 let server = McpServer::Stdio(
5211 McpServerStdio::new("test-server", "/usr/bin/server")
5212 .args(vec!["--port".to_string(), "3000".to_string()])
5213 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5214 );
5215
5216 let json = serde_json::to_value(&server).unwrap();
5217 assert_eq!(
5218 json,
5219 json!({
5220 "type": "stdio",
5221 "name": "test-server",
5222 "command": "/usr/bin/server",
5223 "args": ["--port", "3000"],
5224 "env": [
5225 {
5226 "name": "API_KEY",
5227 "value": "secret123"
5228 }
5229 ]
5230 })
5231 );
5232
5233 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5234 match deserialized {
5235 McpServer::Stdio(McpServerStdio {
5236 name,
5237 command,
5238 args,
5239 env,
5240 meta: _,
5241 }) => {
5242 assert_eq!(name, "test-server");
5243 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5244 assert_eq!(args, vec!["--port", "3000"]);
5245 assert_eq!(env.len(), 1);
5246 assert_eq!(env[0].name, "API_KEY");
5247 assert_eq!(env[0].value, "secret123");
5248 }
5249 _ => panic!("Expected Stdio variant"),
5250 }
5251 }
5252
5253 #[test]
5254 fn test_mcp_server_unknown_transport_serialization() {
5255 let json = json!({
5256 "type": "websocket",
5257 "name": "future-server",
5258 "url": "wss://example.com/mcp",
5259 "protocolVersion": "2026-01-01"
5260 });
5261
5262 let deserialized: McpServer = serde_json::from_value(json.clone()).unwrap();
5263 let McpServer::Other(OtherMcpServer { type_, fields }) = &deserialized else {
5264 panic!("Expected Other variant");
5265 };
5266
5267 assert_eq!(type_, "websocket");
5268 assert_eq!(fields["name"], "future-server");
5269 assert_eq!(fields["url"], "wss://example.com/mcp");
5270 assert_eq!(fields["protocolVersion"], "2026-01-01");
5271 assert_eq!(serde_json::to_value(&deserialized).unwrap(), json);
5272 }
5273
5274 #[test]
5275 fn test_mcp_server_stdio_requires_type() {
5276 let result = serde_json::from_value::<McpServer>(json!({
5277 "name": "test-server",
5278 "command": "/usr/bin/server",
5279 "args": [],
5280 "env": []
5281 }));
5282
5283 assert!(result.is_err());
5284 }
5285
5286 #[test]
5287 fn test_mcp_server_unknown_does_not_hide_malformed_known_transport() {
5288 let result = serde_json::from_value::<McpServer>(json!({
5289 "type": "stdio",
5290 "name": "test-server",
5291 "args": [],
5292 "env": []
5293 }));
5294
5295 assert!(result.is_err());
5296 }
5297
5298 #[test]
5299 fn test_mcp_server_http_serialization() {
5300 let server = McpServer::Http(
5301 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5302 HttpHeader::new("Authorization", "Bearer token123"),
5303 HttpHeader::new("Content-Type", "application/json"),
5304 ]),
5305 );
5306
5307 let json = serde_json::to_value(&server).unwrap();
5308 assert_eq!(
5309 json,
5310 json!({
5311 "type": "http",
5312 "name": "http-server",
5313 "url": "https://api.example.com",
5314 "headers": [
5315 {
5316 "name": "Authorization",
5317 "value": "Bearer token123"
5318 },
5319 {
5320 "name": "Content-Type",
5321 "value": "application/json"
5322 }
5323 ]
5324 })
5325 );
5326
5327 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5328 match deserialized {
5329 McpServer::Http(McpServerHttp {
5330 name,
5331 url,
5332 headers,
5333 meta: _,
5334 }) => {
5335 assert_eq!(name, "http-server");
5336 assert_eq!(url, "https://api.example.com");
5337 assert_eq!(headers.len(), 2);
5338 assert_eq!(headers[0].name, "Authorization");
5339 assert_eq!(headers[0].value, "Bearer token123");
5340 assert_eq!(headers[1].name, "Content-Type");
5341 assert_eq!(headers[1].value, "application/json");
5342 }
5343 _ => panic!("Expected Http variant"),
5344 }
5345 }
5346
5347 #[cfg(feature = "unstable_mcp_over_acp")]
5348 #[test]
5349 fn test_client_mcp_message_method_names() {
5350 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5351
5352 assert_eq!(
5353 ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
5354 .method(),
5355 "mcp/message"
5356 );
5357 assert_eq!(
5358 ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
5359 "conn-1",
5360 "notifications/progress"
5361 ))
5362 .method(),
5363 "mcp/message"
5364 );
5365 }
5366
5367 #[test]
5368 fn test_session_config_option_category_known_variants() {
5369 assert_eq!(
5371 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5372 json!("mode")
5373 );
5374 assert_eq!(
5375 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5376 json!("model")
5377 );
5378 assert_eq!(
5379 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5380 json!("thought_level")
5381 );
5382
5383 assert_eq!(
5385 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5386 SessionConfigOptionCategory::Mode
5387 );
5388 assert_eq!(
5389 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5390 SessionConfigOptionCategory::Model
5391 );
5392 assert_eq!(
5393 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5394 SessionConfigOptionCategory::ThoughtLevel
5395 );
5396 }
5397
5398 #[test]
5399 fn test_session_config_option_category_unknown_variants() {
5400 let unknown: SessionConfigOptionCategory =
5402 serde_json::from_str("\"some_future_category\"").unwrap();
5403 assert_eq!(
5404 unknown,
5405 SessionConfigOptionCategory::Other("some_future_category".to_string())
5406 );
5407
5408 let json = serde_json::to_value(&unknown).unwrap();
5410 assert_eq!(json, json!("some_future_category"));
5411 }
5412
5413 #[test]
5414 fn test_session_config_option_category_custom_categories() {
5415 let custom: SessionConfigOptionCategory =
5417 serde_json::from_str("\"_my_custom_category\"").unwrap();
5418 assert_eq!(
5419 custom,
5420 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5421 );
5422
5423 let json = serde_json::to_value(&custom).unwrap();
5425 assert_eq!(json, json!("_my_custom_category"));
5426
5427 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5429 assert_eq!(
5430 deserialized,
5431 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5432 );
5433 }
5434
5435 #[test]
5436 fn test_auth_method_agent_serialization() {
5437 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5438
5439 let json = serde_json::to_value(&method).unwrap();
5440 assert_eq!(
5441 json,
5442 json!({
5443 "id": "default-auth",
5444 "name": "Default Auth"
5445 })
5446 );
5447 assert!(!json.as_object().unwrap().contains_key("description"));
5449 assert!(!json.as_object().unwrap().contains_key("type"));
5451
5452 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5453 match deserialized {
5454 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5455 assert_eq!(id.0.as_ref(), "default-auth");
5456 assert_eq!(name, "Default Auth");
5457 }
5458 _ => panic!("Expected Agent variant"),
5459 }
5460 }
5461
5462 #[test]
5463 fn test_auth_method_explicit_agent_deserialization() {
5464 let json = json!({
5466 "id": "agent-auth",
5467 "name": "Agent Auth",
5468 "type": "agent"
5469 });
5470
5471 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5472 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5473 }
5474
5475 #[test]
5476 fn test_auth_method_agent_rejects_null_type() {
5477 assert!(
5478 serde_json::from_value::<AuthMethod>(json!({
5479 "id": "agent-auth",
5480 "name": "Agent Auth",
5481 "type": null
5482 }))
5483 .is_err()
5484 );
5485 }
5486
5487 #[test]
5488 fn test_auth_method_unknown_variant_roundtrip() {
5489 let method: AuthMethod = serde_json::from_value(json!({
5490 "id": "oauth",
5491 "name": "OAuth",
5492 "type": "_oauth",
5493 "authorizationUrl": "https://example.com/auth"
5494 }))
5495 .unwrap();
5496
5497 assert_eq!(method.id().0.as_ref(), "oauth");
5498 assert_eq!(method.name(), "OAuth");
5499 let AuthMethod::Other(unknown) = method else {
5500 panic!("expected unknown auth method");
5501 };
5502 assert_eq!(unknown.type_, "_oauth");
5503 assert_eq!(
5504 unknown.fields.get("authorizationUrl"),
5505 Some(&json!("https://example.com/auth"))
5506 );
5507
5508 assert_eq!(
5509 serde_json::to_value(AuthMethod::Other(unknown)).unwrap(),
5510 json!({
5511 "id": "oauth",
5512 "name": "OAuth",
5513 "type": "_oauth",
5514 "authorizationUrl": "https://example.com/auth"
5515 })
5516 );
5517 }
5518
5519 #[cfg(feature = "unstable_auth_methods")]
5520 #[test]
5521 fn test_auth_method_unknown_does_not_hide_malformed_known_variant() {
5522 assert!(
5523 serde_json::from_value::<AuthMethod>(json!({
5524 "id": "api-key",
5525 "name": "API Key",
5526 "type": "env_var"
5527 }))
5528 .is_err()
5529 );
5530 }
5531
5532 #[test]
5533 fn test_session_delete_serialization() {
5534 assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5535 assert_eq!(
5536 ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5537 "session/delete"
5538 );
5539 assert_eq!(
5540 serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5541 json!({
5542 "sessionId": "sess_abc123"
5543 })
5544 );
5545 assert_eq!(
5546 serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5547 json!({})
5548 );
5549 assert_eq!(
5550 serde_json::to_value(
5551 SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5552 )
5553 .unwrap(),
5554 json!({
5555 "delete": {}
5556 })
5557 );
5558 }
5559 #[test]
5560 fn test_session_additional_directories_serialization() {
5561 assert_eq!(
5562 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5563 json!({
5564 "cwd": "/home/user/project",
5565 "mcpServers": []
5566 })
5567 );
5568 assert_eq!(
5569 serde_json::to_value(
5570 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5571 PathBuf::from("/home/user/shared-lib"),
5572 PathBuf::from("/home/user/product-docs"),
5573 ])
5574 )
5575 .unwrap(),
5576 json!({
5577 "cwd": "/home/user/project",
5578 "additionalDirectories": [
5579 "/home/user/shared-lib",
5580 "/home/user/product-docs"
5581 ],
5582 "mcpServers": []
5583 })
5584 );
5585 assert_eq!(
5586 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5587 json!({
5588 "sessionId": "sess_abc123",
5589 "cwd": "/home/user/project"
5590 })
5591 );
5592 assert_eq!(
5593 serde_json::to_value(
5594 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5595 PathBuf::from("/home/user/shared-lib"),
5596 PathBuf::from("/home/user/product-docs"),
5597 ])
5598 )
5599 .unwrap(),
5600 json!({
5601 "sessionId": "sess_abc123",
5602 "cwd": "/home/user/project",
5603 "additionalDirectories": [
5604 "/home/user/shared-lib",
5605 "/home/user/product-docs"
5606 ]
5607 })
5608 );
5609 assert_eq!(
5610 serde_json::from_value::<SessionInfo>(json!({
5611 "sessionId": "sess_abc123",
5612 "cwd": "/home/user/project"
5613 }))
5614 .unwrap()
5615 .additional_directories,
5616 Vec::<PathBuf>::new()
5617 );
5618 }
5619 #[test]
5620 fn test_session_load_capabilities_serialization() {
5621 assert_eq!(
5622 serde_json::to_value(SessionCapabilities::new().load(SessionLoadCapabilities::new()))
5623 .unwrap(),
5624 json!({
5625 "load": {}
5626 })
5627 );
5628 }
5629
5630 #[test]
5631 fn test_session_additional_directories_capabilities_serialization() {
5632 assert_eq!(
5633 serde_json::to_value(
5634 SessionCapabilities::new()
5635 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5636 )
5637 .unwrap(),
5638 json!({
5639 "additionalDirectories": {}
5640 })
5641 );
5642 }
5643
5644 #[cfg(feature = "unstable_auth_methods")]
5645 #[test]
5646 fn test_auth_method_env_var_serialization() {
5647 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5648 "api-key",
5649 "API Key",
5650 vec![AuthEnvVar::new("API_KEY")],
5651 ));
5652
5653 let json = serde_json::to_value(&method).unwrap();
5654 assert_eq!(
5655 json,
5656 json!({
5657 "id": "api-key",
5658 "name": "API Key",
5659 "type": "env_var",
5660 "vars": [{"name": "API_KEY"}]
5661 })
5662 );
5663 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5665 assert!(
5666 !json["vars"][0]
5667 .as_object()
5668 .unwrap()
5669 .contains_key("optional")
5670 );
5671
5672 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5673 match deserialized {
5674 AuthMethod::EnvVar(AuthMethodEnvVar {
5675 id,
5676 name: method_name,
5677 vars,
5678 link,
5679 ..
5680 }) => {
5681 assert_eq!(id.0.as_ref(), "api-key");
5682 assert_eq!(method_name, "API Key");
5683 assert_eq!(vars.len(), 1);
5684 assert_eq!(vars[0].name, "API_KEY");
5685 assert!(vars[0].secret);
5686 assert!(!vars[0].optional);
5687 assert!(link.is_none());
5688 }
5689 _ => panic!("Expected EnvVar variant"),
5690 }
5691 }
5692
5693 #[cfg(feature = "unstable_auth_methods")]
5694 #[test]
5695 fn test_auth_method_env_var_with_link_serialization() {
5696 let method = AuthMethod::EnvVar(
5697 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5698 .link("https://example.com/keys"),
5699 );
5700
5701 let json = serde_json::to_value(&method).unwrap();
5702 assert_eq!(
5703 json,
5704 json!({
5705 "id": "api-key",
5706 "name": "API Key",
5707 "type": "env_var",
5708 "vars": [{"name": "API_KEY"}],
5709 "link": "https://example.com/keys"
5710 })
5711 );
5712
5713 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5714 match deserialized {
5715 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5716 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5717 }
5718 _ => panic!("Expected EnvVar variant"),
5719 }
5720 }
5721
5722 #[cfg(feature = "unstable_auth_methods")]
5723 #[test]
5724 fn test_auth_method_env_var_multiple_vars() {
5725 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5726 "azure-openai",
5727 "Azure OpenAI",
5728 vec![
5729 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5730 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5731 .label("Endpoint URL")
5732 .secret(false),
5733 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5734 .label("API Version")
5735 .secret(false)
5736 .optional(true),
5737 ],
5738 ));
5739
5740 let json = serde_json::to_value(&method).unwrap();
5741 assert_eq!(
5742 json,
5743 json!({
5744 "id": "azure-openai",
5745 "name": "Azure OpenAI",
5746 "type": "env_var",
5747 "vars": [
5748 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5749 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5750 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5751 ]
5752 })
5753 );
5754
5755 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5756 match deserialized {
5757 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5758 assert_eq!(vars.len(), 3);
5759 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5761 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5762 assert!(vars[0].secret);
5763 assert!(!vars[0].optional);
5764 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5766 assert!(!vars[1].secret);
5767 assert!(!vars[1].optional);
5768 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5770 assert!(!vars[2].secret);
5771 assert!(vars[2].optional);
5772 }
5773 _ => panic!("Expected EnvVar variant"),
5774 }
5775 }
5776
5777 #[cfg(feature = "unstable_auth_methods")]
5778 #[test]
5779 fn test_auth_method_terminal_serialization() {
5780 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5781
5782 let json = serde_json::to_value(&method).unwrap();
5783 assert_eq!(
5784 json,
5785 json!({
5786 "id": "tui-auth",
5787 "name": "Terminal Auth",
5788 "type": "terminal"
5789 })
5790 );
5791 assert!(!json.as_object().unwrap().contains_key("args"));
5793 assert!(!json.as_object().unwrap().contains_key("env"));
5794
5795 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5796 match deserialized {
5797 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5798 assert!(args.is_empty());
5799 assert!(env.is_empty());
5800 }
5801 _ => panic!("Expected Terminal variant"),
5802 }
5803 }
5804
5805 #[cfg(feature = "unstable_auth_methods")]
5806 #[test]
5807 fn test_auth_method_terminal_with_args_and_env_serialization() {
5808 use std::collections::HashMap;
5809
5810 let mut env = HashMap::new();
5811 env.insert("TERM".to_string(), "xterm-256color".to_string());
5812
5813 let method = AuthMethod::Terminal(
5814 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5815 .args(vec!["--interactive".to_string(), "--color".to_string()])
5816 .env(env),
5817 );
5818
5819 let json = serde_json::to_value(&method).unwrap();
5820 assert_eq!(
5821 json,
5822 json!({
5823 "id": "tui-auth",
5824 "name": "Terminal Auth",
5825 "type": "terminal",
5826 "args": ["--interactive", "--color"],
5827 "env": {
5828 "TERM": "xterm-256color"
5829 }
5830 })
5831 );
5832
5833 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5834 match deserialized {
5835 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5836 assert_eq!(args, vec!["--interactive", "--color"]);
5837 assert_eq!(env.len(), 1);
5838 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5839 }
5840 _ => panic!("Expected Terminal variant"),
5841 }
5842 }
5843
5844 #[cfg(feature = "unstable_boolean_config")]
5845 #[test]
5846 fn test_session_config_option_value_id_serialize() {
5847 let val = SessionConfigOptionValue::value_id("model-1");
5848 let json = serde_json::to_value(&val).unwrap();
5849 assert_eq!(json, json!({ "value": "model-1" }));
5851 assert!(!json.as_object().unwrap().contains_key("type"));
5852 }
5853
5854 #[cfg(feature = "unstable_boolean_config")]
5855 #[test]
5856 fn test_session_config_option_value_boolean_serialize() {
5857 let val = SessionConfigOptionValue::boolean(true);
5858 let json = serde_json::to_value(&val).unwrap();
5859 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5860 }
5861
5862 #[cfg(feature = "unstable_boolean_config")]
5863 #[test]
5864 fn test_session_config_option_value_deserialize_no_type() {
5865 let json = json!({ "value": "model-1" });
5867 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5868 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5869 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5870 }
5871
5872 #[cfg(feature = "unstable_boolean_config")]
5873 #[test]
5874 fn test_session_config_option_value_deserialize_boolean() {
5875 let json = json!({ "type": "boolean", "value": true });
5876 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5877 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5878 assert_eq!(val.as_bool(), Some(true));
5879 }
5880
5881 #[cfg(feature = "unstable_boolean_config")]
5882 #[test]
5883 fn test_session_config_option_value_deserialize_boolean_false() {
5884 let json = json!({ "type": "boolean", "value": false });
5885 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5886 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5887 assert_eq!(val.as_bool(), Some(false));
5888 }
5889
5890 #[cfg(feature = "unstable_boolean_config")]
5891 #[test]
5892 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5893 let json = json!({ "type": "text", "value": "freeform input" });
5895 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5896 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5897 }
5898
5899 #[cfg(feature = "unstable_boolean_config")]
5900 #[test]
5901 fn test_session_config_option_value_roundtrip_value_id() {
5902 let original = SessionConfigOptionValue::value_id("option-a");
5903 let json = serde_json::to_value(&original).unwrap();
5904 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5905 assert_eq!(original, roundtripped);
5906 }
5907
5908 #[cfg(feature = "unstable_boolean_config")]
5909 #[test]
5910 fn test_session_config_option_value_roundtrip_boolean() {
5911 let original = SessionConfigOptionValue::boolean(false);
5912 let json = serde_json::to_value(&original).unwrap();
5913 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5914 assert_eq!(original, roundtripped);
5915 }
5916
5917 #[cfg(feature = "unstable_boolean_config")]
5918 #[test]
5919 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5920 let json = json!({ "type": "boolean", "value": "not a bool" });
5922 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5923 assert!(result.is_ok());
5925 assert_eq!(
5926 result.unwrap().as_value_id().unwrap().to_string(),
5927 "not a bool"
5928 );
5929 }
5930
5931 #[cfg(feature = "unstable_boolean_config")]
5932 #[test]
5933 fn test_session_config_option_value_from_impls() {
5934 let from_str: SessionConfigOptionValue = "model-1".into();
5935 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5936
5937 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5938 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5939
5940 let from_bool: SessionConfigOptionValue = true.into();
5941 assert_eq!(from_bool.as_bool(), Some(true));
5942 }
5943
5944 #[cfg(feature = "unstable_boolean_config")]
5945 #[test]
5946 fn test_set_session_config_option_request_value_id() {
5947 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5948 let json = serde_json::to_value(&req).unwrap();
5949 assert_eq!(
5950 json,
5951 json!({
5952 "sessionId": "sess_1",
5953 "configId": "model",
5954 "value": "model-1"
5955 })
5956 );
5957 assert!(!json.as_object().unwrap().contains_key("type"));
5959 }
5960
5961 #[cfg(feature = "unstable_boolean_config")]
5962 #[test]
5963 fn test_set_session_config_option_request_boolean() {
5964 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5965 let json = serde_json::to_value(&req).unwrap();
5966 assert_eq!(
5967 json,
5968 json!({
5969 "sessionId": "sess_1",
5970 "configId": "brave_mode",
5971 "type": "boolean",
5972 "value": true
5973 })
5974 );
5975 }
5976
5977 #[cfg(feature = "unstable_boolean_config")]
5978 #[test]
5979 fn test_set_session_config_option_request_deserialize_no_type() {
5980 let json = json!({
5982 "sessionId": "sess_1",
5983 "configId": "model",
5984 "value": "model-1"
5985 });
5986 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5987 assert_eq!(req.session_id.to_string(), "sess_1");
5988 assert_eq!(req.config_id.to_string(), "model");
5989 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5990 }
5991
5992 #[cfg(feature = "unstable_boolean_config")]
5993 #[test]
5994 fn test_set_session_config_option_request_deserialize_boolean() {
5995 let json = json!({
5996 "sessionId": "sess_1",
5997 "configId": "brave_mode",
5998 "type": "boolean",
5999 "value": true
6000 });
6001 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6002 assert_eq!(req.value.as_bool(), Some(true));
6003 }
6004
6005 #[cfg(feature = "unstable_boolean_config")]
6006 #[test]
6007 fn test_set_session_config_option_request_roundtrip_value_id() {
6008 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
6009 let json = serde_json::to_value(&original).unwrap();
6010 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6011 assert_eq!(original, roundtripped);
6012 }
6013
6014 #[cfg(feature = "unstable_boolean_config")]
6015 #[test]
6016 fn test_set_session_config_option_request_roundtrip_boolean() {
6017 let original = SetSessionConfigOptionRequest::new("s", "c", false);
6018 let json = serde_json::to_value(&original).unwrap();
6019 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6020 assert_eq!(original, roundtripped);
6021 }
6022
6023 #[cfg(feature = "unstable_boolean_config")]
6024 #[test]
6025 fn test_session_config_boolean_serialization() {
6026 let cfg = SessionConfigBoolean::new(true);
6027 let json = serde_json::to_value(&cfg).unwrap();
6028 assert_eq!(json, json!({ "currentValue": true }));
6029
6030 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6031 assert!(deserialized.current_value);
6032 }
6033
6034 #[cfg(feature = "unstable_boolean_config")]
6035 #[test]
6036 fn test_session_config_option_boolean_variant() {
6037 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6038 .description("Skip confirmation prompts");
6039 let json = serde_json::to_value(&opt).unwrap();
6040 assert_eq!(
6041 json,
6042 json!({
6043 "id": "brave_mode",
6044 "name": "Brave Mode",
6045 "description": "Skip confirmation prompts",
6046 "type": "boolean",
6047 "currentValue": false
6048 })
6049 );
6050
6051 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6052 assert_eq!(deserialized.id.to_string(), "brave_mode");
6053 assert_eq!(deserialized.name, "Brave Mode");
6054 match deserialized.kind {
6055 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6056 _ => panic!("Expected Boolean kind"),
6057 }
6058 }
6059
6060 #[cfg(feature = "unstable_boolean_config")]
6061 #[test]
6062 fn test_session_config_option_select_still_works() {
6063 let opt = SessionConfigOption::select(
6065 "model",
6066 "Model",
6067 "model-1",
6068 vec![
6069 SessionConfigSelectOption::new("model-1", "Model 1"),
6070 SessionConfigSelectOption::new("model-2", "Model 2"),
6071 ],
6072 );
6073 let json = serde_json::to_value(&opt).unwrap();
6074 assert_eq!(json["type"], "select");
6075 assert_eq!(json["currentValue"], "model-1");
6076 assert_eq!(json["options"].as_array().unwrap().len(), 2);
6077
6078 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6079 match deserialized.kind {
6080 SessionConfigKind::Select(ref s) => {
6081 assert_eq!(s.current_value.to_string(), "model-1");
6082 }
6083 _ => panic!("Expected Select kind"),
6084 }
6085 }
6086
6087 #[test]
6088 fn test_session_config_option_unknown_kind_roundtrip() {
6089 let option: SessionConfigOption = serde_json::from_value(json!({
6090 "id": "verbosity",
6091 "name": "Verbosity",
6092 "type": "_slider",
6093 "currentValue": 3,
6094 "min": 0,
6095 "max": 5
6096 }))
6097 .unwrap();
6098
6099 assert_eq!(option.id.to_string(), "verbosity");
6100 let SessionConfigKind::Other(unknown) = &option.kind else {
6101 panic!("expected unknown config kind");
6102 };
6103 assert_eq!(unknown.type_, "_slider");
6104 assert_eq!(unknown.fields.get("currentValue"), Some(&json!(3)));
6105
6106 let json = serde_json::to_value(&option).unwrap();
6107 assert_eq!(json["type"], "_slider");
6108 assert_eq!(json["currentValue"], 3);
6109 assert_eq!(json["min"], 0);
6110 assert_eq!(json["max"], 5);
6111 }
6112
6113 #[test]
6114 fn test_session_config_option_unknown_does_not_hide_malformed_known_kind() {
6115 assert!(
6116 serde_json::from_value::<SessionConfigOption>(json!({
6117 "id": "model",
6118 "name": "Model",
6119 "type": "select"
6120 }))
6121 .is_err()
6122 );
6123 }
6124
6125 #[cfg(feature = "unstable_llm_providers")]
6126 #[test]
6127 fn test_llm_protocol_known_variants() {
6128 assert_eq!(
6129 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6130 json!("anthropic")
6131 );
6132 assert_eq!(
6133 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6134 json!("openai")
6135 );
6136 assert_eq!(
6137 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6138 json!("azure")
6139 );
6140 assert_eq!(
6141 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6142 json!("vertex")
6143 );
6144 assert_eq!(
6145 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6146 json!("bedrock")
6147 );
6148
6149 assert_eq!(
6150 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6151 LlmProtocol::Anthropic
6152 );
6153 assert_eq!(
6154 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6155 LlmProtocol::OpenAi
6156 );
6157 assert_eq!(
6158 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6159 LlmProtocol::Azure
6160 );
6161 assert_eq!(
6162 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6163 LlmProtocol::Vertex
6164 );
6165 assert_eq!(
6166 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6167 LlmProtocol::Bedrock
6168 );
6169 }
6170
6171 #[cfg(feature = "unstable_llm_providers")]
6172 #[test]
6173 fn test_llm_protocol_unknown_variant() {
6174 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6175 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6176
6177 let json = serde_json::to_value(&unknown).unwrap();
6178 assert_eq!(json, json!("cohere"));
6179 }
6180
6181 #[cfg(feature = "unstable_llm_providers")]
6182 #[test]
6183 fn test_provider_current_config_serialization() {
6184 let config =
6185 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6186
6187 let json = serde_json::to_value(&config).unwrap();
6188 assert_eq!(
6189 json,
6190 json!({
6191 "apiType": "anthropic",
6192 "baseUrl": "https://api.anthropic.com"
6193 })
6194 );
6195
6196 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6197 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6198 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6199 }
6200
6201 #[cfg(feature = "unstable_llm_providers")]
6202 #[test]
6203 fn test_provider_info_with_current_config() {
6204 let info = ProviderInfo::new(
6205 "main",
6206 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6207 true,
6208 Some(ProviderCurrentConfig::new(
6209 LlmProtocol::Anthropic,
6210 "https://api.anthropic.com",
6211 )),
6212 );
6213
6214 let json = serde_json::to_value(&info).unwrap();
6215 assert_eq!(
6216 json,
6217 json!({
6218 "id": "main",
6219 "supported": ["anthropic", "openai"],
6220 "required": true,
6221 "current": {
6222 "apiType": "anthropic",
6223 "baseUrl": "https://api.anthropic.com"
6224 }
6225 })
6226 );
6227
6228 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6229 assert_eq!(deserialized.id, "main");
6230 assert_eq!(deserialized.supported.len(), 2);
6231 assert!(deserialized.required);
6232 assert!(deserialized.current.is_some());
6233 assert_eq!(
6234 deserialized.current.as_ref().unwrap().api_type,
6235 LlmProtocol::Anthropic
6236 );
6237 }
6238
6239 #[cfg(feature = "unstable_llm_providers")]
6240 #[test]
6241 fn test_provider_info_disabled() {
6242 let info = ProviderInfo::new(
6243 "secondary",
6244 vec![LlmProtocol::OpenAi],
6245 false,
6246 None::<ProviderCurrentConfig>,
6247 );
6248
6249 let json = serde_json::to_value(&info).unwrap();
6250 assert_eq!(
6251 json,
6252 json!({
6253 "id": "secondary",
6254 "supported": ["openai"],
6255 "required": false
6256 })
6257 );
6258
6259 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6260 assert_eq!(deserialized.id, "secondary");
6261 assert!(!deserialized.required);
6262 assert!(deserialized.current.is_none());
6263 }
6264
6265 #[cfg(feature = "unstable_llm_providers")]
6266 #[test]
6267 fn test_provider_info_missing_current_defaults_to_none() {
6268 let json = json!({
6270 "id": "main",
6271 "supported": ["anthropic"],
6272 "required": true
6273 });
6274 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6275 assert!(deserialized.current.is_none());
6276 }
6277
6278 #[cfg(feature = "unstable_llm_providers")]
6279 #[test]
6280 fn test_provider_info_explicit_null_current_decodes_to_none() {
6281 let json = json!({
6285 "id": "main",
6286 "supported": ["anthropic"],
6287 "required": true,
6288 "current": null
6289 });
6290 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6291 assert!(deserialized.current.is_none());
6292 }
6293
6294 #[cfg(feature = "unstable_llm_providers")]
6295 #[test]
6296 fn test_list_providers_response_serialization() {
6297 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6298 "main",
6299 vec![LlmProtocol::Anthropic],
6300 true,
6301 Some(ProviderCurrentConfig::new(
6302 LlmProtocol::Anthropic,
6303 "https://api.anthropic.com",
6304 )),
6305 )]);
6306
6307 let json = serde_json::to_value(&response).unwrap();
6308 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6309 assert_eq!(json["providers"][0]["id"], "main");
6310
6311 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6312 assert_eq!(deserialized.providers.len(), 1);
6313 }
6314
6315 #[cfg(feature = "unstable_llm_providers")]
6316 #[test]
6317 fn test_set_provider_request_serialization() {
6318 use std::collections::HashMap;
6319
6320 let mut headers = HashMap::new();
6321 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6322
6323 let request =
6324 SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6325 .headers(headers);
6326
6327 let json = serde_json::to_value(&request).unwrap();
6328 assert_eq!(
6329 json,
6330 json!({
6331 "id": "main",
6332 "apiType": "openai",
6333 "baseUrl": "https://api.openai.com/v1",
6334 "headers": {
6335 "Authorization": "Bearer sk-test"
6336 }
6337 })
6338 );
6339
6340 let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6341 assert_eq!(deserialized.id, "main");
6342 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6343 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6344 assert_eq!(deserialized.headers.len(), 1);
6345 assert_eq!(
6346 deserialized.headers.get("Authorization").unwrap(),
6347 "Bearer sk-test"
6348 );
6349 }
6350
6351 #[cfg(feature = "unstable_llm_providers")]
6352 #[test]
6353 fn test_set_provider_request_omits_empty_headers() {
6354 let request =
6355 SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6356
6357 let json = serde_json::to_value(&request).unwrap();
6358 assert!(!json.as_object().unwrap().contains_key("headers"));
6360 }
6361
6362 #[cfg(feature = "unstable_llm_providers")]
6363 #[test]
6364 fn test_disable_provider_request_serialization() {
6365 let request = DisableProviderRequest::new("secondary");
6366
6367 let json = serde_json::to_value(&request).unwrap();
6368 assert_eq!(json, json!({ "id": "secondary" }));
6369
6370 let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6371 assert_eq!(deserialized.id, "secondary");
6372 }
6373
6374 #[cfg(feature = "unstable_llm_providers")]
6375 #[test]
6376 fn test_providers_capabilities_serialization() {
6377 let caps = ProvidersCapabilities::new();
6378
6379 let json = serde_json::to_value(&caps).unwrap();
6380 assert_eq!(json, json!({}));
6381
6382 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6383 assert!(deserialized.meta.is_none());
6384 }
6385
6386 #[cfg(feature = "unstable_llm_providers")]
6387 #[test]
6388 fn test_agent_capabilities_with_providers() {
6389 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6390
6391 let json = serde_json::to_value(&caps).unwrap();
6392 assert_eq!(json["providers"], json!({}));
6393
6394 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6395 assert!(deserialized.providers.is_some());
6396 }
6397
6398 #[test]
6399 fn test_prompt_capabilities_serialize_supported_content_as_objects() {
6400 let caps = PromptCapabilities::new()
6401 .image(PromptImageCapabilities::new())
6402 .audio(PromptAudioCapabilities::new())
6403 .embedded_context(PromptEmbeddedContextCapabilities::new());
6404
6405 assert_eq!(
6406 serde_json::to_value(&caps).unwrap(),
6407 json!({
6408 "image": {},
6409 "audio": {},
6410 "embeddedContext": {}
6411 })
6412 );
6413
6414 let deserialized: PromptCapabilities = serde_json::from_value(json!({
6415 "image": null,
6416 "audio": false,
6417 "embeddedContext": {}
6418 }))
6419 .unwrap();
6420 assert!(deserialized.image.is_none());
6421 assert!(deserialized.audio.is_none());
6422 assert!(deserialized.embedded_context.is_some());
6423 }
6424
6425 #[test]
6426 fn test_mcp_capabilities_serialize_supported_transports_as_objects() {
6427 let caps = McpCapabilities::new()
6428 .stdio(McpStdioCapabilities::new())
6429 .http(McpHttpCapabilities::new());
6430
6431 assert_eq!(
6432 serde_json::to_value(&caps).unwrap(),
6433 json!({
6434 "stdio": {},
6435 "http": {}
6436 })
6437 );
6438
6439 let deserialized: McpCapabilities = serde_json::from_value(json!({
6440 "stdio": null,
6441 "http": false
6442 }))
6443 .unwrap();
6444 assert!(deserialized.stdio.is_none());
6445 assert!(deserialized.http.is_none());
6446 }
6447
6448 #[cfg(feature = "unstable_mcp_over_acp")]
6449 #[test]
6450 fn test_mcp_capabilities_serialize_acp_support_as_object() {
6451 let caps = McpCapabilities::new().acp(McpAcpCapabilities::new());
6452
6453 assert_eq!(
6454 serde_json::to_value(&caps).unwrap(),
6455 json!({
6456 "acp": {}
6457 })
6458 );
6459 }
6460}