1use std::{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;
13use serde::{Deserialize, Serialize};
14use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
15
16#[cfg(feature = "unstable_llm_providers")]
17use crate::RequiredNullable;
18use crate::{
19 ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta,
20 ProtocolVersion, SessionId, SkipListener,
21};
22
23#[cfg(feature = "unstable_nes")]
24use crate::{
25 AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
26 DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
27 DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
28 StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
29};
30
31#[cfg(feature = "unstable_nes")]
32use crate::nes::{
33 DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
34 DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
35 NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
36 NES_SUGGEST_METHOD_NAME,
37};
38
39#[serde_as]
47#[skip_serializing_none]
48#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
49#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
50#[serde(rename_all = "camelCase")]
51#[non_exhaustive]
52pub struct InitializeRequest {
53 pub protocol_version: ProtocolVersion,
55 #[serde(default)]
57 pub client_capabilities: ClientCapabilities,
58 #[serde_as(deserialize_as = "DefaultOnError")]
62 #[serde(default)]
63 pub client_info: Option<Implementation>,
64 #[serde(rename = "_meta")]
70 pub meta: Option<Meta>,
71}
72
73impl InitializeRequest {
74 #[must_use]
75 pub fn new(protocol_version: ProtocolVersion) -> Self {
76 Self {
77 protocol_version,
78 client_capabilities: ClientCapabilities::default(),
79 client_info: None,
80 meta: None,
81 }
82 }
83
84 #[must_use]
86 pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
87 self.client_capabilities = client_capabilities;
88 self
89 }
90
91 #[must_use]
93 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
94 self.client_info = client_info.into_option();
95 self
96 }
97
98 #[must_use]
104 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
105 self.meta = meta.into_option();
106 self
107 }
108}
109
110#[serde_as]
116#[skip_serializing_none]
117#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
118#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
119#[serde(rename_all = "camelCase")]
120#[non_exhaustive]
121pub struct InitializeResponse {
122 pub protocol_version: ProtocolVersion,
127 #[serde(default)]
129 pub agent_capabilities: AgentCapabilities,
130 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
132 #[serde(default)]
133 pub auth_methods: Vec<AuthMethod>,
134 #[serde_as(deserialize_as = "DefaultOnError")]
138 #[serde(default)]
139 pub agent_info: Option<Implementation>,
140 #[serde(rename = "_meta")]
146 pub meta: Option<Meta>,
147}
148
149impl InitializeResponse {
150 #[must_use]
151 pub fn new(protocol_version: ProtocolVersion) -> Self {
152 Self {
153 protocol_version,
154 agent_capabilities: AgentCapabilities::default(),
155 auth_methods: vec![],
156 agent_info: None,
157 meta: None,
158 }
159 }
160
161 #[must_use]
163 pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
164 self.agent_capabilities = agent_capabilities;
165 self
166 }
167
168 #[must_use]
170 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
171 self.auth_methods = auth_methods;
172 self
173 }
174
175 #[must_use]
177 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
178 self.agent_info = agent_info.into_option();
179 self
180 }
181
182 #[must_use]
188 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
189 self.meta = meta.into_option();
190 self
191 }
192}
193
194#[skip_serializing_none]
198#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
199#[serde(rename_all = "camelCase")]
200#[non_exhaustive]
201pub struct Implementation {
202 pub name: String,
205 pub title: Option<String>,
210 pub version: String,
213 #[serde(rename = "_meta")]
219 pub meta: Option<Meta>,
220}
221
222impl Implementation {
223 #[must_use]
224 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
225 Self {
226 name: name.into(),
227 title: None,
228 version: version.into(),
229 meta: None,
230 }
231 }
232
233 #[must_use]
238 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
239 self.title = title.into_option();
240 self
241 }
242
243 #[must_use]
249 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
250 self.meta = meta.into_option();
251 self
252 }
253}
254
255#[skip_serializing_none]
261#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
262#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
263#[serde(rename_all = "camelCase")]
264#[non_exhaustive]
265pub struct AuthenticateRequest {
266 pub method_id: AuthMethodId,
269 #[serde(rename = "_meta")]
275 pub meta: Option<Meta>,
276}
277
278impl AuthenticateRequest {
279 #[must_use]
280 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
281 Self {
282 method_id: method_id.into(),
283 meta: None,
284 }
285 }
286
287 #[must_use]
293 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
294 self.meta = meta.into_option();
295 self
296 }
297}
298
299#[skip_serializing_none]
301#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
302#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
303#[serde(rename_all = "camelCase")]
304#[non_exhaustive]
305pub struct AuthenticateResponse {
306 #[serde(rename = "_meta")]
312 pub meta: Option<Meta>,
313}
314
315impl AuthenticateResponse {
316 #[must_use]
317 pub fn new() -> Self {
318 Self::default()
319 }
320
321 #[must_use]
327 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
328 self.meta = meta.into_option();
329 self
330 }
331}
332
333#[cfg(feature = "unstable_logout")]
343#[skip_serializing_none]
344#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
345#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
346#[serde(rename_all = "camelCase")]
347#[non_exhaustive]
348pub struct LogoutRequest {
349 #[serde(rename = "_meta")]
355 pub meta: Option<Meta>,
356}
357
358#[cfg(feature = "unstable_logout")]
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#[cfg(feature = "unstable_logout")]
383#[skip_serializing_none]
384#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
385#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
386#[serde(rename_all = "camelCase")]
387#[non_exhaustive]
388pub struct LogoutResponse {
389 #[serde(rename = "_meta")]
395 pub meta: Option<Meta>,
396}
397
398#[cfg(feature = "unstable_logout")]
399impl LogoutResponse {
400 #[must_use]
401 pub fn new() -> Self {
402 Self::default()
403 }
404
405 #[must_use]
411 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
412 self.meta = meta.into_option();
413 self
414 }
415}
416
417#[cfg(feature = "unstable_logout")]
423#[serde_as]
424#[skip_serializing_none]
425#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
426#[serde(rename_all = "camelCase")]
427#[non_exhaustive]
428pub struct AgentAuthCapabilities {
429 #[serde_as(deserialize_as = "DefaultOnError")]
433 #[serde(default)]
434 pub logout: Option<LogoutCapabilities>,
435 #[serde(rename = "_meta")]
441 pub meta: Option<Meta>,
442}
443
444#[cfg(feature = "unstable_logout")]
445impl AgentAuthCapabilities {
446 #[must_use]
447 pub fn new() -> Self {
448 Self::default()
449 }
450
451 #[must_use]
453 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
454 self.logout = logout.into_option();
455 self
456 }
457
458 #[must_use]
464 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
465 self.meta = meta.into_option();
466 self
467 }
468}
469
470#[cfg(feature = "unstable_logout")]
478#[skip_serializing_none]
479#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
480#[non_exhaustive]
481pub struct LogoutCapabilities {
482 #[serde(rename = "_meta")]
488 pub meta: Option<Meta>,
489}
490
491#[cfg(feature = "unstable_logout")]
492impl LogoutCapabilities {
493 #[must_use]
494 pub fn new() -> Self {
495 Self::default()
496 }
497
498 #[must_use]
504 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
505 self.meta = meta.into_option();
506 self
507 }
508}
509
510#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
511#[serde(transparent)]
512#[from(Arc<str>, String, &'static str)]
513#[non_exhaustive]
514pub struct AuthMethodId(pub Arc<str>);
515
516impl AuthMethodId {
517 #[must_use]
518 pub fn new(id: impl Into<Arc<str>>) -> Self {
519 Self(id.into())
520 }
521}
522
523#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
528#[serde(tag = "type", rename_all = "snake_case")]
529#[non_exhaustive]
530pub enum AuthMethod {
531 #[cfg(feature = "unstable_auth_methods")]
537 EnvVar(AuthMethodEnvVar),
538 #[cfg(feature = "unstable_auth_methods")]
544 Terminal(AuthMethodTerminal),
545 #[serde(untagged)]
549 Agent(AuthMethodAgent),
550}
551
552impl AuthMethod {
553 #[must_use]
555 pub fn id(&self) -> &AuthMethodId {
556 match self {
557 Self::Agent(a) => &a.id,
558 #[cfg(feature = "unstable_auth_methods")]
559 Self::EnvVar(e) => &e.id,
560 #[cfg(feature = "unstable_auth_methods")]
561 Self::Terminal(t) => &t.id,
562 }
563 }
564
565 #[must_use]
567 pub fn name(&self) -> &str {
568 match self {
569 Self::Agent(a) => &a.name,
570 #[cfg(feature = "unstable_auth_methods")]
571 Self::EnvVar(e) => &e.name,
572 #[cfg(feature = "unstable_auth_methods")]
573 Self::Terminal(t) => &t.name,
574 }
575 }
576
577 #[must_use]
579 pub fn description(&self) -> Option<&str> {
580 match self {
581 Self::Agent(a) => a.description.as_deref(),
582 #[cfg(feature = "unstable_auth_methods")]
583 Self::EnvVar(e) => e.description.as_deref(),
584 #[cfg(feature = "unstable_auth_methods")]
585 Self::Terminal(t) => t.description.as_deref(),
586 }
587 }
588
589 #[must_use]
595 pub fn meta(&self) -> Option<&Meta> {
596 match self {
597 Self::Agent(a) => a.meta.as_ref(),
598 #[cfg(feature = "unstable_auth_methods")]
599 Self::EnvVar(e) => e.meta.as_ref(),
600 #[cfg(feature = "unstable_auth_methods")]
601 Self::Terminal(t) => t.meta.as_ref(),
602 }
603 }
604}
605
606#[skip_serializing_none]
610#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
611#[serde(rename_all = "camelCase")]
612#[non_exhaustive]
613pub struct AuthMethodAgent {
614 pub id: AuthMethodId,
616 pub name: String,
618 pub description: Option<String>,
620 #[serde(rename = "_meta")]
626 pub meta: Option<Meta>,
627}
628
629impl AuthMethodAgent {
630 #[must_use]
631 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
632 Self {
633 id: id.into(),
634 name: name.into(),
635 description: None,
636 meta: None,
637 }
638 }
639
640 #[must_use]
642 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
643 self.description = description.into_option();
644 self
645 }
646
647 #[must_use]
653 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
654 self.meta = meta.into_option();
655 self
656 }
657}
658
659#[cfg(feature = "unstable_auth_methods")]
667#[skip_serializing_none]
668#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
669#[serde(rename_all = "camelCase")]
670#[non_exhaustive]
671pub struct AuthMethodEnvVar {
672 pub id: AuthMethodId,
674 pub name: String,
676 pub description: Option<String>,
678 pub vars: Vec<AuthEnvVar>,
680 pub link: Option<String>,
682 #[serde(rename = "_meta")]
688 pub meta: Option<Meta>,
689}
690
691#[cfg(feature = "unstable_auth_methods")]
692impl AuthMethodEnvVar {
693 #[must_use]
694 pub fn new(
695 id: impl Into<AuthMethodId>,
696 name: impl Into<String>,
697 vars: Vec<AuthEnvVar>,
698 ) -> Self {
699 Self {
700 id: id.into(),
701 name: name.into(),
702 description: None,
703 vars,
704 link: None,
705 meta: None,
706 }
707 }
708
709 #[must_use]
711 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
712 self.link = link.into_option();
713 self
714 }
715
716 #[must_use]
718 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
719 self.description = description.into_option();
720 self
721 }
722
723 #[must_use]
729 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
730 self.meta = meta.into_option();
731 self
732 }
733}
734
735#[cfg(feature = "unstable_auth_methods")]
741#[skip_serializing_none]
742#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
743#[serde(rename_all = "camelCase")]
744#[non_exhaustive]
745pub struct AuthEnvVar {
746 pub name: String,
748 pub label: Option<String>,
750 #[serde(default = "default_true", skip_serializing_if = "is_true")]
755 #[schemars(extend("default" = true))]
756 pub secret: bool,
757 #[serde(default, skip_serializing_if = "is_false")]
761 #[schemars(extend("default" = false))]
762 pub optional: bool,
763 #[serde(rename = "_meta")]
769 pub meta: Option<Meta>,
770}
771
772#[cfg(feature = "unstable_auth_methods")]
773fn default_true() -> bool {
774 true
775}
776
777#[cfg(feature = "unstable_auth_methods")]
778#[expect(clippy::trivially_copy_pass_by_ref)]
779fn is_true(v: &bool) -> bool {
780 *v
781}
782
783#[cfg(feature = "unstable_auth_methods")]
784#[expect(clippy::trivially_copy_pass_by_ref)]
785fn is_false(v: &bool) -> bool {
786 !*v
787}
788
789#[cfg(feature = "unstable_auth_methods")]
790impl AuthEnvVar {
791 #[must_use]
793 pub fn new(name: impl Into<String>) -> Self {
794 Self {
795 name: name.into(),
796 label: None,
797 secret: true,
798 optional: false,
799 meta: None,
800 }
801 }
802
803 #[must_use]
805 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
806 self.label = label.into_option();
807 self
808 }
809
810 #[must_use]
813 pub fn secret(mut self, secret: bool) -> Self {
814 self.secret = secret;
815 self
816 }
817
818 #[must_use]
820 pub fn optional(mut self, optional: bool) -> Self {
821 self.optional = optional;
822 self
823 }
824
825 #[must_use]
831 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
832 self.meta = meta.into_option();
833 self
834 }
835}
836
837#[cfg(feature = "unstable_auth_methods")]
845#[skip_serializing_none]
846#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
847#[serde(rename_all = "camelCase")]
848#[non_exhaustive]
849pub struct AuthMethodTerminal {
850 pub id: AuthMethodId,
852 pub name: String,
854 pub description: Option<String>,
856 #[serde(default, skip_serializing_if = "Vec::is_empty")]
858 pub args: Vec<String>,
859 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
861 pub env: HashMap<String, String>,
862 #[serde(rename = "_meta")]
868 pub meta: Option<Meta>,
869}
870
871#[cfg(feature = "unstable_auth_methods")]
872impl AuthMethodTerminal {
873 #[must_use]
874 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
875 Self {
876 id: id.into(),
877 name: name.into(),
878 description: None,
879 args: Vec::new(),
880 env: HashMap::new(),
881 meta: None,
882 }
883 }
884
885 #[must_use]
887 pub fn args(mut self, args: Vec<String>) -> Self {
888 self.args = args;
889 self
890 }
891
892 #[must_use]
894 pub fn env(mut self, env: HashMap<String, String>) -> Self {
895 self.env = env;
896 self
897 }
898
899 #[must_use]
901 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
902 self.description = description.into_option();
903 self
904 }
905
906 #[must_use]
912 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
913 self.meta = meta.into_option();
914 self
915 }
916}
917
918#[skip_serializing_none]
924#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
925#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
926#[serde(rename_all = "camelCase")]
927#[non_exhaustive]
928pub struct NewSessionRequest {
929 pub cwd: PathBuf,
931 #[cfg(feature = "unstable_session_additional_directories")]
941 #[serde(default, skip_serializing_if = "Vec::is_empty")]
942 pub additional_directories: Vec<PathBuf>,
943 pub mcp_servers: Vec<McpServer>,
945 #[serde(rename = "_meta")]
951 pub meta: Option<Meta>,
952}
953
954impl NewSessionRequest {
955 #[must_use]
956 pub fn new(cwd: impl Into<PathBuf>) -> Self {
957 Self {
958 cwd: cwd.into(),
959 #[cfg(feature = "unstable_session_additional_directories")]
960 additional_directories: vec![],
961 mcp_servers: vec![],
962 meta: None,
963 }
964 }
965
966 #[cfg(feature = "unstable_session_additional_directories")]
972 #[must_use]
973 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
974 self.additional_directories = additional_directories;
975 self
976 }
977
978 #[must_use]
980 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
981 self.mcp_servers = mcp_servers;
982 self
983 }
984
985 #[must_use]
991 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
992 self.meta = meta.into_option();
993 self
994 }
995}
996
997#[serde_as]
1001#[skip_serializing_none]
1002#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1003#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1004#[serde(rename_all = "camelCase")]
1005#[non_exhaustive]
1006pub struct NewSessionResponse {
1007 pub session_id: SessionId,
1011 #[serde_as(deserialize_as = "DefaultOnError")]
1015 #[serde(default)]
1016 pub modes: Option<SessionModeState>,
1017 #[cfg(feature = "unstable_session_model")]
1023 #[serde_as(deserialize_as = "DefaultOnError")]
1024 #[serde(default)]
1025 pub models: Option<SessionModelState>,
1026 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1028 #[serde(default)]
1029 pub config_options: Option<Vec<SessionConfigOption>>,
1030 #[serde(rename = "_meta")]
1036 pub meta: Option<Meta>,
1037}
1038
1039impl NewSessionResponse {
1040 #[must_use]
1041 pub fn new(session_id: impl Into<SessionId>) -> Self {
1042 Self {
1043 session_id: session_id.into(),
1044 modes: None,
1045 #[cfg(feature = "unstable_session_model")]
1046 models: None,
1047 config_options: None,
1048 meta: None,
1049 }
1050 }
1051
1052 #[must_use]
1056 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1057 self.modes = modes.into_option();
1058 self
1059 }
1060
1061 #[cfg(feature = "unstable_session_model")]
1067 #[must_use]
1068 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1069 self.models = models.into_option();
1070 self
1071 }
1072
1073 #[must_use]
1075 pub fn config_options(
1076 mut self,
1077 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1078 ) -> Self {
1079 self.config_options = config_options.into_option();
1080 self
1081 }
1082
1083 #[must_use]
1089 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1090 self.meta = meta.into_option();
1091 self
1092 }
1093}
1094
1095#[skip_serializing_none]
1103#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1104#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1105#[serde(rename_all = "camelCase")]
1106#[non_exhaustive]
1107pub struct LoadSessionRequest {
1108 pub mcp_servers: Vec<McpServer>,
1110 pub cwd: PathBuf,
1112 #[cfg(feature = "unstable_session_additional_directories")]
1122 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1123 pub additional_directories: Vec<PathBuf>,
1124 pub session_id: SessionId,
1126 #[serde(rename = "_meta")]
1132 pub meta: Option<Meta>,
1133}
1134
1135impl LoadSessionRequest {
1136 #[must_use]
1137 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1138 Self {
1139 mcp_servers: vec![],
1140 cwd: cwd.into(),
1141 #[cfg(feature = "unstable_session_additional_directories")]
1142 additional_directories: vec![],
1143 session_id: session_id.into(),
1144 meta: None,
1145 }
1146 }
1147
1148 #[cfg(feature = "unstable_session_additional_directories")]
1154 #[must_use]
1155 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1156 self.additional_directories = additional_directories;
1157 self
1158 }
1159
1160 #[must_use]
1162 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1163 self.mcp_servers = mcp_servers;
1164 self
1165 }
1166
1167 #[must_use]
1173 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1174 self.meta = meta.into_option();
1175 self
1176 }
1177}
1178
1179#[serde_as]
1181#[skip_serializing_none]
1182#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1183#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1184#[serde(rename_all = "camelCase")]
1185#[non_exhaustive]
1186pub struct LoadSessionResponse {
1187 #[serde_as(deserialize_as = "DefaultOnError")]
1191 #[serde(default)]
1192 pub modes: Option<SessionModeState>,
1193 #[cfg(feature = "unstable_session_model")]
1199 #[serde_as(deserialize_as = "DefaultOnError")]
1200 #[serde(default)]
1201 pub models: Option<SessionModelState>,
1202 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1204 #[serde(default)]
1205 pub config_options: Option<Vec<SessionConfigOption>>,
1206 #[serde(rename = "_meta")]
1212 pub meta: Option<Meta>,
1213}
1214
1215impl LoadSessionResponse {
1216 #[must_use]
1217 pub fn new() -> Self {
1218 Self::default()
1219 }
1220
1221 #[must_use]
1225 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1226 self.modes = modes.into_option();
1227 self
1228 }
1229
1230 #[cfg(feature = "unstable_session_model")]
1236 #[must_use]
1237 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1238 self.models = models.into_option();
1239 self
1240 }
1241
1242 #[must_use]
1244 pub fn config_options(
1245 mut self,
1246 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1247 ) -> Self {
1248 self.config_options = config_options.into_option();
1249 self
1250 }
1251
1252 #[must_use]
1258 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1259 self.meta = meta.into_option();
1260 self
1261 }
1262}
1263
1264#[cfg(feature = "unstable_session_fork")]
1277#[skip_serializing_none]
1278#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1279#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1280#[serde(rename_all = "camelCase")]
1281#[non_exhaustive]
1282pub struct ForkSessionRequest {
1283 pub session_id: SessionId,
1285 pub cwd: PathBuf,
1287 #[cfg(feature = "unstable_session_additional_directories")]
1297 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1298 pub additional_directories: Vec<PathBuf>,
1299 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1301 pub mcp_servers: Vec<McpServer>,
1302 #[serde(rename = "_meta")]
1308 pub meta: Option<Meta>,
1309}
1310
1311#[cfg(feature = "unstable_session_fork")]
1312impl ForkSessionRequest {
1313 #[must_use]
1314 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1315 Self {
1316 session_id: session_id.into(),
1317 cwd: cwd.into(),
1318 #[cfg(feature = "unstable_session_additional_directories")]
1319 additional_directories: vec![],
1320 mcp_servers: vec![],
1321 meta: None,
1322 }
1323 }
1324
1325 #[cfg(feature = "unstable_session_additional_directories")]
1331 #[must_use]
1332 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1333 self.additional_directories = additional_directories;
1334 self
1335 }
1336
1337 #[must_use]
1339 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1340 self.mcp_servers = mcp_servers;
1341 self
1342 }
1343
1344 #[must_use]
1350 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1351 self.meta = meta.into_option();
1352 self
1353 }
1354}
1355
1356#[cfg(feature = "unstable_session_fork")]
1362#[serde_as]
1363#[skip_serializing_none]
1364#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1365#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1366#[serde(rename_all = "camelCase")]
1367#[non_exhaustive]
1368pub struct ForkSessionResponse {
1369 pub session_id: SessionId,
1371 #[serde_as(deserialize_as = "DefaultOnError")]
1375 #[serde(default)]
1376 pub modes: Option<SessionModeState>,
1377 #[cfg(feature = "unstable_session_model")]
1383 #[serde_as(deserialize_as = "DefaultOnError")]
1384 #[serde(default)]
1385 pub models: Option<SessionModelState>,
1386 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1388 #[serde(default)]
1389 pub config_options: Option<Vec<SessionConfigOption>>,
1390 #[serde(rename = "_meta")]
1396 pub meta: Option<Meta>,
1397}
1398
1399#[cfg(feature = "unstable_session_fork")]
1400impl ForkSessionResponse {
1401 #[must_use]
1402 pub fn new(session_id: impl Into<SessionId>) -> Self {
1403 Self {
1404 session_id: session_id.into(),
1405 modes: None,
1406 #[cfg(feature = "unstable_session_model")]
1407 models: None,
1408 config_options: None,
1409 meta: None,
1410 }
1411 }
1412
1413 #[must_use]
1417 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1418 self.modes = modes.into_option();
1419 self
1420 }
1421
1422 #[cfg(feature = "unstable_session_model")]
1428 #[must_use]
1429 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1430 self.models = models.into_option();
1431 self
1432 }
1433
1434 #[must_use]
1436 pub fn config_options(
1437 mut self,
1438 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1439 ) -> Self {
1440 self.config_options = config_options.into_option();
1441 self
1442 }
1443
1444 #[must_use]
1450 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1451 self.meta = meta.into_option();
1452 self
1453 }
1454}
1455
1456#[cfg(feature = "unstable_session_resume")]
1469#[skip_serializing_none]
1470#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1471#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1472#[serde(rename_all = "camelCase")]
1473#[non_exhaustive]
1474pub struct ResumeSessionRequest {
1475 pub session_id: SessionId,
1477 pub cwd: PathBuf,
1479 #[cfg(feature = "unstable_session_additional_directories")]
1489 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1490 pub additional_directories: Vec<PathBuf>,
1491 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1493 pub mcp_servers: Vec<McpServer>,
1494 #[serde(rename = "_meta")]
1500 pub meta: Option<Meta>,
1501}
1502
1503#[cfg(feature = "unstable_session_resume")]
1504impl ResumeSessionRequest {
1505 #[must_use]
1506 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1507 Self {
1508 session_id: session_id.into(),
1509 cwd: cwd.into(),
1510 #[cfg(feature = "unstable_session_additional_directories")]
1511 additional_directories: vec![],
1512 mcp_servers: vec![],
1513 meta: None,
1514 }
1515 }
1516
1517 #[cfg(feature = "unstable_session_additional_directories")]
1523 #[must_use]
1524 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1525 self.additional_directories = additional_directories;
1526 self
1527 }
1528
1529 #[must_use]
1531 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1532 self.mcp_servers = mcp_servers;
1533 self
1534 }
1535
1536 #[must_use]
1542 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1543 self.meta = meta.into_option();
1544 self
1545 }
1546}
1547
1548#[cfg(feature = "unstable_session_resume")]
1554#[serde_as]
1555#[skip_serializing_none]
1556#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1557#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1558#[serde(rename_all = "camelCase")]
1559#[non_exhaustive]
1560pub struct ResumeSessionResponse {
1561 #[serde_as(deserialize_as = "DefaultOnError")]
1565 #[serde(default)]
1566 pub modes: Option<SessionModeState>,
1567 #[cfg(feature = "unstable_session_model")]
1573 #[serde_as(deserialize_as = "DefaultOnError")]
1574 #[serde(default)]
1575 pub models: Option<SessionModelState>,
1576 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1578 #[serde(default)]
1579 pub config_options: Option<Vec<SessionConfigOption>>,
1580 #[serde(rename = "_meta")]
1586 pub meta: Option<Meta>,
1587}
1588
1589#[cfg(feature = "unstable_session_resume")]
1590impl ResumeSessionResponse {
1591 #[must_use]
1592 pub fn new() -> Self {
1593 Self::default()
1594 }
1595
1596 #[must_use]
1600 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1601 self.modes = modes.into_option();
1602 self
1603 }
1604
1605 #[cfg(feature = "unstable_session_model")]
1611 #[must_use]
1612 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1613 self.models = models.into_option();
1614 self
1615 }
1616
1617 #[must_use]
1619 pub fn config_options(
1620 mut self,
1621 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1622 ) -> Self {
1623 self.config_options = config_options.into_option();
1624 self
1625 }
1626
1627 #[must_use]
1633 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1634 self.meta = meta.into_option();
1635 self
1636 }
1637}
1638
1639#[cfg(feature = "unstable_session_close")]
1653#[skip_serializing_none]
1654#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1655#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1656#[serde(rename_all = "camelCase")]
1657#[non_exhaustive]
1658pub struct CloseSessionRequest {
1659 pub session_id: SessionId,
1661 #[serde(rename = "_meta")]
1667 pub meta: Option<Meta>,
1668}
1669
1670#[cfg(feature = "unstable_session_close")]
1671impl CloseSessionRequest {
1672 #[must_use]
1673 pub fn new(session_id: impl Into<SessionId>) -> Self {
1674 Self {
1675 session_id: session_id.into(),
1676 meta: None,
1677 }
1678 }
1679
1680 #[must_use]
1686 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1687 self.meta = meta.into_option();
1688 self
1689 }
1690}
1691
1692#[cfg(feature = "unstable_session_close")]
1698#[skip_serializing_none]
1699#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1700#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1701#[serde(rename_all = "camelCase")]
1702#[non_exhaustive]
1703pub struct CloseSessionResponse {
1704 #[serde(rename = "_meta")]
1710 pub meta: Option<Meta>,
1711}
1712
1713#[cfg(feature = "unstable_session_close")]
1714impl CloseSessionResponse {
1715 #[must_use]
1716 pub fn new() -> Self {
1717 Self::default()
1718 }
1719
1720 #[must_use]
1726 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1727 self.meta = meta.into_option();
1728 self
1729 }
1730}
1731
1732#[skip_serializing_none]
1738#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1739#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1740#[serde(rename_all = "camelCase")]
1741#[non_exhaustive]
1742pub struct ListSessionsRequest {
1743 pub cwd: Option<PathBuf>,
1745 #[cfg(feature = "unstable_session_additional_directories")]
1754 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1755 pub additional_directories: Vec<PathBuf>,
1756 pub cursor: Option<String>,
1758 #[serde(rename = "_meta")]
1764 pub meta: Option<Meta>,
1765}
1766
1767impl ListSessionsRequest {
1768 #[must_use]
1769 pub fn new() -> Self {
1770 Self::default()
1771 }
1772
1773 #[must_use]
1775 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1776 self.cwd = cwd.into_option();
1777 self
1778 }
1779
1780 #[cfg(feature = "unstable_session_additional_directories")]
1786 #[must_use]
1787 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1788 self.additional_directories = additional_directories;
1789 self
1790 }
1791
1792 #[must_use]
1794 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1795 self.cursor = cursor.into_option();
1796 self
1797 }
1798
1799 #[must_use]
1805 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1806 self.meta = meta.into_option();
1807 self
1808 }
1809}
1810
1811#[serde_as]
1813#[skip_serializing_none]
1814#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1815#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1816#[serde(rename_all = "camelCase")]
1817#[non_exhaustive]
1818pub struct ListSessionsResponse {
1819 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1821 pub sessions: Vec<SessionInfo>,
1822 pub next_cursor: Option<String>,
1825 #[serde(rename = "_meta")]
1831 pub meta: Option<Meta>,
1832}
1833
1834impl ListSessionsResponse {
1835 #[must_use]
1836 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1837 Self {
1838 sessions,
1839 next_cursor: None,
1840 meta: None,
1841 }
1842 }
1843
1844 #[must_use]
1845 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1846 self.next_cursor = next_cursor.into_option();
1847 self
1848 }
1849
1850 #[must_use]
1856 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1857 self.meta = meta.into_option();
1858 self
1859 }
1860}
1861
1862#[serde_as]
1864#[skip_serializing_none]
1865#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1866#[serde(rename_all = "camelCase")]
1867#[non_exhaustive]
1868pub struct SessionInfo {
1869 pub session_id: SessionId,
1871 pub cwd: PathBuf,
1873 #[cfg(feature = "unstable_session_additional_directories")]
1881 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1882 pub additional_directories: Vec<PathBuf>,
1883
1884 #[serde_as(deserialize_as = "DefaultOnError")]
1886 #[serde(default)]
1887 pub title: Option<String>,
1888 #[serde_as(deserialize_as = "DefaultOnError")]
1890 #[serde(default)]
1891 pub updated_at: Option<String>,
1892 #[serde(rename = "_meta")]
1898 pub meta: Option<Meta>,
1899}
1900
1901impl SessionInfo {
1902 #[must_use]
1903 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1904 Self {
1905 session_id: session_id.into(),
1906 cwd: cwd.into(),
1907 #[cfg(feature = "unstable_session_additional_directories")]
1908 additional_directories: vec![],
1909 title: None,
1910 updated_at: None,
1911 meta: None,
1912 }
1913 }
1914
1915 #[cfg(feature = "unstable_session_additional_directories")]
1921 #[must_use]
1922 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1923 self.additional_directories = additional_directories;
1924 self
1925 }
1926
1927 #[must_use]
1929 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1930 self.title = title.into_option();
1931 self
1932 }
1933
1934 #[must_use]
1936 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1937 self.updated_at = updated_at.into_option();
1938 self
1939 }
1940
1941 #[must_use]
1947 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1948 self.meta = meta.into_option();
1949 self
1950 }
1951}
1952
1953#[serde_as]
1957#[skip_serializing_none]
1958#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1959#[serde(rename_all = "camelCase")]
1960#[non_exhaustive]
1961pub struct SessionModeState {
1962 pub current_mode_id: SessionModeId,
1964 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1966 pub available_modes: Vec<SessionMode>,
1967 #[serde(rename = "_meta")]
1973 pub meta: Option<Meta>,
1974}
1975
1976impl SessionModeState {
1977 #[must_use]
1978 pub fn new(
1979 current_mode_id: impl Into<SessionModeId>,
1980 available_modes: Vec<SessionMode>,
1981 ) -> Self {
1982 Self {
1983 current_mode_id: current_mode_id.into(),
1984 available_modes,
1985 meta: None,
1986 }
1987 }
1988
1989 #[must_use]
1995 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1996 self.meta = meta.into_option();
1997 self
1998 }
1999}
2000
2001#[skip_serializing_none]
2005#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2006#[serde(rename_all = "camelCase")]
2007#[non_exhaustive]
2008pub struct SessionMode {
2009 pub id: SessionModeId,
2010 pub name: String,
2011 #[serde(default)]
2012 pub description: Option<String>,
2013 #[serde(rename = "_meta")]
2019 pub meta: Option<Meta>,
2020}
2021
2022impl SessionMode {
2023 #[must_use]
2024 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
2025 Self {
2026 id: id.into(),
2027 name: name.into(),
2028 description: None,
2029 meta: None,
2030 }
2031 }
2032
2033 #[must_use]
2034 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2035 self.description = description.into_option();
2036 self
2037 }
2038
2039 #[must_use]
2045 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2046 self.meta = meta.into_option();
2047 self
2048 }
2049}
2050
2051#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2053#[serde(transparent)]
2054#[from(Arc<str>, String, &'static str)]
2055#[non_exhaustive]
2056pub struct SessionModeId(pub Arc<str>);
2057
2058impl SessionModeId {
2059 #[must_use]
2060 pub fn new(id: impl Into<Arc<str>>) -> Self {
2061 Self(id.into())
2062 }
2063}
2064
2065#[skip_serializing_none]
2067#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2068#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2069#[serde(rename_all = "camelCase")]
2070#[non_exhaustive]
2071pub struct SetSessionModeRequest {
2072 pub session_id: SessionId,
2074 pub mode_id: SessionModeId,
2076 #[serde(rename = "_meta")]
2082 pub meta: Option<Meta>,
2083}
2084
2085impl SetSessionModeRequest {
2086 #[must_use]
2087 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
2088 Self {
2089 session_id: session_id.into(),
2090 mode_id: mode_id.into(),
2091 meta: None,
2092 }
2093 }
2094
2095 #[must_use]
2096 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2097 self.meta = meta.into_option();
2098 self
2099 }
2100}
2101
2102#[skip_serializing_none]
2104#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2105#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2106#[serde(rename_all = "camelCase")]
2107#[non_exhaustive]
2108pub struct SetSessionModeResponse {
2109 #[serde(rename = "_meta")]
2115 pub meta: Option<Meta>,
2116}
2117
2118impl SetSessionModeResponse {
2119 #[must_use]
2120 pub fn new() -> Self {
2121 Self::default()
2122 }
2123
2124 #[must_use]
2130 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2131 self.meta = meta.into_option();
2132 self
2133 }
2134}
2135
2136#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2140#[serde(transparent)]
2141#[from(Arc<str>, String, &'static str)]
2142#[non_exhaustive]
2143pub struct SessionConfigId(pub Arc<str>);
2144
2145impl SessionConfigId {
2146 #[must_use]
2147 pub fn new(id: impl Into<Arc<str>>) -> Self {
2148 Self(id.into())
2149 }
2150}
2151
2152#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2154#[serde(transparent)]
2155#[from(Arc<str>, String, &'static str)]
2156#[non_exhaustive]
2157pub struct SessionConfigValueId(pub Arc<str>);
2158
2159impl SessionConfigValueId {
2160 #[must_use]
2161 pub fn new(id: impl Into<Arc<str>>) -> Self {
2162 Self(id.into())
2163 }
2164}
2165
2166#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2168#[serde(transparent)]
2169#[from(Arc<str>, String, &'static str)]
2170#[non_exhaustive]
2171pub struct SessionConfigGroupId(pub Arc<str>);
2172
2173impl SessionConfigGroupId {
2174 #[must_use]
2175 pub fn new(id: impl Into<Arc<str>>) -> Self {
2176 Self(id.into())
2177 }
2178}
2179
2180#[skip_serializing_none]
2182#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2183#[serde(rename_all = "camelCase")]
2184#[non_exhaustive]
2185pub struct SessionConfigSelectOption {
2186 pub value: SessionConfigValueId,
2188 pub name: String,
2190 #[serde(default)]
2192 pub description: Option<String>,
2193 #[serde(rename = "_meta")]
2199 pub meta: Option<Meta>,
2200}
2201
2202impl SessionConfigSelectOption {
2203 #[must_use]
2204 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2205 Self {
2206 value: value.into(),
2207 name: name.into(),
2208 description: None,
2209 meta: None,
2210 }
2211 }
2212
2213 #[must_use]
2214 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2215 self.description = description.into_option();
2216 self
2217 }
2218
2219 #[must_use]
2225 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2226 self.meta = meta.into_option();
2227 self
2228 }
2229}
2230
2231#[skip_serializing_none]
2233#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2234#[serde(rename_all = "camelCase")]
2235#[non_exhaustive]
2236pub struct SessionConfigSelectGroup {
2237 pub group: SessionConfigGroupId,
2239 pub name: String,
2241 pub options: Vec<SessionConfigSelectOption>,
2243 #[serde(rename = "_meta")]
2249 pub meta: Option<Meta>,
2250}
2251
2252impl SessionConfigSelectGroup {
2253 #[must_use]
2254 pub fn new(
2255 group: impl Into<SessionConfigGroupId>,
2256 name: impl Into<String>,
2257 options: Vec<SessionConfigSelectOption>,
2258 ) -> Self {
2259 Self {
2260 group: group.into(),
2261 name: name.into(),
2262 options,
2263 meta: None,
2264 }
2265 }
2266
2267 #[must_use]
2273 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2274 self.meta = meta.into_option();
2275 self
2276 }
2277}
2278
2279#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2281#[serde(untagged)]
2282#[non_exhaustive]
2283pub enum SessionConfigSelectOptions {
2284 Ungrouped(Vec<SessionConfigSelectOption>),
2286 Grouped(Vec<SessionConfigSelectGroup>),
2288}
2289
2290impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2291 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2292 SessionConfigSelectOptions::Ungrouped(options)
2293 }
2294}
2295
2296impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2297 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2298 SessionConfigSelectOptions::Grouped(groups)
2299 }
2300}
2301
2302#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2304#[serde(rename_all = "camelCase")]
2305#[non_exhaustive]
2306pub struct SessionConfigSelect {
2307 pub current_value: SessionConfigValueId,
2309 pub options: SessionConfigSelectOptions,
2311}
2312
2313impl SessionConfigSelect {
2314 #[must_use]
2315 pub fn new(
2316 current_value: impl Into<SessionConfigValueId>,
2317 options: impl Into<SessionConfigSelectOptions>,
2318 ) -> Self {
2319 Self {
2320 current_value: current_value.into(),
2321 options: options.into(),
2322 }
2323 }
2324}
2325
2326#[cfg(feature = "unstable_boolean_config")]
2332#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2333#[serde(rename_all = "camelCase")]
2334#[non_exhaustive]
2335pub struct SessionConfigBoolean {
2336 pub current_value: bool,
2338}
2339
2340#[cfg(feature = "unstable_boolean_config")]
2341impl SessionConfigBoolean {
2342 #[must_use]
2343 pub fn new(current_value: bool) -> Self {
2344 Self { current_value }
2345 }
2346}
2347
2348#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2358#[serde(rename_all = "snake_case")]
2359#[non_exhaustive]
2360pub enum SessionConfigOptionCategory {
2361 Mode,
2363 Model,
2365 ThoughtLevel,
2367 #[serde(untagged)]
2369 Other(String),
2370}
2371
2372#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2374#[serde(tag = "type", rename_all = "snake_case")]
2375#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2376#[non_exhaustive]
2377pub enum SessionConfigKind {
2378 Select(SessionConfigSelect),
2380 #[cfg(feature = "unstable_boolean_config")]
2386 Boolean(SessionConfigBoolean),
2387}
2388
2389#[serde_as]
2391#[skip_serializing_none]
2392#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2393#[serde(rename_all = "camelCase")]
2394#[non_exhaustive]
2395pub struct SessionConfigOption {
2396 pub id: SessionConfigId,
2398 pub name: String,
2400 #[serde(default)]
2402 pub description: Option<String>,
2403 #[serde_as(deserialize_as = "DefaultOnError")]
2405 #[serde(default)]
2406 pub category: Option<SessionConfigOptionCategory>,
2407 #[serde(flatten)]
2409 pub kind: SessionConfigKind,
2410 #[serde(rename = "_meta")]
2416 pub meta: Option<Meta>,
2417}
2418
2419impl SessionConfigOption {
2420 #[must_use]
2421 pub fn new(
2422 id: impl Into<SessionConfigId>,
2423 name: impl Into<String>,
2424 kind: SessionConfigKind,
2425 ) -> Self {
2426 Self {
2427 id: id.into(),
2428 name: name.into(),
2429 description: None,
2430 category: None,
2431 kind,
2432 meta: None,
2433 }
2434 }
2435
2436 #[must_use]
2437 pub fn select(
2438 id: impl Into<SessionConfigId>,
2439 name: impl Into<String>,
2440 current_value: impl Into<SessionConfigValueId>,
2441 options: impl Into<SessionConfigSelectOptions>,
2442 ) -> Self {
2443 Self::new(
2444 id,
2445 name,
2446 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2447 )
2448 }
2449
2450 #[cfg(feature = "unstable_boolean_config")]
2454 #[must_use]
2455 pub fn boolean(
2456 id: impl Into<SessionConfigId>,
2457 name: impl Into<String>,
2458 current_value: bool,
2459 ) -> Self {
2460 Self::new(
2461 id,
2462 name,
2463 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2464 )
2465 }
2466
2467 #[must_use]
2468 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2469 self.description = description.into_option();
2470 self
2471 }
2472
2473 #[must_use]
2474 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2475 self.category = category.into_option();
2476 self
2477 }
2478
2479 #[must_use]
2485 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2486 self.meta = meta.into_option();
2487 self
2488 }
2489}
2490
2491#[cfg(feature = "unstable_boolean_config")]
2506#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2507#[serde(tag = "type", rename_all = "snake_case")]
2508#[non_exhaustive]
2509pub enum SessionConfigOptionValue {
2510 Boolean {
2512 value: bool,
2514 },
2515 #[serde(untagged)]
2521 ValueId {
2522 value: SessionConfigValueId,
2524 },
2525}
2526
2527#[cfg(feature = "unstable_boolean_config")]
2528impl SessionConfigOptionValue {
2529 #[must_use]
2531 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2532 Self::ValueId { value: id.into() }
2533 }
2534
2535 #[must_use]
2537 pub fn boolean(val: bool) -> Self {
2538 Self::Boolean { value: val }
2539 }
2540
2541 #[must_use]
2544 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2545 match self {
2546 Self::ValueId { value } => Some(value),
2547 _ => None,
2548 }
2549 }
2550
2551 #[must_use]
2553 pub fn as_bool(&self) -> Option<bool> {
2554 match self {
2555 Self::Boolean { value } => Some(*value),
2556 _ => None,
2557 }
2558 }
2559}
2560
2561#[cfg(feature = "unstable_boolean_config")]
2562impl From<SessionConfigValueId> for SessionConfigOptionValue {
2563 fn from(value: SessionConfigValueId) -> Self {
2564 Self::ValueId { value }
2565 }
2566}
2567
2568#[cfg(feature = "unstable_boolean_config")]
2569impl From<bool> for SessionConfigOptionValue {
2570 fn from(value: bool) -> Self {
2571 Self::Boolean { value }
2572 }
2573}
2574
2575#[cfg(feature = "unstable_boolean_config")]
2576impl From<&str> for SessionConfigOptionValue {
2577 fn from(value: &str) -> Self {
2578 Self::ValueId {
2579 value: SessionConfigValueId::new(value),
2580 }
2581 }
2582}
2583
2584#[skip_serializing_none]
2586#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2587#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2588#[serde(rename_all = "camelCase")]
2589#[non_exhaustive]
2590pub struct SetSessionConfigOptionRequest {
2591 pub session_id: SessionId,
2593 pub config_id: SessionConfigId,
2595 #[cfg(feature = "unstable_boolean_config")]
2600 #[serde(flatten)]
2601 pub value: SessionConfigOptionValue,
2602 #[cfg(not(feature = "unstable_boolean_config"))]
2604 pub value: SessionConfigValueId,
2605 #[serde(rename = "_meta")]
2611 pub meta: Option<Meta>,
2612}
2613
2614impl SetSessionConfigOptionRequest {
2615 #[cfg(feature = "unstable_boolean_config")]
2616 #[must_use]
2617 pub fn new(
2618 session_id: impl Into<SessionId>,
2619 config_id: impl Into<SessionConfigId>,
2620 value: impl Into<SessionConfigOptionValue>,
2621 ) -> Self {
2622 Self {
2623 session_id: session_id.into(),
2624 config_id: config_id.into(),
2625 value: value.into(),
2626 meta: None,
2627 }
2628 }
2629
2630 #[cfg(not(feature = "unstable_boolean_config"))]
2631 #[must_use]
2632 pub fn new(
2633 session_id: impl Into<SessionId>,
2634 config_id: impl Into<SessionConfigId>,
2635 value: impl Into<SessionConfigValueId>,
2636 ) -> Self {
2637 Self {
2638 session_id: session_id.into(),
2639 config_id: config_id.into(),
2640 value: value.into(),
2641 meta: None,
2642 }
2643 }
2644
2645 #[must_use]
2651 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2652 self.meta = meta.into_option();
2653 self
2654 }
2655}
2656
2657#[serde_as]
2659#[skip_serializing_none]
2660#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2661#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2662#[serde(rename_all = "camelCase")]
2663#[non_exhaustive]
2664pub struct SetSessionConfigOptionResponse {
2665 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2667 pub config_options: Vec<SessionConfigOption>,
2668 #[serde(rename = "_meta")]
2674 pub meta: Option<Meta>,
2675}
2676
2677impl SetSessionConfigOptionResponse {
2678 #[must_use]
2679 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2680 Self {
2681 config_options,
2682 meta: None,
2683 }
2684 }
2685
2686 #[must_use]
2692 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2693 self.meta = meta.into_option();
2694 self
2695 }
2696}
2697
2698#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2707#[serde(tag = "type", rename_all = "snake_case")]
2708#[non_exhaustive]
2709pub enum McpServer {
2710 Http(McpServerHttp),
2714 Sse(McpServerSse),
2718 #[serde(untagged)]
2722 Stdio(McpServerStdio),
2723}
2724
2725#[skip_serializing_none]
2727#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2728#[serde(rename_all = "camelCase")]
2729#[non_exhaustive]
2730pub struct McpServerHttp {
2731 pub name: String,
2733 pub url: String,
2735 pub headers: Vec<HttpHeader>,
2737 #[serde(rename = "_meta")]
2743 pub meta: Option<Meta>,
2744}
2745
2746impl McpServerHttp {
2747 #[must_use]
2748 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2749 Self {
2750 name: name.into(),
2751 url: url.into(),
2752 headers: Vec::new(),
2753 meta: None,
2754 }
2755 }
2756
2757 #[must_use]
2759 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2760 self.headers = headers;
2761 self
2762 }
2763
2764 #[must_use]
2770 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2771 self.meta = meta.into_option();
2772 self
2773 }
2774}
2775
2776#[skip_serializing_none]
2778#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2779#[serde(rename_all = "camelCase")]
2780#[non_exhaustive]
2781pub struct McpServerSse {
2782 pub name: String,
2784 pub url: String,
2786 pub headers: Vec<HttpHeader>,
2788 #[serde(rename = "_meta")]
2794 pub meta: Option<Meta>,
2795}
2796
2797impl McpServerSse {
2798 #[must_use]
2799 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2800 Self {
2801 name: name.into(),
2802 url: url.into(),
2803 headers: Vec::new(),
2804 meta: None,
2805 }
2806 }
2807
2808 #[must_use]
2810 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2811 self.headers = headers;
2812 self
2813 }
2814
2815 #[must_use]
2821 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2822 self.meta = meta.into_option();
2823 self
2824 }
2825}
2826
2827#[skip_serializing_none]
2829#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2830#[serde(rename_all = "camelCase")]
2831#[non_exhaustive]
2832pub struct McpServerStdio {
2833 pub name: String,
2835 pub command: PathBuf,
2837 pub args: Vec<String>,
2839 pub env: Vec<EnvVariable>,
2841 #[serde(rename = "_meta")]
2847 pub meta: Option<Meta>,
2848}
2849
2850impl McpServerStdio {
2851 #[must_use]
2852 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2853 Self {
2854 name: name.into(),
2855 command: command.into(),
2856 args: Vec::new(),
2857 env: Vec::new(),
2858 meta: None,
2859 }
2860 }
2861
2862 #[must_use]
2864 pub fn args(mut self, args: Vec<String>) -> Self {
2865 self.args = args;
2866 self
2867 }
2868
2869 #[must_use]
2871 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2872 self.env = env;
2873 self
2874 }
2875
2876 #[must_use]
2882 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2883 self.meta = meta.into_option();
2884 self
2885 }
2886}
2887
2888#[skip_serializing_none]
2890#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2891#[serde(rename_all = "camelCase")]
2892#[non_exhaustive]
2893pub struct EnvVariable {
2894 pub name: String,
2896 pub value: String,
2898 #[serde(rename = "_meta")]
2904 pub meta: Option<Meta>,
2905}
2906
2907impl EnvVariable {
2908 #[must_use]
2909 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2910 Self {
2911 name: name.into(),
2912 value: value.into(),
2913 meta: None,
2914 }
2915 }
2916
2917 #[must_use]
2923 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2924 self.meta = meta.into_option();
2925 self
2926 }
2927}
2928
2929#[skip_serializing_none]
2931#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2932#[serde(rename_all = "camelCase")]
2933#[non_exhaustive]
2934pub struct HttpHeader {
2935 pub name: String,
2937 pub value: String,
2939 #[serde(rename = "_meta")]
2945 pub meta: Option<Meta>,
2946}
2947
2948impl HttpHeader {
2949 #[must_use]
2950 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2951 Self {
2952 name: name.into(),
2953 value: value.into(),
2954 meta: None,
2955 }
2956 }
2957
2958 #[must_use]
2964 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2965 self.meta = meta.into_option();
2966 self
2967 }
2968}
2969
2970#[skip_serializing_none]
2978#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
2979#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2980#[serde(rename_all = "camelCase")]
2981#[non_exhaustive]
2982pub struct PromptRequest {
2983 pub session_id: SessionId,
2985 #[cfg(feature = "unstable_message_id")]
2995 pub message_id: Option<String>,
2996 pub prompt: Vec<ContentBlock>,
3010 #[serde(rename = "_meta")]
3016 pub meta: Option<Meta>,
3017}
3018
3019impl PromptRequest {
3020 #[must_use]
3021 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3022 Self {
3023 session_id: session_id.into(),
3024 #[cfg(feature = "unstable_message_id")]
3025 message_id: None,
3026 prompt,
3027 meta: None,
3028 }
3029 }
3030
3031 #[cfg(feature = "unstable_message_id")]
3041 #[must_use]
3042 pub fn message_id(mut self, message_id: impl IntoOption<String>) -> Self {
3043 self.message_id = message_id.into_option();
3044 self
3045 }
3046
3047 #[must_use]
3053 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3054 self.meta = meta.into_option();
3055 self
3056 }
3057}
3058
3059#[serde_as]
3063#[skip_serializing_none]
3064#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3065#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3066#[serde(rename_all = "camelCase")]
3067#[non_exhaustive]
3068pub struct PromptResponse {
3069 #[cfg(feature = "unstable_message_id")]
3079 pub user_message_id: Option<String>,
3080 pub stop_reason: StopReason,
3082 #[cfg(feature = "unstable_session_usage")]
3088 #[serde_as(deserialize_as = "DefaultOnError")]
3089 #[serde(default)]
3090 pub usage: Option<Usage>,
3091 #[serde(rename = "_meta")]
3097 pub meta: Option<Meta>,
3098}
3099
3100impl PromptResponse {
3101 #[must_use]
3102 pub fn new(stop_reason: StopReason) -> Self {
3103 Self {
3104 #[cfg(feature = "unstable_message_id")]
3105 user_message_id: None,
3106 stop_reason,
3107 #[cfg(feature = "unstable_session_usage")]
3108 usage: None,
3109 meta: None,
3110 }
3111 }
3112
3113 #[cfg(feature = "unstable_message_id")]
3123 #[must_use]
3124 pub fn user_message_id(mut self, user_message_id: impl IntoOption<String>) -> Self {
3125 self.user_message_id = user_message_id.into_option();
3126 self
3127 }
3128
3129 #[cfg(feature = "unstable_session_usage")]
3135 #[must_use]
3136 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3137 self.usage = usage.into_option();
3138 self
3139 }
3140
3141 #[must_use]
3147 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3148 self.meta = meta.into_option();
3149 self
3150 }
3151}
3152
3153#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3157#[serde(rename_all = "snake_case")]
3158#[non_exhaustive]
3159pub enum StopReason {
3160 EndTurn,
3162 MaxTokens,
3164 MaxTurnRequests,
3167 Refusal,
3171 Cancelled,
3178}
3179
3180#[cfg(feature = "unstable_session_usage")]
3186#[skip_serializing_none]
3187#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3188#[serde(rename_all = "camelCase")]
3189#[non_exhaustive]
3190pub struct Usage {
3191 pub total_tokens: u64,
3193 pub input_tokens: u64,
3195 pub output_tokens: u64,
3197 pub thought_tokens: Option<u64>,
3199 pub cached_read_tokens: Option<u64>,
3201 pub cached_write_tokens: Option<u64>,
3203}
3204
3205#[cfg(feature = "unstable_session_usage")]
3206impl Usage {
3207 #[must_use]
3208 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3209 Self {
3210 total_tokens,
3211 input_tokens,
3212 output_tokens,
3213 thought_tokens: None,
3214 cached_read_tokens: None,
3215 cached_write_tokens: None,
3216 }
3217 }
3218
3219 #[must_use]
3221 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3222 self.thought_tokens = thought_tokens.into_option();
3223 self
3224 }
3225
3226 #[must_use]
3228 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3229 self.cached_read_tokens = cached_read_tokens.into_option();
3230 self
3231 }
3232
3233 #[must_use]
3235 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3236 self.cached_write_tokens = cached_write_tokens.into_option();
3237 self
3238 }
3239}
3240
3241#[cfg(feature = "unstable_session_model")]
3249#[serde_as]
3250#[skip_serializing_none]
3251#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3252#[serde(rename_all = "camelCase")]
3253#[non_exhaustive]
3254pub struct SessionModelState {
3255 pub current_model_id: ModelId,
3257 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3259 pub available_models: Vec<ModelInfo>,
3260 #[serde(rename = "_meta")]
3266 pub meta: Option<Meta>,
3267}
3268
3269#[cfg(feature = "unstable_session_model")]
3270impl SessionModelState {
3271 #[must_use]
3272 pub fn new(current_model_id: impl Into<ModelId>, available_models: Vec<ModelInfo>) -> Self {
3273 Self {
3274 current_model_id: current_model_id.into(),
3275 available_models,
3276 meta: None,
3277 }
3278 }
3279
3280 #[must_use]
3286 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3287 self.meta = meta.into_option();
3288 self
3289 }
3290}
3291
3292#[cfg(feature = "unstable_session_model")]
3298#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
3299#[serde(transparent)]
3300#[from(Arc<str>, String, &'static str)]
3301#[non_exhaustive]
3302pub struct ModelId(pub Arc<str>);
3303
3304#[cfg(feature = "unstable_session_model")]
3305impl ModelId {
3306 #[must_use]
3307 pub fn new(id: impl Into<Arc<str>>) -> Self {
3308 Self(id.into())
3309 }
3310}
3311
3312#[cfg(feature = "unstable_session_model")]
3318#[skip_serializing_none]
3319#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3320#[serde(rename_all = "camelCase")]
3321#[non_exhaustive]
3322pub struct ModelInfo {
3323 pub model_id: ModelId,
3325 pub name: String,
3327 #[serde(default)]
3329 pub description: Option<String>,
3330 #[serde(rename = "_meta")]
3336 pub meta: Option<Meta>,
3337}
3338
3339#[cfg(feature = "unstable_session_model")]
3340impl ModelInfo {
3341 #[must_use]
3342 pub fn new(model_id: impl Into<ModelId>, name: impl Into<String>) -> Self {
3343 Self {
3344 model_id: model_id.into(),
3345 name: name.into(),
3346 description: None,
3347 meta: None,
3348 }
3349 }
3350
3351 #[must_use]
3353 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
3354 self.description = description.into_option();
3355 self
3356 }
3357
3358 #[must_use]
3364 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3365 self.meta = meta.into_option();
3366 self
3367 }
3368}
3369
3370#[cfg(feature = "unstable_session_model")]
3376#[skip_serializing_none]
3377#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3378#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3379#[serde(rename_all = "camelCase")]
3380#[non_exhaustive]
3381pub struct SetSessionModelRequest {
3382 pub session_id: SessionId,
3384 pub model_id: ModelId,
3386 #[serde(rename = "_meta")]
3392 pub meta: Option<Meta>,
3393}
3394
3395#[cfg(feature = "unstable_session_model")]
3396impl SetSessionModelRequest {
3397 #[must_use]
3398 pub fn new(session_id: impl Into<SessionId>, model_id: impl Into<ModelId>) -> Self {
3399 Self {
3400 session_id: session_id.into(),
3401 model_id: model_id.into(),
3402 meta: None,
3403 }
3404 }
3405
3406 #[must_use]
3412 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3413 self.meta = meta.into_option();
3414 self
3415 }
3416}
3417
3418#[cfg(feature = "unstable_session_model")]
3424#[skip_serializing_none]
3425#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3426#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3427#[serde(rename_all = "camelCase")]
3428#[non_exhaustive]
3429pub struct SetSessionModelResponse {
3430 #[serde(rename = "_meta")]
3436 pub meta: Option<Meta>,
3437}
3438
3439#[cfg(feature = "unstable_session_model")]
3440impl SetSessionModelResponse {
3441 #[must_use]
3442 pub fn new() -> Self {
3443 Self::default()
3444 }
3445
3446 #[must_use]
3452 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3453 self.meta = meta.into_option();
3454 self
3455 }
3456}
3457
3458#[cfg(feature = "unstable_llm_providers")]
3471#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3472#[serde(rename_all = "snake_case")]
3473#[non_exhaustive]
3474#[expect(clippy::doc_markdown)]
3475pub enum LlmProtocol {
3476 Anthropic,
3478 #[serde(rename = "openai")]
3480 OpenAi,
3481 Azure,
3483 Vertex,
3485 Bedrock,
3487 #[serde(untagged)]
3489 Other(String),
3490}
3491
3492#[cfg(feature = "unstable_llm_providers")]
3498#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3499#[serde(rename_all = "camelCase")]
3500#[non_exhaustive]
3501pub struct ProviderCurrentConfig {
3502 pub api_type: LlmProtocol,
3504 pub base_url: String,
3506}
3507
3508#[cfg(feature = "unstable_llm_providers")]
3509impl ProviderCurrentConfig {
3510 #[must_use]
3511 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3512 Self {
3513 api_type,
3514 base_url: base_url.into(),
3515 }
3516 }
3517}
3518
3519#[cfg(feature = "unstable_llm_providers")]
3525#[serde_as]
3526#[skip_serializing_none]
3527#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3528#[serde(rename_all = "camelCase")]
3529#[non_exhaustive]
3530pub struct ProviderInfo {
3531 pub id: String,
3533 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3535 pub supported: Vec<LlmProtocol>,
3536 pub required: bool,
3539 pub current: RequiredNullable<ProviderCurrentConfig>,
3542 #[serde(rename = "_meta")]
3548 pub meta: Option<Meta>,
3549}
3550
3551#[cfg(feature = "unstable_llm_providers")]
3552impl ProviderInfo {
3553 #[must_use]
3554 pub fn new(
3555 id: impl Into<String>,
3556 supported: Vec<LlmProtocol>,
3557 required: bool,
3558 current: impl Into<RequiredNullable<ProviderCurrentConfig>>,
3559 ) -> Self {
3560 Self {
3561 id: id.into(),
3562 supported,
3563 required,
3564 current: current.into(),
3565 meta: None,
3566 }
3567 }
3568
3569 #[must_use]
3575 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3576 self.meta = meta.into_option();
3577 self
3578 }
3579}
3580
3581#[cfg(feature = "unstable_llm_providers")]
3587#[skip_serializing_none]
3588#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3589#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3590#[serde(rename_all = "camelCase")]
3591#[non_exhaustive]
3592pub struct ListProvidersRequest {
3593 #[serde(rename = "_meta")]
3599 pub meta: Option<Meta>,
3600}
3601
3602#[cfg(feature = "unstable_llm_providers")]
3603impl ListProvidersRequest {
3604 #[must_use]
3605 pub fn new() -> Self {
3606 Self::default()
3607 }
3608
3609 #[must_use]
3615 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3616 self.meta = meta.into_option();
3617 self
3618 }
3619}
3620
3621#[cfg(feature = "unstable_llm_providers")]
3627#[serde_as]
3628#[skip_serializing_none]
3629#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3630#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3631#[serde(rename_all = "camelCase")]
3632#[non_exhaustive]
3633pub struct ListProvidersResponse {
3634 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3636 pub providers: Vec<ProviderInfo>,
3637 #[serde(rename = "_meta")]
3643 pub meta: Option<Meta>,
3644}
3645
3646#[cfg(feature = "unstable_llm_providers")]
3647impl ListProvidersResponse {
3648 #[must_use]
3649 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3650 Self {
3651 providers,
3652 meta: None,
3653 }
3654 }
3655
3656 #[must_use]
3662 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3663 self.meta = meta.into_option();
3664 self
3665 }
3666}
3667
3668#[cfg(feature = "unstable_llm_providers")]
3676#[skip_serializing_none]
3677#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3678#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3679#[serde(rename_all = "camelCase")]
3680#[non_exhaustive]
3681pub struct SetProvidersRequest {
3682 pub id: String,
3684 pub api_type: LlmProtocol,
3686 pub base_url: String,
3688 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3691 pub headers: HashMap<String, String>,
3692 #[serde(rename = "_meta")]
3698 pub meta: Option<Meta>,
3699}
3700
3701#[cfg(feature = "unstable_llm_providers")]
3702impl SetProvidersRequest {
3703 #[must_use]
3704 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3705 Self {
3706 id: id.into(),
3707 api_type,
3708 base_url: base_url.into(),
3709 headers: HashMap::new(),
3710 meta: None,
3711 }
3712 }
3713
3714 #[must_use]
3717 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3718 self.headers = headers;
3719 self
3720 }
3721
3722 #[must_use]
3728 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3729 self.meta = meta.into_option();
3730 self
3731 }
3732}
3733
3734#[cfg(feature = "unstable_llm_providers")]
3740#[skip_serializing_none]
3741#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3742#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3743#[serde(rename_all = "camelCase")]
3744#[non_exhaustive]
3745pub struct SetProvidersResponse {
3746 #[serde(rename = "_meta")]
3752 pub meta: Option<Meta>,
3753}
3754
3755#[cfg(feature = "unstable_llm_providers")]
3756impl SetProvidersResponse {
3757 #[must_use]
3758 pub fn new() -> Self {
3759 Self::default()
3760 }
3761
3762 #[must_use]
3768 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3769 self.meta = meta.into_option();
3770 self
3771 }
3772}
3773
3774#[cfg(feature = "unstable_llm_providers")]
3780#[skip_serializing_none]
3781#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3782#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3783#[serde(rename_all = "camelCase")]
3784#[non_exhaustive]
3785pub struct DisableProvidersRequest {
3786 pub id: String,
3788 #[serde(rename = "_meta")]
3794 pub meta: Option<Meta>,
3795}
3796
3797#[cfg(feature = "unstable_llm_providers")]
3798impl DisableProvidersRequest {
3799 #[must_use]
3800 pub fn new(id: impl Into<String>) -> Self {
3801 Self {
3802 id: id.into(),
3803 meta: None,
3804 }
3805 }
3806
3807 #[must_use]
3813 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3814 self.meta = meta.into_option();
3815 self
3816 }
3817}
3818
3819#[cfg(feature = "unstable_llm_providers")]
3825#[skip_serializing_none]
3826#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3827#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3828#[serde(rename_all = "camelCase")]
3829#[non_exhaustive]
3830pub struct DisableProvidersResponse {
3831 #[serde(rename = "_meta")]
3837 pub meta: Option<Meta>,
3838}
3839
3840#[cfg(feature = "unstable_llm_providers")]
3841impl DisableProvidersResponse {
3842 #[must_use]
3843 pub fn new() -> Self {
3844 Self::default()
3845 }
3846
3847 #[must_use]
3853 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3854 self.meta = meta.into_option();
3855 self
3856 }
3857}
3858
3859#[serde_as]
3868#[skip_serializing_none]
3869#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3870#[serde(rename_all = "camelCase")]
3871#[non_exhaustive]
3872pub struct AgentCapabilities {
3873 #[serde(default)]
3875 pub load_session: bool,
3876 #[serde(default)]
3878 pub prompt_capabilities: PromptCapabilities,
3879 #[serde(default)]
3881 pub mcp_capabilities: McpCapabilities,
3882 #[serde(default)]
3883 pub session_capabilities: SessionCapabilities,
3884 #[cfg(feature = "unstable_logout")]
3890 #[serde(default)]
3891 pub auth: AgentAuthCapabilities,
3892 #[cfg(feature = "unstable_llm_providers")]
3900 #[serde_as(deserialize_as = "DefaultOnError")]
3901 #[serde(default)]
3902 pub providers: Option<ProvidersCapabilities>,
3903 #[cfg(feature = "unstable_nes")]
3909 #[serde_as(deserialize_as = "DefaultOnError")]
3910 #[serde(default)]
3911 pub nes: Option<NesCapabilities>,
3912 #[cfg(feature = "unstable_nes")]
3918 #[serde_as(deserialize_as = "DefaultOnError")]
3919 #[serde(default)]
3920 pub position_encoding: Option<PositionEncodingKind>,
3921 #[serde(rename = "_meta")]
3927 pub meta: Option<Meta>,
3928}
3929
3930impl AgentCapabilities {
3931 #[must_use]
3932 pub fn new() -> Self {
3933 Self::default()
3934 }
3935
3936 #[must_use]
3938 pub fn load_session(mut self, load_session: bool) -> Self {
3939 self.load_session = load_session;
3940 self
3941 }
3942
3943 #[must_use]
3945 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3946 self.prompt_capabilities = prompt_capabilities;
3947 self
3948 }
3949
3950 #[must_use]
3952 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3953 self.mcp_capabilities = mcp_capabilities;
3954 self
3955 }
3956
3957 #[must_use]
3959 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3960 self.session_capabilities = session_capabilities;
3961 self
3962 }
3963
3964 #[cfg(feature = "unstable_logout")]
3970 #[must_use]
3971 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3972 self.auth = auth;
3973 self
3974 }
3975
3976 #[cfg(feature = "unstable_llm_providers")]
3982 #[must_use]
3983 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3984 self.providers = providers.into_option();
3985 self
3986 }
3987
3988 #[cfg(feature = "unstable_nes")]
3994 #[must_use]
3995 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3996 self.nes = nes.into_option();
3997 self
3998 }
3999
4000 #[cfg(feature = "unstable_nes")]
4004 #[must_use]
4005 pub fn position_encoding(
4006 mut self,
4007 position_encoding: impl IntoOption<PositionEncodingKind>,
4008 ) -> Self {
4009 self.position_encoding = position_encoding.into_option();
4010 self
4011 }
4012
4013 #[must_use]
4019 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4020 self.meta = meta.into_option();
4021 self
4022 }
4023}
4024
4025#[cfg(feature = "unstable_llm_providers")]
4033#[skip_serializing_none]
4034#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4035#[non_exhaustive]
4036pub struct ProvidersCapabilities {
4037 #[serde(rename = "_meta")]
4043 pub meta: Option<Meta>,
4044}
4045
4046#[cfg(feature = "unstable_llm_providers")]
4047impl ProvidersCapabilities {
4048 #[must_use]
4049 pub fn new() -> Self {
4050 Self::default()
4051 }
4052
4053 #[must_use]
4059 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4060 self.meta = meta.into_option();
4061 self
4062 }
4063}
4064
4065#[serde_as]
4075#[skip_serializing_none]
4076#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4077#[serde(rename_all = "camelCase")]
4078#[non_exhaustive]
4079pub struct SessionCapabilities {
4080 #[serde_as(deserialize_as = "DefaultOnError")]
4082 #[serde(default)]
4083 pub list: Option<SessionListCapabilities>,
4084 #[cfg(feature = "unstable_session_additional_directories")]
4090 #[serde_as(deserialize_as = "DefaultOnError")]
4091 #[serde(default)]
4092 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
4093 #[cfg(feature = "unstable_session_fork")]
4099 #[serde_as(deserialize_as = "DefaultOnError")]
4100 #[serde(default)]
4101 pub fork: Option<SessionForkCapabilities>,
4102 #[cfg(feature = "unstable_session_resume")]
4108 #[serde_as(deserialize_as = "DefaultOnError")]
4109 #[serde(default)]
4110 pub resume: Option<SessionResumeCapabilities>,
4111 #[cfg(feature = "unstable_session_close")]
4117 #[serde_as(deserialize_as = "DefaultOnError")]
4118 #[serde(default)]
4119 pub close: Option<SessionCloseCapabilities>,
4120 #[serde(rename = "_meta")]
4126 pub meta: Option<Meta>,
4127}
4128
4129impl SessionCapabilities {
4130 #[must_use]
4131 pub fn new() -> Self {
4132 Self::default()
4133 }
4134
4135 #[must_use]
4137 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
4138 self.list = list.into_option();
4139 self
4140 }
4141
4142 #[cfg(feature = "unstable_session_additional_directories")]
4148 #[must_use]
4149 pub fn additional_directories(
4150 mut self,
4151 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4152 ) -> Self {
4153 self.additional_directories = additional_directories.into_option();
4154 self
4155 }
4156
4157 #[cfg(feature = "unstable_session_fork")]
4158 #[must_use]
4160 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4161 self.fork = fork.into_option();
4162 self
4163 }
4164
4165 #[cfg(feature = "unstable_session_resume")]
4166 #[must_use]
4168 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4169 self.resume = resume.into_option();
4170 self
4171 }
4172
4173 #[cfg(feature = "unstable_session_close")]
4174 #[must_use]
4176 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4177 self.close = close.into_option();
4178 self
4179 }
4180
4181 #[must_use]
4187 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4188 self.meta = meta.into_option();
4189 self
4190 }
4191}
4192
4193#[skip_serializing_none]
4197#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4198#[non_exhaustive]
4199pub struct SessionListCapabilities {
4200 #[serde(rename = "_meta")]
4206 pub meta: Option<Meta>,
4207}
4208
4209impl SessionListCapabilities {
4210 #[must_use]
4211 pub fn new() -> Self {
4212 Self::default()
4213 }
4214
4215 #[must_use]
4221 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4222 self.meta = meta.into_option();
4223 self
4224 }
4225}
4226
4227#[cfg(feature = "unstable_session_additional_directories")]
4236#[skip_serializing_none]
4237#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4238#[non_exhaustive]
4239pub struct SessionAdditionalDirectoriesCapabilities {
4240 #[serde(rename = "_meta")]
4246 pub meta: Option<Meta>,
4247}
4248
4249#[cfg(feature = "unstable_session_additional_directories")]
4250impl SessionAdditionalDirectoriesCapabilities {
4251 #[must_use]
4252 pub fn new() -> Self {
4253 Self::default()
4254 }
4255
4256 #[must_use]
4262 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4263 self.meta = meta.into_option();
4264 self
4265 }
4266}
4267
4268#[cfg(feature = "unstable_session_fork")]
4276#[skip_serializing_none]
4277#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4278#[non_exhaustive]
4279pub struct SessionForkCapabilities {
4280 #[serde(rename = "_meta")]
4286 pub meta: Option<Meta>,
4287}
4288
4289#[cfg(feature = "unstable_session_fork")]
4290impl SessionForkCapabilities {
4291 #[must_use]
4292 pub fn new() -> Self {
4293 Self::default()
4294 }
4295
4296 #[must_use]
4302 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4303 self.meta = meta.into_option();
4304 self
4305 }
4306}
4307
4308#[cfg(feature = "unstable_session_resume")]
4316#[skip_serializing_none]
4317#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4318#[non_exhaustive]
4319pub struct SessionResumeCapabilities {
4320 #[serde(rename = "_meta")]
4326 pub meta: Option<Meta>,
4327}
4328
4329#[cfg(feature = "unstable_session_resume")]
4330impl SessionResumeCapabilities {
4331 #[must_use]
4332 pub fn new() -> Self {
4333 Self::default()
4334 }
4335
4336 #[must_use]
4342 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4343 self.meta = meta.into_option();
4344 self
4345 }
4346}
4347
4348#[cfg(feature = "unstable_session_close")]
4356#[skip_serializing_none]
4357#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4358#[non_exhaustive]
4359pub struct SessionCloseCapabilities {
4360 #[serde(rename = "_meta")]
4366 pub meta: Option<Meta>,
4367}
4368
4369#[cfg(feature = "unstable_session_close")]
4370impl SessionCloseCapabilities {
4371 #[must_use]
4372 pub fn new() -> Self {
4373 Self::default()
4374 }
4375
4376 #[must_use]
4382 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4383 self.meta = meta.into_option();
4384 self
4385 }
4386}
4387
4388#[skip_serializing_none]
4401#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4402#[serde(rename_all = "camelCase")]
4403#[non_exhaustive]
4404pub struct PromptCapabilities {
4405 #[serde(default)]
4407 pub image: bool,
4408 #[serde(default)]
4410 pub audio: bool,
4411 #[serde(default)]
4416 pub embedded_context: bool,
4417 #[serde(rename = "_meta")]
4423 pub meta: Option<Meta>,
4424}
4425
4426impl PromptCapabilities {
4427 #[must_use]
4428 pub fn new() -> Self {
4429 Self::default()
4430 }
4431
4432 #[must_use]
4434 pub fn image(mut self, image: bool) -> Self {
4435 self.image = image;
4436 self
4437 }
4438
4439 #[must_use]
4441 pub fn audio(mut self, audio: bool) -> Self {
4442 self.audio = audio;
4443 self
4444 }
4445
4446 #[must_use]
4451 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4452 self.embedded_context = embedded_context;
4453 self
4454 }
4455
4456 #[must_use]
4462 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4463 self.meta = meta.into_option();
4464 self
4465 }
4466}
4467
4468#[skip_serializing_none]
4470#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4471#[serde(rename_all = "camelCase")]
4472#[non_exhaustive]
4473pub struct McpCapabilities {
4474 #[serde(default)]
4476 pub http: bool,
4477 #[serde(default)]
4479 pub sse: bool,
4480 #[serde(rename = "_meta")]
4486 pub meta: Option<Meta>,
4487}
4488
4489impl McpCapabilities {
4490 #[must_use]
4491 pub fn new() -> Self {
4492 Self::default()
4493 }
4494
4495 #[must_use]
4497 pub fn http(mut self, http: bool) -> Self {
4498 self.http = http;
4499 self
4500 }
4501
4502 #[must_use]
4504 pub fn sse(mut self, sse: bool) -> Self {
4505 self.sse = sse;
4506 self
4507 }
4508
4509 #[must_use]
4515 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4516 self.meta = meta.into_option();
4517 self
4518 }
4519}
4520
4521#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4527#[non_exhaustive]
4528pub struct AgentMethodNames {
4529 pub initialize: &'static str,
4531 pub authenticate: &'static str,
4533 #[cfg(feature = "unstable_llm_providers")]
4535 pub providers_list: &'static str,
4536 #[cfg(feature = "unstable_llm_providers")]
4538 pub providers_set: &'static str,
4539 #[cfg(feature = "unstable_llm_providers")]
4541 pub providers_disable: &'static str,
4542 pub session_new: &'static str,
4544 pub session_load: &'static str,
4546 pub session_set_mode: &'static str,
4548 pub session_set_config_option: &'static str,
4550 pub session_prompt: &'static str,
4552 pub session_cancel: &'static str,
4554 #[cfg(feature = "unstable_session_model")]
4556 pub session_set_model: &'static str,
4557 pub session_list: &'static str,
4559 #[cfg(feature = "unstable_session_fork")]
4561 pub session_fork: &'static str,
4562 #[cfg(feature = "unstable_session_resume")]
4564 pub session_resume: &'static str,
4565 #[cfg(feature = "unstable_session_close")]
4567 pub session_close: &'static str,
4568 #[cfg(feature = "unstable_logout")]
4570 pub logout: &'static str,
4571 #[cfg(feature = "unstable_nes")]
4573 pub nes_start: &'static str,
4574 #[cfg(feature = "unstable_nes")]
4576 pub nes_suggest: &'static str,
4577 #[cfg(feature = "unstable_nes")]
4579 pub nes_accept: &'static str,
4580 #[cfg(feature = "unstable_nes")]
4582 pub nes_reject: &'static str,
4583 #[cfg(feature = "unstable_nes")]
4585 pub nes_close: &'static str,
4586 #[cfg(feature = "unstable_nes")]
4588 pub document_did_open: &'static str,
4589 #[cfg(feature = "unstable_nes")]
4591 pub document_did_change: &'static str,
4592 #[cfg(feature = "unstable_nes")]
4594 pub document_did_close: &'static str,
4595 #[cfg(feature = "unstable_nes")]
4597 pub document_did_save: &'static str,
4598 #[cfg(feature = "unstable_nes")]
4600 pub document_did_focus: &'static str,
4601}
4602
4603pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4605 initialize: INITIALIZE_METHOD_NAME,
4606 authenticate: AUTHENTICATE_METHOD_NAME,
4607 #[cfg(feature = "unstable_llm_providers")]
4608 providers_list: PROVIDERS_LIST_METHOD_NAME,
4609 #[cfg(feature = "unstable_llm_providers")]
4610 providers_set: PROVIDERS_SET_METHOD_NAME,
4611 #[cfg(feature = "unstable_llm_providers")]
4612 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4613 session_new: SESSION_NEW_METHOD_NAME,
4614 session_load: SESSION_LOAD_METHOD_NAME,
4615 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4616 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4617 session_prompt: SESSION_PROMPT_METHOD_NAME,
4618 session_cancel: SESSION_CANCEL_METHOD_NAME,
4619 #[cfg(feature = "unstable_session_model")]
4620 session_set_model: SESSION_SET_MODEL_METHOD_NAME,
4621 session_list: SESSION_LIST_METHOD_NAME,
4622 #[cfg(feature = "unstable_session_fork")]
4623 session_fork: SESSION_FORK_METHOD_NAME,
4624 #[cfg(feature = "unstable_session_resume")]
4625 session_resume: SESSION_RESUME_METHOD_NAME,
4626 #[cfg(feature = "unstable_session_close")]
4627 session_close: SESSION_CLOSE_METHOD_NAME,
4628 #[cfg(feature = "unstable_logout")]
4629 logout: LOGOUT_METHOD_NAME,
4630 #[cfg(feature = "unstable_nes")]
4631 nes_start: NES_START_METHOD_NAME,
4632 #[cfg(feature = "unstable_nes")]
4633 nes_suggest: NES_SUGGEST_METHOD_NAME,
4634 #[cfg(feature = "unstable_nes")]
4635 nes_accept: NES_ACCEPT_METHOD_NAME,
4636 #[cfg(feature = "unstable_nes")]
4637 nes_reject: NES_REJECT_METHOD_NAME,
4638 #[cfg(feature = "unstable_nes")]
4639 nes_close: NES_CLOSE_METHOD_NAME,
4640 #[cfg(feature = "unstable_nes")]
4641 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4642 #[cfg(feature = "unstable_nes")]
4643 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4644 #[cfg(feature = "unstable_nes")]
4645 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4646 #[cfg(feature = "unstable_nes")]
4647 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4648 #[cfg(feature = "unstable_nes")]
4649 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4650};
4651
4652pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4654pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4656#[cfg(feature = "unstable_llm_providers")]
4658pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4659#[cfg(feature = "unstable_llm_providers")]
4661pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4662#[cfg(feature = "unstable_llm_providers")]
4664pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4665pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4667pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4669pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4671pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4673pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4675pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4677#[cfg(feature = "unstable_session_model")]
4679pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
4680pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4682#[cfg(feature = "unstable_session_fork")]
4684pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4685#[cfg(feature = "unstable_session_resume")]
4687pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4688#[cfg(feature = "unstable_session_close")]
4690pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4691#[cfg(feature = "unstable_logout")]
4693pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4694
4695#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4702#[serde(untagged)]
4703#[schemars(inline)]
4704#[non_exhaustive]
4705#[allow(clippy::large_enum_variant)]
4706pub enum ClientRequest {
4707 InitializeRequest(InitializeRequest),
4718 AuthenticateRequest(AuthenticateRequest),
4728 #[cfg(feature = "unstable_llm_providers")]
4734 ListProvidersRequest(ListProvidersRequest),
4735 #[cfg(feature = "unstable_llm_providers")]
4741 SetProvidersRequest(SetProvidersRequest),
4742 #[cfg(feature = "unstable_llm_providers")]
4748 DisableProvidersRequest(DisableProvidersRequest),
4749 #[cfg(feature = "unstable_logout")]
4758 LogoutRequest(LogoutRequest),
4759 NewSessionRequest(NewSessionRequest),
4772 LoadSessionRequest(LoadSessionRequest),
4783 ListSessionsRequest(ListSessionsRequest),
4789 #[cfg(feature = "unstable_session_fork")]
4790 ForkSessionRequest(ForkSessionRequest),
4802 #[cfg(feature = "unstable_session_resume")]
4803 ResumeSessionRequest(ResumeSessionRequest),
4814 #[cfg(feature = "unstable_session_close")]
4815 CloseSessionRequest(CloseSessionRequest),
4826 SetSessionModeRequest(SetSessionModeRequest),
4840 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4842 PromptRequest(PromptRequest),
4854 #[cfg(feature = "unstable_session_model")]
4855 SetSessionModelRequest(SetSessionModelRequest),
4861 #[cfg(feature = "unstable_nes")]
4862 StartNesRequest(StartNesRequest),
4868 #[cfg(feature = "unstable_nes")]
4869 SuggestNesRequest(SuggestNesRequest),
4875 #[cfg(feature = "unstable_nes")]
4876 CloseNesRequest(CloseNesRequest),
4885 ExtMethodRequest(ExtRequest),
4892}
4893
4894impl ClientRequest {
4895 #[must_use]
4897 pub fn method(&self) -> &str {
4898 match self {
4899 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4900 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4901 #[cfg(feature = "unstable_llm_providers")]
4902 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4903 #[cfg(feature = "unstable_llm_providers")]
4904 Self::SetProvidersRequest(_) => AGENT_METHOD_NAMES.providers_set,
4905 #[cfg(feature = "unstable_llm_providers")]
4906 Self::DisableProvidersRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4907 #[cfg(feature = "unstable_logout")]
4908 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4909 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4910 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4911 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4912 #[cfg(feature = "unstable_session_fork")]
4913 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
4914 #[cfg(feature = "unstable_session_resume")]
4915 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
4916 #[cfg(feature = "unstable_session_close")]
4917 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
4918 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
4919 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
4920 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
4921 #[cfg(feature = "unstable_session_model")]
4922 Self::SetSessionModelRequest(_) => AGENT_METHOD_NAMES.session_set_model,
4923 #[cfg(feature = "unstable_nes")]
4924 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
4925 #[cfg(feature = "unstable_nes")]
4926 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
4927 #[cfg(feature = "unstable_nes")]
4928 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
4929 Self::ExtMethodRequest(ext_request) => &ext_request.method,
4930 }
4931 }
4932}
4933
4934#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4941#[serde(untagged)]
4942#[schemars(inline)]
4943#[non_exhaustive]
4944#[allow(clippy::large_enum_variant)]
4945pub enum AgentResponse {
4946 InitializeResponse(InitializeResponse),
4947 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
4948 #[cfg(feature = "unstable_llm_providers")]
4949 ListProvidersResponse(ListProvidersResponse),
4950 #[cfg(feature = "unstable_llm_providers")]
4951 SetProvidersResponse(#[serde(default)] SetProvidersResponse),
4952 #[cfg(feature = "unstable_llm_providers")]
4953 DisableProvidersResponse(#[serde(default)] DisableProvidersResponse),
4954 #[cfg(feature = "unstable_logout")]
4955 LogoutResponse(#[serde(default)] LogoutResponse),
4956 NewSessionResponse(NewSessionResponse),
4957 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
4958 ListSessionsResponse(ListSessionsResponse),
4959 #[cfg(feature = "unstable_session_fork")]
4960 ForkSessionResponse(ForkSessionResponse),
4961 #[cfg(feature = "unstable_session_resume")]
4962 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
4963 #[cfg(feature = "unstable_session_close")]
4964 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
4965 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
4966 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
4967 PromptResponse(PromptResponse),
4968 #[cfg(feature = "unstable_session_model")]
4969 SetSessionModelResponse(#[serde(default)] SetSessionModelResponse),
4970 #[cfg(feature = "unstable_nes")]
4971 StartNesResponse(StartNesResponse),
4972 #[cfg(feature = "unstable_nes")]
4973 SuggestNesResponse(SuggestNesResponse),
4974 #[cfg(feature = "unstable_nes")]
4975 CloseNesResponse(#[serde(default)] CloseNesResponse),
4976 ExtMethodResponse(ExtResponse),
4977}
4978
4979#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4986#[serde(untagged)]
4987#[schemars(inline)]
4988#[non_exhaustive]
4989pub enum ClientNotification {
4990 CancelNotification(CancelNotification),
5002 #[cfg(feature = "unstable_nes")]
5003 DidOpenDocumentNotification(DidOpenDocumentNotification),
5007 #[cfg(feature = "unstable_nes")]
5008 DidChangeDocumentNotification(DidChangeDocumentNotification),
5012 #[cfg(feature = "unstable_nes")]
5013 DidCloseDocumentNotification(DidCloseDocumentNotification),
5017 #[cfg(feature = "unstable_nes")]
5018 DidSaveDocumentNotification(DidSaveDocumentNotification),
5022 #[cfg(feature = "unstable_nes")]
5023 DidFocusDocumentNotification(DidFocusDocumentNotification),
5027 #[cfg(feature = "unstable_nes")]
5028 AcceptNesNotification(AcceptNesNotification),
5032 #[cfg(feature = "unstable_nes")]
5033 RejectNesNotification(RejectNesNotification),
5037 ExtNotification(ExtNotification),
5044}
5045
5046impl ClientNotification {
5047 #[must_use]
5049 pub fn method(&self) -> &str {
5050 match self {
5051 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5052 #[cfg(feature = "unstable_nes")]
5053 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5054 #[cfg(feature = "unstable_nes")]
5055 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5056 #[cfg(feature = "unstable_nes")]
5057 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5058 #[cfg(feature = "unstable_nes")]
5059 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5060 #[cfg(feature = "unstable_nes")]
5061 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5062 #[cfg(feature = "unstable_nes")]
5063 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5064 #[cfg(feature = "unstable_nes")]
5065 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5066 Self::ExtNotification(ext_notification) => &ext_notification.method,
5067 }
5068 }
5069}
5070
5071#[skip_serializing_none]
5075#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5076#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5077#[serde(rename_all = "camelCase")]
5078#[non_exhaustive]
5079pub struct CancelNotification {
5080 pub session_id: SessionId,
5082 #[serde(rename = "_meta")]
5088 pub meta: Option<Meta>,
5089}
5090
5091impl CancelNotification {
5092 #[must_use]
5093 pub fn new(session_id: impl Into<SessionId>) -> Self {
5094 Self {
5095 session_id: session_id.into(),
5096 meta: None,
5097 }
5098 }
5099
5100 #[must_use]
5106 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5107 self.meta = meta.into_option();
5108 self
5109 }
5110}
5111
5112#[cfg(test)]
5113mod test_serialization {
5114 use super::*;
5115 use serde_json::json;
5116
5117 #[test]
5118 fn test_mcp_server_stdio_serialization() {
5119 let server = McpServer::Stdio(
5120 McpServerStdio::new("test-server", "/usr/bin/server")
5121 .args(vec!["--port".to_string(), "3000".to_string()])
5122 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5123 );
5124
5125 let json = serde_json::to_value(&server).unwrap();
5126 assert_eq!(
5127 json,
5128 json!({
5129 "name": "test-server",
5130 "command": "/usr/bin/server",
5131 "args": ["--port", "3000"],
5132 "env": [
5133 {
5134 "name": "API_KEY",
5135 "value": "secret123"
5136 }
5137 ]
5138 })
5139 );
5140
5141 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5142 match deserialized {
5143 McpServer::Stdio(McpServerStdio {
5144 name,
5145 command,
5146 args,
5147 env,
5148 meta: _,
5149 }) => {
5150 assert_eq!(name, "test-server");
5151 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5152 assert_eq!(args, vec!["--port", "3000"]);
5153 assert_eq!(env.len(), 1);
5154 assert_eq!(env[0].name, "API_KEY");
5155 assert_eq!(env[0].value, "secret123");
5156 }
5157 _ => panic!("Expected Stdio variant"),
5158 }
5159 }
5160
5161 #[test]
5162 fn test_mcp_server_http_serialization() {
5163 let server = McpServer::Http(
5164 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5165 HttpHeader::new("Authorization", "Bearer token123"),
5166 HttpHeader::new("Content-Type", "application/json"),
5167 ]),
5168 );
5169
5170 let json = serde_json::to_value(&server).unwrap();
5171 assert_eq!(
5172 json,
5173 json!({
5174 "type": "http",
5175 "name": "http-server",
5176 "url": "https://api.example.com",
5177 "headers": [
5178 {
5179 "name": "Authorization",
5180 "value": "Bearer token123"
5181 },
5182 {
5183 "name": "Content-Type",
5184 "value": "application/json"
5185 }
5186 ]
5187 })
5188 );
5189
5190 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5191 match deserialized {
5192 McpServer::Http(McpServerHttp {
5193 name,
5194 url,
5195 headers,
5196 meta: _,
5197 }) => {
5198 assert_eq!(name, "http-server");
5199 assert_eq!(url, "https://api.example.com");
5200 assert_eq!(headers.len(), 2);
5201 assert_eq!(headers[0].name, "Authorization");
5202 assert_eq!(headers[0].value, "Bearer token123");
5203 assert_eq!(headers[1].name, "Content-Type");
5204 assert_eq!(headers[1].value, "application/json");
5205 }
5206 _ => panic!("Expected Http variant"),
5207 }
5208 }
5209
5210 #[test]
5211 fn test_mcp_server_sse_serialization() {
5212 let server = McpServer::Sse(
5213 McpServerSse::new("sse-server", "https://sse.example.com/events")
5214 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5215 );
5216
5217 let json = serde_json::to_value(&server).unwrap();
5218 assert_eq!(
5219 json,
5220 json!({
5221 "type": "sse",
5222 "name": "sse-server",
5223 "url": "https://sse.example.com/events",
5224 "headers": [
5225 {
5226 "name": "X-API-Key",
5227 "value": "apikey456"
5228 }
5229 ]
5230 })
5231 );
5232
5233 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5234 match deserialized {
5235 McpServer::Sse(McpServerSse {
5236 name,
5237 url,
5238 headers,
5239 meta: _,
5240 }) => {
5241 assert_eq!(name, "sse-server");
5242 assert_eq!(url, "https://sse.example.com/events");
5243 assert_eq!(headers.len(), 1);
5244 assert_eq!(headers[0].name, "X-API-Key");
5245 assert_eq!(headers[0].value, "apikey456");
5246 }
5247 _ => panic!("Expected Sse variant"),
5248 }
5249 }
5250
5251 #[test]
5252 fn test_session_config_option_category_known_variants() {
5253 assert_eq!(
5255 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5256 json!("mode")
5257 );
5258 assert_eq!(
5259 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5260 json!("model")
5261 );
5262 assert_eq!(
5263 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5264 json!("thought_level")
5265 );
5266
5267 assert_eq!(
5269 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5270 SessionConfigOptionCategory::Mode
5271 );
5272 assert_eq!(
5273 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5274 SessionConfigOptionCategory::Model
5275 );
5276 assert_eq!(
5277 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5278 SessionConfigOptionCategory::ThoughtLevel
5279 );
5280 }
5281
5282 #[test]
5283 fn test_session_config_option_category_unknown_variants() {
5284 let unknown: SessionConfigOptionCategory =
5286 serde_json::from_str("\"some_future_category\"").unwrap();
5287 assert_eq!(
5288 unknown,
5289 SessionConfigOptionCategory::Other("some_future_category".to_string())
5290 );
5291
5292 let json = serde_json::to_value(&unknown).unwrap();
5294 assert_eq!(json, json!("some_future_category"));
5295 }
5296
5297 #[test]
5298 fn test_session_config_option_category_custom_categories() {
5299 let custom: SessionConfigOptionCategory =
5301 serde_json::from_str("\"_my_custom_category\"").unwrap();
5302 assert_eq!(
5303 custom,
5304 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5305 );
5306
5307 let json = serde_json::to_value(&custom).unwrap();
5309 assert_eq!(json, json!("_my_custom_category"));
5310
5311 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5313 assert_eq!(
5314 deserialized,
5315 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5316 );
5317 }
5318
5319 #[test]
5320 fn test_auth_method_agent_serialization() {
5321 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5322
5323 let json = serde_json::to_value(&method).unwrap();
5324 assert_eq!(
5325 json,
5326 json!({
5327 "id": "default-auth",
5328 "name": "Default Auth"
5329 })
5330 );
5331 assert!(!json.as_object().unwrap().contains_key("description"));
5333 assert!(!json.as_object().unwrap().contains_key("type"));
5335
5336 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5337 match deserialized {
5338 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5339 assert_eq!(id.0.as_ref(), "default-auth");
5340 assert_eq!(name, "Default Auth");
5341 }
5342 #[cfg(feature = "unstable_auth_methods")]
5343 _ => panic!("Expected Agent variant"),
5344 }
5345 }
5346
5347 #[test]
5348 fn test_auth_method_explicit_agent_deserialization() {
5349 let json = json!({
5351 "id": "agent-auth",
5352 "name": "Agent Auth",
5353 "type": "agent"
5354 });
5355
5356 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5357 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5358 }
5359
5360 #[cfg(feature = "unstable_session_additional_directories")]
5361 #[test]
5362 fn test_session_additional_directories_serialization() {
5363 assert_eq!(
5364 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5365 json!({
5366 "cwd": "/home/user/project",
5367 "mcpServers": []
5368 })
5369 );
5370 assert_eq!(
5371 serde_json::to_value(
5372 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5373 PathBuf::from("/home/user/shared-lib"),
5374 PathBuf::from("/home/user/product-docs"),
5375 ])
5376 )
5377 .unwrap(),
5378 json!({
5379 "cwd": "/home/user/project",
5380 "additionalDirectories": [
5381 "/home/user/shared-lib",
5382 "/home/user/product-docs"
5383 ],
5384 "mcpServers": []
5385 })
5386 );
5387 assert_eq!(
5388 serde_json::to_value(
5389 ListSessionsRequest::new().additional_directories(Vec::<PathBuf>::new())
5390 )
5391 .unwrap(),
5392 json!({})
5393 );
5394 assert_eq!(
5395 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5396 json!({
5397 "sessionId": "sess_abc123",
5398 "cwd": "/home/user/project"
5399 })
5400 );
5401 assert_eq!(
5402 serde_json::to_value(
5403 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5404 PathBuf::from("/home/user/shared-lib"),
5405 PathBuf::from("/home/user/product-docs"),
5406 ])
5407 )
5408 .unwrap(),
5409 json!({
5410 "sessionId": "sess_abc123",
5411 "cwd": "/home/user/project",
5412 "additionalDirectories": [
5413 "/home/user/shared-lib",
5414 "/home/user/product-docs"
5415 ]
5416 })
5417 );
5418 assert_eq!(
5419 serde_json::from_value::<SessionInfo>(json!({
5420 "sessionId": "sess_abc123",
5421 "cwd": "/home/user/project"
5422 }))
5423 .unwrap()
5424 .additional_directories,
5425 Vec::<PathBuf>::new()
5426 );
5427
5428 assert_eq!(
5429 serde_json::from_value::<ListSessionsRequest>(json!({}))
5430 .unwrap()
5431 .additional_directories,
5432 Vec::<PathBuf>::new()
5433 );
5434
5435 assert_eq!(
5436 serde_json::from_value::<ListSessionsRequest>(json!({
5437 "additionalDirectories": []
5438 }))
5439 .unwrap()
5440 .additional_directories,
5441 Vec::<PathBuf>::new()
5442 );
5443 }
5444
5445 #[cfg(feature = "unstable_session_additional_directories")]
5446 #[test]
5447 fn test_session_additional_directories_capabilities_serialization() {
5448 assert_eq!(
5449 serde_json::to_value(
5450 SessionCapabilities::new()
5451 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5452 )
5453 .unwrap(),
5454 json!({
5455 "additionalDirectories": {}
5456 })
5457 );
5458 }
5459
5460 #[cfg(feature = "unstable_auth_methods")]
5461 #[test]
5462 fn test_auth_method_env_var_serialization() {
5463 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5464 "api-key",
5465 "API Key",
5466 vec![AuthEnvVar::new("API_KEY")],
5467 ));
5468
5469 let json = serde_json::to_value(&method).unwrap();
5470 assert_eq!(
5471 json,
5472 json!({
5473 "id": "api-key",
5474 "name": "API Key",
5475 "type": "env_var",
5476 "vars": [{"name": "API_KEY"}]
5477 })
5478 );
5479 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5481 assert!(
5482 !json["vars"][0]
5483 .as_object()
5484 .unwrap()
5485 .contains_key("optional")
5486 );
5487
5488 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5489 match deserialized {
5490 AuthMethod::EnvVar(AuthMethodEnvVar {
5491 id,
5492 name: method_name,
5493 vars,
5494 link,
5495 ..
5496 }) => {
5497 assert_eq!(id.0.as_ref(), "api-key");
5498 assert_eq!(method_name, "API Key");
5499 assert_eq!(vars.len(), 1);
5500 assert_eq!(vars[0].name, "API_KEY");
5501 assert!(vars[0].secret);
5502 assert!(!vars[0].optional);
5503 assert!(link.is_none());
5504 }
5505 _ => panic!("Expected EnvVar variant"),
5506 }
5507 }
5508
5509 #[cfg(feature = "unstable_auth_methods")]
5510 #[test]
5511 fn test_auth_method_env_var_with_link_serialization() {
5512 let method = AuthMethod::EnvVar(
5513 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5514 .link("https://example.com/keys"),
5515 );
5516
5517 let json = serde_json::to_value(&method).unwrap();
5518 assert_eq!(
5519 json,
5520 json!({
5521 "id": "api-key",
5522 "name": "API Key",
5523 "type": "env_var",
5524 "vars": [{"name": "API_KEY"}],
5525 "link": "https://example.com/keys"
5526 })
5527 );
5528
5529 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5530 match deserialized {
5531 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5532 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5533 }
5534 _ => panic!("Expected EnvVar variant"),
5535 }
5536 }
5537
5538 #[cfg(feature = "unstable_auth_methods")]
5539 #[test]
5540 fn test_auth_method_env_var_multiple_vars() {
5541 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5542 "azure-openai",
5543 "Azure OpenAI",
5544 vec![
5545 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5546 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5547 .label("Endpoint URL")
5548 .secret(false),
5549 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5550 .label("API Version")
5551 .secret(false)
5552 .optional(true),
5553 ],
5554 ));
5555
5556 let json = serde_json::to_value(&method).unwrap();
5557 assert_eq!(
5558 json,
5559 json!({
5560 "id": "azure-openai",
5561 "name": "Azure OpenAI",
5562 "type": "env_var",
5563 "vars": [
5564 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5565 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5566 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5567 ]
5568 })
5569 );
5570
5571 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5572 match deserialized {
5573 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5574 assert_eq!(vars.len(), 3);
5575 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5577 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5578 assert!(vars[0].secret);
5579 assert!(!vars[0].optional);
5580 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5582 assert!(!vars[1].secret);
5583 assert!(!vars[1].optional);
5584 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5586 assert!(!vars[2].secret);
5587 assert!(vars[2].optional);
5588 }
5589 _ => panic!("Expected EnvVar variant"),
5590 }
5591 }
5592
5593 #[cfg(feature = "unstable_auth_methods")]
5594 #[test]
5595 fn test_auth_method_terminal_serialization() {
5596 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5597
5598 let json = serde_json::to_value(&method).unwrap();
5599 assert_eq!(
5600 json,
5601 json!({
5602 "id": "tui-auth",
5603 "name": "Terminal Auth",
5604 "type": "terminal"
5605 })
5606 );
5607 assert!(!json.as_object().unwrap().contains_key("args"));
5609 assert!(!json.as_object().unwrap().contains_key("env"));
5610
5611 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5612 match deserialized {
5613 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5614 assert!(args.is_empty());
5615 assert!(env.is_empty());
5616 }
5617 _ => panic!("Expected Terminal variant"),
5618 }
5619 }
5620
5621 #[cfg(feature = "unstable_auth_methods")]
5622 #[test]
5623 fn test_auth_method_terminal_with_args_and_env_serialization() {
5624 use std::collections::HashMap;
5625
5626 let mut env = HashMap::new();
5627 env.insert("TERM".to_string(), "xterm-256color".to_string());
5628
5629 let method = AuthMethod::Terminal(
5630 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5631 .args(vec!["--interactive".to_string(), "--color".to_string()])
5632 .env(env),
5633 );
5634
5635 let json = serde_json::to_value(&method).unwrap();
5636 assert_eq!(
5637 json,
5638 json!({
5639 "id": "tui-auth",
5640 "name": "Terminal Auth",
5641 "type": "terminal",
5642 "args": ["--interactive", "--color"],
5643 "env": {
5644 "TERM": "xterm-256color"
5645 }
5646 })
5647 );
5648
5649 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5650 match deserialized {
5651 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5652 assert_eq!(args, vec!["--interactive", "--color"]);
5653 assert_eq!(env.len(), 1);
5654 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5655 }
5656 _ => panic!("Expected Terminal variant"),
5657 }
5658 }
5659
5660 #[cfg(feature = "unstable_boolean_config")]
5661 #[test]
5662 fn test_session_config_option_value_id_serialize() {
5663 let val = SessionConfigOptionValue::value_id("model-1");
5664 let json = serde_json::to_value(&val).unwrap();
5665 assert_eq!(json, json!({ "value": "model-1" }));
5667 assert!(!json.as_object().unwrap().contains_key("type"));
5668 }
5669
5670 #[cfg(feature = "unstable_boolean_config")]
5671 #[test]
5672 fn test_session_config_option_value_boolean_serialize() {
5673 let val = SessionConfigOptionValue::boolean(true);
5674 let json = serde_json::to_value(&val).unwrap();
5675 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5676 }
5677
5678 #[cfg(feature = "unstable_boolean_config")]
5679 #[test]
5680 fn test_session_config_option_value_deserialize_no_type() {
5681 let json = json!({ "value": "model-1" });
5683 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5684 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5685 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5686 }
5687
5688 #[cfg(feature = "unstable_boolean_config")]
5689 #[test]
5690 fn test_session_config_option_value_deserialize_boolean() {
5691 let json = json!({ "type": "boolean", "value": true });
5692 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5693 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5694 assert_eq!(val.as_bool(), Some(true));
5695 }
5696
5697 #[cfg(feature = "unstable_boolean_config")]
5698 #[test]
5699 fn test_session_config_option_value_deserialize_boolean_false() {
5700 let json = json!({ "type": "boolean", "value": false });
5701 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5702 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5703 assert_eq!(val.as_bool(), Some(false));
5704 }
5705
5706 #[cfg(feature = "unstable_boolean_config")]
5707 #[test]
5708 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5709 let json = json!({ "type": "text", "value": "freeform input" });
5711 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5712 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5713 }
5714
5715 #[cfg(feature = "unstable_boolean_config")]
5716 #[test]
5717 fn test_session_config_option_value_roundtrip_value_id() {
5718 let original = SessionConfigOptionValue::value_id("option-a");
5719 let json = serde_json::to_value(&original).unwrap();
5720 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5721 assert_eq!(original, roundtripped);
5722 }
5723
5724 #[cfg(feature = "unstable_boolean_config")]
5725 #[test]
5726 fn test_session_config_option_value_roundtrip_boolean() {
5727 let original = SessionConfigOptionValue::boolean(false);
5728 let json = serde_json::to_value(&original).unwrap();
5729 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5730 assert_eq!(original, roundtripped);
5731 }
5732
5733 #[cfg(feature = "unstable_boolean_config")]
5734 #[test]
5735 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5736 let json = json!({ "type": "boolean", "value": "not a bool" });
5738 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5739 assert!(result.is_ok());
5741 assert_eq!(
5742 result.unwrap().as_value_id().unwrap().to_string(),
5743 "not a bool"
5744 );
5745 }
5746
5747 #[cfg(feature = "unstable_boolean_config")]
5748 #[test]
5749 fn test_session_config_option_value_from_impls() {
5750 let from_str: SessionConfigOptionValue = "model-1".into();
5751 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5752
5753 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5754 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5755
5756 let from_bool: SessionConfigOptionValue = true.into();
5757 assert_eq!(from_bool.as_bool(), Some(true));
5758 }
5759
5760 #[cfg(feature = "unstable_boolean_config")]
5761 #[test]
5762 fn test_set_session_config_option_request_value_id() {
5763 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5764 let json = serde_json::to_value(&req).unwrap();
5765 assert_eq!(
5766 json,
5767 json!({
5768 "sessionId": "sess_1",
5769 "configId": "model",
5770 "value": "model-1"
5771 })
5772 );
5773 assert!(!json.as_object().unwrap().contains_key("type"));
5775 }
5776
5777 #[cfg(feature = "unstable_boolean_config")]
5778 #[test]
5779 fn test_set_session_config_option_request_boolean() {
5780 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5781 let json = serde_json::to_value(&req).unwrap();
5782 assert_eq!(
5783 json,
5784 json!({
5785 "sessionId": "sess_1",
5786 "configId": "brave_mode",
5787 "type": "boolean",
5788 "value": true
5789 })
5790 );
5791 }
5792
5793 #[cfg(feature = "unstable_boolean_config")]
5794 #[test]
5795 fn test_set_session_config_option_request_deserialize_no_type() {
5796 let json = json!({
5798 "sessionId": "sess_1",
5799 "configId": "model",
5800 "value": "model-1"
5801 });
5802 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5803 assert_eq!(req.session_id.to_string(), "sess_1");
5804 assert_eq!(req.config_id.to_string(), "model");
5805 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5806 }
5807
5808 #[cfg(feature = "unstable_boolean_config")]
5809 #[test]
5810 fn test_set_session_config_option_request_deserialize_boolean() {
5811 let json = json!({
5812 "sessionId": "sess_1",
5813 "configId": "brave_mode",
5814 "type": "boolean",
5815 "value": true
5816 });
5817 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5818 assert_eq!(req.value.as_bool(), Some(true));
5819 }
5820
5821 #[cfg(feature = "unstable_boolean_config")]
5822 #[test]
5823 fn test_set_session_config_option_request_roundtrip_value_id() {
5824 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5825 let json = serde_json::to_value(&original).unwrap();
5826 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5827 assert_eq!(original, roundtripped);
5828 }
5829
5830 #[cfg(feature = "unstable_boolean_config")]
5831 #[test]
5832 fn test_set_session_config_option_request_roundtrip_boolean() {
5833 let original = SetSessionConfigOptionRequest::new("s", "c", false);
5834 let json = serde_json::to_value(&original).unwrap();
5835 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5836 assert_eq!(original, roundtripped);
5837 }
5838
5839 #[cfg(feature = "unstable_boolean_config")]
5840 #[test]
5841 fn test_session_config_boolean_serialization() {
5842 let cfg = SessionConfigBoolean::new(true);
5843 let json = serde_json::to_value(&cfg).unwrap();
5844 assert_eq!(json, json!({ "currentValue": true }));
5845
5846 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
5847 assert!(deserialized.current_value);
5848 }
5849
5850 #[cfg(feature = "unstable_boolean_config")]
5851 #[test]
5852 fn test_session_config_option_boolean_variant() {
5853 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
5854 .description("Skip confirmation prompts");
5855 let json = serde_json::to_value(&opt).unwrap();
5856 assert_eq!(
5857 json,
5858 json!({
5859 "id": "brave_mode",
5860 "name": "Brave Mode",
5861 "description": "Skip confirmation prompts",
5862 "type": "boolean",
5863 "currentValue": false
5864 })
5865 );
5866
5867 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5868 assert_eq!(deserialized.id.to_string(), "brave_mode");
5869 assert_eq!(deserialized.name, "Brave Mode");
5870 match deserialized.kind {
5871 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
5872 _ => panic!("Expected Boolean kind"),
5873 }
5874 }
5875
5876 #[cfg(feature = "unstable_boolean_config")]
5877 #[test]
5878 fn test_session_config_option_select_still_works() {
5879 let opt = SessionConfigOption::select(
5881 "model",
5882 "Model",
5883 "model-1",
5884 vec![
5885 SessionConfigSelectOption::new("model-1", "Model 1"),
5886 SessionConfigSelectOption::new("model-2", "Model 2"),
5887 ],
5888 );
5889 let json = serde_json::to_value(&opt).unwrap();
5890 assert_eq!(json["type"], "select");
5891 assert_eq!(json["currentValue"], "model-1");
5892 assert_eq!(json["options"].as_array().unwrap().len(), 2);
5893
5894 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5895 match deserialized.kind {
5896 SessionConfigKind::Select(ref s) => {
5897 assert_eq!(s.current_value.to_string(), "model-1");
5898 }
5899 _ => panic!("Expected Select kind"),
5900 }
5901 }
5902
5903 #[cfg(feature = "unstable_llm_providers")]
5904 #[test]
5905 fn test_llm_protocol_known_variants() {
5906 assert_eq!(
5907 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
5908 json!("anthropic")
5909 );
5910 assert_eq!(
5911 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
5912 json!("openai")
5913 );
5914 assert_eq!(
5915 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
5916 json!("azure")
5917 );
5918 assert_eq!(
5919 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
5920 json!("vertex")
5921 );
5922 assert_eq!(
5923 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
5924 json!("bedrock")
5925 );
5926
5927 assert_eq!(
5928 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
5929 LlmProtocol::Anthropic
5930 );
5931 assert_eq!(
5932 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
5933 LlmProtocol::OpenAi
5934 );
5935 assert_eq!(
5936 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
5937 LlmProtocol::Azure
5938 );
5939 assert_eq!(
5940 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
5941 LlmProtocol::Vertex
5942 );
5943 assert_eq!(
5944 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
5945 LlmProtocol::Bedrock
5946 );
5947 }
5948
5949 #[cfg(feature = "unstable_llm_providers")]
5950 #[test]
5951 fn test_llm_protocol_unknown_variant() {
5952 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
5953 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
5954
5955 let json = serde_json::to_value(&unknown).unwrap();
5956 assert_eq!(json, json!("cohere"));
5957 }
5958
5959 #[cfg(feature = "unstable_llm_providers")]
5960 #[test]
5961 fn test_provider_current_config_serialization() {
5962 let config =
5963 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
5964
5965 let json = serde_json::to_value(&config).unwrap();
5966 assert_eq!(
5967 json,
5968 json!({
5969 "apiType": "anthropic",
5970 "baseUrl": "https://api.anthropic.com"
5971 })
5972 );
5973
5974 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
5975 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
5976 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
5977 }
5978
5979 #[cfg(feature = "unstable_llm_providers")]
5980 #[test]
5981 fn test_provider_info_with_current_config() {
5982 let info = ProviderInfo::new(
5983 "main",
5984 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
5985 true,
5986 Some(ProviderCurrentConfig::new(
5987 LlmProtocol::Anthropic,
5988 "https://api.anthropic.com",
5989 )),
5990 );
5991
5992 let json = serde_json::to_value(&info).unwrap();
5993 assert_eq!(
5994 json,
5995 json!({
5996 "id": "main",
5997 "supported": ["anthropic", "openai"],
5998 "required": true,
5999 "current": {
6000 "apiType": "anthropic",
6001 "baseUrl": "https://api.anthropic.com"
6002 }
6003 })
6004 );
6005
6006 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6007 assert_eq!(deserialized.id, "main");
6008 assert_eq!(deserialized.supported.len(), 2);
6009 assert!(deserialized.required);
6010 assert!(deserialized.current.is_value());
6011 assert_eq!(
6012 deserialized.current.value().unwrap().api_type,
6013 LlmProtocol::Anthropic
6014 );
6015 }
6016
6017 #[cfg(feature = "unstable_llm_providers")]
6018 #[test]
6019 fn test_provider_info_disabled() {
6020 let info = ProviderInfo::new(
6021 "secondary",
6022 vec![LlmProtocol::OpenAi],
6023 false,
6024 RequiredNullable::<ProviderCurrentConfig>::null(),
6025 );
6026
6027 let json = serde_json::to_value(&info).unwrap();
6028 assert_eq!(
6029 json,
6030 json!({
6031 "id": "secondary",
6032 "supported": ["openai"],
6033 "required": false,
6034 "current": null
6035 })
6036 );
6037
6038 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6039 assert_eq!(deserialized.id, "secondary");
6040 assert!(!deserialized.required);
6041 assert!(deserialized.current.is_null());
6042 }
6043
6044 #[cfg(feature = "unstable_llm_providers")]
6045 #[test]
6046 fn test_provider_info_missing_current_fails() {
6047 let json = json!({
6049 "id": "main",
6050 "supported": ["anthropic"],
6051 "required": true
6052 });
6053 assert!(serde_json::from_value::<ProviderInfo>(json).is_err());
6054 }
6055
6056 #[cfg(feature = "unstable_llm_providers")]
6057 #[test]
6058 fn test_list_providers_response_serialization() {
6059 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6060 "main",
6061 vec![LlmProtocol::Anthropic],
6062 true,
6063 Some(ProviderCurrentConfig::new(
6064 LlmProtocol::Anthropic,
6065 "https://api.anthropic.com",
6066 )),
6067 )]);
6068
6069 let json = serde_json::to_value(&response).unwrap();
6070 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6071 assert_eq!(json["providers"][0]["id"], "main");
6072
6073 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6074 assert_eq!(deserialized.providers.len(), 1);
6075 }
6076
6077 #[cfg(feature = "unstable_llm_providers")]
6078 #[test]
6079 fn test_set_providers_request_serialization() {
6080 use std::collections::HashMap;
6081
6082 let mut headers = HashMap::new();
6083 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6084
6085 let request =
6086 SetProvidersRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6087 .headers(headers);
6088
6089 let json = serde_json::to_value(&request).unwrap();
6090 assert_eq!(
6091 json,
6092 json!({
6093 "id": "main",
6094 "apiType": "openai",
6095 "baseUrl": "https://api.openai.com/v1",
6096 "headers": {
6097 "Authorization": "Bearer sk-test"
6098 }
6099 })
6100 );
6101
6102 let deserialized: SetProvidersRequest = serde_json::from_value(json).unwrap();
6103 assert_eq!(deserialized.id, "main");
6104 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6105 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6106 assert_eq!(deserialized.headers.len(), 1);
6107 assert_eq!(
6108 deserialized.headers.get("Authorization").unwrap(),
6109 "Bearer sk-test"
6110 );
6111 }
6112
6113 #[cfg(feature = "unstable_llm_providers")]
6114 #[test]
6115 fn test_set_providers_request_omits_empty_headers() {
6116 let request =
6117 SetProvidersRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6118
6119 let json = serde_json::to_value(&request).unwrap();
6120 assert!(!json.as_object().unwrap().contains_key("headers"));
6122 }
6123
6124 #[cfg(feature = "unstable_llm_providers")]
6125 #[test]
6126 fn test_disable_providers_request_serialization() {
6127 let request = DisableProvidersRequest::new("secondary");
6128
6129 let json = serde_json::to_value(&request).unwrap();
6130 assert_eq!(json, json!({ "id": "secondary" }));
6131
6132 let deserialized: DisableProvidersRequest = serde_json::from_value(json).unwrap();
6133 assert_eq!(deserialized.id, "secondary");
6134 }
6135
6136 #[cfg(feature = "unstable_llm_providers")]
6137 #[test]
6138 fn test_providers_capabilities_serialization() {
6139 let caps = ProvidersCapabilities::new();
6140
6141 let json = serde_json::to_value(&caps).unwrap();
6142 assert_eq!(json, json!({}));
6143
6144 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6145 assert!(deserialized.meta.is_none());
6146 }
6147
6148 #[cfg(feature = "unstable_llm_providers")]
6149 #[test]
6150 fn test_agent_capabilities_with_providers() {
6151 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6152
6153 let json = serde_json::to_value(&caps).unwrap();
6154 assert_eq!(json["providers"], json!({}));
6155
6156 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6157 assert!(deserialized.providers.is_some());
6158 }
6159}