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#[skip_serializing_none]
1463#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1464#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1465#[serde(rename_all = "camelCase")]
1466#[non_exhaustive]
1467pub struct ResumeSessionRequest {
1468 pub session_id: SessionId,
1470 pub cwd: PathBuf,
1472 #[cfg(feature = "unstable_session_additional_directories")]
1482 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1483 pub additional_directories: Vec<PathBuf>,
1484 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1486 pub mcp_servers: Vec<McpServer>,
1487 #[serde(rename = "_meta")]
1493 pub meta: Option<Meta>,
1494}
1495
1496impl ResumeSessionRequest {
1497 #[must_use]
1498 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1499 Self {
1500 session_id: session_id.into(),
1501 cwd: cwd.into(),
1502 #[cfg(feature = "unstable_session_additional_directories")]
1503 additional_directories: vec![],
1504 mcp_servers: vec![],
1505 meta: None,
1506 }
1507 }
1508
1509 #[cfg(feature = "unstable_session_additional_directories")]
1515 #[must_use]
1516 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1517 self.additional_directories = additional_directories;
1518 self
1519 }
1520
1521 #[must_use]
1523 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1524 self.mcp_servers = mcp_servers;
1525 self
1526 }
1527
1528 #[must_use]
1534 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1535 self.meta = meta.into_option();
1536 self
1537 }
1538}
1539
1540#[serde_as]
1542#[skip_serializing_none]
1543#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1544#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1545#[serde(rename_all = "camelCase")]
1546#[non_exhaustive]
1547pub struct ResumeSessionResponse {
1548 #[serde_as(deserialize_as = "DefaultOnError")]
1552 #[serde(default)]
1553 pub modes: Option<SessionModeState>,
1554 #[cfg(feature = "unstable_session_model")]
1560 #[serde_as(deserialize_as = "DefaultOnError")]
1561 #[serde(default)]
1562 pub models: Option<SessionModelState>,
1563 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1565 #[serde(default)]
1566 pub config_options: Option<Vec<SessionConfigOption>>,
1567 #[serde(rename = "_meta")]
1573 pub meta: Option<Meta>,
1574}
1575
1576impl ResumeSessionResponse {
1577 #[must_use]
1578 pub fn new() -> Self {
1579 Self::default()
1580 }
1581
1582 #[must_use]
1586 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1587 self.modes = modes.into_option();
1588 self
1589 }
1590
1591 #[cfg(feature = "unstable_session_model")]
1597 #[must_use]
1598 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1599 self.models = models.into_option();
1600 self
1601 }
1602
1603 #[must_use]
1605 pub fn config_options(
1606 mut self,
1607 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1608 ) -> Self {
1609 self.config_options = config_options.into_option();
1610 self
1611 }
1612
1613 #[must_use]
1619 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1620 self.meta = meta.into_option();
1621 self
1622 }
1623}
1624
1625#[skip_serializing_none]
1635#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1636#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1637#[serde(rename_all = "camelCase")]
1638#[non_exhaustive]
1639pub struct CloseSessionRequest {
1640 pub session_id: SessionId,
1642 #[serde(rename = "_meta")]
1648 pub meta: Option<Meta>,
1649}
1650
1651impl CloseSessionRequest {
1652 #[must_use]
1653 pub fn new(session_id: impl Into<SessionId>) -> Self {
1654 Self {
1655 session_id: session_id.into(),
1656 meta: None,
1657 }
1658 }
1659
1660 #[must_use]
1666 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1667 self.meta = meta.into_option();
1668 self
1669 }
1670}
1671
1672#[skip_serializing_none]
1674#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1675#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1676#[serde(rename_all = "camelCase")]
1677#[non_exhaustive]
1678pub struct CloseSessionResponse {
1679 #[serde(rename = "_meta")]
1685 pub meta: Option<Meta>,
1686}
1687
1688impl CloseSessionResponse {
1689 #[must_use]
1690 pub fn new() -> Self {
1691 Self::default()
1692 }
1693
1694 #[must_use]
1700 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1701 self.meta = meta.into_option();
1702 self
1703 }
1704}
1705
1706#[skip_serializing_none]
1712#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1713#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1714#[serde(rename_all = "camelCase")]
1715#[non_exhaustive]
1716pub struct ListSessionsRequest {
1717 pub cwd: Option<PathBuf>,
1719 #[cfg(feature = "unstable_session_additional_directories")]
1728 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1729 pub additional_directories: Vec<PathBuf>,
1730 pub cursor: Option<String>,
1732 #[serde(rename = "_meta")]
1738 pub meta: Option<Meta>,
1739}
1740
1741impl ListSessionsRequest {
1742 #[must_use]
1743 pub fn new() -> Self {
1744 Self::default()
1745 }
1746
1747 #[must_use]
1749 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1750 self.cwd = cwd.into_option();
1751 self
1752 }
1753
1754 #[cfg(feature = "unstable_session_additional_directories")]
1760 #[must_use]
1761 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1762 self.additional_directories = additional_directories;
1763 self
1764 }
1765
1766 #[must_use]
1768 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1769 self.cursor = cursor.into_option();
1770 self
1771 }
1772
1773 #[must_use]
1779 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1780 self.meta = meta.into_option();
1781 self
1782 }
1783}
1784
1785#[serde_as]
1787#[skip_serializing_none]
1788#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1789#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1790#[serde(rename_all = "camelCase")]
1791#[non_exhaustive]
1792pub struct ListSessionsResponse {
1793 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1795 pub sessions: Vec<SessionInfo>,
1796 pub next_cursor: Option<String>,
1799 #[serde(rename = "_meta")]
1805 pub meta: Option<Meta>,
1806}
1807
1808impl ListSessionsResponse {
1809 #[must_use]
1810 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1811 Self {
1812 sessions,
1813 next_cursor: None,
1814 meta: None,
1815 }
1816 }
1817
1818 #[must_use]
1819 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1820 self.next_cursor = next_cursor.into_option();
1821 self
1822 }
1823
1824 #[must_use]
1830 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1831 self.meta = meta.into_option();
1832 self
1833 }
1834}
1835
1836#[serde_as]
1838#[skip_serializing_none]
1839#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1840#[serde(rename_all = "camelCase")]
1841#[non_exhaustive]
1842pub struct SessionInfo {
1843 pub session_id: SessionId,
1845 pub cwd: PathBuf,
1847 #[cfg(feature = "unstable_session_additional_directories")]
1855 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1856 pub additional_directories: Vec<PathBuf>,
1857
1858 #[serde_as(deserialize_as = "DefaultOnError")]
1860 #[serde(default)]
1861 pub title: Option<String>,
1862 #[serde_as(deserialize_as = "DefaultOnError")]
1864 #[serde(default)]
1865 pub updated_at: Option<String>,
1866 #[serde(rename = "_meta")]
1872 pub meta: Option<Meta>,
1873}
1874
1875impl SessionInfo {
1876 #[must_use]
1877 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1878 Self {
1879 session_id: session_id.into(),
1880 cwd: cwd.into(),
1881 #[cfg(feature = "unstable_session_additional_directories")]
1882 additional_directories: vec![],
1883 title: None,
1884 updated_at: None,
1885 meta: None,
1886 }
1887 }
1888
1889 #[cfg(feature = "unstable_session_additional_directories")]
1895 #[must_use]
1896 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1897 self.additional_directories = additional_directories;
1898 self
1899 }
1900
1901 #[must_use]
1903 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1904 self.title = title.into_option();
1905 self
1906 }
1907
1908 #[must_use]
1910 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1911 self.updated_at = updated_at.into_option();
1912 self
1913 }
1914
1915 #[must_use]
1921 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1922 self.meta = meta.into_option();
1923 self
1924 }
1925}
1926
1927#[serde_as]
1931#[skip_serializing_none]
1932#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1933#[serde(rename_all = "camelCase")]
1934#[non_exhaustive]
1935pub struct SessionModeState {
1936 pub current_mode_id: SessionModeId,
1938 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1940 pub available_modes: Vec<SessionMode>,
1941 #[serde(rename = "_meta")]
1947 pub meta: Option<Meta>,
1948}
1949
1950impl SessionModeState {
1951 #[must_use]
1952 pub fn new(
1953 current_mode_id: impl Into<SessionModeId>,
1954 available_modes: Vec<SessionMode>,
1955 ) -> Self {
1956 Self {
1957 current_mode_id: current_mode_id.into(),
1958 available_modes,
1959 meta: None,
1960 }
1961 }
1962
1963 #[must_use]
1969 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1970 self.meta = meta.into_option();
1971 self
1972 }
1973}
1974
1975#[skip_serializing_none]
1979#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1980#[serde(rename_all = "camelCase")]
1981#[non_exhaustive]
1982pub struct SessionMode {
1983 pub id: SessionModeId,
1984 pub name: String,
1985 #[serde(default)]
1986 pub description: Option<String>,
1987 #[serde(rename = "_meta")]
1993 pub meta: Option<Meta>,
1994}
1995
1996impl SessionMode {
1997 #[must_use]
1998 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
1999 Self {
2000 id: id.into(),
2001 name: name.into(),
2002 description: None,
2003 meta: None,
2004 }
2005 }
2006
2007 #[must_use]
2008 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2009 self.description = description.into_option();
2010 self
2011 }
2012
2013 #[must_use]
2019 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2020 self.meta = meta.into_option();
2021 self
2022 }
2023}
2024
2025#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2027#[serde(transparent)]
2028#[from(Arc<str>, String, &'static str)]
2029#[non_exhaustive]
2030pub struct SessionModeId(pub Arc<str>);
2031
2032impl SessionModeId {
2033 #[must_use]
2034 pub fn new(id: impl Into<Arc<str>>) -> Self {
2035 Self(id.into())
2036 }
2037}
2038
2039#[skip_serializing_none]
2041#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2042#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2043#[serde(rename_all = "camelCase")]
2044#[non_exhaustive]
2045pub struct SetSessionModeRequest {
2046 pub session_id: SessionId,
2048 pub mode_id: SessionModeId,
2050 #[serde(rename = "_meta")]
2056 pub meta: Option<Meta>,
2057}
2058
2059impl SetSessionModeRequest {
2060 #[must_use]
2061 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
2062 Self {
2063 session_id: session_id.into(),
2064 mode_id: mode_id.into(),
2065 meta: None,
2066 }
2067 }
2068
2069 #[must_use]
2070 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2071 self.meta = meta.into_option();
2072 self
2073 }
2074}
2075
2076#[skip_serializing_none]
2078#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2079#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2080#[serde(rename_all = "camelCase")]
2081#[non_exhaustive]
2082pub struct SetSessionModeResponse {
2083 #[serde(rename = "_meta")]
2089 pub meta: Option<Meta>,
2090}
2091
2092impl SetSessionModeResponse {
2093 #[must_use]
2094 pub fn new() -> Self {
2095 Self::default()
2096 }
2097
2098 #[must_use]
2104 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2105 self.meta = meta.into_option();
2106 self
2107 }
2108}
2109
2110#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2114#[serde(transparent)]
2115#[from(Arc<str>, String, &'static str)]
2116#[non_exhaustive]
2117pub struct SessionConfigId(pub Arc<str>);
2118
2119impl SessionConfigId {
2120 #[must_use]
2121 pub fn new(id: impl Into<Arc<str>>) -> Self {
2122 Self(id.into())
2123 }
2124}
2125
2126#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2128#[serde(transparent)]
2129#[from(Arc<str>, String, &'static str)]
2130#[non_exhaustive]
2131pub struct SessionConfigValueId(pub Arc<str>);
2132
2133impl SessionConfigValueId {
2134 #[must_use]
2135 pub fn new(id: impl Into<Arc<str>>) -> Self {
2136 Self(id.into())
2137 }
2138}
2139
2140#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2142#[serde(transparent)]
2143#[from(Arc<str>, String, &'static str)]
2144#[non_exhaustive]
2145pub struct SessionConfigGroupId(pub Arc<str>);
2146
2147impl SessionConfigGroupId {
2148 #[must_use]
2149 pub fn new(id: impl Into<Arc<str>>) -> Self {
2150 Self(id.into())
2151 }
2152}
2153
2154#[skip_serializing_none]
2156#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2157#[serde(rename_all = "camelCase")]
2158#[non_exhaustive]
2159pub struct SessionConfigSelectOption {
2160 pub value: SessionConfigValueId,
2162 pub name: String,
2164 #[serde(default)]
2166 pub description: Option<String>,
2167 #[serde(rename = "_meta")]
2173 pub meta: Option<Meta>,
2174}
2175
2176impl SessionConfigSelectOption {
2177 #[must_use]
2178 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2179 Self {
2180 value: value.into(),
2181 name: name.into(),
2182 description: None,
2183 meta: None,
2184 }
2185 }
2186
2187 #[must_use]
2188 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2189 self.description = description.into_option();
2190 self
2191 }
2192
2193 #[must_use]
2199 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2200 self.meta = meta.into_option();
2201 self
2202 }
2203}
2204
2205#[skip_serializing_none]
2207#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2208#[serde(rename_all = "camelCase")]
2209#[non_exhaustive]
2210pub struct SessionConfigSelectGroup {
2211 pub group: SessionConfigGroupId,
2213 pub name: String,
2215 pub options: Vec<SessionConfigSelectOption>,
2217 #[serde(rename = "_meta")]
2223 pub meta: Option<Meta>,
2224}
2225
2226impl SessionConfigSelectGroup {
2227 #[must_use]
2228 pub fn new(
2229 group: impl Into<SessionConfigGroupId>,
2230 name: impl Into<String>,
2231 options: Vec<SessionConfigSelectOption>,
2232 ) -> Self {
2233 Self {
2234 group: group.into(),
2235 name: name.into(),
2236 options,
2237 meta: None,
2238 }
2239 }
2240
2241 #[must_use]
2247 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2248 self.meta = meta.into_option();
2249 self
2250 }
2251}
2252
2253#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2255#[serde(untagged)]
2256#[non_exhaustive]
2257pub enum SessionConfigSelectOptions {
2258 Ungrouped(Vec<SessionConfigSelectOption>),
2260 Grouped(Vec<SessionConfigSelectGroup>),
2262}
2263
2264impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2265 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2266 SessionConfigSelectOptions::Ungrouped(options)
2267 }
2268}
2269
2270impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2271 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2272 SessionConfigSelectOptions::Grouped(groups)
2273 }
2274}
2275
2276#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2278#[serde(rename_all = "camelCase")]
2279#[non_exhaustive]
2280pub struct SessionConfigSelect {
2281 pub current_value: SessionConfigValueId,
2283 pub options: SessionConfigSelectOptions,
2285}
2286
2287impl SessionConfigSelect {
2288 #[must_use]
2289 pub fn new(
2290 current_value: impl Into<SessionConfigValueId>,
2291 options: impl Into<SessionConfigSelectOptions>,
2292 ) -> Self {
2293 Self {
2294 current_value: current_value.into(),
2295 options: options.into(),
2296 }
2297 }
2298}
2299
2300#[cfg(feature = "unstable_boolean_config")]
2306#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2307#[serde(rename_all = "camelCase")]
2308#[non_exhaustive]
2309pub struct SessionConfigBoolean {
2310 pub current_value: bool,
2312}
2313
2314#[cfg(feature = "unstable_boolean_config")]
2315impl SessionConfigBoolean {
2316 #[must_use]
2317 pub fn new(current_value: bool) -> Self {
2318 Self { current_value }
2319 }
2320}
2321
2322#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2332#[serde(rename_all = "snake_case")]
2333#[non_exhaustive]
2334pub enum SessionConfigOptionCategory {
2335 Mode,
2337 Model,
2339 ThoughtLevel,
2341 #[serde(untagged)]
2343 Other(String),
2344}
2345
2346#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2348#[serde(tag = "type", rename_all = "snake_case")]
2349#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2350#[non_exhaustive]
2351pub enum SessionConfigKind {
2352 Select(SessionConfigSelect),
2354 #[cfg(feature = "unstable_boolean_config")]
2360 Boolean(SessionConfigBoolean),
2361}
2362
2363#[serde_as]
2365#[skip_serializing_none]
2366#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2367#[serde(rename_all = "camelCase")]
2368#[non_exhaustive]
2369pub struct SessionConfigOption {
2370 pub id: SessionConfigId,
2372 pub name: String,
2374 #[serde(default)]
2376 pub description: Option<String>,
2377 #[serde_as(deserialize_as = "DefaultOnError")]
2379 #[serde(default)]
2380 pub category: Option<SessionConfigOptionCategory>,
2381 #[serde(flatten)]
2383 pub kind: SessionConfigKind,
2384 #[serde(rename = "_meta")]
2390 pub meta: Option<Meta>,
2391}
2392
2393impl SessionConfigOption {
2394 #[must_use]
2395 pub fn new(
2396 id: impl Into<SessionConfigId>,
2397 name: impl Into<String>,
2398 kind: SessionConfigKind,
2399 ) -> Self {
2400 Self {
2401 id: id.into(),
2402 name: name.into(),
2403 description: None,
2404 category: None,
2405 kind,
2406 meta: None,
2407 }
2408 }
2409
2410 #[must_use]
2411 pub fn select(
2412 id: impl Into<SessionConfigId>,
2413 name: impl Into<String>,
2414 current_value: impl Into<SessionConfigValueId>,
2415 options: impl Into<SessionConfigSelectOptions>,
2416 ) -> Self {
2417 Self::new(
2418 id,
2419 name,
2420 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2421 )
2422 }
2423
2424 #[cfg(feature = "unstable_boolean_config")]
2428 #[must_use]
2429 pub fn boolean(
2430 id: impl Into<SessionConfigId>,
2431 name: impl Into<String>,
2432 current_value: bool,
2433 ) -> Self {
2434 Self::new(
2435 id,
2436 name,
2437 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2438 )
2439 }
2440
2441 #[must_use]
2442 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2443 self.description = description.into_option();
2444 self
2445 }
2446
2447 #[must_use]
2448 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2449 self.category = category.into_option();
2450 self
2451 }
2452
2453 #[must_use]
2459 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2460 self.meta = meta.into_option();
2461 self
2462 }
2463}
2464
2465#[cfg(feature = "unstable_boolean_config")]
2480#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2481#[serde(tag = "type", rename_all = "snake_case")]
2482#[non_exhaustive]
2483pub enum SessionConfigOptionValue {
2484 Boolean {
2486 value: bool,
2488 },
2489 #[serde(untagged)]
2495 ValueId {
2496 value: SessionConfigValueId,
2498 },
2499}
2500
2501#[cfg(feature = "unstable_boolean_config")]
2502impl SessionConfigOptionValue {
2503 #[must_use]
2505 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2506 Self::ValueId { value: id.into() }
2507 }
2508
2509 #[must_use]
2511 pub fn boolean(val: bool) -> Self {
2512 Self::Boolean { value: val }
2513 }
2514
2515 #[must_use]
2518 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2519 match self {
2520 Self::ValueId { value } => Some(value),
2521 _ => None,
2522 }
2523 }
2524
2525 #[must_use]
2527 pub fn as_bool(&self) -> Option<bool> {
2528 match self {
2529 Self::Boolean { value } => Some(*value),
2530 _ => None,
2531 }
2532 }
2533}
2534
2535#[cfg(feature = "unstable_boolean_config")]
2536impl From<SessionConfigValueId> for SessionConfigOptionValue {
2537 fn from(value: SessionConfigValueId) -> Self {
2538 Self::ValueId { value }
2539 }
2540}
2541
2542#[cfg(feature = "unstable_boolean_config")]
2543impl From<bool> for SessionConfigOptionValue {
2544 fn from(value: bool) -> Self {
2545 Self::Boolean { value }
2546 }
2547}
2548
2549#[cfg(feature = "unstable_boolean_config")]
2550impl From<&str> for SessionConfigOptionValue {
2551 fn from(value: &str) -> Self {
2552 Self::ValueId {
2553 value: SessionConfigValueId::new(value),
2554 }
2555 }
2556}
2557
2558#[skip_serializing_none]
2560#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2561#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2562#[serde(rename_all = "camelCase")]
2563#[non_exhaustive]
2564pub struct SetSessionConfigOptionRequest {
2565 pub session_id: SessionId,
2567 pub config_id: SessionConfigId,
2569 #[cfg(feature = "unstable_boolean_config")]
2574 #[serde(flatten)]
2575 pub value: SessionConfigOptionValue,
2576 #[cfg(not(feature = "unstable_boolean_config"))]
2578 pub value: SessionConfigValueId,
2579 #[serde(rename = "_meta")]
2585 pub meta: Option<Meta>,
2586}
2587
2588impl SetSessionConfigOptionRequest {
2589 #[cfg(feature = "unstable_boolean_config")]
2590 #[must_use]
2591 pub fn new(
2592 session_id: impl Into<SessionId>,
2593 config_id: impl Into<SessionConfigId>,
2594 value: impl Into<SessionConfigOptionValue>,
2595 ) -> Self {
2596 Self {
2597 session_id: session_id.into(),
2598 config_id: config_id.into(),
2599 value: value.into(),
2600 meta: None,
2601 }
2602 }
2603
2604 #[cfg(not(feature = "unstable_boolean_config"))]
2605 #[must_use]
2606 pub fn new(
2607 session_id: impl Into<SessionId>,
2608 config_id: impl Into<SessionConfigId>,
2609 value: impl Into<SessionConfigValueId>,
2610 ) -> Self {
2611 Self {
2612 session_id: session_id.into(),
2613 config_id: config_id.into(),
2614 value: value.into(),
2615 meta: None,
2616 }
2617 }
2618
2619 #[must_use]
2625 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2626 self.meta = meta.into_option();
2627 self
2628 }
2629}
2630
2631#[serde_as]
2633#[skip_serializing_none]
2634#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2635#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2636#[serde(rename_all = "camelCase")]
2637#[non_exhaustive]
2638pub struct SetSessionConfigOptionResponse {
2639 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2641 pub config_options: Vec<SessionConfigOption>,
2642 #[serde(rename = "_meta")]
2648 pub meta: Option<Meta>,
2649}
2650
2651impl SetSessionConfigOptionResponse {
2652 #[must_use]
2653 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2654 Self {
2655 config_options,
2656 meta: None,
2657 }
2658 }
2659
2660 #[must_use]
2666 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2667 self.meta = meta.into_option();
2668 self
2669 }
2670}
2671
2672#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2681#[serde(tag = "type", rename_all = "snake_case")]
2682#[non_exhaustive]
2683pub enum McpServer {
2684 Http(McpServerHttp),
2688 Sse(McpServerSse),
2692 #[serde(untagged)]
2696 Stdio(McpServerStdio),
2697}
2698
2699#[skip_serializing_none]
2701#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2702#[serde(rename_all = "camelCase")]
2703#[non_exhaustive]
2704pub struct McpServerHttp {
2705 pub name: String,
2707 pub url: String,
2709 pub headers: Vec<HttpHeader>,
2711 #[serde(rename = "_meta")]
2717 pub meta: Option<Meta>,
2718}
2719
2720impl McpServerHttp {
2721 #[must_use]
2722 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2723 Self {
2724 name: name.into(),
2725 url: url.into(),
2726 headers: Vec::new(),
2727 meta: None,
2728 }
2729 }
2730
2731 #[must_use]
2733 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2734 self.headers = headers;
2735 self
2736 }
2737
2738 #[must_use]
2744 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2745 self.meta = meta.into_option();
2746 self
2747 }
2748}
2749
2750#[skip_serializing_none]
2752#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2753#[serde(rename_all = "camelCase")]
2754#[non_exhaustive]
2755pub struct McpServerSse {
2756 pub name: String,
2758 pub url: String,
2760 pub headers: Vec<HttpHeader>,
2762 #[serde(rename = "_meta")]
2768 pub meta: Option<Meta>,
2769}
2770
2771impl McpServerSse {
2772 #[must_use]
2773 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2774 Self {
2775 name: name.into(),
2776 url: url.into(),
2777 headers: Vec::new(),
2778 meta: None,
2779 }
2780 }
2781
2782 #[must_use]
2784 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2785 self.headers = headers;
2786 self
2787 }
2788
2789 #[must_use]
2795 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2796 self.meta = meta.into_option();
2797 self
2798 }
2799}
2800
2801#[skip_serializing_none]
2803#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2804#[serde(rename_all = "camelCase")]
2805#[non_exhaustive]
2806pub struct McpServerStdio {
2807 pub name: String,
2809 pub command: PathBuf,
2811 pub args: Vec<String>,
2813 pub env: Vec<EnvVariable>,
2815 #[serde(rename = "_meta")]
2821 pub meta: Option<Meta>,
2822}
2823
2824impl McpServerStdio {
2825 #[must_use]
2826 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2827 Self {
2828 name: name.into(),
2829 command: command.into(),
2830 args: Vec::new(),
2831 env: Vec::new(),
2832 meta: None,
2833 }
2834 }
2835
2836 #[must_use]
2838 pub fn args(mut self, args: Vec<String>) -> Self {
2839 self.args = args;
2840 self
2841 }
2842
2843 #[must_use]
2845 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2846 self.env = env;
2847 self
2848 }
2849
2850 #[must_use]
2856 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2857 self.meta = meta.into_option();
2858 self
2859 }
2860}
2861
2862#[skip_serializing_none]
2864#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2865#[serde(rename_all = "camelCase")]
2866#[non_exhaustive]
2867pub struct EnvVariable {
2868 pub name: String,
2870 pub value: String,
2872 #[serde(rename = "_meta")]
2878 pub meta: Option<Meta>,
2879}
2880
2881impl EnvVariable {
2882 #[must_use]
2883 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2884 Self {
2885 name: name.into(),
2886 value: value.into(),
2887 meta: None,
2888 }
2889 }
2890
2891 #[must_use]
2897 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2898 self.meta = meta.into_option();
2899 self
2900 }
2901}
2902
2903#[skip_serializing_none]
2905#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2906#[serde(rename_all = "camelCase")]
2907#[non_exhaustive]
2908pub struct HttpHeader {
2909 pub name: String,
2911 pub value: String,
2913 #[serde(rename = "_meta")]
2919 pub meta: Option<Meta>,
2920}
2921
2922impl HttpHeader {
2923 #[must_use]
2924 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2925 Self {
2926 name: name.into(),
2927 value: value.into(),
2928 meta: None,
2929 }
2930 }
2931
2932 #[must_use]
2938 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2939 self.meta = meta.into_option();
2940 self
2941 }
2942}
2943
2944#[skip_serializing_none]
2952#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
2953#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2954#[serde(rename_all = "camelCase")]
2955#[non_exhaustive]
2956pub struct PromptRequest {
2957 pub session_id: SessionId,
2959 #[cfg(feature = "unstable_message_id")]
2969 pub message_id: Option<String>,
2970 pub prompt: Vec<ContentBlock>,
2984 #[serde(rename = "_meta")]
2990 pub meta: Option<Meta>,
2991}
2992
2993impl PromptRequest {
2994 #[must_use]
2995 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
2996 Self {
2997 session_id: session_id.into(),
2998 #[cfg(feature = "unstable_message_id")]
2999 message_id: None,
3000 prompt,
3001 meta: None,
3002 }
3003 }
3004
3005 #[cfg(feature = "unstable_message_id")]
3015 #[must_use]
3016 pub fn message_id(mut self, message_id: impl IntoOption<String>) -> Self {
3017 self.message_id = message_id.into_option();
3018 self
3019 }
3020
3021 #[must_use]
3027 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3028 self.meta = meta.into_option();
3029 self
3030 }
3031}
3032
3033#[serde_as]
3037#[skip_serializing_none]
3038#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3039#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3040#[serde(rename_all = "camelCase")]
3041#[non_exhaustive]
3042pub struct PromptResponse {
3043 #[cfg(feature = "unstable_message_id")]
3053 pub user_message_id: Option<String>,
3054 pub stop_reason: StopReason,
3056 #[cfg(feature = "unstable_session_usage")]
3062 #[serde_as(deserialize_as = "DefaultOnError")]
3063 #[serde(default)]
3064 pub usage: Option<Usage>,
3065 #[serde(rename = "_meta")]
3071 pub meta: Option<Meta>,
3072}
3073
3074impl PromptResponse {
3075 #[must_use]
3076 pub fn new(stop_reason: StopReason) -> Self {
3077 Self {
3078 #[cfg(feature = "unstable_message_id")]
3079 user_message_id: None,
3080 stop_reason,
3081 #[cfg(feature = "unstable_session_usage")]
3082 usage: None,
3083 meta: None,
3084 }
3085 }
3086
3087 #[cfg(feature = "unstable_message_id")]
3097 #[must_use]
3098 pub fn user_message_id(mut self, user_message_id: impl IntoOption<String>) -> Self {
3099 self.user_message_id = user_message_id.into_option();
3100 self
3101 }
3102
3103 #[cfg(feature = "unstable_session_usage")]
3109 #[must_use]
3110 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3111 self.usage = usage.into_option();
3112 self
3113 }
3114
3115 #[must_use]
3121 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3122 self.meta = meta.into_option();
3123 self
3124 }
3125}
3126
3127#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3131#[serde(rename_all = "snake_case")]
3132#[non_exhaustive]
3133pub enum StopReason {
3134 EndTurn,
3136 MaxTokens,
3138 MaxTurnRequests,
3141 Refusal,
3145 Cancelled,
3152}
3153
3154#[cfg(feature = "unstable_session_usage")]
3160#[skip_serializing_none]
3161#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3162#[serde(rename_all = "camelCase")]
3163#[non_exhaustive]
3164pub struct Usage {
3165 pub total_tokens: u64,
3167 pub input_tokens: u64,
3169 pub output_tokens: u64,
3171 pub thought_tokens: Option<u64>,
3173 pub cached_read_tokens: Option<u64>,
3175 pub cached_write_tokens: Option<u64>,
3177}
3178
3179#[cfg(feature = "unstable_session_usage")]
3180impl Usage {
3181 #[must_use]
3182 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3183 Self {
3184 total_tokens,
3185 input_tokens,
3186 output_tokens,
3187 thought_tokens: None,
3188 cached_read_tokens: None,
3189 cached_write_tokens: None,
3190 }
3191 }
3192
3193 #[must_use]
3195 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3196 self.thought_tokens = thought_tokens.into_option();
3197 self
3198 }
3199
3200 #[must_use]
3202 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3203 self.cached_read_tokens = cached_read_tokens.into_option();
3204 self
3205 }
3206
3207 #[must_use]
3209 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3210 self.cached_write_tokens = cached_write_tokens.into_option();
3211 self
3212 }
3213}
3214
3215#[cfg(feature = "unstable_session_model")]
3223#[serde_as]
3224#[skip_serializing_none]
3225#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3226#[serde(rename_all = "camelCase")]
3227#[non_exhaustive]
3228pub struct SessionModelState {
3229 pub current_model_id: ModelId,
3231 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3233 pub available_models: Vec<ModelInfo>,
3234 #[serde(rename = "_meta")]
3240 pub meta: Option<Meta>,
3241}
3242
3243#[cfg(feature = "unstable_session_model")]
3244impl SessionModelState {
3245 #[must_use]
3246 pub fn new(current_model_id: impl Into<ModelId>, available_models: Vec<ModelInfo>) -> Self {
3247 Self {
3248 current_model_id: current_model_id.into(),
3249 available_models,
3250 meta: None,
3251 }
3252 }
3253
3254 #[must_use]
3260 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3261 self.meta = meta.into_option();
3262 self
3263 }
3264}
3265
3266#[cfg(feature = "unstable_session_model")]
3272#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
3273#[serde(transparent)]
3274#[from(Arc<str>, String, &'static str)]
3275#[non_exhaustive]
3276pub struct ModelId(pub Arc<str>);
3277
3278#[cfg(feature = "unstable_session_model")]
3279impl ModelId {
3280 #[must_use]
3281 pub fn new(id: impl Into<Arc<str>>) -> Self {
3282 Self(id.into())
3283 }
3284}
3285
3286#[cfg(feature = "unstable_session_model")]
3292#[skip_serializing_none]
3293#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3294#[serde(rename_all = "camelCase")]
3295#[non_exhaustive]
3296pub struct ModelInfo {
3297 pub model_id: ModelId,
3299 pub name: String,
3301 #[serde(default)]
3303 pub description: Option<String>,
3304 #[serde(rename = "_meta")]
3310 pub meta: Option<Meta>,
3311}
3312
3313#[cfg(feature = "unstable_session_model")]
3314impl ModelInfo {
3315 #[must_use]
3316 pub fn new(model_id: impl Into<ModelId>, name: impl Into<String>) -> Self {
3317 Self {
3318 model_id: model_id.into(),
3319 name: name.into(),
3320 description: None,
3321 meta: None,
3322 }
3323 }
3324
3325 #[must_use]
3327 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
3328 self.description = description.into_option();
3329 self
3330 }
3331
3332 #[must_use]
3338 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3339 self.meta = meta.into_option();
3340 self
3341 }
3342}
3343
3344#[cfg(feature = "unstable_session_model")]
3350#[skip_serializing_none]
3351#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3352#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3353#[serde(rename_all = "camelCase")]
3354#[non_exhaustive]
3355pub struct SetSessionModelRequest {
3356 pub session_id: SessionId,
3358 pub model_id: ModelId,
3360 #[serde(rename = "_meta")]
3366 pub meta: Option<Meta>,
3367}
3368
3369#[cfg(feature = "unstable_session_model")]
3370impl SetSessionModelRequest {
3371 #[must_use]
3372 pub fn new(session_id: impl Into<SessionId>, model_id: impl Into<ModelId>) -> Self {
3373 Self {
3374 session_id: session_id.into(),
3375 model_id: model_id.into(),
3376 meta: None,
3377 }
3378 }
3379
3380 #[must_use]
3386 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3387 self.meta = meta.into_option();
3388 self
3389 }
3390}
3391
3392#[cfg(feature = "unstable_session_model")]
3398#[skip_serializing_none]
3399#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3400#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3401#[serde(rename_all = "camelCase")]
3402#[non_exhaustive]
3403pub struct SetSessionModelResponse {
3404 #[serde(rename = "_meta")]
3410 pub meta: Option<Meta>,
3411}
3412
3413#[cfg(feature = "unstable_session_model")]
3414impl SetSessionModelResponse {
3415 #[must_use]
3416 pub fn new() -> Self {
3417 Self::default()
3418 }
3419
3420 #[must_use]
3426 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3427 self.meta = meta.into_option();
3428 self
3429 }
3430}
3431
3432#[cfg(feature = "unstable_llm_providers")]
3445#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3446#[serde(rename_all = "snake_case")]
3447#[non_exhaustive]
3448#[expect(clippy::doc_markdown)]
3449pub enum LlmProtocol {
3450 Anthropic,
3452 #[serde(rename = "openai")]
3454 OpenAi,
3455 Azure,
3457 Vertex,
3459 Bedrock,
3461 #[serde(untagged)]
3463 Other(String),
3464}
3465
3466#[cfg(feature = "unstable_llm_providers")]
3472#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3473#[serde(rename_all = "camelCase")]
3474#[non_exhaustive]
3475pub struct ProviderCurrentConfig {
3476 pub api_type: LlmProtocol,
3478 pub base_url: String,
3480}
3481
3482#[cfg(feature = "unstable_llm_providers")]
3483impl ProviderCurrentConfig {
3484 #[must_use]
3485 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3486 Self {
3487 api_type,
3488 base_url: base_url.into(),
3489 }
3490 }
3491}
3492
3493#[cfg(feature = "unstable_llm_providers")]
3499#[serde_as]
3500#[skip_serializing_none]
3501#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3502#[serde(rename_all = "camelCase")]
3503#[non_exhaustive]
3504pub struct ProviderInfo {
3505 pub id: String,
3507 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3509 pub supported: Vec<LlmProtocol>,
3510 pub required: bool,
3513 pub current: Option<ProviderCurrentConfig>,
3516 #[serde(rename = "_meta")]
3522 pub meta: Option<Meta>,
3523}
3524
3525#[cfg(feature = "unstable_llm_providers")]
3526impl ProviderInfo {
3527 #[must_use]
3528 pub fn new(
3529 id: impl Into<String>,
3530 supported: Vec<LlmProtocol>,
3531 required: bool,
3532 current: impl IntoOption<ProviderCurrentConfig>,
3533 ) -> Self {
3534 Self {
3535 id: id.into(),
3536 supported,
3537 required,
3538 current: current.into_option(),
3539 meta: None,
3540 }
3541 }
3542
3543 #[must_use]
3549 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3550 self.meta = meta.into_option();
3551 self
3552 }
3553}
3554
3555#[cfg(feature = "unstable_llm_providers")]
3561#[skip_serializing_none]
3562#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3563#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3564#[serde(rename_all = "camelCase")]
3565#[non_exhaustive]
3566pub struct ListProvidersRequest {
3567 #[serde(rename = "_meta")]
3573 pub meta: Option<Meta>,
3574}
3575
3576#[cfg(feature = "unstable_llm_providers")]
3577impl ListProvidersRequest {
3578 #[must_use]
3579 pub fn new() -> Self {
3580 Self::default()
3581 }
3582
3583 #[must_use]
3589 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3590 self.meta = meta.into_option();
3591 self
3592 }
3593}
3594
3595#[cfg(feature = "unstable_llm_providers")]
3601#[serde_as]
3602#[skip_serializing_none]
3603#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3604#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3605#[serde(rename_all = "camelCase")]
3606#[non_exhaustive]
3607pub struct ListProvidersResponse {
3608 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3610 pub providers: Vec<ProviderInfo>,
3611 #[serde(rename = "_meta")]
3617 pub meta: Option<Meta>,
3618}
3619
3620#[cfg(feature = "unstable_llm_providers")]
3621impl ListProvidersResponse {
3622 #[must_use]
3623 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3624 Self {
3625 providers,
3626 meta: None,
3627 }
3628 }
3629
3630 #[must_use]
3636 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3637 self.meta = meta.into_option();
3638 self
3639 }
3640}
3641
3642#[cfg(feature = "unstable_llm_providers")]
3650#[skip_serializing_none]
3651#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3652#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3653#[serde(rename_all = "camelCase")]
3654#[non_exhaustive]
3655pub struct SetProvidersRequest {
3656 pub id: String,
3658 pub api_type: LlmProtocol,
3660 pub base_url: String,
3662 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3665 pub headers: HashMap<String, String>,
3666 #[serde(rename = "_meta")]
3672 pub meta: Option<Meta>,
3673}
3674
3675#[cfg(feature = "unstable_llm_providers")]
3676impl SetProvidersRequest {
3677 #[must_use]
3678 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3679 Self {
3680 id: id.into(),
3681 api_type,
3682 base_url: base_url.into(),
3683 headers: HashMap::new(),
3684 meta: None,
3685 }
3686 }
3687
3688 #[must_use]
3691 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3692 self.headers = headers;
3693 self
3694 }
3695
3696 #[must_use]
3702 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3703 self.meta = meta.into_option();
3704 self
3705 }
3706}
3707
3708#[cfg(feature = "unstable_llm_providers")]
3714#[skip_serializing_none]
3715#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3716#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3717#[serde(rename_all = "camelCase")]
3718#[non_exhaustive]
3719pub struct SetProvidersResponse {
3720 #[serde(rename = "_meta")]
3726 pub meta: Option<Meta>,
3727}
3728
3729#[cfg(feature = "unstable_llm_providers")]
3730impl SetProvidersResponse {
3731 #[must_use]
3732 pub fn new() -> Self {
3733 Self::default()
3734 }
3735
3736 #[must_use]
3742 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3743 self.meta = meta.into_option();
3744 self
3745 }
3746}
3747
3748#[cfg(feature = "unstable_llm_providers")]
3754#[skip_serializing_none]
3755#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3756#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3757#[serde(rename_all = "camelCase")]
3758#[non_exhaustive]
3759pub struct DisableProvidersRequest {
3760 pub id: String,
3762 #[serde(rename = "_meta")]
3768 pub meta: Option<Meta>,
3769}
3770
3771#[cfg(feature = "unstable_llm_providers")]
3772impl DisableProvidersRequest {
3773 #[must_use]
3774 pub fn new(id: impl Into<String>) -> Self {
3775 Self {
3776 id: id.into(),
3777 meta: None,
3778 }
3779 }
3780
3781 #[must_use]
3787 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3788 self.meta = meta.into_option();
3789 self
3790 }
3791}
3792
3793#[cfg(feature = "unstable_llm_providers")]
3799#[skip_serializing_none]
3800#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3801#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3802#[serde(rename_all = "camelCase")]
3803#[non_exhaustive]
3804pub struct DisableProvidersResponse {
3805 #[serde(rename = "_meta")]
3811 pub meta: Option<Meta>,
3812}
3813
3814#[cfg(feature = "unstable_llm_providers")]
3815impl DisableProvidersResponse {
3816 #[must_use]
3817 pub fn new() -> Self {
3818 Self::default()
3819 }
3820
3821 #[must_use]
3827 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3828 self.meta = meta.into_option();
3829 self
3830 }
3831}
3832
3833#[serde_as]
3842#[skip_serializing_none]
3843#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3844#[serde(rename_all = "camelCase")]
3845#[non_exhaustive]
3846pub struct AgentCapabilities {
3847 #[serde(default)]
3849 pub load_session: bool,
3850 #[serde(default)]
3852 pub prompt_capabilities: PromptCapabilities,
3853 #[serde(default)]
3855 pub mcp_capabilities: McpCapabilities,
3856 #[serde(default)]
3857 pub session_capabilities: SessionCapabilities,
3858 #[cfg(feature = "unstable_logout")]
3864 #[serde(default)]
3865 pub auth: AgentAuthCapabilities,
3866 #[cfg(feature = "unstable_llm_providers")]
3874 #[serde_as(deserialize_as = "DefaultOnError")]
3875 #[serde(default)]
3876 pub providers: Option<ProvidersCapabilities>,
3877 #[cfg(feature = "unstable_nes")]
3883 #[serde_as(deserialize_as = "DefaultOnError")]
3884 #[serde(default)]
3885 pub nes: Option<NesCapabilities>,
3886 #[cfg(feature = "unstable_nes")]
3892 #[serde_as(deserialize_as = "DefaultOnError")]
3893 #[serde(default)]
3894 pub position_encoding: Option<PositionEncodingKind>,
3895 #[serde(rename = "_meta")]
3901 pub meta: Option<Meta>,
3902}
3903
3904impl AgentCapabilities {
3905 #[must_use]
3906 pub fn new() -> Self {
3907 Self::default()
3908 }
3909
3910 #[must_use]
3912 pub fn load_session(mut self, load_session: bool) -> Self {
3913 self.load_session = load_session;
3914 self
3915 }
3916
3917 #[must_use]
3919 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3920 self.prompt_capabilities = prompt_capabilities;
3921 self
3922 }
3923
3924 #[must_use]
3926 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3927 self.mcp_capabilities = mcp_capabilities;
3928 self
3929 }
3930
3931 #[must_use]
3933 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3934 self.session_capabilities = session_capabilities;
3935 self
3936 }
3937
3938 #[cfg(feature = "unstable_logout")]
3944 #[must_use]
3945 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3946 self.auth = auth;
3947 self
3948 }
3949
3950 #[cfg(feature = "unstable_llm_providers")]
3956 #[must_use]
3957 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3958 self.providers = providers.into_option();
3959 self
3960 }
3961
3962 #[cfg(feature = "unstable_nes")]
3968 #[must_use]
3969 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3970 self.nes = nes.into_option();
3971 self
3972 }
3973
3974 #[cfg(feature = "unstable_nes")]
3978 #[must_use]
3979 pub fn position_encoding(
3980 mut self,
3981 position_encoding: impl IntoOption<PositionEncodingKind>,
3982 ) -> Self {
3983 self.position_encoding = position_encoding.into_option();
3984 self
3985 }
3986
3987 #[must_use]
3993 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3994 self.meta = meta.into_option();
3995 self
3996 }
3997}
3998
3999#[cfg(feature = "unstable_llm_providers")]
4007#[skip_serializing_none]
4008#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4009#[non_exhaustive]
4010pub struct ProvidersCapabilities {
4011 #[serde(rename = "_meta")]
4017 pub meta: Option<Meta>,
4018}
4019
4020#[cfg(feature = "unstable_llm_providers")]
4021impl ProvidersCapabilities {
4022 #[must_use]
4023 pub fn new() -> Self {
4024 Self::default()
4025 }
4026
4027 #[must_use]
4033 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4034 self.meta = meta.into_option();
4035 self
4036 }
4037}
4038
4039#[serde_as]
4049#[skip_serializing_none]
4050#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4051#[serde(rename_all = "camelCase")]
4052#[non_exhaustive]
4053pub struct SessionCapabilities {
4054 #[serde_as(deserialize_as = "DefaultOnError")]
4056 #[serde(default)]
4057 pub list: Option<SessionListCapabilities>,
4058 #[cfg(feature = "unstable_session_additional_directories")]
4064 #[serde_as(deserialize_as = "DefaultOnError")]
4065 #[serde(default)]
4066 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
4067 #[cfg(feature = "unstable_session_fork")]
4073 #[serde_as(deserialize_as = "DefaultOnError")]
4074 #[serde(default)]
4075 pub fork: Option<SessionForkCapabilities>,
4076 #[serde_as(deserialize_as = "DefaultOnError")]
4078 #[serde(default)]
4079 pub resume: Option<SessionResumeCapabilities>,
4080 #[serde_as(deserialize_as = "DefaultOnError")]
4082 #[serde(default)]
4083 pub close: Option<SessionCloseCapabilities>,
4084 #[serde(rename = "_meta")]
4090 pub meta: Option<Meta>,
4091}
4092
4093impl SessionCapabilities {
4094 #[must_use]
4095 pub fn new() -> Self {
4096 Self::default()
4097 }
4098
4099 #[must_use]
4101 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
4102 self.list = list.into_option();
4103 self
4104 }
4105
4106 #[cfg(feature = "unstable_session_additional_directories")]
4112 #[must_use]
4113 pub fn additional_directories(
4114 mut self,
4115 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4116 ) -> Self {
4117 self.additional_directories = additional_directories.into_option();
4118 self
4119 }
4120
4121 #[cfg(feature = "unstable_session_fork")]
4122 #[must_use]
4124 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4125 self.fork = fork.into_option();
4126 self
4127 }
4128
4129 #[must_use]
4131 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4132 self.resume = resume.into_option();
4133 self
4134 }
4135
4136 #[must_use]
4138 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4139 self.close = close.into_option();
4140 self
4141 }
4142
4143 #[must_use]
4149 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4150 self.meta = meta.into_option();
4151 self
4152 }
4153}
4154
4155#[skip_serializing_none]
4159#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4160#[non_exhaustive]
4161pub struct SessionListCapabilities {
4162 #[serde(rename = "_meta")]
4168 pub meta: Option<Meta>,
4169}
4170
4171impl SessionListCapabilities {
4172 #[must_use]
4173 pub fn new() -> Self {
4174 Self::default()
4175 }
4176
4177 #[must_use]
4183 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4184 self.meta = meta.into_option();
4185 self
4186 }
4187}
4188
4189#[cfg(feature = "unstable_session_additional_directories")]
4198#[skip_serializing_none]
4199#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4200#[non_exhaustive]
4201pub struct SessionAdditionalDirectoriesCapabilities {
4202 #[serde(rename = "_meta")]
4208 pub meta: Option<Meta>,
4209}
4210
4211#[cfg(feature = "unstable_session_additional_directories")]
4212impl SessionAdditionalDirectoriesCapabilities {
4213 #[must_use]
4214 pub fn new() -> Self {
4215 Self::default()
4216 }
4217
4218 #[must_use]
4224 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4225 self.meta = meta.into_option();
4226 self
4227 }
4228}
4229
4230#[cfg(feature = "unstable_session_fork")]
4238#[skip_serializing_none]
4239#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4240#[non_exhaustive]
4241pub struct SessionForkCapabilities {
4242 #[serde(rename = "_meta")]
4248 pub meta: Option<Meta>,
4249}
4250
4251#[cfg(feature = "unstable_session_fork")]
4252impl SessionForkCapabilities {
4253 #[must_use]
4254 pub fn new() -> Self {
4255 Self::default()
4256 }
4257
4258 #[must_use]
4264 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4265 self.meta = meta.into_option();
4266 self
4267 }
4268}
4269
4270#[skip_serializing_none]
4274#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4275#[non_exhaustive]
4276pub struct SessionResumeCapabilities {
4277 #[serde(rename = "_meta")]
4283 pub meta: Option<Meta>,
4284}
4285
4286impl SessionResumeCapabilities {
4287 #[must_use]
4288 pub fn new() -> Self {
4289 Self::default()
4290 }
4291
4292 #[must_use]
4298 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4299 self.meta = meta.into_option();
4300 self
4301 }
4302}
4303
4304#[skip_serializing_none]
4308#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4309#[non_exhaustive]
4310pub struct SessionCloseCapabilities {
4311 #[serde(rename = "_meta")]
4317 pub meta: Option<Meta>,
4318}
4319
4320impl SessionCloseCapabilities {
4321 #[must_use]
4322 pub fn new() -> Self {
4323 Self::default()
4324 }
4325
4326 #[must_use]
4332 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4333 self.meta = meta.into_option();
4334 self
4335 }
4336}
4337
4338#[skip_serializing_none]
4351#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4352#[serde(rename_all = "camelCase")]
4353#[non_exhaustive]
4354pub struct PromptCapabilities {
4355 #[serde(default)]
4357 pub image: bool,
4358 #[serde(default)]
4360 pub audio: bool,
4361 #[serde(default)]
4366 pub embedded_context: bool,
4367 #[serde(rename = "_meta")]
4373 pub meta: Option<Meta>,
4374}
4375
4376impl PromptCapabilities {
4377 #[must_use]
4378 pub fn new() -> Self {
4379 Self::default()
4380 }
4381
4382 #[must_use]
4384 pub fn image(mut self, image: bool) -> Self {
4385 self.image = image;
4386 self
4387 }
4388
4389 #[must_use]
4391 pub fn audio(mut self, audio: bool) -> Self {
4392 self.audio = audio;
4393 self
4394 }
4395
4396 #[must_use]
4401 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4402 self.embedded_context = embedded_context;
4403 self
4404 }
4405
4406 #[must_use]
4412 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4413 self.meta = meta.into_option();
4414 self
4415 }
4416}
4417
4418#[skip_serializing_none]
4420#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4421#[serde(rename_all = "camelCase")]
4422#[non_exhaustive]
4423pub struct McpCapabilities {
4424 #[serde(default)]
4426 pub http: bool,
4427 #[serde(default)]
4429 pub sse: bool,
4430 #[serde(rename = "_meta")]
4436 pub meta: Option<Meta>,
4437}
4438
4439impl McpCapabilities {
4440 #[must_use]
4441 pub fn new() -> Self {
4442 Self::default()
4443 }
4444
4445 #[must_use]
4447 pub fn http(mut self, http: bool) -> Self {
4448 self.http = http;
4449 self
4450 }
4451
4452 #[must_use]
4454 pub fn sse(mut self, sse: bool) -> Self {
4455 self.sse = sse;
4456 self
4457 }
4458
4459 #[must_use]
4465 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4466 self.meta = meta.into_option();
4467 self
4468 }
4469}
4470
4471#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4477#[non_exhaustive]
4478pub struct AgentMethodNames {
4479 pub initialize: &'static str,
4481 pub authenticate: &'static str,
4483 #[cfg(feature = "unstable_llm_providers")]
4485 pub providers_list: &'static str,
4486 #[cfg(feature = "unstable_llm_providers")]
4488 pub providers_set: &'static str,
4489 #[cfg(feature = "unstable_llm_providers")]
4491 pub providers_disable: &'static str,
4492 pub session_new: &'static str,
4494 pub session_load: &'static str,
4496 pub session_set_mode: &'static str,
4498 pub session_set_config_option: &'static str,
4500 pub session_prompt: &'static str,
4502 pub session_cancel: &'static str,
4504 #[cfg(feature = "unstable_session_model")]
4506 pub session_set_model: &'static str,
4507 pub session_list: &'static str,
4509 #[cfg(feature = "unstable_session_fork")]
4511 pub session_fork: &'static str,
4512 pub session_resume: &'static str,
4514 pub session_close: &'static str,
4516 #[cfg(feature = "unstable_logout")]
4518 pub logout: &'static str,
4519 #[cfg(feature = "unstable_nes")]
4521 pub nes_start: &'static str,
4522 #[cfg(feature = "unstable_nes")]
4524 pub nes_suggest: &'static str,
4525 #[cfg(feature = "unstable_nes")]
4527 pub nes_accept: &'static str,
4528 #[cfg(feature = "unstable_nes")]
4530 pub nes_reject: &'static str,
4531 #[cfg(feature = "unstable_nes")]
4533 pub nes_close: &'static str,
4534 #[cfg(feature = "unstable_nes")]
4536 pub document_did_open: &'static str,
4537 #[cfg(feature = "unstable_nes")]
4539 pub document_did_change: &'static str,
4540 #[cfg(feature = "unstable_nes")]
4542 pub document_did_close: &'static str,
4543 #[cfg(feature = "unstable_nes")]
4545 pub document_did_save: &'static str,
4546 #[cfg(feature = "unstable_nes")]
4548 pub document_did_focus: &'static str,
4549}
4550
4551pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4553 initialize: INITIALIZE_METHOD_NAME,
4554 authenticate: AUTHENTICATE_METHOD_NAME,
4555 #[cfg(feature = "unstable_llm_providers")]
4556 providers_list: PROVIDERS_LIST_METHOD_NAME,
4557 #[cfg(feature = "unstable_llm_providers")]
4558 providers_set: PROVIDERS_SET_METHOD_NAME,
4559 #[cfg(feature = "unstable_llm_providers")]
4560 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4561 session_new: SESSION_NEW_METHOD_NAME,
4562 session_load: SESSION_LOAD_METHOD_NAME,
4563 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4564 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4565 session_prompt: SESSION_PROMPT_METHOD_NAME,
4566 session_cancel: SESSION_CANCEL_METHOD_NAME,
4567 #[cfg(feature = "unstable_session_model")]
4568 session_set_model: SESSION_SET_MODEL_METHOD_NAME,
4569 session_list: SESSION_LIST_METHOD_NAME,
4570 #[cfg(feature = "unstable_session_fork")]
4571 session_fork: SESSION_FORK_METHOD_NAME,
4572 session_resume: SESSION_RESUME_METHOD_NAME,
4573 session_close: SESSION_CLOSE_METHOD_NAME,
4574 #[cfg(feature = "unstable_logout")]
4575 logout: LOGOUT_METHOD_NAME,
4576 #[cfg(feature = "unstable_nes")]
4577 nes_start: NES_START_METHOD_NAME,
4578 #[cfg(feature = "unstable_nes")]
4579 nes_suggest: NES_SUGGEST_METHOD_NAME,
4580 #[cfg(feature = "unstable_nes")]
4581 nes_accept: NES_ACCEPT_METHOD_NAME,
4582 #[cfg(feature = "unstable_nes")]
4583 nes_reject: NES_REJECT_METHOD_NAME,
4584 #[cfg(feature = "unstable_nes")]
4585 nes_close: NES_CLOSE_METHOD_NAME,
4586 #[cfg(feature = "unstable_nes")]
4587 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4588 #[cfg(feature = "unstable_nes")]
4589 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4590 #[cfg(feature = "unstable_nes")]
4591 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4592 #[cfg(feature = "unstable_nes")]
4593 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4594 #[cfg(feature = "unstable_nes")]
4595 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4596};
4597
4598pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4600pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4602#[cfg(feature = "unstable_llm_providers")]
4604pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4605#[cfg(feature = "unstable_llm_providers")]
4607pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4608#[cfg(feature = "unstable_llm_providers")]
4610pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4611pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4613pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4615pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4617pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4619pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4621pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4623#[cfg(feature = "unstable_session_model")]
4625pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
4626pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4628#[cfg(feature = "unstable_session_fork")]
4630pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4631pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4633pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4635#[cfg(feature = "unstable_logout")]
4637pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4638
4639#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4646#[serde(untagged)]
4647#[schemars(inline)]
4648#[non_exhaustive]
4649#[allow(clippy::large_enum_variant)]
4650pub enum ClientRequest {
4651 InitializeRequest(InitializeRequest),
4662 AuthenticateRequest(AuthenticateRequest),
4672 #[cfg(feature = "unstable_llm_providers")]
4678 ListProvidersRequest(ListProvidersRequest),
4679 #[cfg(feature = "unstable_llm_providers")]
4685 SetProvidersRequest(SetProvidersRequest),
4686 #[cfg(feature = "unstable_llm_providers")]
4692 DisableProvidersRequest(DisableProvidersRequest),
4693 #[cfg(feature = "unstable_logout")]
4702 LogoutRequest(LogoutRequest),
4703 NewSessionRequest(NewSessionRequest),
4716 LoadSessionRequest(LoadSessionRequest),
4727 ListSessionsRequest(ListSessionsRequest),
4733 #[cfg(feature = "unstable_session_fork")]
4734 ForkSessionRequest(ForkSessionRequest),
4746 ResumeSessionRequest(ResumeSessionRequest),
4753 CloseSessionRequest(CloseSessionRequest),
4760 SetSessionModeRequest(SetSessionModeRequest),
4774 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4776 PromptRequest(PromptRequest),
4788 #[cfg(feature = "unstable_session_model")]
4789 SetSessionModelRequest(SetSessionModelRequest),
4795 #[cfg(feature = "unstable_nes")]
4796 StartNesRequest(StartNesRequest),
4802 #[cfg(feature = "unstable_nes")]
4803 SuggestNesRequest(SuggestNesRequest),
4809 #[cfg(feature = "unstable_nes")]
4810 CloseNesRequest(CloseNesRequest),
4819 ExtMethodRequest(ExtRequest),
4826}
4827
4828impl ClientRequest {
4829 #[must_use]
4831 pub fn method(&self) -> &str {
4832 match self {
4833 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4834 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4835 #[cfg(feature = "unstable_llm_providers")]
4836 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4837 #[cfg(feature = "unstable_llm_providers")]
4838 Self::SetProvidersRequest(_) => AGENT_METHOD_NAMES.providers_set,
4839 #[cfg(feature = "unstable_llm_providers")]
4840 Self::DisableProvidersRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4841 #[cfg(feature = "unstable_logout")]
4842 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4843 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4844 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4845 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4846 #[cfg(feature = "unstable_session_fork")]
4847 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
4848 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
4849 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
4850 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
4851 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
4852 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
4853 #[cfg(feature = "unstable_session_model")]
4854 Self::SetSessionModelRequest(_) => AGENT_METHOD_NAMES.session_set_model,
4855 #[cfg(feature = "unstable_nes")]
4856 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
4857 #[cfg(feature = "unstable_nes")]
4858 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
4859 #[cfg(feature = "unstable_nes")]
4860 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
4861 Self::ExtMethodRequest(ext_request) => &ext_request.method,
4862 }
4863 }
4864}
4865
4866#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4873#[serde(untagged)]
4874#[schemars(inline)]
4875#[non_exhaustive]
4876#[allow(clippy::large_enum_variant)]
4877pub enum AgentResponse {
4878 InitializeResponse(InitializeResponse),
4879 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
4880 #[cfg(feature = "unstable_llm_providers")]
4881 ListProvidersResponse(ListProvidersResponse),
4882 #[cfg(feature = "unstable_llm_providers")]
4883 SetProvidersResponse(#[serde(default)] SetProvidersResponse),
4884 #[cfg(feature = "unstable_llm_providers")]
4885 DisableProvidersResponse(#[serde(default)] DisableProvidersResponse),
4886 #[cfg(feature = "unstable_logout")]
4887 LogoutResponse(#[serde(default)] LogoutResponse),
4888 NewSessionResponse(NewSessionResponse),
4889 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
4890 ListSessionsResponse(ListSessionsResponse),
4891 #[cfg(feature = "unstable_session_fork")]
4892 ForkSessionResponse(ForkSessionResponse),
4893 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
4894 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
4895 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
4896 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
4897 PromptResponse(PromptResponse),
4898 #[cfg(feature = "unstable_session_model")]
4899 SetSessionModelResponse(#[serde(default)] SetSessionModelResponse),
4900 #[cfg(feature = "unstable_nes")]
4901 StartNesResponse(StartNesResponse),
4902 #[cfg(feature = "unstable_nes")]
4903 SuggestNesResponse(SuggestNesResponse),
4904 #[cfg(feature = "unstable_nes")]
4905 CloseNesResponse(#[serde(default)] CloseNesResponse),
4906 ExtMethodResponse(ExtResponse),
4907}
4908
4909#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4916#[serde(untagged)]
4917#[schemars(inline)]
4918#[non_exhaustive]
4919pub enum ClientNotification {
4920 CancelNotification(CancelNotification),
4932 #[cfg(feature = "unstable_nes")]
4933 DidOpenDocumentNotification(DidOpenDocumentNotification),
4937 #[cfg(feature = "unstable_nes")]
4938 DidChangeDocumentNotification(DidChangeDocumentNotification),
4942 #[cfg(feature = "unstable_nes")]
4943 DidCloseDocumentNotification(DidCloseDocumentNotification),
4947 #[cfg(feature = "unstable_nes")]
4948 DidSaveDocumentNotification(DidSaveDocumentNotification),
4952 #[cfg(feature = "unstable_nes")]
4953 DidFocusDocumentNotification(DidFocusDocumentNotification),
4957 #[cfg(feature = "unstable_nes")]
4958 AcceptNesNotification(AcceptNesNotification),
4962 #[cfg(feature = "unstable_nes")]
4963 RejectNesNotification(RejectNesNotification),
4967 ExtNotification(ExtNotification),
4974}
4975
4976impl ClientNotification {
4977 #[must_use]
4979 pub fn method(&self) -> &str {
4980 match self {
4981 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
4982 #[cfg(feature = "unstable_nes")]
4983 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
4984 #[cfg(feature = "unstable_nes")]
4985 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
4986 #[cfg(feature = "unstable_nes")]
4987 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
4988 #[cfg(feature = "unstable_nes")]
4989 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
4990 #[cfg(feature = "unstable_nes")]
4991 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
4992 #[cfg(feature = "unstable_nes")]
4993 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
4994 #[cfg(feature = "unstable_nes")]
4995 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
4996 Self::ExtNotification(ext_notification) => &ext_notification.method,
4997 }
4998 }
4999}
5000
5001#[skip_serializing_none]
5005#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5006#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5007#[serde(rename_all = "camelCase")]
5008#[non_exhaustive]
5009pub struct CancelNotification {
5010 pub session_id: SessionId,
5012 #[serde(rename = "_meta")]
5018 pub meta: Option<Meta>,
5019}
5020
5021impl CancelNotification {
5022 #[must_use]
5023 pub fn new(session_id: impl Into<SessionId>) -> Self {
5024 Self {
5025 session_id: session_id.into(),
5026 meta: None,
5027 }
5028 }
5029
5030 #[must_use]
5036 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5037 self.meta = meta.into_option();
5038 self
5039 }
5040}
5041
5042#[cfg(test)]
5043mod test_serialization {
5044 use super::*;
5045 use serde_json::json;
5046
5047 #[test]
5048 fn test_mcp_server_stdio_serialization() {
5049 let server = McpServer::Stdio(
5050 McpServerStdio::new("test-server", "/usr/bin/server")
5051 .args(vec!["--port".to_string(), "3000".to_string()])
5052 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5053 );
5054
5055 let json = serde_json::to_value(&server).unwrap();
5056 assert_eq!(
5057 json,
5058 json!({
5059 "name": "test-server",
5060 "command": "/usr/bin/server",
5061 "args": ["--port", "3000"],
5062 "env": [
5063 {
5064 "name": "API_KEY",
5065 "value": "secret123"
5066 }
5067 ]
5068 })
5069 );
5070
5071 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5072 match deserialized {
5073 McpServer::Stdio(McpServerStdio {
5074 name,
5075 command,
5076 args,
5077 env,
5078 meta: _,
5079 }) => {
5080 assert_eq!(name, "test-server");
5081 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5082 assert_eq!(args, vec!["--port", "3000"]);
5083 assert_eq!(env.len(), 1);
5084 assert_eq!(env[0].name, "API_KEY");
5085 assert_eq!(env[0].value, "secret123");
5086 }
5087 _ => panic!("Expected Stdio variant"),
5088 }
5089 }
5090
5091 #[test]
5092 fn test_mcp_server_http_serialization() {
5093 let server = McpServer::Http(
5094 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5095 HttpHeader::new("Authorization", "Bearer token123"),
5096 HttpHeader::new("Content-Type", "application/json"),
5097 ]),
5098 );
5099
5100 let json = serde_json::to_value(&server).unwrap();
5101 assert_eq!(
5102 json,
5103 json!({
5104 "type": "http",
5105 "name": "http-server",
5106 "url": "https://api.example.com",
5107 "headers": [
5108 {
5109 "name": "Authorization",
5110 "value": "Bearer token123"
5111 },
5112 {
5113 "name": "Content-Type",
5114 "value": "application/json"
5115 }
5116 ]
5117 })
5118 );
5119
5120 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5121 match deserialized {
5122 McpServer::Http(McpServerHttp {
5123 name,
5124 url,
5125 headers,
5126 meta: _,
5127 }) => {
5128 assert_eq!(name, "http-server");
5129 assert_eq!(url, "https://api.example.com");
5130 assert_eq!(headers.len(), 2);
5131 assert_eq!(headers[0].name, "Authorization");
5132 assert_eq!(headers[0].value, "Bearer token123");
5133 assert_eq!(headers[1].name, "Content-Type");
5134 assert_eq!(headers[1].value, "application/json");
5135 }
5136 _ => panic!("Expected Http variant"),
5137 }
5138 }
5139
5140 #[test]
5141 fn test_mcp_server_sse_serialization() {
5142 let server = McpServer::Sse(
5143 McpServerSse::new("sse-server", "https://sse.example.com/events")
5144 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5145 );
5146
5147 let json = serde_json::to_value(&server).unwrap();
5148 assert_eq!(
5149 json,
5150 json!({
5151 "type": "sse",
5152 "name": "sse-server",
5153 "url": "https://sse.example.com/events",
5154 "headers": [
5155 {
5156 "name": "X-API-Key",
5157 "value": "apikey456"
5158 }
5159 ]
5160 })
5161 );
5162
5163 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5164 match deserialized {
5165 McpServer::Sse(McpServerSse {
5166 name,
5167 url,
5168 headers,
5169 meta: _,
5170 }) => {
5171 assert_eq!(name, "sse-server");
5172 assert_eq!(url, "https://sse.example.com/events");
5173 assert_eq!(headers.len(), 1);
5174 assert_eq!(headers[0].name, "X-API-Key");
5175 assert_eq!(headers[0].value, "apikey456");
5176 }
5177 _ => panic!("Expected Sse variant"),
5178 }
5179 }
5180
5181 #[test]
5182 fn test_session_config_option_category_known_variants() {
5183 assert_eq!(
5185 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5186 json!("mode")
5187 );
5188 assert_eq!(
5189 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5190 json!("model")
5191 );
5192 assert_eq!(
5193 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5194 json!("thought_level")
5195 );
5196
5197 assert_eq!(
5199 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5200 SessionConfigOptionCategory::Mode
5201 );
5202 assert_eq!(
5203 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5204 SessionConfigOptionCategory::Model
5205 );
5206 assert_eq!(
5207 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5208 SessionConfigOptionCategory::ThoughtLevel
5209 );
5210 }
5211
5212 #[test]
5213 fn test_session_config_option_category_unknown_variants() {
5214 let unknown: SessionConfigOptionCategory =
5216 serde_json::from_str("\"some_future_category\"").unwrap();
5217 assert_eq!(
5218 unknown,
5219 SessionConfigOptionCategory::Other("some_future_category".to_string())
5220 );
5221
5222 let json = serde_json::to_value(&unknown).unwrap();
5224 assert_eq!(json, json!("some_future_category"));
5225 }
5226
5227 #[test]
5228 fn test_session_config_option_category_custom_categories() {
5229 let custom: SessionConfigOptionCategory =
5231 serde_json::from_str("\"_my_custom_category\"").unwrap();
5232 assert_eq!(
5233 custom,
5234 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5235 );
5236
5237 let json = serde_json::to_value(&custom).unwrap();
5239 assert_eq!(json, json!("_my_custom_category"));
5240
5241 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5243 assert_eq!(
5244 deserialized,
5245 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5246 );
5247 }
5248
5249 #[test]
5250 fn test_auth_method_agent_serialization() {
5251 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5252
5253 let json = serde_json::to_value(&method).unwrap();
5254 assert_eq!(
5255 json,
5256 json!({
5257 "id": "default-auth",
5258 "name": "Default Auth"
5259 })
5260 );
5261 assert!(!json.as_object().unwrap().contains_key("description"));
5263 assert!(!json.as_object().unwrap().contains_key("type"));
5265
5266 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5267 match deserialized {
5268 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5269 assert_eq!(id.0.as_ref(), "default-auth");
5270 assert_eq!(name, "Default Auth");
5271 }
5272 #[cfg(feature = "unstable_auth_methods")]
5273 _ => panic!("Expected Agent variant"),
5274 }
5275 }
5276
5277 #[test]
5278 fn test_auth_method_explicit_agent_deserialization() {
5279 let json = json!({
5281 "id": "agent-auth",
5282 "name": "Agent Auth",
5283 "type": "agent"
5284 });
5285
5286 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5287 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5288 }
5289
5290 #[cfg(feature = "unstable_session_additional_directories")]
5291 #[test]
5292 fn test_session_additional_directories_serialization() {
5293 assert_eq!(
5294 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5295 json!({
5296 "cwd": "/home/user/project",
5297 "mcpServers": []
5298 })
5299 );
5300 assert_eq!(
5301 serde_json::to_value(
5302 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5303 PathBuf::from("/home/user/shared-lib"),
5304 PathBuf::from("/home/user/product-docs"),
5305 ])
5306 )
5307 .unwrap(),
5308 json!({
5309 "cwd": "/home/user/project",
5310 "additionalDirectories": [
5311 "/home/user/shared-lib",
5312 "/home/user/product-docs"
5313 ],
5314 "mcpServers": []
5315 })
5316 );
5317 assert_eq!(
5318 serde_json::to_value(
5319 ListSessionsRequest::new().additional_directories(Vec::<PathBuf>::new())
5320 )
5321 .unwrap(),
5322 json!({})
5323 );
5324 assert_eq!(
5325 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5326 json!({
5327 "sessionId": "sess_abc123",
5328 "cwd": "/home/user/project"
5329 })
5330 );
5331 assert_eq!(
5332 serde_json::to_value(
5333 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5334 PathBuf::from("/home/user/shared-lib"),
5335 PathBuf::from("/home/user/product-docs"),
5336 ])
5337 )
5338 .unwrap(),
5339 json!({
5340 "sessionId": "sess_abc123",
5341 "cwd": "/home/user/project",
5342 "additionalDirectories": [
5343 "/home/user/shared-lib",
5344 "/home/user/product-docs"
5345 ]
5346 })
5347 );
5348 assert_eq!(
5349 serde_json::from_value::<SessionInfo>(json!({
5350 "sessionId": "sess_abc123",
5351 "cwd": "/home/user/project"
5352 }))
5353 .unwrap()
5354 .additional_directories,
5355 Vec::<PathBuf>::new()
5356 );
5357
5358 assert_eq!(
5359 serde_json::from_value::<ListSessionsRequest>(json!({}))
5360 .unwrap()
5361 .additional_directories,
5362 Vec::<PathBuf>::new()
5363 );
5364
5365 assert_eq!(
5366 serde_json::from_value::<ListSessionsRequest>(json!({
5367 "additionalDirectories": []
5368 }))
5369 .unwrap()
5370 .additional_directories,
5371 Vec::<PathBuf>::new()
5372 );
5373 }
5374
5375 #[cfg(feature = "unstable_session_additional_directories")]
5376 #[test]
5377 fn test_session_additional_directories_capabilities_serialization() {
5378 assert_eq!(
5379 serde_json::to_value(
5380 SessionCapabilities::new()
5381 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5382 )
5383 .unwrap(),
5384 json!({
5385 "additionalDirectories": {}
5386 })
5387 );
5388 }
5389
5390 #[cfg(feature = "unstable_auth_methods")]
5391 #[test]
5392 fn test_auth_method_env_var_serialization() {
5393 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5394 "api-key",
5395 "API Key",
5396 vec![AuthEnvVar::new("API_KEY")],
5397 ));
5398
5399 let json = serde_json::to_value(&method).unwrap();
5400 assert_eq!(
5401 json,
5402 json!({
5403 "id": "api-key",
5404 "name": "API Key",
5405 "type": "env_var",
5406 "vars": [{"name": "API_KEY"}]
5407 })
5408 );
5409 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5411 assert!(
5412 !json["vars"][0]
5413 .as_object()
5414 .unwrap()
5415 .contains_key("optional")
5416 );
5417
5418 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5419 match deserialized {
5420 AuthMethod::EnvVar(AuthMethodEnvVar {
5421 id,
5422 name: method_name,
5423 vars,
5424 link,
5425 ..
5426 }) => {
5427 assert_eq!(id.0.as_ref(), "api-key");
5428 assert_eq!(method_name, "API Key");
5429 assert_eq!(vars.len(), 1);
5430 assert_eq!(vars[0].name, "API_KEY");
5431 assert!(vars[0].secret);
5432 assert!(!vars[0].optional);
5433 assert!(link.is_none());
5434 }
5435 _ => panic!("Expected EnvVar variant"),
5436 }
5437 }
5438
5439 #[cfg(feature = "unstable_auth_methods")]
5440 #[test]
5441 fn test_auth_method_env_var_with_link_serialization() {
5442 let method = AuthMethod::EnvVar(
5443 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5444 .link("https://example.com/keys"),
5445 );
5446
5447 let json = serde_json::to_value(&method).unwrap();
5448 assert_eq!(
5449 json,
5450 json!({
5451 "id": "api-key",
5452 "name": "API Key",
5453 "type": "env_var",
5454 "vars": [{"name": "API_KEY"}],
5455 "link": "https://example.com/keys"
5456 })
5457 );
5458
5459 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5460 match deserialized {
5461 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5462 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5463 }
5464 _ => panic!("Expected EnvVar variant"),
5465 }
5466 }
5467
5468 #[cfg(feature = "unstable_auth_methods")]
5469 #[test]
5470 fn test_auth_method_env_var_multiple_vars() {
5471 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5472 "azure-openai",
5473 "Azure OpenAI",
5474 vec![
5475 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5476 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5477 .label("Endpoint URL")
5478 .secret(false),
5479 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5480 .label("API Version")
5481 .secret(false)
5482 .optional(true),
5483 ],
5484 ));
5485
5486 let json = serde_json::to_value(&method).unwrap();
5487 assert_eq!(
5488 json,
5489 json!({
5490 "id": "azure-openai",
5491 "name": "Azure OpenAI",
5492 "type": "env_var",
5493 "vars": [
5494 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5495 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5496 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5497 ]
5498 })
5499 );
5500
5501 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5502 match deserialized {
5503 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5504 assert_eq!(vars.len(), 3);
5505 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5507 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5508 assert!(vars[0].secret);
5509 assert!(!vars[0].optional);
5510 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5512 assert!(!vars[1].secret);
5513 assert!(!vars[1].optional);
5514 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5516 assert!(!vars[2].secret);
5517 assert!(vars[2].optional);
5518 }
5519 _ => panic!("Expected EnvVar variant"),
5520 }
5521 }
5522
5523 #[cfg(feature = "unstable_auth_methods")]
5524 #[test]
5525 fn test_auth_method_terminal_serialization() {
5526 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5527
5528 let json = serde_json::to_value(&method).unwrap();
5529 assert_eq!(
5530 json,
5531 json!({
5532 "id": "tui-auth",
5533 "name": "Terminal Auth",
5534 "type": "terminal"
5535 })
5536 );
5537 assert!(!json.as_object().unwrap().contains_key("args"));
5539 assert!(!json.as_object().unwrap().contains_key("env"));
5540
5541 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5542 match deserialized {
5543 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5544 assert!(args.is_empty());
5545 assert!(env.is_empty());
5546 }
5547 _ => panic!("Expected Terminal variant"),
5548 }
5549 }
5550
5551 #[cfg(feature = "unstable_auth_methods")]
5552 #[test]
5553 fn test_auth_method_terminal_with_args_and_env_serialization() {
5554 use std::collections::HashMap;
5555
5556 let mut env = HashMap::new();
5557 env.insert("TERM".to_string(), "xterm-256color".to_string());
5558
5559 let method = AuthMethod::Terminal(
5560 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5561 .args(vec!["--interactive".to_string(), "--color".to_string()])
5562 .env(env),
5563 );
5564
5565 let json = serde_json::to_value(&method).unwrap();
5566 assert_eq!(
5567 json,
5568 json!({
5569 "id": "tui-auth",
5570 "name": "Terminal Auth",
5571 "type": "terminal",
5572 "args": ["--interactive", "--color"],
5573 "env": {
5574 "TERM": "xterm-256color"
5575 }
5576 })
5577 );
5578
5579 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5580 match deserialized {
5581 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5582 assert_eq!(args, vec!["--interactive", "--color"]);
5583 assert_eq!(env.len(), 1);
5584 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5585 }
5586 _ => panic!("Expected Terminal variant"),
5587 }
5588 }
5589
5590 #[cfg(feature = "unstable_boolean_config")]
5591 #[test]
5592 fn test_session_config_option_value_id_serialize() {
5593 let val = SessionConfigOptionValue::value_id("model-1");
5594 let json = serde_json::to_value(&val).unwrap();
5595 assert_eq!(json, json!({ "value": "model-1" }));
5597 assert!(!json.as_object().unwrap().contains_key("type"));
5598 }
5599
5600 #[cfg(feature = "unstable_boolean_config")]
5601 #[test]
5602 fn test_session_config_option_value_boolean_serialize() {
5603 let val = SessionConfigOptionValue::boolean(true);
5604 let json = serde_json::to_value(&val).unwrap();
5605 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5606 }
5607
5608 #[cfg(feature = "unstable_boolean_config")]
5609 #[test]
5610 fn test_session_config_option_value_deserialize_no_type() {
5611 let json = json!({ "value": "model-1" });
5613 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5614 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5615 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5616 }
5617
5618 #[cfg(feature = "unstable_boolean_config")]
5619 #[test]
5620 fn test_session_config_option_value_deserialize_boolean() {
5621 let json = json!({ "type": "boolean", "value": true });
5622 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5623 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5624 assert_eq!(val.as_bool(), Some(true));
5625 }
5626
5627 #[cfg(feature = "unstable_boolean_config")]
5628 #[test]
5629 fn test_session_config_option_value_deserialize_boolean_false() {
5630 let json = json!({ "type": "boolean", "value": false });
5631 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5632 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5633 assert_eq!(val.as_bool(), Some(false));
5634 }
5635
5636 #[cfg(feature = "unstable_boolean_config")]
5637 #[test]
5638 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5639 let json = json!({ "type": "text", "value": "freeform input" });
5641 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5642 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5643 }
5644
5645 #[cfg(feature = "unstable_boolean_config")]
5646 #[test]
5647 fn test_session_config_option_value_roundtrip_value_id() {
5648 let original = SessionConfigOptionValue::value_id("option-a");
5649 let json = serde_json::to_value(&original).unwrap();
5650 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5651 assert_eq!(original, roundtripped);
5652 }
5653
5654 #[cfg(feature = "unstable_boolean_config")]
5655 #[test]
5656 fn test_session_config_option_value_roundtrip_boolean() {
5657 let original = SessionConfigOptionValue::boolean(false);
5658 let json = serde_json::to_value(&original).unwrap();
5659 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5660 assert_eq!(original, roundtripped);
5661 }
5662
5663 #[cfg(feature = "unstable_boolean_config")]
5664 #[test]
5665 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5666 let json = json!({ "type": "boolean", "value": "not a bool" });
5668 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5669 assert!(result.is_ok());
5671 assert_eq!(
5672 result.unwrap().as_value_id().unwrap().to_string(),
5673 "not a bool"
5674 );
5675 }
5676
5677 #[cfg(feature = "unstable_boolean_config")]
5678 #[test]
5679 fn test_session_config_option_value_from_impls() {
5680 let from_str: SessionConfigOptionValue = "model-1".into();
5681 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5682
5683 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5684 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5685
5686 let from_bool: SessionConfigOptionValue = true.into();
5687 assert_eq!(from_bool.as_bool(), Some(true));
5688 }
5689
5690 #[cfg(feature = "unstable_boolean_config")]
5691 #[test]
5692 fn test_set_session_config_option_request_value_id() {
5693 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5694 let json = serde_json::to_value(&req).unwrap();
5695 assert_eq!(
5696 json,
5697 json!({
5698 "sessionId": "sess_1",
5699 "configId": "model",
5700 "value": "model-1"
5701 })
5702 );
5703 assert!(!json.as_object().unwrap().contains_key("type"));
5705 }
5706
5707 #[cfg(feature = "unstable_boolean_config")]
5708 #[test]
5709 fn test_set_session_config_option_request_boolean() {
5710 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5711 let json = serde_json::to_value(&req).unwrap();
5712 assert_eq!(
5713 json,
5714 json!({
5715 "sessionId": "sess_1",
5716 "configId": "brave_mode",
5717 "type": "boolean",
5718 "value": true
5719 })
5720 );
5721 }
5722
5723 #[cfg(feature = "unstable_boolean_config")]
5724 #[test]
5725 fn test_set_session_config_option_request_deserialize_no_type() {
5726 let json = json!({
5728 "sessionId": "sess_1",
5729 "configId": "model",
5730 "value": "model-1"
5731 });
5732 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5733 assert_eq!(req.session_id.to_string(), "sess_1");
5734 assert_eq!(req.config_id.to_string(), "model");
5735 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5736 }
5737
5738 #[cfg(feature = "unstable_boolean_config")]
5739 #[test]
5740 fn test_set_session_config_option_request_deserialize_boolean() {
5741 let json = json!({
5742 "sessionId": "sess_1",
5743 "configId": "brave_mode",
5744 "type": "boolean",
5745 "value": true
5746 });
5747 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5748 assert_eq!(req.value.as_bool(), Some(true));
5749 }
5750
5751 #[cfg(feature = "unstable_boolean_config")]
5752 #[test]
5753 fn test_set_session_config_option_request_roundtrip_value_id() {
5754 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5755 let json = serde_json::to_value(&original).unwrap();
5756 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5757 assert_eq!(original, roundtripped);
5758 }
5759
5760 #[cfg(feature = "unstable_boolean_config")]
5761 #[test]
5762 fn test_set_session_config_option_request_roundtrip_boolean() {
5763 let original = SetSessionConfigOptionRequest::new("s", "c", false);
5764 let json = serde_json::to_value(&original).unwrap();
5765 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5766 assert_eq!(original, roundtripped);
5767 }
5768
5769 #[cfg(feature = "unstable_boolean_config")]
5770 #[test]
5771 fn test_session_config_boolean_serialization() {
5772 let cfg = SessionConfigBoolean::new(true);
5773 let json = serde_json::to_value(&cfg).unwrap();
5774 assert_eq!(json, json!({ "currentValue": true }));
5775
5776 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
5777 assert!(deserialized.current_value);
5778 }
5779
5780 #[cfg(feature = "unstable_boolean_config")]
5781 #[test]
5782 fn test_session_config_option_boolean_variant() {
5783 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
5784 .description("Skip confirmation prompts");
5785 let json = serde_json::to_value(&opt).unwrap();
5786 assert_eq!(
5787 json,
5788 json!({
5789 "id": "brave_mode",
5790 "name": "Brave Mode",
5791 "description": "Skip confirmation prompts",
5792 "type": "boolean",
5793 "currentValue": false
5794 })
5795 );
5796
5797 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5798 assert_eq!(deserialized.id.to_string(), "brave_mode");
5799 assert_eq!(deserialized.name, "Brave Mode");
5800 match deserialized.kind {
5801 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
5802 _ => panic!("Expected Boolean kind"),
5803 }
5804 }
5805
5806 #[cfg(feature = "unstable_boolean_config")]
5807 #[test]
5808 fn test_session_config_option_select_still_works() {
5809 let opt = SessionConfigOption::select(
5811 "model",
5812 "Model",
5813 "model-1",
5814 vec![
5815 SessionConfigSelectOption::new("model-1", "Model 1"),
5816 SessionConfigSelectOption::new("model-2", "Model 2"),
5817 ],
5818 );
5819 let json = serde_json::to_value(&opt).unwrap();
5820 assert_eq!(json["type"], "select");
5821 assert_eq!(json["currentValue"], "model-1");
5822 assert_eq!(json["options"].as_array().unwrap().len(), 2);
5823
5824 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5825 match deserialized.kind {
5826 SessionConfigKind::Select(ref s) => {
5827 assert_eq!(s.current_value.to_string(), "model-1");
5828 }
5829 _ => panic!("Expected Select kind"),
5830 }
5831 }
5832
5833 #[cfg(feature = "unstable_llm_providers")]
5834 #[test]
5835 fn test_llm_protocol_known_variants() {
5836 assert_eq!(
5837 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
5838 json!("anthropic")
5839 );
5840 assert_eq!(
5841 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
5842 json!("openai")
5843 );
5844 assert_eq!(
5845 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
5846 json!("azure")
5847 );
5848 assert_eq!(
5849 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
5850 json!("vertex")
5851 );
5852 assert_eq!(
5853 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
5854 json!("bedrock")
5855 );
5856
5857 assert_eq!(
5858 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
5859 LlmProtocol::Anthropic
5860 );
5861 assert_eq!(
5862 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
5863 LlmProtocol::OpenAi
5864 );
5865 assert_eq!(
5866 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
5867 LlmProtocol::Azure
5868 );
5869 assert_eq!(
5870 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
5871 LlmProtocol::Vertex
5872 );
5873 assert_eq!(
5874 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
5875 LlmProtocol::Bedrock
5876 );
5877 }
5878
5879 #[cfg(feature = "unstable_llm_providers")]
5880 #[test]
5881 fn test_llm_protocol_unknown_variant() {
5882 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
5883 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
5884
5885 let json = serde_json::to_value(&unknown).unwrap();
5886 assert_eq!(json, json!("cohere"));
5887 }
5888
5889 #[cfg(feature = "unstable_llm_providers")]
5890 #[test]
5891 fn test_provider_current_config_serialization() {
5892 let config =
5893 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
5894
5895 let json = serde_json::to_value(&config).unwrap();
5896 assert_eq!(
5897 json,
5898 json!({
5899 "apiType": "anthropic",
5900 "baseUrl": "https://api.anthropic.com"
5901 })
5902 );
5903
5904 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
5905 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
5906 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
5907 }
5908
5909 #[cfg(feature = "unstable_llm_providers")]
5910 #[test]
5911 fn test_provider_info_with_current_config() {
5912 let info = ProviderInfo::new(
5913 "main",
5914 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
5915 true,
5916 Some(ProviderCurrentConfig::new(
5917 LlmProtocol::Anthropic,
5918 "https://api.anthropic.com",
5919 )),
5920 );
5921
5922 let json = serde_json::to_value(&info).unwrap();
5923 assert_eq!(
5924 json,
5925 json!({
5926 "id": "main",
5927 "supported": ["anthropic", "openai"],
5928 "required": true,
5929 "current": {
5930 "apiType": "anthropic",
5931 "baseUrl": "https://api.anthropic.com"
5932 }
5933 })
5934 );
5935
5936 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5937 assert_eq!(deserialized.id, "main");
5938 assert_eq!(deserialized.supported.len(), 2);
5939 assert!(deserialized.required);
5940 assert!(deserialized.current.is_some());
5941 assert_eq!(
5942 deserialized.current.as_ref().unwrap().api_type,
5943 LlmProtocol::Anthropic
5944 );
5945 }
5946
5947 #[cfg(feature = "unstable_llm_providers")]
5948 #[test]
5949 fn test_provider_info_disabled() {
5950 let info = ProviderInfo::new(
5951 "secondary",
5952 vec![LlmProtocol::OpenAi],
5953 false,
5954 None::<ProviderCurrentConfig>,
5955 );
5956
5957 let json = serde_json::to_value(&info).unwrap();
5958 assert_eq!(
5959 json,
5960 json!({
5961 "id": "secondary",
5962 "supported": ["openai"],
5963 "required": false
5964 })
5965 );
5966
5967 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5968 assert_eq!(deserialized.id, "secondary");
5969 assert!(!deserialized.required);
5970 assert!(deserialized.current.is_none());
5971 }
5972
5973 #[cfg(feature = "unstable_llm_providers")]
5974 #[test]
5975 fn test_provider_info_missing_current_defaults_to_none() {
5976 let json = json!({
5978 "id": "main",
5979 "supported": ["anthropic"],
5980 "required": true
5981 });
5982 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5983 assert!(deserialized.current.is_none());
5984 }
5985
5986 #[cfg(feature = "unstable_llm_providers")]
5987 #[test]
5988 fn test_provider_info_explicit_null_current_decodes_to_none() {
5989 let json = json!({
5993 "id": "main",
5994 "supported": ["anthropic"],
5995 "required": true,
5996 "current": null
5997 });
5998 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5999 assert!(deserialized.current.is_none());
6000 }
6001
6002 #[cfg(feature = "unstable_llm_providers")]
6003 #[test]
6004 fn test_list_providers_response_serialization() {
6005 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6006 "main",
6007 vec![LlmProtocol::Anthropic],
6008 true,
6009 Some(ProviderCurrentConfig::new(
6010 LlmProtocol::Anthropic,
6011 "https://api.anthropic.com",
6012 )),
6013 )]);
6014
6015 let json = serde_json::to_value(&response).unwrap();
6016 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6017 assert_eq!(json["providers"][0]["id"], "main");
6018
6019 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6020 assert_eq!(deserialized.providers.len(), 1);
6021 }
6022
6023 #[cfg(feature = "unstable_llm_providers")]
6024 #[test]
6025 fn test_set_providers_request_serialization() {
6026 use std::collections::HashMap;
6027
6028 let mut headers = HashMap::new();
6029 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6030
6031 let request =
6032 SetProvidersRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6033 .headers(headers);
6034
6035 let json = serde_json::to_value(&request).unwrap();
6036 assert_eq!(
6037 json,
6038 json!({
6039 "id": "main",
6040 "apiType": "openai",
6041 "baseUrl": "https://api.openai.com/v1",
6042 "headers": {
6043 "Authorization": "Bearer sk-test"
6044 }
6045 })
6046 );
6047
6048 let deserialized: SetProvidersRequest = serde_json::from_value(json).unwrap();
6049 assert_eq!(deserialized.id, "main");
6050 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6051 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6052 assert_eq!(deserialized.headers.len(), 1);
6053 assert_eq!(
6054 deserialized.headers.get("Authorization").unwrap(),
6055 "Bearer sk-test"
6056 );
6057 }
6058
6059 #[cfg(feature = "unstable_llm_providers")]
6060 #[test]
6061 fn test_set_providers_request_omits_empty_headers() {
6062 let request =
6063 SetProvidersRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6064
6065 let json = serde_json::to_value(&request).unwrap();
6066 assert!(!json.as_object().unwrap().contains_key("headers"));
6068 }
6069
6070 #[cfg(feature = "unstable_llm_providers")]
6071 #[test]
6072 fn test_disable_providers_request_serialization() {
6073 let request = DisableProvidersRequest::new("secondary");
6074
6075 let json = serde_json::to_value(&request).unwrap();
6076 assert_eq!(json, json!({ "id": "secondary" }));
6077
6078 let deserialized: DisableProvidersRequest = serde_json::from_value(json).unwrap();
6079 assert_eq!(deserialized.id, "secondary");
6080 }
6081
6082 #[cfg(feature = "unstable_llm_providers")]
6083 #[test]
6084 fn test_providers_capabilities_serialization() {
6085 let caps = ProvidersCapabilities::new();
6086
6087 let json = serde_json::to_value(&caps).unwrap();
6088 assert_eq!(json, json!({}));
6089
6090 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6091 assert!(deserialized.meta.is_none());
6092 }
6093
6094 #[cfg(feature = "unstable_llm_providers")]
6095 #[test]
6096 fn test_agent_capabilities_with_providers() {
6097 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6098
6099 let json = serde_json::to_value(&caps).unwrap();
6100 assert_eq!(json["providers"], json!({}));
6101
6102 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6103 assert!(deserialized.providers.is_some());
6104 }
6105}