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
16use crate::{
17 ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta,
18 ProtocolVersion, SessionId, SkipListener,
19};
20
21#[cfg(feature = "unstable_nes")]
22use crate::{
23 AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
24 DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
25 DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
26 StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
27};
28
29#[cfg(feature = "unstable_nes")]
30use crate::nes::{
31 DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
32 DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
33 NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
34 NES_SUGGEST_METHOD_NAME,
35};
36
37#[serde_as]
45#[skip_serializing_none]
46#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
47#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
48#[serde(rename_all = "camelCase")]
49#[non_exhaustive]
50pub struct InitializeRequest {
51 pub protocol_version: ProtocolVersion,
53 #[serde(default)]
55 pub client_capabilities: ClientCapabilities,
56 #[serde_as(deserialize_as = "DefaultOnError")]
60 #[serde(default)]
61 pub client_info: Option<Implementation>,
62 #[serde(rename = "_meta")]
68 pub meta: Option<Meta>,
69}
70
71impl InitializeRequest {
72 #[must_use]
73 pub fn new(protocol_version: ProtocolVersion) -> Self {
74 Self {
75 protocol_version,
76 client_capabilities: ClientCapabilities::default(),
77 client_info: None,
78 meta: None,
79 }
80 }
81
82 #[must_use]
84 pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
85 self.client_capabilities = client_capabilities;
86 self
87 }
88
89 #[must_use]
91 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
92 self.client_info = client_info.into_option();
93 self
94 }
95
96 #[must_use]
102 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
103 self.meta = meta.into_option();
104 self
105 }
106}
107
108#[serde_as]
114#[skip_serializing_none]
115#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
116#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
117#[serde(rename_all = "camelCase")]
118#[non_exhaustive]
119pub struct InitializeResponse {
120 pub protocol_version: ProtocolVersion,
125 #[serde(default)]
127 pub agent_capabilities: AgentCapabilities,
128 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
130 #[serde(default)]
131 pub auth_methods: Vec<AuthMethod>,
132 #[serde_as(deserialize_as = "DefaultOnError")]
136 #[serde(default)]
137 pub agent_info: Option<Implementation>,
138 #[serde(rename = "_meta")]
144 pub meta: Option<Meta>,
145}
146
147impl InitializeResponse {
148 #[must_use]
149 pub fn new(protocol_version: ProtocolVersion) -> Self {
150 Self {
151 protocol_version,
152 agent_capabilities: AgentCapabilities::default(),
153 auth_methods: vec![],
154 agent_info: None,
155 meta: None,
156 }
157 }
158
159 #[must_use]
161 pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
162 self.agent_capabilities = agent_capabilities;
163 self
164 }
165
166 #[must_use]
168 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
169 self.auth_methods = auth_methods;
170 self
171 }
172
173 #[must_use]
175 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
176 self.agent_info = agent_info.into_option();
177 self
178 }
179
180 #[must_use]
186 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
187 self.meta = meta.into_option();
188 self
189 }
190}
191
192#[skip_serializing_none]
196#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
197#[serde(rename_all = "camelCase")]
198#[non_exhaustive]
199pub struct Implementation {
200 pub name: String,
203 pub title: Option<String>,
208 pub version: String,
211 #[serde(rename = "_meta")]
217 pub meta: Option<Meta>,
218}
219
220impl Implementation {
221 #[must_use]
222 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
223 Self {
224 name: name.into(),
225 title: None,
226 version: version.into(),
227 meta: None,
228 }
229 }
230
231 #[must_use]
236 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
237 self.title = title.into_option();
238 self
239 }
240
241 #[must_use]
247 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
248 self.meta = meta.into_option();
249 self
250 }
251}
252
253#[skip_serializing_none]
259#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
260#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
261#[serde(rename_all = "camelCase")]
262#[non_exhaustive]
263pub struct AuthenticateRequest {
264 pub method_id: AuthMethodId,
267 #[serde(rename = "_meta")]
273 pub meta: Option<Meta>,
274}
275
276impl AuthenticateRequest {
277 #[must_use]
278 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
279 Self {
280 method_id: method_id.into(),
281 meta: None,
282 }
283 }
284
285 #[must_use]
291 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
292 self.meta = meta.into_option();
293 self
294 }
295}
296
297#[skip_serializing_none]
299#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
300#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
301#[serde(rename_all = "camelCase")]
302#[non_exhaustive]
303pub struct AuthenticateResponse {
304 #[serde(rename = "_meta")]
310 pub meta: Option<Meta>,
311}
312
313impl AuthenticateResponse {
314 #[must_use]
315 pub fn new() -> Self {
316 Self::default()
317 }
318
319 #[must_use]
325 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
326 self.meta = meta.into_option();
327 self
328 }
329}
330
331#[cfg(feature = "unstable_logout")]
341#[skip_serializing_none]
342#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
343#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
344#[serde(rename_all = "camelCase")]
345#[non_exhaustive]
346pub struct LogoutRequest {
347 #[serde(rename = "_meta")]
353 pub meta: Option<Meta>,
354}
355
356#[cfg(feature = "unstable_logout")]
357impl LogoutRequest {
358 #[must_use]
359 pub fn new() -> Self {
360 Self::default()
361 }
362
363 #[must_use]
369 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
370 self.meta = meta.into_option();
371 self
372 }
373}
374
375#[cfg(feature = "unstable_logout")]
381#[skip_serializing_none]
382#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
383#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
384#[serde(rename_all = "camelCase")]
385#[non_exhaustive]
386pub struct LogoutResponse {
387 #[serde(rename = "_meta")]
393 pub meta: Option<Meta>,
394}
395
396#[cfg(feature = "unstable_logout")]
397impl LogoutResponse {
398 #[must_use]
399 pub fn new() -> Self {
400 Self::default()
401 }
402
403 #[must_use]
409 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
410 self.meta = meta.into_option();
411 self
412 }
413}
414
415#[cfg(feature = "unstable_logout")]
421#[serde_as]
422#[skip_serializing_none]
423#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
424#[serde(rename_all = "camelCase")]
425#[non_exhaustive]
426pub struct AgentAuthCapabilities {
427 #[serde_as(deserialize_as = "DefaultOnError")]
431 #[serde(default)]
432 pub logout: Option<LogoutCapabilities>,
433 #[serde(rename = "_meta")]
439 pub meta: Option<Meta>,
440}
441
442#[cfg(feature = "unstable_logout")]
443impl AgentAuthCapabilities {
444 #[must_use]
445 pub fn new() -> Self {
446 Self::default()
447 }
448
449 #[must_use]
451 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
452 self.logout = logout.into_option();
453 self
454 }
455
456 #[must_use]
462 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
463 self.meta = meta.into_option();
464 self
465 }
466}
467
468#[cfg(feature = "unstable_logout")]
476#[skip_serializing_none]
477#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
478#[non_exhaustive]
479pub struct LogoutCapabilities {
480 #[serde(rename = "_meta")]
486 pub meta: Option<Meta>,
487}
488
489#[cfg(feature = "unstable_logout")]
490impl LogoutCapabilities {
491 #[must_use]
492 pub fn new() -> Self {
493 Self::default()
494 }
495
496 #[must_use]
502 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
503 self.meta = meta.into_option();
504 self
505 }
506}
507
508#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
509#[serde(transparent)]
510#[from(Arc<str>, String, &'static str)]
511#[non_exhaustive]
512pub struct AuthMethodId(pub Arc<str>);
513
514impl AuthMethodId {
515 #[must_use]
516 pub fn new(id: impl Into<Arc<str>>) -> Self {
517 Self(id.into())
518 }
519}
520
521#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
526#[serde(tag = "type", rename_all = "snake_case")]
527#[non_exhaustive]
528pub enum AuthMethod {
529 #[cfg(feature = "unstable_auth_methods")]
535 EnvVar(AuthMethodEnvVar),
536 #[cfg(feature = "unstable_auth_methods")]
542 Terminal(AuthMethodTerminal),
543 #[serde(untagged)]
547 Agent(AuthMethodAgent),
548}
549
550impl AuthMethod {
551 #[must_use]
553 pub fn id(&self) -> &AuthMethodId {
554 match self {
555 Self::Agent(a) => &a.id,
556 #[cfg(feature = "unstable_auth_methods")]
557 Self::EnvVar(e) => &e.id,
558 #[cfg(feature = "unstable_auth_methods")]
559 Self::Terminal(t) => &t.id,
560 }
561 }
562
563 #[must_use]
565 pub fn name(&self) -> &str {
566 match self {
567 Self::Agent(a) => &a.name,
568 #[cfg(feature = "unstable_auth_methods")]
569 Self::EnvVar(e) => &e.name,
570 #[cfg(feature = "unstable_auth_methods")]
571 Self::Terminal(t) => &t.name,
572 }
573 }
574
575 #[must_use]
577 pub fn description(&self) -> Option<&str> {
578 match self {
579 Self::Agent(a) => a.description.as_deref(),
580 #[cfg(feature = "unstable_auth_methods")]
581 Self::EnvVar(e) => e.description.as_deref(),
582 #[cfg(feature = "unstable_auth_methods")]
583 Self::Terminal(t) => t.description.as_deref(),
584 }
585 }
586
587 #[must_use]
593 pub fn meta(&self) -> Option<&Meta> {
594 match self {
595 Self::Agent(a) => a.meta.as_ref(),
596 #[cfg(feature = "unstable_auth_methods")]
597 Self::EnvVar(e) => e.meta.as_ref(),
598 #[cfg(feature = "unstable_auth_methods")]
599 Self::Terminal(t) => t.meta.as_ref(),
600 }
601 }
602}
603
604#[skip_serializing_none]
608#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
609#[serde(rename_all = "camelCase")]
610#[non_exhaustive]
611pub struct AuthMethodAgent {
612 pub id: AuthMethodId,
614 pub name: String,
616 pub description: Option<String>,
618 #[serde(rename = "_meta")]
624 pub meta: Option<Meta>,
625}
626
627impl AuthMethodAgent {
628 #[must_use]
629 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
630 Self {
631 id: id.into(),
632 name: name.into(),
633 description: None,
634 meta: None,
635 }
636 }
637
638 #[must_use]
640 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
641 self.description = description.into_option();
642 self
643 }
644
645 #[must_use]
651 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
652 self.meta = meta.into_option();
653 self
654 }
655}
656
657#[cfg(feature = "unstable_auth_methods")]
665#[skip_serializing_none]
666#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
667#[serde(rename_all = "camelCase")]
668#[non_exhaustive]
669pub struct AuthMethodEnvVar {
670 pub id: AuthMethodId,
672 pub name: String,
674 pub description: Option<String>,
676 pub vars: Vec<AuthEnvVar>,
678 pub link: Option<String>,
680 #[serde(rename = "_meta")]
686 pub meta: Option<Meta>,
687}
688
689#[cfg(feature = "unstable_auth_methods")]
690impl AuthMethodEnvVar {
691 #[must_use]
692 pub fn new(
693 id: impl Into<AuthMethodId>,
694 name: impl Into<String>,
695 vars: Vec<AuthEnvVar>,
696 ) -> Self {
697 Self {
698 id: id.into(),
699 name: name.into(),
700 description: None,
701 vars,
702 link: None,
703 meta: None,
704 }
705 }
706
707 #[must_use]
709 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
710 self.link = link.into_option();
711 self
712 }
713
714 #[must_use]
716 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
717 self.description = description.into_option();
718 self
719 }
720
721 #[must_use]
727 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
728 self.meta = meta.into_option();
729 self
730 }
731}
732
733#[cfg(feature = "unstable_auth_methods")]
739#[skip_serializing_none]
740#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
741#[serde(rename_all = "camelCase")]
742#[non_exhaustive]
743pub struct AuthEnvVar {
744 pub name: String,
746 pub label: Option<String>,
748 #[serde(default = "default_true", skip_serializing_if = "is_true")]
753 #[schemars(extend("default" = true))]
754 pub secret: bool,
755 #[serde(default, skip_serializing_if = "is_false")]
759 #[schemars(extend("default" = false))]
760 pub optional: bool,
761 #[serde(rename = "_meta")]
767 pub meta: Option<Meta>,
768}
769
770#[cfg(feature = "unstable_auth_methods")]
771fn default_true() -> bool {
772 true
773}
774
775#[cfg(feature = "unstable_auth_methods")]
776#[expect(clippy::trivially_copy_pass_by_ref)]
777fn is_true(v: &bool) -> bool {
778 *v
779}
780
781#[cfg(feature = "unstable_auth_methods")]
782#[expect(clippy::trivially_copy_pass_by_ref)]
783fn is_false(v: &bool) -> bool {
784 !*v
785}
786
787#[cfg(feature = "unstable_auth_methods")]
788impl AuthEnvVar {
789 #[must_use]
791 pub fn new(name: impl Into<String>) -> Self {
792 Self {
793 name: name.into(),
794 label: None,
795 secret: true,
796 optional: false,
797 meta: None,
798 }
799 }
800
801 #[must_use]
803 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
804 self.label = label.into_option();
805 self
806 }
807
808 #[must_use]
811 pub fn secret(mut self, secret: bool) -> Self {
812 self.secret = secret;
813 self
814 }
815
816 #[must_use]
818 pub fn optional(mut self, optional: bool) -> Self {
819 self.optional = optional;
820 self
821 }
822
823 #[must_use]
829 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
830 self.meta = meta.into_option();
831 self
832 }
833}
834
835#[cfg(feature = "unstable_auth_methods")]
843#[skip_serializing_none]
844#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
845#[serde(rename_all = "camelCase")]
846#[non_exhaustive]
847pub struct AuthMethodTerminal {
848 pub id: AuthMethodId,
850 pub name: String,
852 pub description: Option<String>,
854 #[serde(default, skip_serializing_if = "Vec::is_empty")]
856 pub args: Vec<String>,
857 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
859 pub env: HashMap<String, String>,
860 #[serde(rename = "_meta")]
866 pub meta: Option<Meta>,
867}
868
869#[cfg(feature = "unstable_auth_methods")]
870impl AuthMethodTerminal {
871 #[must_use]
872 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
873 Self {
874 id: id.into(),
875 name: name.into(),
876 description: None,
877 args: Vec::new(),
878 env: HashMap::new(),
879 meta: None,
880 }
881 }
882
883 #[must_use]
885 pub fn args(mut self, args: Vec<String>) -> Self {
886 self.args = args;
887 self
888 }
889
890 #[must_use]
892 pub fn env(mut self, env: HashMap<String, String>) -> Self {
893 self.env = env;
894 self
895 }
896
897 #[must_use]
899 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
900 self.description = description.into_option();
901 self
902 }
903
904 #[must_use]
910 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
911 self.meta = meta.into_option();
912 self
913 }
914}
915
916#[skip_serializing_none]
922#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
923#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
924#[serde(rename_all = "camelCase")]
925#[non_exhaustive]
926pub struct NewSessionRequest {
927 pub cwd: PathBuf,
929 #[cfg(feature = "unstable_session_additional_directories")]
939 #[serde(default, skip_serializing_if = "Vec::is_empty")]
940 pub additional_directories: Vec<PathBuf>,
941 pub mcp_servers: Vec<McpServer>,
943 #[serde(rename = "_meta")]
949 pub meta: Option<Meta>,
950}
951
952impl NewSessionRequest {
953 #[must_use]
954 pub fn new(cwd: impl Into<PathBuf>) -> Self {
955 Self {
956 cwd: cwd.into(),
957 #[cfg(feature = "unstable_session_additional_directories")]
958 additional_directories: vec![],
959 mcp_servers: vec![],
960 meta: None,
961 }
962 }
963
964 #[cfg(feature = "unstable_session_additional_directories")]
970 #[must_use]
971 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
972 self.additional_directories = additional_directories;
973 self
974 }
975
976 #[must_use]
978 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
979 self.mcp_servers = mcp_servers;
980 self
981 }
982
983 #[must_use]
989 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
990 self.meta = meta.into_option();
991 self
992 }
993}
994
995#[serde_as]
999#[skip_serializing_none]
1000#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1001#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1002#[serde(rename_all = "camelCase")]
1003#[non_exhaustive]
1004pub struct NewSessionResponse {
1005 pub session_id: SessionId,
1009 #[serde_as(deserialize_as = "DefaultOnError")]
1013 #[serde(default)]
1014 pub modes: Option<SessionModeState>,
1015 #[cfg(feature = "unstable_session_model")]
1021 #[serde_as(deserialize_as = "DefaultOnError")]
1022 #[serde(default)]
1023 pub models: Option<SessionModelState>,
1024 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1026 #[serde(default)]
1027 pub config_options: Option<Vec<SessionConfigOption>>,
1028 #[serde(rename = "_meta")]
1034 pub meta: Option<Meta>,
1035}
1036
1037impl NewSessionResponse {
1038 #[must_use]
1039 pub fn new(session_id: impl Into<SessionId>) -> Self {
1040 Self {
1041 session_id: session_id.into(),
1042 modes: None,
1043 #[cfg(feature = "unstable_session_model")]
1044 models: None,
1045 config_options: None,
1046 meta: None,
1047 }
1048 }
1049
1050 #[must_use]
1054 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1055 self.modes = modes.into_option();
1056 self
1057 }
1058
1059 #[cfg(feature = "unstable_session_model")]
1065 #[must_use]
1066 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1067 self.models = models.into_option();
1068 self
1069 }
1070
1071 #[must_use]
1073 pub fn config_options(
1074 mut self,
1075 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1076 ) -> Self {
1077 self.config_options = config_options.into_option();
1078 self
1079 }
1080
1081 #[must_use]
1087 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1088 self.meta = meta.into_option();
1089 self
1090 }
1091}
1092
1093#[skip_serializing_none]
1101#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1102#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1103#[serde(rename_all = "camelCase")]
1104#[non_exhaustive]
1105pub struct LoadSessionRequest {
1106 pub mcp_servers: Vec<McpServer>,
1108 pub cwd: PathBuf,
1110 #[cfg(feature = "unstable_session_additional_directories")]
1120 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1121 pub additional_directories: Vec<PathBuf>,
1122 pub session_id: SessionId,
1124 #[serde(rename = "_meta")]
1130 pub meta: Option<Meta>,
1131}
1132
1133impl LoadSessionRequest {
1134 #[must_use]
1135 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1136 Self {
1137 mcp_servers: vec![],
1138 cwd: cwd.into(),
1139 #[cfg(feature = "unstable_session_additional_directories")]
1140 additional_directories: vec![],
1141 session_id: session_id.into(),
1142 meta: None,
1143 }
1144 }
1145
1146 #[cfg(feature = "unstable_session_additional_directories")]
1152 #[must_use]
1153 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1154 self.additional_directories = additional_directories;
1155 self
1156 }
1157
1158 #[must_use]
1160 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1161 self.mcp_servers = mcp_servers;
1162 self
1163 }
1164
1165 #[must_use]
1171 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1172 self.meta = meta.into_option();
1173 self
1174 }
1175}
1176
1177#[serde_as]
1179#[skip_serializing_none]
1180#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1181#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1182#[serde(rename_all = "camelCase")]
1183#[non_exhaustive]
1184pub struct LoadSessionResponse {
1185 #[serde_as(deserialize_as = "DefaultOnError")]
1189 #[serde(default)]
1190 pub modes: Option<SessionModeState>,
1191 #[cfg(feature = "unstable_session_model")]
1197 #[serde_as(deserialize_as = "DefaultOnError")]
1198 #[serde(default)]
1199 pub models: Option<SessionModelState>,
1200 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1202 #[serde(default)]
1203 pub config_options: Option<Vec<SessionConfigOption>>,
1204 #[serde(rename = "_meta")]
1210 pub meta: Option<Meta>,
1211}
1212
1213impl LoadSessionResponse {
1214 #[must_use]
1215 pub fn new() -> Self {
1216 Self::default()
1217 }
1218
1219 #[must_use]
1223 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1224 self.modes = modes.into_option();
1225 self
1226 }
1227
1228 #[cfg(feature = "unstable_session_model")]
1234 #[must_use]
1235 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1236 self.models = models.into_option();
1237 self
1238 }
1239
1240 #[must_use]
1242 pub fn config_options(
1243 mut self,
1244 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1245 ) -> Self {
1246 self.config_options = config_options.into_option();
1247 self
1248 }
1249
1250 #[must_use]
1256 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1257 self.meta = meta.into_option();
1258 self
1259 }
1260}
1261
1262#[cfg(feature = "unstable_session_fork")]
1275#[skip_serializing_none]
1276#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1277#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1278#[serde(rename_all = "camelCase")]
1279#[non_exhaustive]
1280pub struct ForkSessionRequest {
1281 pub session_id: SessionId,
1283 pub cwd: PathBuf,
1285 #[cfg(feature = "unstable_session_additional_directories")]
1295 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1296 pub additional_directories: Vec<PathBuf>,
1297 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1299 pub mcp_servers: Vec<McpServer>,
1300 #[serde(rename = "_meta")]
1306 pub meta: Option<Meta>,
1307}
1308
1309#[cfg(feature = "unstable_session_fork")]
1310impl ForkSessionRequest {
1311 #[must_use]
1312 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1313 Self {
1314 session_id: session_id.into(),
1315 cwd: cwd.into(),
1316 #[cfg(feature = "unstable_session_additional_directories")]
1317 additional_directories: vec![],
1318 mcp_servers: vec![],
1319 meta: None,
1320 }
1321 }
1322
1323 #[cfg(feature = "unstable_session_additional_directories")]
1329 #[must_use]
1330 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1331 self.additional_directories = additional_directories;
1332 self
1333 }
1334
1335 #[must_use]
1337 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1338 self.mcp_servers = mcp_servers;
1339 self
1340 }
1341
1342 #[must_use]
1348 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1349 self.meta = meta.into_option();
1350 self
1351 }
1352}
1353
1354#[cfg(feature = "unstable_session_fork")]
1360#[serde_as]
1361#[skip_serializing_none]
1362#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1363#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1364#[serde(rename_all = "camelCase")]
1365#[non_exhaustive]
1366pub struct ForkSessionResponse {
1367 pub session_id: SessionId,
1369 #[serde_as(deserialize_as = "DefaultOnError")]
1373 #[serde(default)]
1374 pub modes: Option<SessionModeState>,
1375 #[cfg(feature = "unstable_session_model")]
1381 #[serde_as(deserialize_as = "DefaultOnError")]
1382 #[serde(default)]
1383 pub models: Option<SessionModelState>,
1384 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1386 #[serde(default)]
1387 pub config_options: Option<Vec<SessionConfigOption>>,
1388 #[serde(rename = "_meta")]
1394 pub meta: Option<Meta>,
1395}
1396
1397#[cfg(feature = "unstable_session_fork")]
1398impl ForkSessionResponse {
1399 #[must_use]
1400 pub fn new(session_id: impl Into<SessionId>) -> Self {
1401 Self {
1402 session_id: session_id.into(),
1403 modes: None,
1404 #[cfg(feature = "unstable_session_model")]
1405 models: None,
1406 config_options: None,
1407 meta: None,
1408 }
1409 }
1410
1411 #[must_use]
1415 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1416 self.modes = modes.into_option();
1417 self
1418 }
1419
1420 #[cfg(feature = "unstable_session_model")]
1426 #[must_use]
1427 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1428 self.models = models.into_option();
1429 self
1430 }
1431
1432 #[must_use]
1434 pub fn config_options(
1435 mut self,
1436 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1437 ) -> Self {
1438 self.config_options = config_options.into_option();
1439 self
1440 }
1441
1442 #[must_use]
1448 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1449 self.meta = meta.into_option();
1450 self
1451 }
1452}
1453
1454#[cfg(feature = "unstable_session_resume")]
1467#[skip_serializing_none]
1468#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1469#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1470#[serde(rename_all = "camelCase")]
1471#[non_exhaustive]
1472pub struct ResumeSessionRequest {
1473 pub session_id: SessionId,
1475 pub cwd: PathBuf,
1477 #[cfg(feature = "unstable_session_additional_directories")]
1487 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1488 pub additional_directories: Vec<PathBuf>,
1489 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1491 pub mcp_servers: Vec<McpServer>,
1492 #[serde(rename = "_meta")]
1498 pub meta: Option<Meta>,
1499}
1500
1501#[cfg(feature = "unstable_session_resume")]
1502impl ResumeSessionRequest {
1503 #[must_use]
1504 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1505 Self {
1506 session_id: session_id.into(),
1507 cwd: cwd.into(),
1508 #[cfg(feature = "unstable_session_additional_directories")]
1509 additional_directories: vec![],
1510 mcp_servers: vec![],
1511 meta: None,
1512 }
1513 }
1514
1515 #[cfg(feature = "unstable_session_additional_directories")]
1521 #[must_use]
1522 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1523 self.additional_directories = additional_directories;
1524 self
1525 }
1526
1527 #[must_use]
1529 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1530 self.mcp_servers = mcp_servers;
1531 self
1532 }
1533
1534 #[must_use]
1540 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1541 self.meta = meta.into_option();
1542 self
1543 }
1544}
1545
1546#[cfg(feature = "unstable_session_resume")]
1552#[serde_as]
1553#[skip_serializing_none]
1554#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1555#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1556#[serde(rename_all = "camelCase")]
1557#[non_exhaustive]
1558pub struct ResumeSessionResponse {
1559 #[serde_as(deserialize_as = "DefaultOnError")]
1563 #[serde(default)]
1564 pub modes: Option<SessionModeState>,
1565 #[cfg(feature = "unstable_session_model")]
1571 #[serde_as(deserialize_as = "DefaultOnError")]
1572 #[serde(default)]
1573 pub models: Option<SessionModelState>,
1574 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1576 #[serde(default)]
1577 pub config_options: Option<Vec<SessionConfigOption>>,
1578 #[serde(rename = "_meta")]
1584 pub meta: Option<Meta>,
1585}
1586
1587#[cfg(feature = "unstable_session_resume")]
1588impl ResumeSessionResponse {
1589 #[must_use]
1590 pub fn new() -> Self {
1591 Self::default()
1592 }
1593
1594 #[must_use]
1598 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1599 self.modes = modes.into_option();
1600 self
1601 }
1602
1603 #[cfg(feature = "unstable_session_model")]
1609 #[must_use]
1610 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1611 self.models = models.into_option();
1612 self
1613 }
1614
1615 #[must_use]
1617 pub fn config_options(
1618 mut self,
1619 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1620 ) -> Self {
1621 self.config_options = config_options.into_option();
1622 self
1623 }
1624
1625 #[must_use]
1631 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1632 self.meta = meta.into_option();
1633 self
1634 }
1635}
1636
1637#[cfg(feature = "unstable_session_close")]
1651#[skip_serializing_none]
1652#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1653#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1654#[serde(rename_all = "camelCase")]
1655#[non_exhaustive]
1656pub struct CloseSessionRequest {
1657 pub session_id: SessionId,
1659 #[serde(rename = "_meta")]
1665 pub meta: Option<Meta>,
1666}
1667
1668#[cfg(feature = "unstable_session_close")]
1669impl CloseSessionRequest {
1670 #[must_use]
1671 pub fn new(session_id: impl Into<SessionId>) -> Self {
1672 Self {
1673 session_id: session_id.into(),
1674 meta: None,
1675 }
1676 }
1677
1678 #[must_use]
1684 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1685 self.meta = meta.into_option();
1686 self
1687 }
1688}
1689
1690#[cfg(feature = "unstable_session_close")]
1696#[skip_serializing_none]
1697#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1698#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1699#[serde(rename_all = "camelCase")]
1700#[non_exhaustive]
1701pub struct CloseSessionResponse {
1702 #[serde(rename = "_meta")]
1708 pub meta: Option<Meta>,
1709}
1710
1711#[cfg(feature = "unstable_session_close")]
1712impl CloseSessionResponse {
1713 #[must_use]
1714 pub fn new() -> Self {
1715 Self::default()
1716 }
1717
1718 #[must_use]
1724 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1725 self.meta = meta.into_option();
1726 self
1727 }
1728}
1729
1730#[skip_serializing_none]
1736#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1737#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1738#[serde(rename_all = "camelCase")]
1739#[non_exhaustive]
1740pub struct ListSessionsRequest {
1741 pub cwd: Option<PathBuf>,
1743 #[cfg(feature = "unstable_session_additional_directories")]
1752 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1753 pub additional_directories: Vec<PathBuf>,
1754 pub cursor: Option<String>,
1756 #[serde(rename = "_meta")]
1762 pub meta: Option<Meta>,
1763}
1764
1765impl ListSessionsRequest {
1766 #[must_use]
1767 pub fn new() -> Self {
1768 Self::default()
1769 }
1770
1771 #[must_use]
1773 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1774 self.cwd = cwd.into_option();
1775 self
1776 }
1777
1778 #[cfg(feature = "unstable_session_additional_directories")]
1784 #[must_use]
1785 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1786 self.additional_directories = additional_directories;
1787 self
1788 }
1789
1790 #[must_use]
1792 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1793 self.cursor = cursor.into_option();
1794 self
1795 }
1796
1797 #[must_use]
1803 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1804 self.meta = meta.into_option();
1805 self
1806 }
1807}
1808
1809#[serde_as]
1811#[skip_serializing_none]
1812#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1813#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1814#[serde(rename_all = "camelCase")]
1815#[non_exhaustive]
1816pub struct ListSessionsResponse {
1817 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1819 pub sessions: Vec<SessionInfo>,
1820 pub next_cursor: Option<String>,
1823 #[serde(rename = "_meta")]
1829 pub meta: Option<Meta>,
1830}
1831
1832impl ListSessionsResponse {
1833 #[must_use]
1834 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1835 Self {
1836 sessions,
1837 next_cursor: None,
1838 meta: None,
1839 }
1840 }
1841
1842 #[must_use]
1843 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1844 self.next_cursor = next_cursor.into_option();
1845 self
1846 }
1847
1848 #[must_use]
1854 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1855 self.meta = meta.into_option();
1856 self
1857 }
1858}
1859
1860#[serde_as]
1862#[skip_serializing_none]
1863#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1864#[serde(rename_all = "camelCase")]
1865#[non_exhaustive]
1866pub struct SessionInfo {
1867 pub session_id: SessionId,
1869 pub cwd: PathBuf,
1871 #[cfg(feature = "unstable_session_additional_directories")]
1879 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1880 pub additional_directories: Vec<PathBuf>,
1881
1882 #[serde_as(deserialize_as = "DefaultOnError")]
1884 #[serde(default)]
1885 pub title: Option<String>,
1886 #[serde_as(deserialize_as = "DefaultOnError")]
1888 #[serde(default)]
1889 pub updated_at: Option<String>,
1890 #[serde(rename = "_meta")]
1896 pub meta: Option<Meta>,
1897}
1898
1899impl SessionInfo {
1900 #[must_use]
1901 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1902 Self {
1903 session_id: session_id.into(),
1904 cwd: cwd.into(),
1905 #[cfg(feature = "unstable_session_additional_directories")]
1906 additional_directories: vec![],
1907 title: None,
1908 updated_at: None,
1909 meta: None,
1910 }
1911 }
1912
1913 #[cfg(feature = "unstable_session_additional_directories")]
1919 #[must_use]
1920 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1921 self.additional_directories = additional_directories;
1922 self
1923 }
1924
1925 #[must_use]
1927 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1928 self.title = title.into_option();
1929 self
1930 }
1931
1932 #[must_use]
1934 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1935 self.updated_at = updated_at.into_option();
1936 self
1937 }
1938
1939 #[must_use]
1945 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1946 self.meta = meta.into_option();
1947 self
1948 }
1949}
1950
1951#[serde_as]
1955#[skip_serializing_none]
1956#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1957#[serde(rename_all = "camelCase")]
1958#[non_exhaustive]
1959pub struct SessionModeState {
1960 pub current_mode_id: SessionModeId,
1962 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1964 pub available_modes: Vec<SessionMode>,
1965 #[serde(rename = "_meta")]
1971 pub meta: Option<Meta>,
1972}
1973
1974impl SessionModeState {
1975 #[must_use]
1976 pub fn new(
1977 current_mode_id: impl Into<SessionModeId>,
1978 available_modes: Vec<SessionMode>,
1979 ) -> Self {
1980 Self {
1981 current_mode_id: current_mode_id.into(),
1982 available_modes,
1983 meta: None,
1984 }
1985 }
1986
1987 #[must_use]
1993 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1994 self.meta = meta.into_option();
1995 self
1996 }
1997}
1998
1999#[skip_serializing_none]
2003#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2004#[serde(rename_all = "camelCase")]
2005#[non_exhaustive]
2006pub struct SessionMode {
2007 pub id: SessionModeId,
2008 pub name: String,
2009 #[serde(default)]
2010 pub description: Option<String>,
2011 #[serde(rename = "_meta")]
2017 pub meta: Option<Meta>,
2018}
2019
2020impl SessionMode {
2021 #[must_use]
2022 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
2023 Self {
2024 id: id.into(),
2025 name: name.into(),
2026 description: None,
2027 meta: None,
2028 }
2029 }
2030
2031 #[must_use]
2032 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2033 self.description = description.into_option();
2034 self
2035 }
2036
2037 #[must_use]
2043 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2044 self.meta = meta.into_option();
2045 self
2046 }
2047}
2048
2049#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2051#[serde(transparent)]
2052#[from(Arc<str>, String, &'static str)]
2053#[non_exhaustive]
2054pub struct SessionModeId(pub Arc<str>);
2055
2056impl SessionModeId {
2057 #[must_use]
2058 pub fn new(id: impl Into<Arc<str>>) -> Self {
2059 Self(id.into())
2060 }
2061}
2062
2063#[skip_serializing_none]
2065#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2066#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2067#[serde(rename_all = "camelCase")]
2068#[non_exhaustive]
2069pub struct SetSessionModeRequest {
2070 pub session_id: SessionId,
2072 pub mode_id: SessionModeId,
2074 #[serde(rename = "_meta")]
2080 pub meta: Option<Meta>,
2081}
2082
2083impl SetSessionModeRequest {
2084 #[must_use]
2085 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
2086 Self {
2087 session_id: session_id.into(),
2088 mode_id: mode_id.into(),
2089 meta: None,
2090 }
2091 }
2092
2093 #[must_use]
2094 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2095 self.meta = meta.into_option();
2096 self
2097 }
2098}
2099
2100#[skip_serializing_none]
2102#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2103#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2104#[serde(rename_all = "camelCase")]
2105#[non_exhaustive]
2106pub struct SetSessionModeResponse {
2107 #[serde(rename = "_meta")]
2113 pub meta: Option<Meta>,
2114}
2115
2116impl SetSessionModeResponse {
2117 #[must_use]
2118 pub fn new() -> Self {
2119 Self::default()
2120 }
2121
2122 #[must_use]
2128 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2129 self.meta = meta.into_option();
2130 self
2131 }
2132}
2133
2134#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2138#[serde(transparent)]
2139#[from(Arc<str>, String, &'static str)]
2140#[non_exhaustive]
2141pub struct SessionConfigId(pub Arc<str>);
2142
2143impl SessionConfigId {
2144 #[must_use]
2145 pub fn new(id: impl Into<Arc<str>>) -> Self {
2146 Self(id.into())
2147 }
2148}
2149
2150#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2152#[serde(transparent)]
2153#[from(Arc<str>, String, &'static str)]
2154#[non_exhaustive]
2155pub struct SessionConfigValueId(pub Arc<str>);
2156
2157impl SessionConfigValueId {
2158 #[must_use]
2159 pub fn new(id: impl Into<Arc<str>>) -> Self {
2160 Self(id.into())
2161 }
2162}
2163
2164#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2166#[serde(transparent)]
2167#[from(Arc<str>, String, &'static str)]
2168#[non_exhaustive]
2169pub struct SessionConfigGroupId(pub Arc<str>);
2170
2171impl SessionConfigGroupId {
2172 #[must_use]
2173 pub fn new(id: impl Into<Arc<str>>) -> Self {
2174 Self(id.into())
2175 }
2176}
2177
2178#[skip_serializing_none]
2180#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2181#[serde(rename_all = "camelCase")]
2182#[non_exhaustive]
2183pub struct SessionConfigSelectOption {
2184 pub value: SessionConfigValueId,
2186 pub name: String,
2188 #[serde(default)]
2190 pub description: Option<String>,
2191 #[serde(rename = "_meta")]
2197 pub meta: Option<Meta>,
2198}
2199
2200impl SessionConfigSelectOption {
2201 #[must_use]
2202 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2203 Self {
2204 value: value.into(),
2205 name: name.into(),
2206 description: None,
2207 meta: None,
2208 }
2209 }
2210
2211 #[must_use]
2212 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2213 self.description = description.into_option();
2214 self
2215 }
2216
2217 #[must_use]
2223 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2224 self.meta = meta.into_option();
2225 self
2226 }
2227}
2228
2229#[skip_serializing_none]
2231#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2232#[serde(rename_all = "camelCase")]
2233#[non_exhaustive]
2234pub struct SessionConfigSelectGroup {
2235 pub group: SessionConfigGroupId,
2237 pub name: String,
2239 pub options: Vec<SessionConfigSelectOption>,
2241 #[serde(rename = "_meta")]
2247 pub meta: Option<Meta>,
2248}
2249
2250impl SessionConfigSelectGroup {
2251 #[must_use]
2252 pub fn new(
2253 group: impl Into<SessionConfigGroupId>,
2254 name: impl Into<String>,
2255 options: Vec<SessionConfigSelectOption>,
2256 ) -> Self {
2257 Self {
2258 group: group.into(),
2259 name: name.into(),
2260 options,
2261 meta: None,
2262 }
2263 }
2264
2265 #[must_use]
2271 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2272 self.meta = meta.into_option();
2273 self
2274 }
2275}
2276
2277#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2279#[serde(untagged)]
2280#[non_exhaustive]
2281pub enum SessionConfigSelectOptions {
2282 Ungrouped(Vec<SessionConfigSelectOption>),
2284 Grouped(Vec<SessionConfigSelectGroup>),
2286}
2287
2288impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2289 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2290 SessionConfigSelectOptions::Ungrouped(options)
2291 }
2292}
2293
2294impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2295 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2296 SessionConfigSelectOptions::Grouped(groups)
2297 }
2298}
2299
2300#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2302#[serde(rename_all = "camelCase")]
2303#[non_exhaustive]
2304pub struct SessionConfigSelect {
2305 pub current_value: SessionConfigValueId,
2307 pub options: SessionConfigSelectOptions,
2309}
2310
2311impl SessionConfigSelect {
2312 #[must_use]
2313 pub fn new(
2314 current_value: impl Into<SessionConfigValueId>,
2315 options: impl Into<SessionConfigSelectOptions>,
2316 ) -> Self {
2317 Self {
2318 current_value: current_value.into(),
2319 options: options.into(),
2320 }
2321 }
2322}
2323
2324#[cfg(feature = "unstable_boolean_config")]
2330#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2331#[serde(rename_all = "camelCase")]
2332#[non_exhaustive]
2333pub struct SessionConfigBoolean {
2334 pub current_value: bool,
2336}
2337
2338#[cfg(feature = "unstable_boolean_config")]
2339impl SessionConfigBoolean {
2340 #[must_use]
2341 pub fn new(current_value: bool) -> Self {
2342 Self { current_value }
2343 }
2344}
2345
2346#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2356#[serde(rename_all = "snake_case")]
2357#[non_exhaustive]
2358pub enum SessionConfigOptionCategory {
2359 Mode,
2361 Model,
2363 ThoughtLevel,
2365 #[serde(untagged)]
2367 Other(String),
2368}
2369
2370#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2372#[serde(tag = "type", rename_all = "snake_case")]
2373#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2374#[non_exhaustive]
2375pub enum SessionConfigKind {
2376 Select(SessionConfigSelect),
2378 #[cfg(feature = "unstable_boolean_config")]
2384 Boolean(SessionConfigBoolean),
2385}
2386
2387#[serde_as]
2389#[skip_serializing_none]
2390#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2391#[serde(rename_all = "camelCase")]
2392#[non_exhaustive]
2393pub struct SessionConfigOption {
2394 pub id: SessionConfigId,
2396 pub name: String,
2398 #[serde(default)]
2400 pub description: Option<String>,
2401 #[serde_as(deserialize_as = "DefaultOnError")]
2403 #[serde(default)]
2404 pub category: Option<SessionConfigOptionCategory>,
2405 #[serde(flatten)]
2407 pub kind: SessionConfigKind,
2408 #[serde(rename = "_meta")]
2414 pub meta: Option<Meta>,
2415}
2416
2417impl SessionConfigOption {
2418 #[must_use]
2419 pub fn new(
2420 id: impl Into<SessionConfigId>,
2421 name: impl Into<String>,
2422 kind: SessionConfigKind,
2423 ) -> Self {
2424 Self {
2425 id: id.into(),
2426 name: name.into(),
2427 description: None,
2428 category: None,
2429 kind,
2430 meta: None,
2431 }
2432 }
2433
2434 #[must_use]
2435 pub fn select(
2436 id: impl Into<SessionConfigId>,
2437 name: impl Into<String>,
2438 current_value: impl Into<SessionConfigValueId>,
2439 options: impl Into<SessionConfigSelectOptions>,
2440 ) -> Self {
2441 Self::new(
2442 id,
2443 name,
2444 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2445 )
2446 }
2447
2448 #[cfg(feature = "unstable_boolean_config")]
2452 #[must_use]
2453 pub fn boolean(
2454 id: impl Into<SessionConfigId>,
2455 name: impl Into<String>,
2456 current_value: bool,
2457 ) -> Self {
2458 Self::new(
2459 id,
2460 name,
2461 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2462 )
2463 }
2464
2465 #[must_use]
2466 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2467 self.description = description.into_option();
2468 self
2469 }
2470
2471 #[must_use]
2472 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2473 self.category = category.into_option();
2474 self
2475 }
2476
2477 #[must_use]
2483 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2484 self.meta = meta.into_option();
2485 self
2486 }
2487}
2488
2489#[cfg(feature = "unstable_boolean_config")]
2504#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2505#[serde(tag = "type", rename_all = "snake_case")]
2506#[non_exhaustive]
2507pub enum SessionConfigOptionValue {
2508 Boolean {
2510 value: bool,
2512 },
2513 #[serde(untagged)]
2519 ValueId {
2520 value: SessionConfigValueId,
2522 },
2523}
2524
2525#[cfg(feature = "unstable_boolean_config")]
2526impl SessionConfigOptionValue {
2527 #[must_use]
2529 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2530 Self::ValueId { value: id.into() }
2531 }
2532
2533 #[must_use]
2535 pub fn boolean(val: bool) -> Self {
2536 Self::Boolean { value: val }
2537 }
2538
2539 #[must_use]
2542 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2543 match self {
2544 Self::ValueId { value } => Some(value),
2545 _ => None,
2546 }
2547 }
2548
2549 #[must_use]
2551 pub fn as_bool(&self) -> Option<bool> {
2552 match self {
2553 Self::Boolean { value } => Some(*value),
2554 _ => None,
2555 }
2556 }
2557}
2558
2559#[cfg(feature = "unstable_boolean_config")]
2560impl From<SessionConfigValueId> for SessionConfigOptionValue {
2561 fn from(value: SessionConfigValueId) -> Self {
2562 Self::ValueId { value }
2563 }
2564}
2565
2566#[cfg(feature = "unstable_boolean_config")]
2567impl From<bool> for SessionConfigOptionValue {
2568 fn from(value: bool) -> Self {
2569 Self::Boolean { value }
2570 }
2571}
2572
2573#[cfg(feature = "unstable_boolean_config")]
2574impl From<&str> for SessionConfigOptionValue {
2575 fn from(value: &str) -> Self {
2576 Self::ValueId {
2577 value: SessionConfigValueId::new(value),
2578 }
2579 }
2580}
2581
2582#[skip_serializing_none]
2584#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2585#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2586#[serde(rename_all = "camelCase")]
2587#[non_exhaustive]
2588pub struct SetSessionConfigOptionRequest {
2589 pub session_id: SessionId,
2591 pub config_id: SessionConfigId,
2593 #[cfg(feature = "unstable_boolean_config")]
2598 #[serde(flatten)]
2599 pub value: SessionConfigOptionValue,
2600 #[cfg(not(feature = "unstable_boolean_config"))]
2602 pub value: SessionConfigValueId,
2603 #[serde(rename = "_meta")]
2609 pub meta: Option<Meta>,
2610}
2611
2612impl SetSessionConfigOptionRequest {
2613 #[cfg(feature = "unstable_boolean_config")]
2614 #[must_use]
2615 pub fn new(
2616 session_id: impl Into<SessionId>,
2617 config_id: impl Into<SessionConfigId>,
2618 value: impl Into<SessionConfigOptionValue>,
2619 ) -> Self {
2620 Self {
2621 session_id: session_id.into(),
2622 config_id: config_id.into(),
2623 value: value.into(),
2624 meta: None,
2625 }
2626 }
2627
2628 #[cfg(not(feature = "unstable_boolean_config"))]
2629 #[must_use]
2630 pub fn new(
2631 session_id: impl Into<SessionId>,
2632 config_id: impl Into<SessionConfigId>,
2633 value: impl Into<SessionConfigValueId>,
2634 ) -> Self {
2635 Self {
2636 session_id: session_id.into(),
2637 config_id: config_id.into(),
2638 value: value.into(),
2639 meta: None,
2640 }
2641 }
2642
2643 #[must_use]
2649 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2650 self.meta = meta.into_option();
2651 self
2652 }
2653}
2654
2655#[serde_as]
2657#[skip_serializing_none]
2658#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2659#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2660#[serde(rename_all = "camelCase")]
2661#[non_exhaustive]
2662pub struct SetSessionConfigOptionResponse {
2663 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2665 pub config_options: Vec<SessionConfigOption>,
2666 #[serde(rename = "_meta")]
2672 pub meta: Option<Meta>,
2673}
2674
2675impl SetSessionConfigOptionResponse {
2676 #[must_use]
2677 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2678 Self {
2679 config_options,
2680 meta: None,
2681 }
2682 }
2683
2684 #[must_use]
2690 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2691 self.meta = meta.into_option();
2692 self
2693 }
2694}
2695
2696#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2705#[serde(tag = "type", rename_all = "snake_case")]
2706#[non_exhaustive]
2707pub enum McpServer {
2708 Http(McpServerHttp),
2712 Sse(McpServerSse),
2716 #[serde(untagged)]
2720 Stdio(McpServerStdio),
2721}
2722
2723#[skip_serializing_none]
2725#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2726#[serde(rename_all = "camelCase")]
2727#[non_exhaustive]
2728pub struct McpServerHttp {
2729 pub name: String,
2731 pub url: String,
2733 pub headers: Vec<HttpHeader>,
2735 #[serde(rename = "_meta")]
2741 pub meta: Option<Meta>,
2742}
2743
2744impl McpServerHttp {
2745 #[must_use]
2746 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2747 Self {
2748 name: name.into(),
2749 url: url.into(),
2750 headers: Vec::new(),
2751 meta: None,
2752 }
2753 }
2754
2755 #[must_use]
2757 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2758 self.headers = headers;
2759 self
2760 }
2761
2762 #[must_use]
2768 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2769 self.meta = meta.into_option();
2770 self
2771 }
2772}
2773
2774#[skip_serializing_none]
2776#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2777#[serde(rename_all = "camelCase")]
2778#[non_exhaustive]
2779pub struct McpServerSse {
2780 pub name: String,
2782 pub url: String,
2784 pub headers: Vec<HttpHeader>,
2786 #[serde(rename = "_meta")]
2792 pub meta: Option<Meta>,
2793}
2794
2795impl McpServerSse {
2796 #[must_use]
2797 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2798 Self {
2799 name: name.into(),
2800 url: url.into(),
2801 headers: Vec::new(),
2802 meta: None,
2803 }
2804 }
2805
2806 #[must_use]
2808 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2809 self.headers = headers;
2810 self
2811 }
2812
2813 #[must_use]
2819 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2820 self.meta = meta.into_option();
2821 self
2822 }
2823}
2824
2825#[skip_serializing_none]
2827#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2828#[serde(rename_all = "camelCase")]
2829#[non_exhaustive]
2830pub struct McpServerStdio {
2831 pub name: String,
2833 pub command: PathBuf,
2835 pub args: Vec<String>,
2837 pub env: Vec<EnvVariable>,
2839 #[serde(rename = "_meta")]
2845 pub meta: Option<Meta>,
2846}
2847
2848impl McpServerStdio {
2849 #[must_use]
2850 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2851 Self {
2852 name: name.into(),
2853 command: command.into(),
2854 args: Vec::new(),
2855 env: Vec::new(),
2856 meta: None,
2857 }
2858 }
2859
2860 #[must_use]
2862 pub fn args(mut self, args: Vec<String>) -> Self {
2863 self.args = args;
2864 self
2865 }
2866
2867 #[must_use]
2869 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2870 self.env = env;
2871 self
2872 }
2873
2874 #[must_use]
2880 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2881 self.meta = meta.into_option();
2882 self
2883 }
2884}
2885
2886#[skip_serializing_none]
2888#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2889#[serde(rename_all = "camelCase")]
2890#[non_exhaustive]
2891pub struct EnvVariable {
2892 pub name: String,
2894 pub value: String,
2896 #[serde(rename = "_meta")]
2902 pub meta: Option<Meta>,
2903}
2904
2905impl EnvVariable {
2906 #[must_use]
2907 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2908 Self {
2909 name: name.into(),
2910 value: value.into(),
2911 meta: None,
2912 }
2913 }
2914
2915 #[must_use]
2921 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2922 self.meta = meta.into_option();
2923 self
2924 }
2925}
2926
2927#[skip_serializing_none]
2929#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2930#[serde(rename_all = "camelCase")]
2931#[non_exhaustive]
2932pub struct HttpHeader {
2933 pub name: String,
2935 pub value: String,
2937 #[serde(rename = "_meta")]
2943 pub meta: Option<Meta>,
2944}
2945
2946impl HttpHeader {
2947 #[must_use]
2948 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2949 Self {
2950 name: name.into(),
2951 value: value.into(),
2952 meta: None,
2953 }
2954 }
2955
2956 #[must_use]
2962 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2963 self.meta = meta.into_option();
2964 self
2965 }
2966}
2967
2968#[skip_serializing_none]
2976#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
2977#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2978#[serde(rename_all = "camelCase")]
2979#[non_exhaustive]
2980pub struct PromptRequest {
2981 pub session_id: SessionId,
2983 #[cfg(feature = "unstable_message_id")]
2993 pub message_id: Option<String>,
2994 pub prompt: Vec<ContentBlock>,
3008 #[serde(rename = "_meta")]
3014 pub meta: Option<Meta>,
3015}
3016
3017impl PromptRequest {
3018 #[must_use]
3019 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3020 Self {
3021 session_id: session_id.into(),
3022 #[cfg(feature = "unstable_message_id")]
3023 message_id: None,
3024 prompt,
3025 meta: None,
3026 }
3027 }
3028
3029 #[cfg(feature = "unstable_message_id")]
3039 #[must_use]
3040 pub fn message_id(mut self, message_id: impl IntoOption<String>) -> Self {
3041 self.message_id = message_id.into_option();
3042 self
3043 }
3044
3045 #[must_use]
3051 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3052 self.meta = meta.into_option();
3053 self
3054 }
3055}
3056
3057#[serde_as]
3061#[skip_serializing_none]
3062#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3063#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3064#[serde(rename_all = "camelCase")]
3065#[non_exhaustive]
3066pub struct PromptResponse {
3067 #[cfg(feature = "unstable_message_id")]
3077 pub user_message_id: Option<String>,
3078 pub stop_reason: StopReason,
3080 #[cfg(feature = "unstable_session_usage")]
3086 #[serde_as(deserialize_as = "DefaultOnError")]
3087 #[serde(default)]
3088 pub usage: Option<Usage>,
3089 #[serde(rename = "_meta")]
3095 pub meta: Option<Meta>,
3096}
3097
3098impl PromptResponse {
3099 #[must_use]
3100 pub fn new(stop_reason: StopReason) -> Self {
3101 Self {
3102 #[cfg(feature = "unstable_message_id")]
3103 user_message_id: None,
3104 stop_reason,
3105 #[cfg(feature = "unstable_session_usage")]
3106 usage: None,
3107 meta: None,
3108 }
3109 }
3110
3111 #[cfg(feature = "unstable_message_id")]
3121 #[must_use]
3122 pub fn user_message_id(mut self, user_message_id: impl IntoOption<String>) -> Self {
3123 self.user_message_id = user_message_id.into_option();
3124 self
3125 }
3126
3127 #[cfg(feature = "unstable_session_usage")]
3133 #[must_use]
3134 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3135 self.usage = usage.into_option();
3136 self
3137 }
3138
3139 #[must_use]
3145 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3146 self.meta = meta.into_option();
3147 self
3148 }
3149}
3150
3151#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3155#[serde(rename_all = "snake_case")]
3156#[non_exhaustive]
3157pub enum StopReason {
3158 EndTurn,
3160 MaxTokens,
3162 MaxTurnRequests,
3165 Refusal,
3169 Cancelled,
3176}
3177
3178#[cfg(feature = "unstable_session_usage")]
3184#[skip_serializing_none]
3185#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3186#[serde(rename_all = "camelCase")]
3187#[non_exhaustive]
3188pub struct Usage {
3189 pub total_tokens: u64,
3191 pub input_tokens: u64,
3193 pub output_tokens: u64,
3195 pub thought_tokens: Option<u64>,
3197 pub cached_read_tokens: Option<u64>,
3199 pub cached_write_tokens: Option<u64>,
3201}
3202
3203#[cfg(feature = "unstable_session_usage")]
3204impl Usage {
3205 #[must_use]
3206 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3207 Self {
3208 total_tokens,
3209 input_tokens,
3210 output_tokens,
3211 thought_tokens: None,
3212 cached_read_tokens: None,
3213 cached_write_tokens: None,
3214 }
3215 }
3216
3217 #[must_use]
3219 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3220 self.thought_tokens = thought_tokens.into_option();
3221 self
3222 }
3223
3224 #[must_use]
3226 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3227 self.cached_read_tokens = cached_read_tokens.into_option();
3228 self
3229 }
3230
3231 #[must_use]
3233 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3234 self.cached_write_tokens = cached_write_tokens.into_option();
3235 self
3236 }
3237}
3238
3239#[cfg(feature = "unstable_session_model")]
3247#[serde_as]
3248#[skip_serializing_none]
3249#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3250#[serde(rename_all = "camelCase")]
3251#[non_exhaustive]
3252pub struct SessionModelState {
3253 pub current_model_id: ModelId,
3255 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3257 pub available_models: Vec<ModelInfo>,
3258 #[serde(rename = "_meta")]
3264 pub meta: Option<Meta>,
3265}
3266
3267#[cfg(feature = "unstable_session_model")]
3268impl SessionModelState {
3269 #[must_use]
3270 pub fn new(current_model_id: impl Into<ModelId>, available_models: Vec<ModelInfo>) -> Self {
3271 Self {
3272 current_model_id: current_model_id.into(),
3273 available_models,
3274 meta: None,
3275 }
3276 }
3277
3278 #[must_use]
3284 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3285 self.meta = meta.into_option();
3286 self
3287 }
3288}
3289
3290#[cfg(feature = "unstable_session_model")]
3296#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
3297#[serde(transparent)]
3298#[from(Arc<str>, String, &'static str)]
3299#[non_exhaustive]
3300pub struct ModelId(pub Arc<str>);
3301
3302#[cfg(feature = "unstable_session_model")]
3303impl ModelId {
3304 #[must_use]
3305 pub fn new(id: impl Into<Arc<str>>) -> Self {
3306 Self(id.into())
3307 }
3308}
3309
3310#[cfg(feature = "unstable_session_model")]
3316#[skip_serializing_none]
3317#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3318#[serde(rename_all = "camelCase")]
3319#[non_exhaustive]
3320pub struct ModelInfo {
3321 pub model_id: ModelId,
3323 pub name: String,
3325 #[serde(default)]
3327 pub description: Option<String>,
3328 #[serde(rename = "_meta")]
3334 pub meta: Option<Meta>,
3335}
3336
3337#[cfg(feature = "unstable_session_model")]
3338impl ModelInfo {
3339 #[must_use]
3340 pub fn new(model_id: impl Into<ModelId>, name: impl Into<String>) -> Self {
3341 Self {
3342 model_id: model_id.into(),
3343 name: name.into(),
3344 description: None,
3345 meta: None,
3346 }
3347 }
3348
3349 #[must_use]
3351 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
3352 self.description = description.into_option();
3353 self
3354 }
3355
3356 #[must_use]
3362 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3363 self.meta = meta.into_option();
3364 self
3365 }
3366}
3367
3368#[cfg(feature = "unstable_session_model")]
3374#[skip_serializing_none]
3375#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3376#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3377#[serde(rename_all = "camelCase")]
3378#[non_exhaustive]
3379pub struct SetSessionModelRequest {
3380 pub session_id: SessionId,
3382 pub model_id: ModelId,
3384 #[serde(rename = "_meta")]
3390 pub meta: Option<Meta>,
3391}
3392
3393#[cfg(feature = "unstable_session_model")]
3394impl SetSessionModelRequest {
3395 #[must_use]
3396 pub fn new(session_id: impl Into<SessionId>, model_id: impl Into<ModelId>) -> Self {
3397 Self {
3398 session_id: session_id.into(),
3399 model_id: model_id.into(),
3400 meta: None,
3401 }
3402 }
3403
3404 #[must_use]
3410 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3411 self.meta = meta.into_option();
3412 self
3413 }
3414}
3415
3416#[cfg(feature = "unstable_session_model")]
3422#[skip_serializing_none]
3423#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3424#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3425#[serde(rename_all = "camelCase")]
3426#[non_exhaustive]
3427pub struct SetSessionModelResponse {
3428 #[serde(rename = "_meta")]
3434 pub meta: Option<Meta>,
3435}
3436
3437#[cfg(feature = "unstable_session_model")]
3438impl SetSessionModelResponse {
3439 #[must_use]
3440 pub fn new() -> Self {
3441 Self::default()
3442 }
3443
3444 #[must_use]
3450 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3451 self.meta = meta.into_option();
3452 self
3453 }
3454}
3455
3456#[cfg(feature = "unstable_llm_providers")]
3469#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3470#[serde(rename_all = "snake_case")]
3471#[non_exhaustive]
3472#[expect(clippy::doc_markdown)]
3473pub enum LlmProtocol {
3474 Anthropic,
3476 #[serde(rename = "openai")]
3478 OpenAi,
3479 Azure,
3481 Vertex,
3483 Bedrock,
3485 #[serde(untagged)]
3487 Other(String),
3488}
3489
3490#[cfg(feature = "unstable_llm_providers")]
3496#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3497#[serde(rename_all = "camelCase")]
3498#[non_exhaustive]
3499pub struct ProviderCurrentConfig {
3500 pub api_type: LlmProtocol,
3502 pub base_url: String,
3504}
3505
3506#[cfg(feature = "unstable_llm_providers")]
3507impl ProviderCurrentConfig {
3508 #[must_use]
3509 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3510 Self {
3511 api_type,
3512 base_url: base_url.into(),
3513 }
3514 }
3515}
3516
3517#[cfg(feature = "unstable_llm_providers")]
3523#[serde_as]
3524#[skip_serializing_none]
3525#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3526#[serde(rename_all = "camelCase")]
3527#[non_exhaustive]
3528pub struct ProviderInfo {
3529 pub id: String,
3531 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3533 pub supported: Vec<LlmProtocol>,
3534 pub required: bool,
3537 pub current: Option<ProviderCurrentConfig>,
3540 #[serde(rename = "_meta")]
3546 pub meta: Option<Meta>,
3547}
3548
3549#[cfg(feature = "unstable_llm_providers")]
3550impl ProviderInfo {
3551 #[must_use]
3552 pub fn new(
3553 id: impl Into<String>,
3554 supported: Vec<LlmProtocol>,
3555 required: bool,
3556 current: impl IntoOption<ProviderCurrentConfig>,
3557 ) -> Self {
3558 Self {
3559 id: id.into(),
3560 supported,
3561 required,
3562 current: current.into_option(),
3563 meta: None,
3564 }
3565 }
3566
3567 #[must_use]
3573 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3574 self.meta = meta.into_option();
3575 self
3576 }
3577}
3578
3579#[cfg(feature = "unstable_llm_providers")]
3585#[skip_serializing_none]
3586#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3587#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3588#[serde(rename_all = "camelCase")]
3589#[non_exhaustive]
3590pub struct ListProvidersRequest {
3591 #[serde(rename = "_meta")]
3597 pub meta: Option<Meta>,
3598}
3599
3600#[cfg(feature = "unstable_llm_providers")]
3601impl ListProvidersRequest {
3602 #[must_use]
3603 pub fn new() -> Self {
3604 Self::default()
3605 }
3606
3607 #[must_use]
3613 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3614 self.meta = meta.into_option();
3615 self
3616 }
3617}
3618
3619#[cfg(feature = "unstable_llm_providers")]
3625#[serde_as]
3626#[skip_serializing_none]
3627#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3628#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3629#[serde(rename_all = "camelCase")]
3630#[non_exhaustive]
3631pub struct ListProvidersResponse {
3632 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3634 pub providers: Vec<ProviderInfo>,
3635 #[serde(rename = "_meta")]
3641 pub meta: Option<Meta>,
3642}
3643
3644#[cfg(feature = "unstable_llm_providers")]
3645impl ListProvidersResponse {
3646 #[must_use]
3647 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3648 Self {
3649 providers,
3650 meta: None,
3651 }
3652 }
3653
3654 #[must_use]
3660 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3661 self.meta = meta.into_option();
3662 self
3663 }
3664}
3665
3666#[cfg(feature = "unstable_llm_providers")]
3674#[skip_serializing_none]
3675#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3676#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3677#[serde(rename_all = "camelCase")]
3678#[non_exhaustive]
3679pub struct SetProvidersRequest {
3680 pub id: String,
3682 pub api_type: LlmProtocol,
3684 pub base_url: String,
3686 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3689 pub headers: HashMap<String, String>,
3690 #[serde(rename = "_meta")]
3696 pub meta: Option<Meta>,
3697}
3698
3699#[cfg(feature = "unstable_llm_providers")]
3700impl SetProvidersRequest {
3701 #[must_use]
3702 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3703 Self {
3704 id: id.into(),
3705 api_type,
3706 base_url: base_url.into(),
3707 headers: HashMap::new(),
3708 meta: None,
3709 }
3710 }
3711
3712 #[must_use]
3715 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3716 self.headers = headers;
3717 self
3718 }
3719
3720 #[must_use]
3726 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3727 self.meta = meta.into_option();
3728 self
3729 }
3730}
3731
3732#[cfg(feature = "unstable_llm_providers")]
3738#[skip_serializing_none]
3739#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3740#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3741#[serde(rename_all = "camelCase")]
3742#[non_exhaustive]
3743pub struct SetProvidersResponse {
3744 #[serde(rename = "_meta")]
3750 pub meta: Option<Meta>,
3751}
3752
3753#[cfg(feature = "unstable_llm_providers")]
3754impl SetProvidersResponse {
3755 #[must_use]
3756 pub fn new() -> Self {
3757 Self::default()
3758 }
3759
3760 #[must_use]
3766 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3767 self.meta = meta.into_option();
3768 self
3769 }
3770}
3771
3772#[cfg(feature = "unstable_llm_providers")]
3778#[skip_serializing_none]
3779#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3780#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3781#[serde(rename_all = "camelCase")]
3782#[non_exhaustive]
3783pub struct DisableProvidersRequest {
3784 pub id: String,
3786 #[serde(rename = "_meta")]
3792 pub meta: Option<Meta>,
3793}
3794
3795#[cfg(feature = "unstable_llm_providers")]
3796impl DisableProvidersRequest {
3797 #[must_use]
3798 pub fn new(id: impl Into<String>) -> Self {
3799 Self {
3800 id: id.into(),
3801 meta: None,
3802 }
3803 }
3804
3805 #[must_use]
3811 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3812 self.meta = meta.into_option();
3813 self
3814 }
3815}
3816
3817#[cfg(feature = "unstable_llm_providers")]
3823#[skip_serializing_none]
3824#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3825#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3826#[serde(rename_all = "camelCase")]
3827#[non_exhaustive]
3828pub struct DisableProvidersResponse {
3829 #[serde(rename = "_meta")]
3835 pub meta: Option<Meta>,
3836}
3837
3838#[cfg(feature = "unstable_llm_providers")]
3839impl DisableProvidersResponse {
3840 #[must_use]
3841 pub fn new() -> Self {
3842 Self::default()
3843 }
3844
3845 #[must_use]
3851 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3852 self.meta = meta.into_option();
3853 self
3854 }
3855}
3856
3857#[serde_as]
3866#[skip_serializing_none]
3867#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3868#[serde(rename_all = "camelCase")]
3869#[non_exhaustive]
3870pub struct AgentCapabilities {
3871 #[serde(default)]
3873 pub load_session: bool,
3874 #[serde(default)]
3876 pub prompt_capabilities: PromptCapabilities,
3877 #[serde(default)]
3879 pub mcp_capabilities: McpCapabilities,
3880 #[serde(default)]
3881 pub session_capabilities: SessionCapabilities,
3882 #[cfg(feature = "unstable_logout")]
3888 #[serde(default)]
3889 pub auth: AgentAuthCapabilities,
3890 #[cfg(feature = "unstable_llm_providers")]
3898 #[serde_as(deserialize_as = "DefaultOnError")]
3899 #[serde(default)]
3900 pub providers: Option<ProvidersCapabilities>,
3901 #[cfg(feature = "unstable_nes")]
3907 #[serde_as(deserialize_as = "DefaultOnError")]
3908 #[serde(default)]
3909 pub nes: Option<NesCapabilities>,
3910 #[cfg(feature = "unstable_nes")]
3916 #[serde_as(deserialize_as = "DefaultOnError")]
3917 #[serde(default)]
3918 pub position_encoding: Option<PositionEncodingKind>,
3919 #[serde(rename = "_meta")]
3925 pub meta: Option<Meta>,
3926}
3927
3928impl AgentCapabilities {
3929 #[must_use]
3930 pub fn new() -> Self {
3931 Self::default()
3932 }
3933
3934 #[must_use]
3936 pub fn load_session(mut self, load_session: bool) -> Self {
3937 self.load_session = load_session;
3938 self
3939 }
3940
3941 #[must_use]
3943 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3944 self.prompt_capabilities = prompt_capabilities;
3945 self
3946 }
3947
3948 #[must_use]
3950 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3951 self.mcp_capabilities = mcp_capabilities;
3952 self
3953 }
3954
3955 #[must_use]
3957 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3958 self.session_capabilities = session_capabilities;
3959 self
3960 }
3961
3962 #[cfg(feature = "unstable_logout")]
3968 #[must_use]
3969 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3970 self.auth = auth;
3971 self
3972 }
3973
3974 #[cfg(feature = "unstable_llm_providers")]
3980 #[must_use]
3981 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3982 self.providers = providers.into_option();
3983 self
3984 }
3985
3986 #[cfg(feature = "unstable_nes")]
3992 #[must_use]
3993 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3994 self.nes = nes.into_option();
3995 self
3996 }
3997
3998 #[cfg(feature = "unstable_nes")]
4002 #[must_use]
4003 pub fn position_encoding(
4004 mut self,
4005 position_encoding: impl IntoOption<PositionEncodingKind>,
4006 ) -> Self {
4007 self.position_encoding = position_encoding.into_option();
4008 self
4009 }
4010
4011 #[must_use]
4017 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4018 self.meta = meta.into_option();
4019 self
4020 }
4021}
4022
4023#[cfg(feature = "unstable_llm_providers")]
4031#[skip_serializing_none]
4032#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4033#[non_exhaustive]
4034pub struct ProvidersCapabilities {
4035 #[serde(rename = "_meta")]
4041 pub meta: Option<Meta>,
4042}
4043
4044#[cfg(feature = "unstable_llm_providers")]
4045impl ProvidersCapabilities {
4046 #[must_use]
4047 pub fn new() -> Self {
4048 Self::default()
4049 }
4050
4051 #[must_use]
4057 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4058 self.meta = meta.into_option();
4059 self
4060 }
4061}
4062
4063#[serde_as]
4073#[skip_serializing_none]
4074#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4075#[serde(rename_all = "camelCase")]
4076#[non_exhaustive]
4077pub struct SessionCapabilities {
4078 #[serde_as(deserialize_as = "DefaultOnError")]
4080 #[serde(default)]
4081 pub list: Option<SessionListCapabilities>,
4082 #[cfg(feature = "unstable_session_additional_directories")]
4088 #[serde_as(deserialize_as = "DefaultOnError")]
4089 #[serde(default)]
4090 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
4091 #[cfg(feature = "unstable_session_fork")]
4097 #[serde_as(deserialize_as = "DefaultOnError")]
4098 #[serde(default)]
4099 pub fork: Option<SessionForkCapabilities>,
4100 #[cfg(feature = "unstable_session_resume")]
4106 #[serde_as(deserialize_as = "DefaultOnError")]
4107 #[serde(default)]
4108 pub resume: Option<SessionResumeCapabilities>,
4109 #[cfg(feature = "unstable_session_close")]
4115 #[serde_as(deserialize_as = "DefaultOnError")]
4116 #[serde(default)]
4117 pub close: Option<SessionCloseCapabilities>,
4118 #[serde(rename = "_meta")]
4124 pub meta: Option<Meta>,
4125}
4126
4127impl SessionCapabilities {
4128 #[must_use]
4129 pub fn new() -> Self {
4130 Self::default()
4131 }
4132
4133 #[must_use]
4135 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
4136 self.list = list.into_option();
4137 self
4138 }
4139
4140 #[cfg(feature = "unstable_session_additional_directories")]
4146 #[must_use]
4147 pub fn additional_directories(
4148 mut self,
4149 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4150 ) -> Self {
4151 self.additional_directories = additional_directories.into_option();
4152 self
4153 }
4154
4155 #[cfg(feature = "unstable_session_fork")]
4156 #[must_use]
4158 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4159 self.fork = fork.into_option();
4160 self
4161 }
4162
4163 #[cfg(feature = "unstable_session_resume")]
4164 #[must_use]
4166 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4167 self.resume = resume.into_option();
4168 self
4169 }
4170
4171 #[cfg(feature = "unstable_session_close")]
4172 #[must_use]
4174 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4175 self.close = close.into_option();
4176 self
4177 }
4178
4179 #[must_use]
4185 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4186 self.meta = meta.into_option();
4187 self
4188 }
4189}
4190
4191#[skip_serializing_none]
4195#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4196#[non_exhaustive]
4197pub struct SessionListCapabilities {
4198 #[serde(rename = "_meta")]
4204 pub meta: Option<Meta>,
4205}
4206
4207impl SessionListCapabilities {
4208 #[must_use]
4209 pub fn new() -> Self {
4210 Self::default()
4211 }
4212
4213 #[must_use]
4219 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4220 self.meta = meta.into_option();
4221 self
4222 }
4223}
4224
4225#[cfg(feature = "unstable_session_additional_directories")]
4234#[skip_serializing_none]
4235#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4236#[non_exhaustive]
4237pub struct SessionAdditionalDirectoriesCapabilities {
4238 #[serde(rename = "_meta")]
4244 pub meta: Option<Meta>,
4245}
4246
4247#[cfg(feature = "unstable_session_additional_directories")]
4248impl SessionAdditionalDirectoriesCapabilities {
4249 #[must_use]
4250 pub fn new() -> Self {
4251 Self::default()
4252 }
4253
4254 #[must_use]
4260 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4261 self.meta = meta.into_option();
4262 self
4263 }
4264}
4265
4266#[cfg(feature = "unstable_session_fork")]
4274#[skip_serializing_none]
4275#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4276#[non_exhaustive]
4277pub struct SessionForkCapabilities {
4278 #[serde(rename = "_meta")]
4284 pub meta: Option<Meta>,
4285}
4286
4287#[cfg(feature = "unstable_session_fork")]
4288impl SessionForkCapabilities {
4289 #[must_use]
4290 pub fn new() -> Self {
4291 Self::default()
4292 }
4293
4294 #[must_use]
4300 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4301 self.meta = meta.into_option();
4302 self
4303 }
4304}
4305
4306#[cfg(feature = "unstable_session_resume")]
4314#[skip_serializing_none]
4315#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4316#[non_exhaustive]
4317pub struct SessionResumeCapabilities {
4318 #[serde(rename = "_meta")]
4324 pub meta: Option<Meta>,
4325}
4326
4327#[cfg(feature = "unstable_session_resume")]
4328impl SessionResumeCapabilities {
4329 #[must_use]
4330 pub fn new() -> Self {
4331 Self::default()
4332 }
4333
4334 #[must_use]
4340 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4341 self.meta = meta.into_option();
4342 self
4343 }
4344}
4345
4346#[cfg(feature = "unstable_session_close")]
4354#[skip_serializing_none]
4355#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4356#[non_exhaustive]
4357pub struct SessionCloseCapabilities {
4358 #[serde(rename = "_meta")]
4364 pub meta: Option<Meta>,
4365}
4366
4367#[cfg(feature = "unstable_session_close")]
4368impl SessionCloseCapabilities {
4369 #[must_use]
4370 pub fn new() -> Self {
4371 Self::default()
4372 }
4373
4374 #[must_use]
4380 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4381 self.meta = meta.into_option();
4382 self
4383 }
4384}
4385
4386#[skip_serializing_none]
4399#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4400#[serde(rename_all = "camelCase")]
4401#[non_exhaustive]
4402pub struct PromptCapabilities {
4403 #[serde(default)]
4405 pub image: bool,
4406 #[serde(default)]
4408 pub audio: bool,
4409 #[serde(default)]
4414 pub embedded_context: bool,
4415 #[serde(rename = "_meta")]
4421 pub meta: Option<Meta>,
4422}
4423
4424impl PromptCapabilities {
4425 #[must_use]
4426 pub fn new() -> Self {
4427 Self::default()
4428 }
4429
4430 #[must_use]
4432 pub fn image(mut self, image: bool) -> Self {
4433 self.image = image;
4434 self
4435 }
4436
4437 #[must_use]
4439 pub fn audio(mut self, audio: bool) -> Self {
4440 self.audio = audio;
4441 self
4442 }
4443
4444 #[must_use]
4449 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4450 self.embedded_context = embedded_context;
4451 self
4452 }
4453
4454 #[must_use]
4460 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4461 self.meta = meta.into_option();
4462 self
4463 }
4464}
4465
4466#[skip_serializing_none]
4468#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4469#[serde(rename_all = "camelCase")]
4470#[non_exhaustive]
4471pub struct McpCapabilities {
4472 #[serde(default)]
4474 pub http: bool,
4475 #[serde(default)]
4477 pub sse: bool,
4478 #[serde(rename = "_meta")]
4484 pub meta: Option<Meta>,
4485}
4486
4487impl McpCapabilities {
4488 #[must_use]
4489 pub fn new() -> Self {
4490 Self::default()
4491 }
4492
4493 #[must_use]
4495 pub fn http(mut self, http: bool) -> Self {
4496 self.http = http;
4497 self
4498 }
4499
4500 #[must_use]
4502 pub fn sse(mut self, sse: bool) -> Self {
4503 self.sse = sse;
4504 self
4505 }
4506
4507 #[must_use]
4513 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4514 self.meta = meta.into_option();
4515 self
4516 }
4517}
4518
4519#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4525#[non_exhaustive]
4526pub struct AgentMethodNames {
4527 pub initialize: &'static str,
4529 pub authenticate: &'static str,
4531 #[cfg(feature = "unstable_llm_providers")]
4533 pub providers_list: &'static str,
4534 #[cfg(feature = "unstable_llm_providers")]
4536 pub providers_set: &'static str,
4537 #[cfg(feature = "unstable_llm_providers")]
4539 pub providers_disable: &'static str,
4540 pub session_new: &'static str,
4542 pub session_load: &'static str,
4544 pub session_set_mode: &'static str,
4546 pub session_set_config_option: &'static str,
4548 pub session_prompt: &'static str,
4550 pub session_cancel: &'static str,
4552 #[cfg(feature = "unstable_session_model")]
4554 pub session_set_model: &'static str,
4555 pub session_list: &'static str,
4557 #[cfg(feature = "unstable_session_fork")]
4559 pub session_fork: &'static str,
4560 #[cfg(feature = "unstable_session_resume")]
4562 pub session_resume: &'static str,
4563 #[cfg(feature = "unstable_session_close")]
4565 pub session_close: &'static str,
4566 #[cfg(feature = "unstable_logout")]
4568 pub logout: &'static str,
4569 #[cfg(feature = "unstable_nes")]
4571 pub nes_start: &'static str,
4572 #[cfg(feature = "unstable_nes")]
4574 pub nes_suggest: &'static str,
4575 #[cfg(feature = "unstable_nes")]
4577 pub nes_accept: &'static str,
4578 #[cfg(feature = "unstable_nes")]
4580 pub nes_reject: &'static str,
4581 #[cfg(feature = "unstable_nes")]
4583 pub nes_close: &'static str,
4584 #[cfg(feature = "unstable_nes")]
4586 pub document_did_open: &'static str,
4587 #[cfg(feature = "unstable_nes")]
4589 pub document_did_change: &'static str,
4590 #[cfg(feature = "unstable_nes")]
4592 pub document_did_close: &'static str,
4593 #[cfg(feature = "unstable_nes")]
4595 pub document_did_save: &'static str,
4596 #[cfg(feature = "unstable_nes")]
4598 pub document_did_focus: &'static str,
4599}
4600
4601pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4603 initialize: INITIALIZE_METHOD_NAME,
4604 authenticate: AUTHENTICATE_METHOD_NAME,
4605 #[cfg(feature = "unstable_llm_providers")]
4606 providers_list: PROVIDERS_LIST_METHOD_NAME,
4607 #[cfg(feature = "unstable_llm_providers")]
4608 providers_set: PROVIDERS_SET_METHOD_NAME,
4609 #[cfg(feature = "unstable_llm_providers")]
4610 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4611 session_new: SESSION_NEW_METHOD_NAME,
4612 session_load: SESSION_LOAD_METHOD_NAME,
4613 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4614 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4615 session_prompt: SESSION_PROMPT_METHOD_NAME,
4616 session_cancel: SESSION_CANCEL_METHOD_NAME,
4617 #[cfg(feature = "unstable_session_model")]
4618 session_set_model: SESSION_SET_MODEL_METHOD_NAME,
4619 session_list: SESSION_LIST_METHOD_NAME,
4620 #[cfg(feature = "unstable_session_fork")]
4621 session_fork: SESSION_FORK_METHOD_NAME,
4622 #[cfg(feature = "unstable_session_resume")]
4623 session_resume: SESSION_RESUME_METHOD_NAME,
4624 #[cfg(feature = "unstable_session_close")]
4625 session_close: SESSION_CLOSE_METHOD_NAME,
4626 #[cfg(feature = "unstable_logout")]
4627 logout: LOGOUT_METHOD_NAME,
4628 #[cfg(feature = "unstable_nes")]
4629 nes_start: NES_START_METHOD_NAME,
4630 #[cfg(feature = "unstable_nes")]
4631 nes_suggest: NES_SUGGEST_METHOD_NAME,
4632 #[cfg(feature = "unstable_nes")]
4633 nes_accept: NES_ACCEPT_METHOD_NAME,
4634 #[cfg(feature = "unstable_nes")]
4635 nes_reject: NES_REJECT_METHOD_NAME,
4636 #[cfg(feature = "unstable_nes")]
4637 nes_close: NES_CLOSE_METHOD_NAME,
4638 #[cfg(feature = "unstable_nes")]
4639 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4640 #[cfg(feature = "unstable_nes")]
4641 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4642 #[cfg(feature = "unstable_nes")]
4643 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4644 #[cfg(feature = "unstable_nes")]
4645 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4646 #[cfg(feature = "unstable_nes")]
4647 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4648};
4649
4650pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4652pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4654#[cfg(feature = "unstable_llm_providers")]
4656pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4657#[cfg(feature = "unstable_llm_providers")]
4659pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4660#[cfg(feature = "unstable_llm_providers")]
4662pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4663pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4665pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4667pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4669pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4671pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4673pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4675#[cfg(feature = "unstable_session_model")]
4677pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
4678pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4680#[cfg(feature = "unstable_session_fork")]
4682pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4683#[cfg(feature = "unstable_session_resume")]
4685pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4686#[cfg(feature = "unstable_session_close")]
4688pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4689#[cfg(feature = "unstable_logout")]
4691pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4692
4693#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4700#[serde(untagged)]
4701#[schemars(inline)]
4702#[non_exhaustive]
4703#[allow(clippy::large_enum_variant)]
4704pub enum ClientRequest {
4705 InitializeRequest(InitializeRequest),
4716 AuthenticateRequest(AuthenticateRequest),
4726 #[cfg(feature = "unstable_llm_providers")]
4732 ListProvidersRequest(ListProvidersRequest),
4733 #[cfg(feature = "unstable_llm_providers")]
4739 SetProvidersRequest(SetProvidersRequest),
4740 #[cfg(feature = "unstable_llm_providers")]
4746 DisableProvidersRequest(DisableProvidersRequest),
4747 #[cfg(feature = "unstable_logout")]
4756 LogoutRequest(LogoutRequest),
4757 NewSessionRequest(NewSessionRequest),
4770 LoadSessionRequest(LoadSessionRequest),
4781 ListSessionsRequest(ListSessionsRequest),
4787 #[cfg(feature = "unstable_session_fork")]
4788 ForkSessionRequest(ForkSessionRequest),
4800 #[cfg(feature = "unstable_session_resume")]
4801 ResumeSessionRequest(ResumeSessionRequest),
4812 #[cfg(feature = "unstable_session_close")]
4813 CloseSessionRequest(CloseSessionRequest),
4824 SetSessionModeRequest(SetSessionModeRequest),
4838 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4840 PromptRequest(PromptRequest),
4852 #[cfg(feature = "unstable_session_model")]
4853 SetSessionModelRequest(SetSessionModelRequest),
4859 #[cfg(feature = "unstable_nes")]
4860 StartNesRequest(StartNesRequest),
4866 #[cfg(feature = "unstable_nes")]
4867 SuggestNesRequest(SuggestNesRequest),
4873 #[cfg(feature = "unstable_nes")]
4874 CloseNesRequest(CloseNesRequest),
4883 ExtMethodRequest(ExtRequest),
4890}
4891
4892impl ClientRequest {
4893 #[must_use]
4895 pub fn method(&self) -> &str {
4896 match self {
4897 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4898 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4899 #[cfg(feature = "unstable_llm_providers")]
4900 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4901 #[cfg(feature = "unstable_llm_providers")]
4902 Self::SetProvidersRequest(_) => AGENT_METHOD_NAMES.providers_set,
4903 #[cfg(feature = "unstable_llm_providers")]
4904 Self::DisableProvidersRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4905 #[cfg(feature = "unstable_logout")]
4906 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4907 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4908 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4909 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4910 #[cfg(feature = "unstable_session_fork")]
4911 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
4912 #[cfg(feature = "unstable_session_resume")]
4913 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
4914 #[cfg(feature = "unstable_session_close")]
4915 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
4916 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
4917 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
4918 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
4919 #[cfg(feature = "unstable_session_model")]
4920 Self::SetSessionModelRequest(_) => AGENT_METHOD_NAMES.session_set_model,
4921 #[cfg(feature = "unstable_nes")]
4922 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
4923 #[cfg(feature = "unstable_nes")]
4924 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
4925 #[cfg(feature = "unstable_nes")]
4926 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
4927 Self::ExtMethodRequest(ext_request) => &ext_request.method,
4928 }
4929 }
4930}
4931
4932#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4939#[serde(untagged)]
4940#[schemars(inline)]
4941#[non_exhaustive]
4942#[allow(clippy::large_enum_variant)]
4943pub enum AgentResponse {
4944 InitializeResponse(InitializeResponse),
4945 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
4946 #[cfg(feature = "unstable_llm_providers")]
4947 ListProvidersResponse(ListProvidersResponse),
4948 #[cfg(feature = "unstable_llm_providers")]
4949 SetProvidersResponse(#[serde(default)] SetProvidersResponse),
4950 #[cfg(feature = "unstable_llm_providers")]
4951 DisableProvidersResponse(#[serde(default)] DisableProvidersResponse),
4952 #[cfg(feature = "unstable_logout")]
4953 LogoutResponse(#[serde(default)] LogoutResponse),
4954 NewSessionResponse(NewSessionResponse),
4955 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
4956 ListSessionsResponse(ListSessionsResponse),
4957 #[cfg(feature = "unstable_session_fork")]
4958 ForkSessionResponse(ForkSessionResponse),
4959 #[cfg(feature = "unstable_session_resume")]
4960 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
4961 #[cfg(feature = "unstable_session_close")]
4962 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
4963 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
4964 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
4965 PromptResponse(PromptResponse),
4966 #[cfg(feature = "unstable_session_model")]
4967 SetSessionModelResponse(#[serde(default)] SetSessionModelResponse),
4968 #[cfg(feature = "unstable_nes")]
4969 StartNesResponse(StartNesResponse),
4970 #[cfg(feature = "unstable_nes")]
4971 SuggestNesResponse(SuggestNesResponse),
4972 #[cfg(feature = "unstable_nes")]
4973 CloseNesResponse(#[serde(default)] CloseNesResponse),
4974 ExtMethodResponse(ExtResponse),
4975}
4976
4977#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4984#[serde(untagged)]
4985#[schemars(inline)]
4986#[non_exhaustive]
4987pub enum ClientNotification {
4988 CancelNotification(CancelNotification),
5000 #[cfg(feature = "unstable_nes")]
5001 DidOpenDocumentNotification(DidOpenDocumentNotification),
5005 #[cfg(feature = "unstable_nes")]
5006 DidChangeDocumentNotification(DidChangeDocumentNotification),
5010 #[cfg(feature = "unstable_nes")]
5011 DidCloseDocumentNotification(DidCloseDocumentNotification),
5015 #[cfg(feature = "unstable_nes")]
5016 DidSaveDocumentNotification(DidSaveDocumentNotification),
5020 #[cfg(feature = "unstable_nes")]
5021 DidFocusDocumentNotification(DidFocusDocumentNotification),
5025 #[cfg(feature = "unstable_nes")]
5026 AcceptNesNotification(AcceptNesNotification),
5030 #[cfg(feature = "unstable_nes")]
5031 RejectNesNotification(RejectNesNotification),
5035 ExtNotification(ExtNotification),
5042}
5043
5044impl ClientNotification {
5045 #[must_use]
5047 pub fn method(&self) -> &str {
5048 match self {
5049 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5050 #[cfg(feature = "unstable_nes")]
5051 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5052 #[cfg(feature = "unstable_nes")]
5053 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5054 #[cfg(feature = "unstable_nes")]
5055 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5056 #[cfg(feature = "unstable_nes")]
5057 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5058 #[cfg(feature = "unstable_nes")]
5059 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5060 #[cfg(feature = "unstable_nes")]
5061 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5062 #[cfg(feature = "unstable_nes")]
5063 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5064 Self::ExtNotification(ext_notification) => &ext_notification.method,
5065 }
5066 }
5067}
5068
5069#[skip_serializing_none]
5073#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5074#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5075#[serde(rename_all = "camelCase")]
5076#[non_exhaustive]
5077pub struct CancelNotification {
5078 pub session_id: SessionId,
5080 #[serde(rename = "_meta")]
5086 pub meta: Option<Meta>,
5087}
5088
5089impl CancelNotification {
5090 #[must_use]
5091 pub fn new(session_id: impl Into<SessionId>) -> Self {
5092 Self {
5093 session_id: session_id.into(),
5094 meta: None,
5095 }
5096 }
5097
5098 #[must_use]
5104 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5105 self.meta = meta.into_option();
5106 self
5107 }
5108}
5109
5110#[cfg(test)]
5111mod test_serialization {
5112 use super::*;
5113 use serde_json::json;
5114
5115 #[test]
5116 fn test_mcp_server_stdio_serialization() {
5117 let server = McpServer::Stdio(
5118 McpServerStdio::new("test-server", "/usr/bin/server")
5119 .args(vec!["--port".to_string(), "3000".to_string()])
5120 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5121 );
5122
5123 let json = serde_json::to_value(&server).unwrap();
5124 assert_eq!(
5125 json,
5126 json!({
5127 "name": "test-server",
5128 "command": "/usr/bin/server",
5129 "args": ["--port", "3000"],
5130 "env": [
5131 {
5132 "name": "API_KEY",
5133 "value": "secret123"
5134 }
5135 ]
5136 })
5137 );
5138
5139 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5140 match deserialized {
5141 McpServer::Stdio(McpServerStdio {
5142 name,
5143 command,
5144 args,
5145 env,
5146 meta: _,
5147 }) => {
5148 assert_eq!(name, "test-server");
5149 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5150 assert_eq!(args, vec!["--port", "3000"]);
5151 assert_eq!(env.len(), 1);
5152 assert_eq!(env[0].name, "API_KEY");
5153 assert_eq!(env[0].value, "secret123");
5154 }
5155 _ => panic!("Expected Stdio variant"),
5156 }
5157 }
5158
5159 #[test]
5160 fn test_mcp_server_http_serialization() {
5161 let server = McpServer::Http(
5162 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5163 HttpHeader::new("Authorization", "Bearer token123"),
5164 HttpHeader::new("Content-Type", "application/json"),
5165 ]),
5166 );
5167
5168 let json = serde_json::to_value(&server).unwrap();
5169 assert_eq!(
5170 json,
5171 json!({
5172 "type": "http",
5173 "name": "http-server",
5174 "url": "https://api.example.com",
5175 "headers": [
5176 {
5177 "name": "Authorization",
5178 "value": "Bearer token123"
5179 },
5180 {
5181 "name": "Content-Type",
5182 "value": "application/json"
5183 }
5184 ]
5185 })
5186 );
5187
5188 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5189 match deserialized {
5190 McpServer::Http(McpServerHttp {
5191 name,
5192 url,
5193 headers,
5194 meta: _,
5195 }) => {
5196 assert_eq!(name, "http-server");
5197 assert_eq!(url, "https://api.example.com");
5198 assert_eq!(headers.len(), 2);
5199 assert_eq!(headers[0].name, "Authorization");
5200 assert_eq!(headers[0].value, "Bearer token123");
5201 assert_eq!(headers[1].name, "Content-Type");
5202 assert_eq!(headers[1].value, "application/json");
5203 }
5204 _ => panic!("Expected Http variant"),
5205 }
5206 }
5207
5208 #[test]
5209 fn test_mcp_server_sse_serialization() {
5210 let server = McpServer::Sse(
5211 McpServerSse::new("sse-server", "https://sse.example.com/events")
5212 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5213 );
5214
5215 let json = serde_json::to_value(&server).unwrap();
5216 assert_eq!(
5217 json,
5218 json!({
5219 "type": "sse",
5220 "name": "sse-server",
5221 "url": "https://sse.example.com/events",
5222 "headers": [
5223 {
5224 "name": "X-API-Key",
5225 "value": "apikey456"
5226 }
5227 ]
5228 })
5229 );
5230
5231 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5232 match deserialized {
5233 McpServer::Sse(McpServerSse {
5234 name,
5235 url,
5236 headers,
5237 meta: _,
5238 }) => {
5239 assert_eq!(name, "sse-server");
5240 assert_eq!(url, "https://sse.example.com/events");
5241 assert_eq!(headers.len(), 1);
5242 assert_eq!(headers[0].name, "X-API-Key");
5243 assert_eq!(headers[0].value, "apikey456");
5244 }
5245 _ => panic!("Expected Sse variant"),
5246 }
5247 }
5248
5249 #[test]
5250 fn test_session_config_option_category_known_variants() {
5251 assert_eq!(
5253 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5254 json!("mode")
5255 );
5256 assert_eq!(
5257 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5258 json!("model")
5259 );
5260 assert_eq!(
5261 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5262 json!("thought_level")
5263 );
5264
5265 assert_eq!(
5267 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5268 SessionConfigOptionCategory::Mode
5269 );
5270 assert_eq!(
5271 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5272 SessionConfigOptionCategory::Model
5273 );
5274 assert_eq!(
5275 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5276 SessionConfigOptionCategory::ThoughtLevel
5277 );
5278 }
5279
5280 #[test]
5281 fn test_session_config_option_category_unknown_variants() {
5282 let unknown: SessionConfigOptionCategory =
5284 serde_json::from_str("\"some_future_category\"").unwrap();
5285 assert_eq!(
5286 unknown,
5287 SessionConfigOptionCategory::Other("some_future_category".to_string())
5288 );
5289
5290 let json = serde_json::to_value(&unknown).unwrap();
5292 assert_eq!(json, json!("some_future_category"));
5293 }
5294
5295 #[test]
5296 fn test_session_config_option_category_custom_categories() {
5297 let custom: SessionConfigOptionCategory =
5299 serde_json::from_str("\"_my_custom_category\"").unwrap();
5300 assert_eq!(
5301 custom,
5302 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5303 );
5304
5305 let json = serde_json::to_value(&custom).unwrap();
5307 assert_eq!(json, json!("_my_custom_category"));
5308
5309 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5311 assert_eq!(
5312 deserialized,
5313 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5314 );
5315 }
5316
5317 #[test]
5318 fn test_auth_method_agent_serialization() {
5319 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5320
5321 let json = serde_json::to_value(&method).unwrap();
5322 assert_eq!(
5323 json,
5324 json!({
5325 "id": "default-auth",
5326 "name": "Default Auth"
5327 })
5328 );
5329 assert!(!json.as_object().unwrap().contains_key("description"));
5331 assert!(!json.as_object().unwrap().contains_key("type"));
5333
5334 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5335 match deserialized {
5336 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5337 assert_eq!(id.0.as_ref(), "default-auth");
5338 assert_eq!(name, "Default Auth");
5339 }
5340 #[cfg(feature = "unstable_auth_methods")]
5341 _ => panic!("Expected Agent variant"),
5342 }
5343 }
5344
5345 #[test]
5346 fn test_auth_method_explicit_agent_deserialization() {
5347 let json = json!({
5349 "id": "agent-auth",
5350 "name": "Agent Auth",
5351 "type": "agent"
5352 });
5353
5354 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5355 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5356 }
5357
5358 #[cfg(feature = "unstable_session_additional_directories")]
5359 #[test]
5360 fn test_session_additional_directories_serialization() {
5361 assert_eq!(
5362 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5363 json!({
5364 "cwd": "/home/user/project",
5365 "mcpServers": []
5366 })
5367 );
5368 assert_eq!(
5369 serde_json::to_value(
5370 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5371 PathBuf::from("/home/user/shared-lib"),
5372 PathBuf::from("/home/user/product-docs"),
5373 ])
5374 )
5375 .unwrap(),
5376 json!({
5377 "cwd": "/home/user/project",
5378 "additionalDirectories": [
5379 "/home/user/shared-lib",
5380 "/home/user/product-docs"
5381 ],
5382 "mcpServers": []
5383 })
5384 );
5385 assert_eq!(
5386 serde_json::to_value(
5387 ListSessionsRequest::new().additional_directories(Vec::<PathBuf>::new())
5388 )
5389 .unwrap(),
5390 json!({})
5391 );
5392 assert_eq!(
5393 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5394 json!({
5395 "sessionId": "sess_abc123",
5396 "cwd": "/home/user/project"
5397 })
5398 );
5399 assert_eq!(
5400 serde_json::to_value(
5401 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5402 PathBuf::from("/home/user/shared-lib"),
5403 PathBuf::from("/home/user/product-docs"),
5404 ])
5405 )
5406 .unwrap(),
5407 json!({
5408 "sessionId": "sess_abc123",
5409 "cwd": "/home/user/project",
5410 "additionalDirectories": [
5411 "/home/user/shared-lib",
5412 "/home/user/product-docs"
5413 ]
5414 })
5415 );
5416 assert_eq!(
5417 serde_json::from_value::<SessionInfo>(json!({
5418 "sessionId": "sess_abc123",
5419 "cwd": "/home/user/project"
5420 }))
5421 .unwrap()
5422 .additional_directories,
5423 Vec::<PathBuf>::new()
5424 );
5425
5426 assert_eq!(
5427 serde_json::from_value::<ListSessionsRequest>(json!({}))
5428 .unwrap()
5429 .additional_directories,
5430 Vec::<PathBuf>::new()
5431 );
5432
5433 assert_eq!(
5434 serde_json::from_value::<ListSessionsRequest>(json!({
5435 "additionalDirectories": []
5436 }))
5437 .unwrap()
5438 .additional_directories,
5439 Vec::<PathBuf>::new()
5440 );
5441 }
5442
5443 #[cfg(feature = "unstable_session_additional_directories")]
5444 #[test]
5445 fn test_session_additional_directories_capabilities_serialization() {
5446 assert_eq!(
5447 serde_json::to_value(
5448 SessionCapabilities::new()
5449 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5450 )
5451 .unwrap(),
5452 json!({
5453 "additionalDirectories": {}
5454 })
5455 );
5456 }
5457
5458 #[cfg(feature = "unstable_auth_methods")]
5459 #[test]
5460 fn test_auth_method_env_var_serialization() {
5461 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5462 "api-key",
5463 "API Key",
5464 vec![AuthEnvVar::new("API_KEY")],
5465 ));
5466
5467 let json = serde_json::to_value(&method).unwrap();
5468 assert_eq!(
5469 json,
5470 json!({
5471 "id": "api-key",
5472 "name": "API Key",
5473 "type": "env_var",
5474 "vars": [{"name": "API_KEY"}]
5475 })
5476 );
5477 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5479 assert!(
5480 !json["vars"][0]
5481 .as_object()
5482 .unwrap()
5483 .contains_key("optional")
5484 );
5485
5486 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5487 match deserialized {
5488 AuthMethod::EnvVar(AuthMethodEnvVar {
5489 id,
5490 name: method_name,
5491 vars,
5492 link,
5493 ..
5494 }) => {
5495 assert_eq!(id.0.as_ref(), "api-key");
5496 assert_eq!(method_name, "API Key");
5497 assert_eq!(vars.len(), 1);
5498 assert_eq!(vars[0].name, "API_KEY");
5499 assert!(vars[0].secret);
5500 assert!(!vars[0].optional);
5501 assert!(link.is_none());
5502 }
5503 _ => panic!("Expected EnvVar variant"),
5504 }
5505 }
5506
5507 #[cfg(feature = "unstable_auth_methods")]
5508 #[test]
5509 fn test_auth_method_env_var_with_link_serialization() {
5510 let method = AuthMethod::EnvVar(
5511 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5512 .link("https://example.com/keys"),
5513 );
5514
5515 let json = serde_json::to_value(&method).unwrap();
5516 assert_eq!(
5517 json,
5518 json!({
5519 "id": "api-key",
5520 "name": "API Key",
5521 "type": "env_var",
5522 "vars": [{"name": "API_KEY"}],
5523 "link": "https://example.com/keys"
5524 })
5525 );
5526
5527 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5528 match deserialized {
5529 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5530 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5531 }
5532 _ => panic!("Expected EnvVar variant"),
5533 }
5534 }
5535
5536 #[cfg(feature = "unstable_auth_methods")]
5537 #[test]
5538 fn test_auth_method_env_var_multiple_vars() {
5539 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5540 "azure-openai",
5541 "Azure OpenAI",
5542 vec![
5543 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5544 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5545 .label("Endpoint URL")
5546 .secret(false),
5547 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5548 .label("API Version")
5549 .secret(false)
5550 .optional(true),
5551 ],
5552 ));
5553
5554 let json = serde_json::to_value(&method).unwrap();
5555 assert_eq!(
5556 json,
5557 json!({
5558 "id": "azure-openai",
5559 "name": "Azure OpenAI",
5560 "type": "env_var",
5561 "vars": [
5562 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5563 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5564 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5565 ]
5566 })
5567 );
5568
5569 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5570 match deserialized {
5571 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5572 assert_eq!(vars.len(), 3);
5573 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5575 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5576 assert!(vars[0].secret);
5577 assert!(!vars[0].optional);
5578 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5580 assert!(!vars[1].secret);
5581 assert!(!vars[1].optional);
5582 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5584 assert!(!vars[2].secret);
5585 assert!(vars[2].optional);
5586 }
5587 _ => panic!("Expected EnvVar variant"),
5588 }
5589 }
5590
5591 #[cfg(feature = "unstable_auth_methods")]
5592 #[test]
5593 fn test_auth_method_terminal_serialization() {
5594 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5595
5596 let json = serde_json::to_value(&method).unwrap();
5597 assert_eq!(
5598 json,
5599 json!({
5600 "id": "tui-auth",
5601 "name": "Terminal Auth",
5602 "type": "terminal"
5603 })
5604 );
5605 assert!(!json.as_object().unwrap().contains_key("args"));
5607 assert!(!json.as_object().unwrap().contains_key("env"));
5608
5609 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5610 match deserialized {
5611 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5612 assert!(args.is_empty());
5613 assert!(env.is_empty());
5614 }
5615 _ => panic!("Expected Terminal variant"),
5616 }
5617 }
5618
5619 #[cfg(feature = "unstable_auth_methods")]
5620 #[test]
5621 fn test_auth_method_terminal_with_args_and_env_serialization() {
5622 use std::collections::HashMap;
5623
5624 let mut env = HashMap::new();
5625 env.insert("TERM".to_string(), "xterm-256color".to_string());
5626
5627 let method = AuthMethod::Terminal(
5628 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5629 .args(vec!["--interactive".to_string(), "--color".to_string()])
5630 .env(env),
5631 );
5632
5633 let json = serde_json::to_value(&method).unwrap();
5634 assert_eq!(
5635 json,
5636 json!({
5637 "id": "tui-auth",
5638 "name": "Terminal Auth",
5639 "type": "terminal",
5640 "args": ["--interactive", "--color"],
5641 "env": {
5642 "TERM": "xterm-256color"
5643 }
5644 })
5645 );
5646
5647 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5648 match deserialized {
5649 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5650 assert_eq!(args, vec!["--interactive", "--color"]);
5651 assert_eq!(env.len(), 1);
5652 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5653 }
5654 _ => panic!("Expected Terminal variant"),
5655 }
5656 }
5657
5658 #[cfg(feature = "unstable_boolean_config")]
5659 #[test]
5660 fn test_session_config_option_value_id_serialize() {
5661 let val = SessionConfigOptionValue::value_id("model-1");
5662 let json = serde_json::to_value(&val).unwrap();
5663 assert_eq!(json, json!({ "value": "model-1" }));
5665 assert!(!json.as_object().unwrap().contains_key("type"));
5666 }
5667
5668 #[cfg(feature = "unstable_boolean_config")]
5669 #[test]
5670 fn test_session_config_option_value_boolean_serialize() {
5671 let val = SessionConfigOptionValue::boolean(true);
5672 let json = serde_json::to_value(&val).unwrap();
5673 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5674 }
5675
5676 #[cfg(feature = "unstable_boolean_config")]
5677 #[test]
5678 fn test_session_config_option_value_deserialize_no_type() {
5679 let json = json!({ "value": "model-1" });
5681 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5682 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5683 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5684 }
5685
5686 #[cfg(feature = "unstable_boolean_config")]
5687 #[test]
5688 fn test_session_config_option_value_deserialize_boolean() {
5689 let json = json!({ "type": "boolean", "value": true });
5690 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5691 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5692 assert_eq!(val.as_bool(), Some(true));
5693 }
5694
5695 #[cfg(feature = "unstable_boolean_config")]
5696 #[test]
5697 fn test_session_config_option_value_deserialize_boolean_false() {
5698 let json = json!({ "type": "boolean", "value": false });
5699 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5700 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5701 assert_eq!(val.as_bool(), Some(false));
5702 }
5703
5704 #[cfg(feature = "unstable_boolean_config")]
5705 #[test]
5706 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5707 let json = json!({ "type": "text", "value": "freeform input" });
5709 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5710 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5711 }
5712
5713 #[cfg(feature = "unstable_boolean_config")]
5714 #[test]
5715 fn test_session_config_option_value_roundtrip_value_id() {
5716 let original = SessionConfigOptionValue::value_id("option-a");
5717 let json = serde_json::to_value(&original).unwrap();
5718 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5719 assert_eq!(original, roundtripped);
5720 }
5721
5722 #[cfg(feature = "unstable_boolean_config")]
5723 #[test]
5724 fn test_session_config_option_value_roundtrip_boolean() {
5725 let original = SessionConfigOptionValue::boolean(false);
5726 let json = serde_json::to_value(&original).unwrap();
5727 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5728 assert_eq!(original, roundtripped);
5729 }
5730
5731 #[cfg(feature = "unstable_boolean_config")]
5732 #[test]
5733 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5734 let json = json!({ "type": "boolean", "value": "not a bool" });
5736 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5737 assert!(result.is_ok());
5739 assert_eq!(
5740 result.unwrap().as_value_id().unwrap().to_string(),
5741 "not a bool"
5742 );
5743 }
5744
5745 #[cfg(feature = "unstable_boolean_config")]
5746 #[test]
5747 fn test_session_config_option_value_from_impls() {
5748 let from_str: SessionConfigOptionValue = "model-1".into();
5749 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5750
5751 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5752 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5753
5754 let from_bool: SessionConfigOptionValue = true.into();
5755 assert_eq!(from_bool.as_bool(), Some(true));
5756 }
5757
5758 #[cfg(feature = "unstable_boolean_config")]
5759 #[test]
5760 fn test_set_session_config_option_request_value_id() {
5761 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5762 let json = serde_json::to_value(&req).unwrap();
5763 assert_eq!(
5764 json,
5765 json!({
5766 "sessionId": "sess_1",
5767 "configId": "model",
5768 "value": "model-1"
5769 })
5770 );
5771 assert!(!json.as_object().unwrap().contains_key("type"));
5773 }
5774
5775 #[cfg(feature = "unstable_boolean_config")]
5776 #[test]
5777 fn test_set_session_config_option_request_boolean() {
5778 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5779 let json = serde_json::to_value(&req).unwrap();
5780 assert_eq!(
5781 json,
5782 json!({
5783 "sessionId": "sess_1",
5784 "configId": "brave_mode",
5785 "type": "boolean",
5786 "value": true
5787 })
5788 );
5789 }
5790
5791 #[cfg(feature = "unstable_boolean_config")]
5792 #[test]
5793 fn test_set_session_config_option_request_deserialize_no_type() {
5794 let json = json!({
5796 "sessionId": "sess_1",
5797 "configId": "model",
5798 "value": "model-1"
5799 });
5800 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5801 assert_eq!(req.session_id.to_string(), "sess_1");
5802 assert_eq!(req.config_id.to_string(), "model");
5803 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5804 }
5805
5806 #[cfg(feature = "unstable_boolean_config")]
5807 #[test]
5808 fn test_set_session_config_option_request_deserialize_boolean() {
5809 let json = json!({
5810 "sessionId": "sess_1",
5811 "configId": "brave_mode",
5812 "type": "boolean",
5813 "value": true
5814 });
5815 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5816 assert_eq!(req.value.as_bool(), Some(true));
5817 }
5818
5819 #[cfg(feature = "unstable_boolean_config")]
5820 #[test]
5821 fn test_set_session_config_option_request_roundtrip_value_id() {
5822 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5823 let json = serde_json::to_value(&original).unwrap();
5824 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5825 assert_eq!(original, roundtripped);
5826 }
5827
5828 #[cfg(feature = "unstable_boolean_config")]
5829 #[test]
5830 fn test_set_session_config_option_request_roundtrip_boolean() {
5831 let original = SetSessionConfigOptionRequest::new("s", "c", false);
5832 let json = serde_json::to_value(&original).unwrap();
5833 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5834 assert_eq!(original, roundtripped);
5835 }
5836
5837 #[cfg(feature = "unstable_boolean_config")]
5838 #[test]
5839 fn test_session_config_boolean_serialization() {
5840 let cfg = SessionConfigBoolean::new(true);
5841 let json = serde_json::to_value(&cfg).unwrap();
5842 assert_eq!(json, json!({ "currentValue": true }));
5843
5844 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
5845 assert!(deserialized.current_value);
5846 }
5847
5848 #[cfg(feature = "unstable_boolean_config")]
5849 #[test]
5850 fn test_session_config_option_boolean_variant() {
5851 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
5852 .description("Skip confirmation prompts");
5853 let json = serde_json::to_value(&opt).unwrap();
5854 assert_eq!(
5855 json,
5856 json!({
5857 "id": "brave_mode",
5858 "name": "Brave Mode",
5859 "description": "Skip confirmation prompts",
5860 "type": "boolean",
5861 "currentValue": false
5862 })
5863 );
5864
5865 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5866 assert_eq!(deserialized.id.to_string(), "brave_mode");
5867 assert_eq!(deserialized.name, "Brave Mode");
5868 match deserialized.kind {
5869 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
5870 _ => panic!("Expected Boolean kind"),
5871 }
5872 }
5873
5874 #[cfg(feature = "unstable_boolean_config")]
5875 #[test]
5876 fn test_session_config_option_select_still_works() {
5877 let opt = SessionConfigOption::select(
5879 "model",
5880 "Model",
5881 "model-1",
5882 vec![
5883 SessionConfigSelectOption::new("model-1", "Model 1"),
5884 SessionConfigSelectOption::new("model-2", "Model 2"),
5885 ],
5886 );
5887 let json = serde_json::to_value(&opt).unwrap();
5888 assert_eq!(json["type"], "select");
5889 assert_eq!(json["currentValue"], "model-1");
5890 assert_eq!(json["options"].as_array().unwrap().len(), 2);
5891
5892 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5893 match deserialized.kind {
5894 SessionConfigKind::Select(ref s) => {
5895 assert_eq!(s.current_value.to_string(), "model-1");
5896 }
5897 _ => panic!("Expected Select kind"),
5898 }
5899 }
5900
5901 #[cfg(feature = "unstable_llm_providers")]
5902 #[test]
5903 fn test_llm_protocol_known_variants() {
5904 assert_eq!(
5905 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
5906 json!("anthropic")
5907 );
5908 assert_eq!(
5909 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
5910 json!("openai")
5911 );
5912 assert_eq!(
5913 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
5914 json!("azure")
5915 );
5916 assert_eq!(
5917 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
5918 json!("vertex")
5919 );
5920 assert_eq!(
5921 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
5922 json!("bedrock")
5923 );
5924
5925 assert_eq!(
5926 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
5927 LlmProtocol::Anthropic
5928 );
5929 assert_eq!(
5930 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
5931 LlmProtocol::OpenAi
5932 );
5933 assert_eq!(
5934 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
5935 LlmProtocol::Azure
5936 );
5937 assert_eq!(
5938 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
5939 LlmProtocol::Vertex
5940 );
5941 assert_eq!(
5942 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
5943 LlmProtocol::Bedrock
5944 );
5945 }
5946
5947 #[cfg(feature = "unstable_llm_providers")]
5948 #[test]
5949 fn test_llm_protocol_unknown_variant() {
5950 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
5951 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
5952
5953 let json = serde_json::to_value(&unknown).unwrap();
5954 assert_eq!(json, json!("cohere"));
5955 }
5956
5957 #[cfg(feature = "unstable_llm_providers")]
5958 #[test]
5959 fn test_provider_current_config_serialization() {
5960 let config =
5961 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
5962
5963 let json = serde_json::to_value(&config).unwrap();
5964 assert_eq!(
5965 json,
5966 json!({
5967 "apiType": "anthropic",
5968 "baseUrl": "https://api.anthropic.com"
5969 })
5970 );
5971
5972 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
5973 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
5974 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
5975 }
5976
5977 #[cfg(feature = "unstable_llm_providers")]
5978 #[test]
5979 fn test_provider_info_with_current_config() {
5980 let info = ProviderInfo::new(
5981 "main",
5982 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
5983 true,
5984 Some(ProviderCurrentConfig::new(
5985 LlmProtocol::Anthropic,
5986 "https://api.anthropic.com",
5987 )),
5988 );
5989
5990 let json = serde_json::to_value(&info).unwrap();
5991 assert_eq!(
5992 json,
5993 json!({
5994 "id": "main",
5995 "supported": ["anthropic", "openai"],
5996 "required": true,
5997 "current": {
5998 "apiType": "anthropic",
5999 "baseUrl": "https://api.anthropic.com"
6000 }
6001 })
6002 );
6003
6004 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6005 assert_eq!(deserialized.id, "main");
6006 assert_eq!(deserialized.supported.len(), 2);
6007 assert!(deserialized.required);
6008 assert!(deserialized.current.is_some());
6009 assert_eq!(
6010 deserialized.current.as_ref().unwrap().api_type,
6011 LlmProtocol::Anthropic
6012 );
6013 }
6014
6015 #[cfg(feature = "unstable_llm_providers")]
6016 #[test]
6017 fn test_provider_info_disabled() {
6018 let info = ProviderInfo::new(
6019 "secondary",
6020 vec![LlmProtocol::OpenAi],
6021 false,
6022 None::<ProviderCurrentConfig>,
6023 );
6024
6025 let json = serde_json::to_value(&info).unwrap();
6026 assert_eq!(
6027 json,
6028 json!({
6029 "id": "secondary",
6030 "supported": ["openai"],
6031 "required": false
6032 })
6033 );
6034
6035 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6036 assert_eq!(deserialized.id, "secondary");
6037 assert!(!deserialized.required);
6038 assert!(deserialized.current.is_none());
6039 }
6040
6041 #[cfg(feature = "unstable_llm_providers")]
6042 #[test]
6043 fn test_provider_info_missing_current_defaults_to_none() {
6044 let json = json!({
6046 "id": "main",
6047 "supported": ["anthropic"],
6048 "required": true
6049 });
6050 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6051 assert!(deserialized.current.is_none());
6052 }
6053
6054 #[cfg(feature = "unstable_llm_providers")]
6055 #[test]
6056 fn test_provider_info_explicit_null_current_decodes_to_none() {
6057 let json = json!({
6061 "id": "main",
6062 "supported": ["anthropic"],
6063 "required": true,
6064 "current": null
6065 });
6066 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6067 assert!(deserialized.current.is_none());
6068 }
6069
6070 #[cfg(feature = "unstable_llm_providers")]
6071 #[test]
6072 fn test_list_providers_response_serialization() {
6073 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6074 "main",
6075 vec![LlmProtocol::Anthropic],
6076 true,
6077 Some(ProviderCurrentConfig::new(
6078 LlmProtocol::Anthropic,
6079 "https://api.anthropic.com",
6080 )),
6081 )]);
6082
6083 let json = serde_json::to_value(&response).unwrap();
6084 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6085 assert_eq!(json["providers"][0]["id"], "main");
6086
6087 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6088 assert_eq!(deserialized.providers.len(), 1);
6089 }
6090
6091 #[cfg(feature = "unstable_llm_providers")]
6092 #[test]
6093 fn test_set_providers_request_serialization() {
6094 use std::collections::HashMap;
6095
6096 let mut headers = HashMap::new();
6097 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6098
6099 let request =
6100 SetProvidersRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6101 .headers(headers);
6102
6103 let json = serde_json::to_value(&request).unwrap();
6104 assert_eq!(
6105 json,
6106 json!({
6107 "id": "main",
6108 "apiType": "openai",
6109 "baseUrl": "https://api.openai.com/v1",
6110 "headers": {
6111 "Authorization": "Bearer sk-test"
6112 }
6113 })
6114 );
6115
6116 let deserialized: SetProvidersRequest = serde_json::from_value(json).unwrap();
6117 assert_eq!(deserialized.id, "main");
6118 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6119 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6120 assert_eq!(deserialized.headers.len(), 1);
6121 assert_eq!(
6122 deserialized.headers.get("Authorization").unwrap(),
6123 "Bearer sk-test"
6124 );
6125 }
6126
6127 #[cfg(feature = "unstable_llm_providers")]
6128 #[test]
6129 fn test_set_providers_request_omits_empty_headers() {
6130 let request =
6131 SetProvidersRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6132
6133 let json = serde_json::to_value(&request).unwrap();
6134 assert!(!json.as_object().unwrap().contains_key("headers"));
6136 }
6137
6138 #[cfg(feature = "unstable_llm_providers")]
6139 #[test]
6140 fn test_disable_providers_request_serialization() {
6141 let request = DisableProvidersRequest::new("secondary");
6142
6143 let json = serde_json::to_value(&request).unwrap();
6144 assert_eq!(json, json!({ "id": "secondary" }));
6145
6146 let deserialized: DisableProvidersRequest = serde_json::from_value(json).unwrap();
6147 assert_eq!(deserialized.id, "secondary");
6148 }
6149
6150 #[cfg(feature = "unstable_llm_providers")]
6151 #[test]
6152 fn test_providers_capabilities_serialization() {
6153 let caps = ProvidersCapabilities::new();
6154
6155 let json = serde_json::to_value(&caps).unwrap();
6156 assert_eq!(json, json!({}));
6157
6158 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6159 assert!(deserialized.meta.is_none());
6160 }
6161
6162 #[cfg(feature = "unstable_llm_providers")]
6163 #[test]
6164 fn test_agent_capabilities_with_providers() {
6165 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6166
6167 let json = serde_json::to_value(&caps).unwrap();
6168 assert_eq!(json["providers"], json!({}));
6169
6170 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6171 assert!(deserialized.providers.is_some());
6172 }
6173}