1use std::{path::PathBuf, sync::Arc};
7
8#[cfg(feature = "unstable_auth_methods")]
9use std::collections::HashMap;
10
11use derive_more::{Display, From};
12use schemars::JsonSchema;
13use serde::{Deserialize, Serialize};
14
15use crate::{
16 ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta,
17 ProtocolVersion, SessionId,
18};
19
20#[cfg(feature = "unstable_nes")]
21use crate::{
22 AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
23 DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
24 DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
25 StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
26};
27
28#[cfg(feature = "unstable_nes")]
29use crate::nes::{
30 DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
31 DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
32 NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
33 NES_SUGGEST_METHOD_NAME,
34};
35
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
44#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
45#[serde(rename_all = "camelCase")]
46#[non_exhaustive]
47pub struct InitializeRequest {
48 pub protocol_version: ProtocolVersion,
50 #[serde(default)]
52 pub client_capabilities: ClientCapabilities,
53 #[serde(skip_serializing_if = "Option::is_none")]
57 pub client_info: Option<Implementation>,
58 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
64 pub meta: Option<Meta>,
65}
66
67impl InitializeRequest {
68 #[must_use]
69 pub fn new(protocol_version: ProtocolVersion) -> Self {
70 Self {
71 protocol_version,
72 client_capabilities: ClientCapabilities::default(),
73 client_info: None,
74 meta: None,
75 }
76 }
77
78 #[must_use]
80 pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
81 self.client_capabilities = client_capabilities;
82 self
83 }
84
85 #[must_use]
87 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
88 self.client_info = client_info.into_option();
89 self
90 }
91
92 #[must_use]
98 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
99 self.meta = meta.into_option();
100 self
101 }
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
110#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
111#[serde(rename_all = "camelCase")]
112#[non_exhaustive]
113pub struct InitializeResponse {
114 pub protocol_version: ProtocolVersion,
119 #[serde(default)]
121 pub agent_capabilities: AgentCapabilities,
122 #[serde(default)]
124 pub auth_methods: Vec<AuthMethod>,
125 #[serde(skip_serializing_if = "Option::is_none")]
129 pub agent_info: Option<Implementation>,
130 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
136 pub meta: Option<Meta>,
137}
138
139impl InitializeResponse {
140 #[must_use]
141 pub fn new(protocol_version: ProtocolVersion) -> Self {
142 Self {
143 protocol_version,
144 agent_capabilities: AgentCapabilities::default(),
145 auth_methods: vec![],
146 agent_info: None,
147 meta: None,
148 }
149 }
150
151 #[must_use]
153 pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
154 self.agent_capabilities = agent_capabilities;
155 self
156 }
157
158 #[must_use]
160 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
161 self.auth_methods = auth_methods;
162 self
163 }
164
165 #[must_use]
167 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
168 self.agent_info = agent_info.into_option();
169 self
170 }
171
172 #[must_use]
178 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
179 self.meta = meta.into_option();
180 self
181 }
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
188#[serde(rename_all = "camelCase")]
189#[non_exhaustive]
190pub struct Implementation {
191 pub name: String,
194 pub title: Option<String>,
199 pub version: String,
202 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
208 pub meta: Option<Meta>,
209}
210
211impl Implementation {
212 #[must_use]
213 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
214 Self {
215 name: name.into(),
216 title: None,
217 version: version.into(),
218 meta: None,
219 }
220 }
221
222 #[must_use]
227 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
228 self.title = title.into_option();
229 self
230 }
231
232 #[must_use]
238 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
239 self.meta = meta.into_option();
240 self
241 }
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
250#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
251#[serde(rename_all = "camelCase")]
252#[non_exhaustive]
253pub struct AuthenticateRequest {
254 pub method_id: AuthMethodId,
257 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
263 pub meta: Option<Meta>,
264}
265
266impl AuthenticateRequest {
267 #[must_use]
268 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
269 Self {
270 method_id: method_id.into(),
271 meta: None,
272 }
273 }
274
275 #[must_use]
281 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
282 self.meta = meta.into_option();
283 self
284 }
285}
286
287#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
289#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
290#[serde(rename_all = "camelCase")]
291#[non_exhaustive]
292pub struct AuthenticateResponse {
293 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
299 pub meta: Option<Meta>,
300}
301
302impl AuthenticateResponse {
303 #[must_use]
304 pub fn new() -> Self {
305 Self::default()
306 }
307
308 #[must_use]
314 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
315 self.meta = meta.into_option();
316 self
317 }
318}
319
320#[cfg(feature = "unstable_logout")]
330#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
331#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
332#[serde(rename_all = "camelCase")]
333#[non_exhaustive]
334pub struct LogoutRequest {
335 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
341 pub meta: Option<Meta>,
342}
343
344#[cfg(feature = "unstable_logout")]
345impl LogoutRequest {
346 #[must_use]
347 pub fn new() -> Self {
348 Self::default()
349 }
350
351 #[must_use]
357 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
358 self.meta = meta.into_option();
359 self
360 }
361}
362
363#[cfg(feature = "unstable_logout")]
369#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
370#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
371#[serde(rename_all = "camelCase")]
372#[non_exhaustive]
373pub struct LogoutResponse {
374 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
380 pub meta: Option<Meta>,
381}
382
383#[cfg(feature = "unstable_logout")]
384impl LogoutResponse {
385 #[must_use]
386 pub fn new() -> Self {
387 Self::default()
388 }
389
390 #[must_use]
396 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
397 self.meta = meta.into_option();
398 self
399 }
400}
401
402#[cfg(feature = "unstable_logout")]
408#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
409#[serde(rename_all = "camelCase")]
410#[non_exhaustive]
411pub struct AgentAuthCapabilities {
412 #[serde(skip_serializing_if = "Option::is_none")]
416 pub logout: Option<LogoutCapabilities>,
417 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
423 pub meta: Option<Meta>,
424}
425
426#[cfg(feature = "unstable_logout")]
427impl AgentAuthCapabilities {
428 #[must_use]
429 pub fn new() -> Self {
430 Self::default()
431 }
432
433 #[must_use]
435 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
436 self.logout = logout.into_option();
437 self
438 }
439
440 #[must_use]
446 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
447 self.meta = meta.into_option();
448 self
449 }
450}
451
452#[cfg(feature = "unstable_logout")]
460#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
461#[non_exhaustive]
462pub struct LogoutCapabilities {
463 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
469 pub meta: Option<Meta>,
470}
471
472#[cfg(feature = "unstable_logout")]
473impl LogoutCapabilities {
474 #[must_use]
475 pub fn new() -> Self {
476 Self::default()
477 }
478
479 #[must_use]
485 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
486 self.meta = meta.into_option();
487 self
488 }
489}
490
491#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
492#[serde(transparent)]
493#[from(Arc<str>, String, &'static str)]
494#[non_exhaustive]
495pub struct AuthMethodId(pub Arc<str>);
496
497impl AuthMethodId {
498 #[must_use]
499 pub fn new(id: impl Into<Arc<str>>) -> Self {
500 Self(id.into())
501 }
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
509#[serde(tag = "type", rename_all = "snake_case")]
510#[non_exhaustive]
511pub enum AuthMethod {
512 #[cfg(feature = "unstable_auth_methods")]
518 EnvVar(AuthMethodEnvVar),
519 #[cfg(feature = "unstable_auth_methods")]
525 Terminal(AuthMethodTerminal),
526 #[serde(untagged)]
530 Agent(AuthMethodAgent),
531}
532
533impl AuthMethod {
534 #[must_use]
536 pub fn id(&self) -> &AuthMethodId {
537 match self {
538 Self::Agent(a) => &a.id,
539 #[cfg(feature = "unstable_auth_methods")]
540 Self::EnvVar(e) => &e.id,
541 #[cfg(feature = "unstable_auth_methods")]
542 Self::Terminal(t) => &t.id,
543 }
544 }
545
546 #[must_use]
548 pub fn name(&self) -> &str {
549 match self {
550 Self::Agent(a) => &a.name,
551 #[cfg(feature = "unstable_auth_methods")]
552 Self::EnvVar(e) => &e.name,
553 #[cfg(feature = "unstable_auth_methods")]
554 Self::Terminal(t) => &t.name,
555 }
556 }
557
558 #[must_use]
560 pub fn description(&self) -> Option<&str> {
561 match self {
562 Self::Agent(a) => a.description.as_deref(),
563 #[cfg(feature = "unstable_auth_methods")]
564 Self::EnvVar(e) => e.description.as_deref(),
565 #[cfg(feature = "unstable_auth_methods")]
566 Self::Terminal(t) => t.description.as_deref(),
567 }
568 }
569
570 #[must_use]
576 pub fn meta(&self) -> Option<&Meta> {
577 match self {
578 Self::Agent(a) => a.meta.as_ref(),
579 #[cfg(feature = "unstable_auth_methods")]
580 Self::EnvVar(e) => e.meta.as_ref(),
581 #[cfg(feature = "unstable_auth_methods")]
582 Self::Terminal(t) => t.meta.as_ref(),
583 }
584 }
585}
586
587#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
591#[serde(rename_all = "camelCase")]
592#[non_exhaustive]
593pub struct AuthMethodAgent {
594 pub id: AuthMethodId,
596 pub name: String,
598 #[serde(skip_serializing_if = "Option::is_none")]
600 pub description: Option<String>,
601 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
607 pub meta: Option<Meta>,
608}
609
610impl AuthMethodAgent {
611 #[must_use]
612 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
613 Self {
614 id: id.into(),
615 name: name.into(),
616 description: None,
617 meta: None,
618 }
619 }
620
621 #[must_use]
623 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
624 self.description = description.into_option();
625 self
626 }
627
628 #[must_use]
634 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
635 self.meta = meta.into_option();
636 self
637 }
638}
639
640#[cfg(feature = "unstable_auth_methods")]
648#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
649#[serde(rename_all = "camelCase")]
650#[non_exhaustive]
651pub struct AuthMethodEnvVar {
652 pub id: AuthMethodId,
654 pub name: String,
656 #[serde(skip_serializing_if = "Option::is_none")]
658 pub description: Option<String>,
659 pub vars: Vec<AuthEnvVar>,
661 #[serde(skip_serializing_if = "Option::is_none")]
663 pub link: Option<String>,
664 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
670 pub meta: Option<Meta>,
671}
672
673#[cfg(feature = "unstable_auth_methods")]
674impl AuthMethodEnvVar {
675 #[must_use]
676 pub fn new(
677 id: impl Into<AuthMethodId>,
678 name: impl Into<String>,
679 vars: Vec<AuthEnvVar>,
680 ) -> Self {
681 Self {
682 id: id.into(),
683 name: name.into(),
684 description: None,
685 vars,
686 link: None,
687 meta: None,
688 }
689 }
690
691 #[must_use]
693 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
694 self.link = link.into_option();
695 self
696 }
697
698 #[must_use]
700 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
701 self.description = description.into_option();
702 self
703 }
704
705 #[must_use]
711 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
712 self.meta = meta.into_option();
713 self
714 }
715}
716
717#[cfg(feature = "unstable_auth_methods")]
723#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
724#[serde(rename_all = "camelCase")]
725#[non_exhaustive]
726pub struct AuthEnvVar {
727 pub name: String,
729 #[serde(skip_serializing_if = "Option::is_none")]
731 pub label: Option<String>,
732 #[serde(default = "default_true", skip_serializing_if = "is_true")]
737 #[schemars(extend("default" = true))]
738 pub secret: bool,
739 #[serde(default, skip_serializing_if = "is_false")]
743 #[schemars(extend("default" = false))]
744 pub optional: bool,
745 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
751 pub meta: Option<Meta>,
752}
753
754#[cfg(feature = "unstable_auth_methods")]
755fn default_true() -> bool {
756 true
757}
758
759#[cfg(feature = "unstable_auth_methods")]
760#[expect(clippy::trivially_copy_pass_by_ref)]
761fn is_true(v: &bool) -> bool {
762 *v
763}
764
765#[cfg(feature = "unstable_auth_methods")]
766#[expect(clippy::trivially_copy_pass_by_ref)]
767fn is_false(v: &bool) -> bool {
768 !*v
769}
770
771#[cfg(feature = "unstable_auth_methods")]
772impl AuthEnvVar {
773 #[must_use]
775 pub fn new(name: impl Into<String>) -> Self {
776 Self {
777 name: name.into(),
778 label: None,
779 secret: true,
780 optional: false,
781 meta: None,
782 }
783 }
784
785 #[must_use]
787 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
788 self.label = label.into_option();
789 self
790 }
791
792 #[must_use]
795 pub fn secret(mut self, secret: bool) -> Self {
796 self.secret = secret;
797 self
798 }
799
800 #[must_use]
802 pub fn optional(mut self, optional: bool) -> Self {
803 self.optional = optional;
804 self
805 }
806
807 #[must_use]
813 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
814 self.meta = meta.into_option();
815 self
816 }
817}
818
819#[cfg(feature = "unstable_auth_methods")]
827#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
828#[serde(rename_all = "camelCase")]
829#[non_exhaustive]
830pub struct AuthMethodTerminal {
831 pub id: AuthMethodId,
833 pub name: String,
835 #[serde(skip_serializing_if = "Option::is_none")]
837 pub description: Option<String>,
838 #[serde(default, skip_serializing_if = "Vec::is_empty")]
840 pub args: Vec<String>,
841 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
843 pub env: HashMap<String, String>,
844 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
850 pub meta: Option<Meta>,
851}
852
853#[cfg(feature = "unstable_auth_methods")]
854impl AuthMethodTerminal {
855 #[must_use]
856 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
857 Self {
858 id: id.into(),
859 name: name.into(),
860 description: None,
861 args: Vec::new(),
862 env: HashMap::new(),
863 meta: None,
864 }
865 }
866
867 #[must_use]
869 pub fn args(mut self, args: Vec<String>) -> Self {
870 self.args = args;
871 self
872 }
873
874 #[must_use]
876 pub fn env(mut self, env: HashMap<String, String>) -> Self {
877 self.env = env;
878 self
879 }
880
881 #[must_use]
883 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
884 self.description = description.into_option();
885 self
886 }
887
888 #[must_use]
894 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
895 self.meta = meta.into_option();
896 self
897 }
898}
899
900#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
906#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
907#[serde(rename_all = "camelCase")]
908#[non_exhaustive]
909pub struct NewSessionRequest {
910 pub cwd: PathBuf,
912 #[cfg(feature = "unstable_session_additional_directories")]
922 #[serde(default, skip_serializing_if = "Vec::is_empty")]
923 pub additional_directories: Vec<PathBuf>,
924 pub mcp_servers: Vec<McpServer>,
926 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
932 pub meta: Option<Meta>,
933}
934
935impl NewSessionRequest {
936 #[must_use]
937 pub fn new(cwd: impl Into<PathBuf>) -> Self {
938 Self {
939 cwd: cwd.into(),
940 #[cfg(feature = "unstable_session_additional_directories")]
941 additional_directories: vec![],
942 mcp_servers: vec![],
943 meta: None,
944 }
945 }
946
947 #[cfg(feature = "unstable_session_additional_directories")]
953 #[must_use]
954 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
955 self.additional_directories = additional_directories;
956 self
957 }
958
959 #[must_use]
961 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
962 self.mcp_servers = mcp_servers;
963 self
964 }
965
966 #[must_use]
972 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
973 self.meta = meta.into_option();
974 self
975 }
976}
977
978#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
982#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
983#[serde(rename_all = "camelCase")]
984#[non_exhaustive]
985pub struct NewSessionResponse {
986 pub session_id: SessionId,
990 #[serde(skip_serializing_if = "Option::is_none")]
994 pub modes: Option<SessionModeState>,
995 #[cfg(feature = "unstable_session_model")]
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 pub models: Option<SessionModelState>,
1003 #[serde(skip_serializing_if = "Option::is_none")]
1005 pub config_options: Option<Vec<SessionConfigOption>>,
1006 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1012 pub meta: Option<Meta>,
1013}
1014
1015impl NewSessionResponse {
1016 #[must_use]
1017 pub fn new(session_id: impl Into<SessionId>) -> Self {
1018 Self {
1019 session_id: session_id.into(),
1020 modes: None,
1021 #[cfg(feature = "unstable_session_model")]
1022 models: None,
1023 config_options: None,
1024 meta: None,
1025 }
1026 }
1027
1028 #[must_use]
1032 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1033 self.modes = modes.into_option();
1034 self
1035 }
1036
1037 #[cfg(feature = "unstable_session_model")]
1043 #[must_use]
1044 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1045 self.models = models.into_option();
1046 self
1047 }
1048
1049 #[must_use]
1051 pub fn config_options(
1052 mut self,
1053 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1054 ) -> Self {
1055 self.config_options = config_options.into_option();
1056 self
1057 }
1058
1059 #[must_use]
1065 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1066 self.meta = meta.into_option();
1067 self
1068 }
1069}
1070
1071#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1079#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1080#[serde(rename_all = "camelCase")]
1081#[non_exhaustive]
1082pub struct LoadSessionRequest {
1083 pub mcp_servers: Vec<McpServer>,
1085 pub cwd: PathBuf,
1087 #[cfg(feature = "unstable_session_additional_directories")]
1097 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1098 pub additional_directories: Vec<PathBuf>,
1099 pub session_id: SessionId,
1101 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1107 pub meta: Option<Meta>,
1108}
1109
1110impl LoadSessionRequest {
1111 #[must_use]
1112 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1113 Self {
1114 mcp_servers: vec![],
1115 cwd: cwd.into(),
1116 #[cfg(feature = "unstable_session_additional_directories")]
1117 additional_directories: vec![],
1118 session_id: session_id.into(),
1119 meta: None,
1120 }
1121 }
1122
1123 #[cfg(feature = "unstable_session_additional_directories")]
1129 #[must_use]
1130 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1131 self.additional_directories = additional_directories;
1132 self
1133 }
1134
1135 #[must_use]
1137 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1138 self.mcp_servers = mcp_servers;
1139 self
1140 }
1141
1142 #[must_use]
1148 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1149 self.meta = meta.into_option();
1150 self
1151 }
1152}
1153
1154#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1156#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1157#[serde(rename_all = "camelCase")]
1158#[non_exhaustive]
1159pub struct LoadSessionResponse {
1160 #[serde(default, skip_serializing_if = "Option::is_none")]
1164 pub modes: Option<SessionModeState>,
1165 #[cfg(feature = "unstable_session_model")]
1171 #[serde(default, skip_serializing_if = "Option::is_none")]
1172 pub models: Option<SessionModelState>,
1173 #[serde(default, skip_serializing_if = "Option::is_none")]
1175 pub config_options: Option<Vec<SessionConfigOption>>,
1176 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1182 pub meta: Option<Meta>,
1183}
1184
1185impl LoadSessionResponse {
1186 #[must_use]
1187 pub fn new() -> Self {
1188 Self::default()
1189 }
1190
1191 #[must_use]
1195 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1196 self.modes = modes.into_option();
1197 self
1198 }
1199
1200 #[cfg(feature = "unstable_session_model")]
1206 #[must_use]
1207 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1208 self.models = models.into_option();
1209 self
1210 }
1211
1212 #[must_use]
1214 pub fn config_options(
1215 mut self,
1216 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1217 ) -> Self {
1218 self.config_options = config_options.into_option();
1219 self
1220 }
1221
1222 #[must_use]
1228 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1229 self.meta = meta.into_option();
1230 self
1231 }
1232}
1233
1234#[cfg(feature = "unstable_session_fork")]
1247#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1248#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1249#[serde(rename_all = "camelCase")]
1250#[non_exhaustive]
1251pub struct ForkSessionRequest {
1252 pub session_id: SessionId,
1254 pub cwd: PathBuf,
1256 #[cfg(feature = "unstable_session_additional_directories")]
1266 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1267 pub additional_directories: Vec<PathBuf>,
1268 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1270 pub mcp_servers: Vec<McpServer>,
1271 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1277 pub meta: Option<Meta>,
1278}
1279
1280#[cfg(feature = "unstable_session_fork")]
1281impl ForkSessionRequest {
1282 #[must_use]
1283 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1284 Self {
1285 session_id: session_id.into(),
1286 cwd: cwd.into(),
1287 #[cfg(feature = "unstable_session_additional_directories")]
1288 additional_directories: vec![],
1289 mcp_servers: vec![],
1290 meta: None,
1291 }
1292 }
1293
1294 #[cfg(feature = "unstable_session_additional_directories")]
1300 #[must_use]
1301 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1302 self.additional_directories = additional_directories;
1303 self
1304 }
1305
1306 #[must_use]
1308 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1309 self.mcp_servers = mcp_servers;
1310 self
1311 }
1312
1313 #[must_use]
1319 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1320 self.meta = meta.into_option();
1321 self
1322 }
1323}
1324
1325#[cfg(feature = "unstable_session_fork")]
1331#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1332#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1333#[serde(rename_all = "camelCase")]
1334#[non_exhaustive]
1335pub struct ForkSessionResponse {
1336 pub session_id: SessionId,
1338 #[serde(skip_serializing_if = "Option::is_none")]
1342 pub modes: Option<SessionModeState>,
1343 #[cfg(feature = "unstable_session_model")]
1349 #[serde(skip_serializing_if = "Option::is_none")]
1350 pub models: Option<SessionModelState>,
1351 #[serde(skip_serializing_if = "Option::is_none")]
1353 pub config_options: Option<Vec<SessionConfigOption>>,
1354 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1360 pub meta: Option<Meta>,
1361}
1362
1363#[cfg(feature = "unstable_session_fork")]
1364impl ForkSessionResponse {
1365 #[must_use]
1366 pub fn new(session_id: impl Into<SessionId>) -> Self {
1367 Self {
1368 session_id: session_id.into(),
1369 modes: None,
1370 #[cfg(feature = "unstable_session_model")]
1371 models: None,
1372 config_options: None,
1373 meta: None,
1374 }
1375 }
1376
1377 #[must_use]
1381 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1382 self.modes = modes.into_option();
1383 self
1384 }
1385
1386 #[cfg(feature = "unstable_session_model")]
1392 #[must_use]
1393 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1394 self.models = models.into_option();
1395 self
1396 }
1397
1398 #[must_use]
1400 pub fn config_options(
1401 mut self,
1402 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1403 ) -> Self {
1404 self.config_options = config_options.into_option();
1405 self
1406 }
1407
1408 #[must_use]
1414 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1415 self.meta = meta.into_option();
1416 self
1417 }
1418}
1419
1420#[cfg(feature = "unstable_session_resume")]
1433#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1434#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1435#[serde(rename_all = "camelCase")]
1436#[non_exhaustive]
1437pub struct ResumeSessionRequest {
1438 pub session_id: SessionId,
1440 pub cwd: PathBuf,
1442 #[cfg(feature = "unstable_session_additional_directories")]
1452 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1453 pub additional_directories: Vec<PathBuf>,
1454 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1456 pub mcp_servers: Vec<McpServer>,
1457 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1463 pub meta: Option<Meta>,
1464}
1465
1466#[cfg(feature = "unstable_session_resume")]
1467impl ResumeSessionRequest {
1468 #[must_use]
1469 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1470 Self {
1471 session_id: session_id.into(),
1472 cwd: cwd.into(),
1473 #[cfg(feature = "unstable_session_additional_directories")]
1474 additional_directories: vec![],
1475 mcp_servers: vec![],
1476 meta: None,
1477 }
1478 }
1479
1480 #[cfg(feature = "unstable_session_additional_directories")]
1486 #[must_use]
1487 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1488 self.additional_directories = additional_directories;
1489 self
1490 }
1491
1492 #[must_use]
1494 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1495 self.mcp_servers = mcp_servers;
1496 self
1497 }
1498
1499 #[must_use]
1505 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1506 self.meta = meta.into_option();
1507 self
1508 }
1509}
1510
1511#[cfg(feature = "unstable_session_resume")]
1517#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1518#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1519#[serde(rename_all = "camelCase")]
1520#[non_exhaustive]
1521pub struct ResumeSessionResponse {
1522 #[serde(default, skip_serializing_if = "Option::is_none")]
1526 pub modes: Option<SessionModeState>,
1527 #[cfg(feature = "unstable_session_model")]
1533 #[serde(default, skip_serializing_if = "Option::is_none")]
1534 pub models: Option<SessionModelState>,
1535 #[serde(default, skip_serializing_if = "Option::is_none")]
1537 pub config_options: Option<Vec<SessionConfigOption>>,
1538 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1544 pub meta: Option<Meta>,
1545}
1546
1547#[cfg(feature = "unstable_session_resume")]
1548impl ResumeSessionResponse {
1549 #[must_use]
1550 pub fn new() -> Self {
1551 Self::default()
1552 }
1553
1554 #[must_use]
1558 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1559 self.modes = modes.into_option();
1560 self
1561 }
1562
1563 #[cfg(feature = "unstable_session_model")]
1569 #[must_use]
1570 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1571 self.models = models.into_option();
1572 self
1573 }
1574
1575 #[must_use]
1577 pub fn config_options(
1578 mut self,
1579 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1580 ) -> Self {
1581 self.config_options = config_options.into_option();
1582 self
1583 }
1584
1585 #[must_use]
1591 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1592 self.meta = meta.into_option();
1593 self
1594 }
1595}
1596
1597#[cfg(feature = "unstable_session_close")]
1611#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1612#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1613#[serde(rename_all = "camelCase")]
1614#[non_exhaustive]
1615pub struct CloseSessionRequest {
1616 pub session_id: SessionId,
1618 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1624 pub meta: Option<Meta>,
1625}
1626
1627#[cfg(feature = "unstable_session_close")]
1628impl CloseSessionRequest {
1629 #[must_use]
1630 pub fn new(session_id: impl Into<SessionId>) -> Self {
1631 Self {
1632 session_id: session_id.into(),
1633 meta: None,
1634 }
1635 }
1636
1637 #[must_use]
1643 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1644 self.meta = meta.into_option();
1645 self
1646 }
1647}
1648
1649#[cfg(feature = "unstable_session_close")]
1655#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1656#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1657#[serde(rename_all = "camelCase")]
1658#[non_exhaustive]
1659pub struct CloseSessionResponse {
1660 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1666 pub meta: Option<Meta>,
1667}
1668
1669#[cfg(feature = "unstable_session_close")]
1670impl CloseSessionResponse {
1671 #[must_use]
1672 pub fn new() -> Self {
1673 Self::default()
1674 }
1675
1676 #[must_use]
1682 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1683 self.meta = meta.into_option();
1684 self
1685 }
1686}
1687
1688#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1694#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1695#[serde(rename_all = "camelCase")]
1696#[non_exhaustive]
1697pub struct ListSessionsRequest {
1698 #[serde(skip_serializing_if = "Option::is_none")]
1700 pub cwd: Option<PathBuf>,
1701 #[cfg(feature = "unstable_session_additional_directories")]
1710 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1711 pub additional_directories: Vec<PathBuf>,
1712 #[serde(skip_serializing_if = "Option::is_none")]
1714 pub cursor: Option<String>,
1715 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1721 pub meta: Option<Meta>,
1722}
1723
1724impl ListSessionsRequest {
1725 #[must_use]
1726 pub fn new() -> Self {
1727 Self::default()
1728 }
1729
1730 #[must_use]
1732 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1733 self.cwd = cwd.into_option();
1734 self
1735 }
1736
1737 #[cfg(feature = "unstable_session_additional_directories")]
1743 #[must_use]
1744 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1745 self.additional_directories = additional_directories;
1746 self
1747 }
1748
1749 #[must_use]
1751 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1752 self.cursor = cursor.into_option();
1753 self
1754 }
1755
1756 #[must_use]
1762 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1763 self.meta = meta.into_option();
1764 self
1765 }
1766}
1767
1768#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1770#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1771#[serde(rename_all = "camelCase")]
1772#[non_exhaustive]
1773pub struct ListSessionsResponse {
1774 pub sessions: Vec<SessionInfo>,
1776 #[serde(skip_serializing_if = "Option::is_none")]
1779 pub next_cursor: Option<String>,
1780 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1786 pub meta: Option<Meta>,
1787}
1788
1789impl ListSessionsResponse {
1790 #[must_use]
1791 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1792 Self {
1793 sessions,
1794 next_cursor: None,
1795 meta: None,
1796 }
1797 }
1798
1799 #[must_use]
1800 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1801 self.next_cursor = next_cursor.into_option();
1802 self
1803 }
1804
1805 #[must_use]
1811 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1812 self.meta = meta.into_option();
1813 self
1814 }
1815}
1816
1817#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1819#[serde(rename_all = "camelCase")]
1820#[non_exhaustive]
1821pub struct SessionInfo {
1822 pub session_id: SessionId,
1824 pub cwd: PathBuf,
1826 #[cfg(feature = "unstable_session_additional_directories")]
1834 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1835 pub additional_directories: Vec<PathBuf>,
1836
1837 #[serde(skip_serializing_if = "Option::is_none")]
1839 pub title: Option<String>,
1840 #[serde(skip_serializing_if = "Option::is_none")]
1842 pub updated_at: Option<String>,
1843 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1849 pub meta: Option<Meta>,
1850}
1851
1852impl SessionInfo {
1853 #[must_use]
1854 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1855 Self {
1856 session_id: session_id.into(),
1857 cwd: cwd.into(),
1858 #[cfg(feature = "unstable_session_additional_directories")]
1859 additional_directories: vec![],
1860 title: None,
1861 updated_at: None,
1862 meta: None,
1863 }
1864 }
1865
1866 #[cfg(feature = "unstable_session_additional_directories")]
1872 #[must_use]
1873 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1874 self.additional_directories = additional_directories;
1875 self
1876 }
1877
1878 #[must_use]
1880 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1881 self.title = title.into_option();
1882 self
1883 }
1884
1885 #[must_use]
1887 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1888 self.updated_at = updated_at.into_option();
1889 self
1890 }
1891
1892 #[must_use]
1898 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1899 self.meta = meta.into_option();
1900 self
1901 }
1902}
1903
1904#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1908#[serde(rename_all = "camelCase")]
1909#[non_exhaustive]
1910pub struct SessionModeState {
1911 pub current_mode_id: SessionModeId,
1913 pub available_modes: Vec<SessionMode>,
1915 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1921 pub meta: Option<Meta>,
1922}
1923
1924impl SessionModeState {
1925 #[must_use]
1926 pub fn new(
1927 current_mode_id: impl Into<SessionModeId>,
1928 available_modes: Vec<SessionMode>,
1929 ) -> Self {
1930 Self {
1931 current_mode_id: current_mode_id.into(),
1932 available_modes,
1933 meta: None,
1934 }
1935 }
1936
1937 #[must_use]
1943 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1944 self.meta = meta.into_option();
1945 self
1946 }
1947}
1948
1949#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1953#[serde(rename_all = "camelCase")]
1954#[non_exhaustive]
1955pub struct SessionMode {
1956 pub id: SessionModeId,
1957 pub name: String,
1958 #[serde(default, skip_serializing_if = "Option::is_none")]
1959 pub description: Option<String>,
1960 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1966 pub meta: Option<Meta>,
1967}
1968
1969impl SessionMode {
1970 #[must_use]
1971 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
1972 Self {
1973 id: id.into(),
1974 name: name.into(),
1975 description: None,
1976 meta: None,
1977 }
1978 }
1979
1980 #[must_use]
1981 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1982 self.description = description.into_option();
1983 self
1984 }
1985
1986 #[must_use]
1992 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1993 self.meta = meta.into_option();
1994 self
1995 }
1996}
1997
1998#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2000#[serde(transparent)]
2001#[from(Arc<str>, String, &'static str)]
2002#[non_exhaustive]
2003pub struct SessionModeId(pub Arc<str>);
2004
2005impl SessionModeId {
2006 #[must_use]
2007 pub fn new(id: impl Into<Arc<str>>) -> Self {
2008 Self(id.into())
2009 }
2010}
2011
2012#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2014#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2015#[serde(rename_all = "camelCase")]
2016#[non_exhaustive]
2017pub struct SetSessionModeRequest {
2018 pub session_id: SessionId,
2020 pub mode_id: SessionModeId,
2022 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2028 pub meta: Option<Meta>,
2029}
2030
2031impl SetSessionModeRequest {
2032 #[must_use]
2033 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
2034 Self {
2035 session_id: session_id.into(),
2036 mode_id: mode_id.into(),
2037 meta: None,
2038 }
2039 }
2040
2041 #[must_use]
2042 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2043 self.meta = meta.into_option();
2044 self
2045 }
2046}
2047
2048#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2050#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2051#[serde(rename_all = "camelCase")]
2052#[non_exhaustive]
2053pub struct SetSessionModeResponse {
2054 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2060 pub meta: Option<Meta>,
2061}
2062
2063impl SetSessionModeResponse {
2064 #[must_use]
2065 pub fn new() -> Self {
2066 Self::default()
2067 }
2068
2069 #[must_use]
2075 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2076 self.meta = meta.into_option();
2077 self
2078 }
2079}
2080
2081#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2085#[serde(transparent)]
2086#[from(Arc<str>, String, &'static str)]
2087#[non_exhaustive]
2088pub struct SessionConfigId(pub Arc<str>);
2089
2090impl SessionConfigId {
2091 #[must_use]
2092 pub fn new(id: impl Into<Arc<str>>) -> Self {
2093 Self(id.into())
2094 }
2095}
2096
2097#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2099#[serde(transparent)]
2100#[from(Arc<str>, String, &'static str)]
2101#[non_exhaustive]
2102pub struct SessionConfigValueId(pub Arc<str>);
2103
2104impl SessionConfigValueId {
2105 #[must_use]
2106 pub fn new(id: impl Into<Arc<str>>) -> Self {
2107 Self(id.into())
2108 }
2109}
2110
2111#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2113#[serde(transparent)]
2114#[from(Arc<str>, String, &'static str)]
2115#[non_exhaustive]
2116pub struct SessionConfigGroupId(pub Arc<str>);
2117
2118impl SessionConfigGroupId {
2119 #[must_use]
2120 pub fn new(id: impl Into<Arc<str>>) -> Self {
2121 Self(id.into())
2122 }
2123}
2124
2125#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2127#[serde(rename_all = "camelCase")]
2128#[non_exhaustive]
2129pub struct SessionConfigSelectOption {
2130 pub value: SessionConfigValueId,
2132 pub name: String,
2134 #[serde(default, skip_serializing_if = "Option::is_none")]
2136 pub description: Option<String>,
2137 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2143 pub meta: Option<Meta>,
2144}
2145
2146impl SessionConfigSelectOption {
2147 #[must_use]
2148 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2149 Self {
2150 value: value.into(),
2151 name: name.into(),
2152 description: None,
2153 meta: None,
2154 }
2155 }
2156
2157 #[must_use]
2158 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2159 self.description = description.into_option();
2160 self
2161 }
2162
2163 #[must_use]
2169 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2170 self.meta = meta.into_option();
2171 self
2172 }
2173}
2174
2175#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2177#[serde(rename_all = "camelCase")]
2178#[non_exhaustive]
2179pub struct SessionConfigSelectGroup {
2180 pub group: SessionConfigGroupId,
2182 pub name: String,
2184 pub options: Vec<SessionConfigSelectOption>,
2186 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2192 pub meta: Option<Meta>,
2193}
2194
2195impl SessionConfigSelectGroup {
2196 #[must_use]
2197 pub fn new(
2198 group: impl Into<SessionConfigGroupId>,
2199 name: impl Into<String>,
2200 options: Vec<SessionConfigSelectOption>,
2201 ) -> Self {
2202 Self {
2203 group: group.into(),
2204 name: name.into(),
2205 options,
2206 meta: None,
2207 }
2208 }
2209
2210 #[must_use]
2216 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2217 self.meta = meta.into_option();
2218 self
2219 }
2220}
2221
2222#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2224#[serde(untagged)]
2225#[non_exhaustive]
2226pub enum SessionConfigSelectOptions {
2227 Ungrouped(Vec<SessionConfigSelectOption>),
2229 Grouped(Vec<SessionConfigSelectGroup>),
2231}
2232
2233impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2234 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2235 SessionConfigSelectOptions::Ungrouped(options)
2236 }
2237}
2238
2239impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2240 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2241 SessionConfigSelectOptions::Grouped(groups)
2242 }
2243}
2244
2245#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2247#[serde(rename_all = "camelCase")]
2248#[non_exhaustive]
2249pub struct SessionConfigSelect {
2250 pub current_value: SessionConfigValueId,
2252 pub options: SessionConfigSelectOptions,
2254}
2255
2256impl SessionConfigSelect {
2257 #[must_use]
2258 pub fn new(
2259 current_value: impl Into<SessionConfigValueId>,
2260 options: impl Into<SessionConfigSelectOptions>,
2261 ) -> Self {
2262 Self {
2263 current_value: current_value.into(),
2264 options: options.into(),
2265 }
2266 }
2267}
2268
2269#[cfg(feature = "unstable_boolean_config")]
2275#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2276#[serde(rename_all = "camelCase")]
2277#[non_exhaustive]
2278pub struct SessionConfigBoolean {
2279 pub current_value: bool,
2281}
2282
2283#[cfg(feature = "unstable_boolean_config")]
2284impl SessionConfigBoolean {
2285 #[must_use]
2286 pub fn new(current_value: bool) -> Self {
2287 Self { current_value }
2288 }
2289}
2290
2291#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2301#[serde(rename_all = "snake_case")]
2302#[non_exhaustive]
2303pub enum SessionConfigOptionCategory {
2304 Mode,
2306 Model,
2308 ThoughtLevel,
2310 #[serde(untagged)]
2312 Other(String),
2313}
2314
2315#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2317#[serde(tag = "type", rename_all = "snake_case")]
2318#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2319#[non_exhaustive]
2320pub enum SessionConfigKind {
2321 Select(SessionConfigSelect),
2323 #[cfg(feature = "unstable_boolean_config")]
2329 Boolean(SessionConfigBoolean),
2330}
2331
2332#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2334#[serde(rename_all = "camelCase")]
2335#[non_exhaustive]
2336pub struct SessionConfigOption {
2337 pub id: SessionConfigId,
2339 pub name: String,
2341 #[serde(default, skip_serializing_if = "Option::is_none")]
2343 pub description: Option<String>,
2344 #[serde(default, skip_serializing_if = "Option::is_none")]
2346 pub category: Option<SessionConfigOptionCategory>,
2347 #[serde(flatten)]
2349 pub kind: SessionConfigKind,
2350 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2356 pub meta: Option<Meta>,
2357}
2358
2359impl SessionConfigOption {
2360 #[must_use]
2361 pub fn new(
2362 id: impl Into<SessionConfigId>,
2363 name: impl Into<String>,
2364 kind: SessionConfigKind,
2365 ) -> Self {
2366 Self {
2367 id: id.into(),
2368 name: name.into(),
2369 description: None,
2370 category: None,
2371 kind,
2372 meta: None,
2373 }
2374 }
2375
2376 #[must_use]
2377 pub fn select(
2378 id: impl Into<SessionConfigId>,
2379 name: impl Into<String>,
2380 current_value: impl Into<SessionConfigValueId>,
2381 options: impl Into<SessionConfigSelectOptions>,
2382 ) -> Self {
2383 Self::new(
2384 id,
2385 name,
2386 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2387 )
2388 }
2389
2390 #[cfg(feature = "unstable_boolean_config")]
2394 #[must_use]
2395 pub fn boolean(
2396 id: impl Into<SessionConfigId>,
2397 name: impl Into<String>,
2398 current_value: bool,
2399 ) -> Self {
2400 Self::new(
2401 id,
2402 name,
2403 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2404 )
2405 }
2406
2407 #[must_use]
2408 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2409 self.description = description.into_option();
2410 self
2411 }
2412
2413 #[must_use]
2414 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2415 self.category = category.into_option();
2416 self
2417 }
2418
2419 #[must_use]
2425 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2426 self.meta = meta.into_option();
2427 self
2428 }
2429}
2430
2431#[cfg(feature = "unstable_boolean_config")]
2446#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2447#[serde(tag = "type", rename_all = "snake_case")]
2448#[non_exhaustive]
2449pub enum SessionConfigOptionValue {
2450 Boolean {
2452 value: bool,
2454 },
2455 #[serde(untagged)]
2461 ValueId {
2462 value: SessionConfigValueId,
2464 },
2465}
2466
2467#[cfg(feature = "unstable_boolean_config")]
2468impl SessionConfigOptionValue {
2469 #[must_use]
2471 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2472 Self::ValueId { value: id.into() }
2473 }
2474
2475 #[must_use]
2477 pub fn boolean(val: bool) -> Self {
2478 Self::Boolean { value: val }
2479 }
2480
2481 #[must_use]
2484 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2485 match self {
2486 Self::ValueId { value } => Some(value),
2487 _ => None,
2488 }
2489 }
2490
2491 #[must_use]
2493 pub fn as_bool(&self) -> Option<bool> {
2494 match self {
2495 Self::Boolean { value } => Some(*value),
2496 _ => None,
2497 }
2498 }
2499}
2500
2501#[cfg(feature = "unstable_boolean_config")]
2502impl From<SessionConfigValueId> for SessionConfigOptionValue {
2503 fn from(value: SessionConfigValueId) -> Self {
2504 Self::ValueId { value }
2505 }
2506}
2507
2508#[cfg(feature = "unstable_boolean_config")]
2509impl From<bool> for SessionConfigOptionValue {
2510 fn from(value: bool) -> Self {
2511 Self::Boolean { value }
2512 }
2513}
2514
2515#[cfg(feature = "unstable_boolean_config")]
2516impl From<&str> for SessionConfigOptionValue {
2517 fn from(value: &str) -> Self {
2518 Self::ValueId {
2519 value: SessionConfigValueId::new(value),
2520 }
2521 }
2522}
2523
2524#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2526#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2527#[serde(rename_all = "camelCase")]
2528#[non_exhaustive]
2529pub struct SetSessionConfigOptionRequest {
2530 pub session_id: SessionId,
2532 pub config_id: SessionConfigId,
2534 #[cfg(feature = "unstable_boolean_config")]
2539 #[serde(flatten)]
2540 pub value: SessionConfigOptionValue,
2541 #[cfg(not(feature = "unstable_boolean_config"))]
2543 pub value: SessionConfigValueId,
2544 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2550 pub meta: Option<Meta>,
2551}
2552
2553impl SetSessionConfigOptionRequest {
2554 #[cfg(feature = "unstable_boolean_config")]
2555 #[must_use]
2556 pub fn new(
2557 session_id: impl Into<SessionId>,
2558 config_id: impl Into<SessionConfigId>,
2559 value: impl Into<SessionConfigOptionValue>,
2560 ) -> Self {
2561 Self {
2562 session_id: session_id.into(),
2563 config_id: config_id.into(),
2564 value: value.into(),
2565 meta: None,
2566 }
2567 }
2568
2569 #[cfg(not(feature = "unstable_boolean_config"))]
2570 #[must_use]
2571 pub fn new(
2572 session_id: impl Into<SessionId>,
2573 config_id: impl Into<SessionConfigId>,
2574 value: impl Into<SessionConfigValueId>,
2575 ) -> Self {
2576 Self {
2577 session_id: session_id.into(),
2578 config_id: config_id.into(),
2579 value: value.into(),
2580 meta: None,
2581 }
2582 }
2583
2584 #[must_use]
2590 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2591 self.meta = meta.into_option();
2592 self
2593 }
2594}
2595
2596#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2598#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2599#[serde(rename_all = "camelCase")]
2600#[non_exhaustive]
2601pub struct SetSessionConfigOptionResponse {
2602 pub config_options: Vec<SessionConfigOption>,
2604 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2610 pub meta: Option<Meta>,
2611}
2612
2613impl SetSessionConfigOptionResponse {
2614 #[must_use]
2615 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2616 Self {
2617 config_options,
2618 meta: None,
2619 }
2620 }
2621
2622 #[must_use]
2628 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2629 self.meta = meta.into_option();
2630 self
2631 }
2632}
2633
2634#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2643#[serde(tag = "type", rename_all = "snake_case")]
2644#[non_exhaustive]
2645pub enum McpServer {
2646 Http(McpServerHttp),
2650 Sse(McpServerSse),
2654 #[serde(untagged)]
2658 Stdio(McpServerStdio),
2659}
2660
2661#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2663#[serde(rename_all = "camelCase")]
2664#[non_exhaustive]
2665pub struct McpServerHttp {
2666 pub name: String,
2668 pub url: String,
2670 pub headers: Vec<HttpHeader>,
2672 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2678 pub meta: Option<Meta>,
2679}
2680
2681impl McpServerHttp {
2682 #[must_use]
2683 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2684 Self {
2685 name: name.into(),
2686 url: url.into(),
2687 headers: Vec::new(),
2688 meta: None,
2689 }
2690 }
2691
2692 #[must_use]
2694 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2695 self.headers = headers;
2696 self
2697 }
2698
2699 #[must_use]
2705 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2706 self.meta = meta.into_option();
2707 self
2708 }
2709}
2710
2711#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2713#[serde(rename_all = "camelCase")]
2714#[non_exhaustive]
2715pub struct McpServerSse {
2716 pub name: String,
2718 pub url: String,
2720 pub headers: Vec<HttpHeader>,
2722 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2728 pub meta: Option<Meta>,
2729}
2730
2731impl McpServerSse {
2732 #[must_use]
2733 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2734 Self {
2735 name: name.into(),
2736 url: url.into(),
2737 headers: Vec::new(),
2738 meta: None,
2739 }
2740 }
2741
2742 #[must_use]
2744 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2745 self.headers = headers;
2746 self
2747 }
2748
2749 #[must_use]
2755 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2756 self.meta = meta.into_option();
2757 self
2758 }
2759}
2760
2761#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2763#[serde(rename_all = "camelCase")]
2764#[non_exhaustive]
2765pub struct McpServerStdio {
2766 pub name: String,
2768 pub command: PathBuf,
2770 pub args: Vec<String>,
2772 pub env: Vec<EnvVariable>,
2774 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2780 pub meta: Option<Meta>,
2781}
2782
2783impl McpServerStdio {
2784 #[must_use]
2785 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2786 Self {
2787 name: name.into(),
2788 command: command.into(),
2789 args: Vec::new(),
2790 env: Vec::new(),
2791 meta: None,
2792 }
2793 }
2794
2795 #[must_use]
2797 pub fn args(mut self, args: Vec<String>) -> Self {
2798 self.args = args;
2799 self
2800 }
2801
2802 #[must_use]
2804 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2805 self.env = env;
2806 self
2807 }
2808
2809 #[must_use]
2815 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2816 self.meta = meta.into_option();
2817 self
2818 }
2819}
2820
2821#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2823#[serde(rename_all = "camelCase")]
2824#[non_exhaustive]
2825pub struct EnvVariable {
2826 pub name: String,
2828 pub value: String,
2830 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2836 pub meta: Option<Meta>,
2837}
2838
2839impl EnvVariable {
2840 #[must_use]
2841 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2842 Self {
2843 name: name.into(),
2844 value: value.into(),
2845 meta: None,
2846 }
2847 }
2848
2849 #[must_use]
2855 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2856 self.meta = meta.into_option();
2857 self
2858 }
2859}
2860
2861#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2863#[serde(rename_all = "camelCase")]
2864#[non_exhaustive]
2865pub struct HttpHeader {
2866 pub name: String,
2868 pub value: String,
2870 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2876 pub meta: Option<Meta>,
2877}
2878
2879impl HttpHeader {
2880 #[must_use]
2881 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2882 Self {
2883 name: name.into(),
2884 value: value.into(),
2885 meta: None,
2886 }
2887 }
2888
2889 #[must_use]
2895 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2896 self.meta = meta.into_option();
2897 self
2898 }
2899}
2900
2901#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
2909#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2910#[serde(rename_all = "camelCase")]
2911#[non_exhaustive]
2912pub struct PromptRequest {
2913 pub session_id: SessionId,
2915 #[cfg(feature = "unstable_message_id")]
2925 #[serde(skip_serializing_if = "Option::is_none")]
2926 pub message_id: Option<String>,
2927 pub prompt: Vec<ContentBlock>,
2941 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2947 pub meta: Option<Meta>,
2948}
2949
2950impl PromptRequest {
2951 #[must_use]
2952 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
2953 Self {
2954 session_id: session_id.into(),
2955 #[cfg(feature = "unstable_message_id")]
2956 message_id: None,
2957 prompt,
2958 meta: None,
2959 }
2960 }
2961
2962 #[cfg(feature = "unstable_message_id")]
2972 #[must_use]
2973 pub fn message_id(mut self, message_id: impl IntoOption<String>) -> Self {
2974 self.message_id = message_id.into_option();
2975 self
2976 }
2977
2978 #[must_use]
2984 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2985 self.meta = meta.into_option();
2986 self
2987 }
2988}
2989
2990#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2994#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2995#[serde(rename_all = "camelCase")]
2996#[non_exhaustive]
2997pub struct PromptResponse {
2998 #[cfg(feature = "unstable_message_id")]
3008 #[serde(skip_serializing_if = "Option::is_none")]
3009 pub user_message_id: Option<String>,
3010 pub stop_reason: StopReason,
3012 #[cfg(feature = "unstable_session_usage")]
3018 #[serde(skip_serializing_if = "Option::is_none")]
3019 pub usage: Option<Usage>,
3020 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3026 pub meta: Option<Meta>,
3027}
3028
3029impl PromptResponse {
3030 #[must_use]
3031 pub fn new(stop_reason: StopReason) -> Self {
3032 Self {
3033 #[cfg(feature = "unstable_message_id")]
3034 user_message_id: None,
3035 stop_reason,
3036 #[cfg(feature = "unstable_session_usage")]
3037 usage: None,
3038 meta: None,
3039 }
3040 }
3041
3042 #[cfg(feature = "unstable_message_id")]
3052 #[must_use]
3053 pub fn user_message_id(mut self, user_message_id: impl IntoOption<String>) -> Self {
3054 self.user_message_id = user_message_id.into_option();
3055 self
3056 }
3057
3058 #[cfg(feature = "unstable_session_usage")]
3064 #[must_use]
3065 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3066 self.usage = usage.into_option();
3067 self
3068 }
3069
3070 #[must_use]
3076 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3077 self.meta = meta.into_option();
3078 self
3079 }
3080}
3081
3082#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3086#[serde(rename_all = "snake_case")]
3087#[non_exhaustive]
3088pub enum StopReason {
3089 EndTurn,
3091 MaxTokens,
3093 MaxTurnRequests,
3096 Refusal,
3100 Cancelled,
3107}
3108
3109#[cfg(feature = "unstable_session_usage")]
3115#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3116#[serde(rename_all = "camelCase")]
3117#[non_exhaustive]
3118pub struct Usage {
3119 pub total_tokens: u64,
3121 pub input_tokens: u64,
3123 pub output_tokens: u64,
3125 #[serde(skip_serializing_if = "Option::is_none")]
3127 pub thought_tokens: Option<u64>,
3128 #[serde(skip_serializing_if = "Option::is_none")]
3130 pub cached_read_tokens: Option<u64>,
3131 #[serde(skip_serializing_if = "Option::is_none")]
3133 pub cached_write_tokens: Option<u64>,
3134}
3135
3136#[cfg(feature = "unstable_session_usage")]
3137impl Usage {
3138 #[must_use]
3139 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3140 Self {
3141 total_tokens,
3142 input_tokens,
3143 output_tokens,
3144 thought_tokens: None,
3145 cached_read_tokens: None,
3146 cached_write_tokens: None,
3147 }
3148 }
3149
3150 #[must_use]
3152 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3153 self.thought_tokens = thought_tokens.into_option();
3154 self
3155 }
3156
3157 #[must_use]
3159 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3160 self.cached_read_tokens = cached_read_tokens.into_option();
3161 self
3162 }
3163
3164 #[must_use]
3166 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3167 self.cached_write_tokens = cached_write_tokens.into_option();
3168 self
3169 }
3170}
3171
3172#[cfg(feature = "unstable_session_model")]
3180#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3181#[serde(rename_all = "camelCase")]
3182#[non_exhaustive]
3183pub struct SessionModelState {
3184 pub current_model_id: ModelId,
3186 pub available_models: Vec<ModelInfo>,
3188 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3194 pub meta: Option<Meta>,
3195}
3196
3197#[cfg(feature = "unstable_session_model")]
3198impl SessionModelState {
3199 #[must_use]
3200 pub fn new(current_model_id: impl Into<ModelId>, available_models: Vec<ModelInfo>) -> Self {
3201 Self {
3202 current_model_id: current_model_id.into(),
3203 available_models,
3204 meta: None,
3205 }
3206 }
3207
3208 #[must_use]
3214 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3215 self.meta = meta.into_option();
3216 self
3217 }
3218}
3219
3220#[cfg(feature = "unstable_session_model")]
3226#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
3227#[serde(transparent)]
3228#[from(Arc<str>, String, &'static str)]
3229#[non_exhaustive]
3230pub struct ModelId(pub Arc<str>);
3231
3232#[cfg(feature = "unstable_session_model")]
3233impl ModelId {
3234 #[must_use]
3235 pub fn new(id: impl Into<Arc<str>>) -> Self {
3236 Self(id.into())
3237 }
3238}
3239
3240#[cfg(feature = "unstable_session_model")]
3246#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3247#[serde(rename_all = "camelCase")]
3248#[non_exhaustive]
3249pub struct ModelInfo {
3250 pub model_id: ModelId,
3252 pub name: String,
3254 #[serde(default, skip_serializing_if = "Option::is_none")]
3256 pub description: Option<String>,
3257 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3263 pub meta: Option<Meta>,
3264}
3265
3266#[cfg(feature = "unstable_session_model")]
3267impl ModelInfo {
3268 #[must_use]
3269 pub fn new(model_id: impl Into<ModelId>, name: impl Into<String>) -> Self {
3270 Self {
3271 model_id: model_id.into(),
3272 name: name.into(),
3273 description: None,
3274 meta: None,
3275 }
3276 }
3277
3278 #[must_use]
3280 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
3281 self.description = description.into_option();
3282 self
3283 }
3284
3285 #[must_use]
3291 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3292 self.meta = meta.into_option();
3293 self
3294 }
3295}
3296
3297#[cfg(feature = "unstable_session_model")]
3303#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3304#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3305#[serde(rename_all = "camelCase")]
3306#[non_exhaustive]
3307pub struct SetSessionModelRequest {
3308 pub session_id: SessionId,
3310 pub model_id: ModelId,
3312 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3318 pub meta: Option<Meta>,
3319}
3320
3321#[cfg(feature = "unstable_session_model")]
3322impl SetSessionModelRequest {
3323 #[must_use]
3324 pub fn new(session_id: impl Into<SessionId>, model_id: impl Into<ModelId>) -> Self {
3325 Self {
3326 session_id: session_id.into(),
3327 model_id: model_id.into(),
3328 meta: None,
3329 }
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#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3351#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3352#[serde(rename_all = "camelCase")]
3353#[non_exhaustive]
3354pub struct SetSessionModelResponse {
3355 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3361 pub meta: Option<Meta>,
3362}
3363
3364#[cfg(feature = "unstable_session_model")]
3365impl SetSessionModelResponse {
3366 #[must_use]
3367 pub fn new() -> Self {
3368 Self::default()
3369 }
3370
3371 #[must_use]
3377 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3378 self.meta = meta.into_option();
3379 self
3380 }
3381}
3382
3383#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3392#[serde(rename_all = "camelCase")]
3393#[non_exhaustive]
3394pub struct AgentCapabilities {
3395 #[serde(default)]
3397 pub load_session: bool,
3398 #[serde(default)]
3400 pub prompt_capabilities: PromptCapabilities,
3401 #[serde(default)]
3403 pub mcp_capabilities: McpCapabilities,
3404 #[serde(default)]
3405 pub session_capabilities: SessionCapabilities,
3406 #[cfg(feature = "unstable_logout")]
3412 #[serde(default)]
3413 pub auth: AgentAuthCapabilities,
3414 #[cfg(feature = "unstable_nes")]
3420 #[serde(skip_serializing_if = "Option::is_none")]
3421 pub nes: Option<NesCapabilities>,
3422 #[cfg(feature = "unstable_nes")]
3428 #[serde(skip_serializing_if = "Option::is_none")]
3429 pub position_encoding: Option<PositionEncodingKind>,
3430 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3436 pub meta: Option<Meta>,
3437}
3438
3439impl AgentCapabilities {
3440 #[must_use]
3441 pub fn new() -> Self {
3442 Self::default()
3443 }
3444
3445 #[must_use]
3447 pub fn load_session(mut self, load_session: bool) -> Self {
3448 self.load_session = load_session;
3449 self
3450 }
3451
3452 #[must_use]
3454 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3455 self.prompt_capabilities = prompt_capabilities;
3456 self
3457 }
3458
3459 #[must_use]
3461 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3462 self.mcp_capabilities = mcp_capabilities;
3463 self
3464 }
3465
3466 #[must_use]
3468 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3469 self.session_capabilities = session_capabilities;
3470 self
3471 }
3472
3473 #[cfg(feature = "unstable_logout")]
3479 #[must_use]
3480 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3481 self.auth = auth;
3482 self
3483 }
3484
3485 #[cfg(feature = "unstable_nes")]
3489 #[must_use]
3490 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3491 self.nes = nes.into_option();
3492 self
3493 }
3494
3495 #[cfg(feature = "unstable_nes")]
3499 #[must_use]
3500 pub fn position_encoding(
3501 mut self,
3502 position_encoding: impl IntoOption<PositionEncodingKind>,
3503 ) -> Self {
3504 self.position_encoding = position_encoding.into_option();
3505 self
3506 }
3507
3508 #[must_use]
3514 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3515 self.meta = meta.into_option();
3516 self
3517 }
3518}
3519
3520#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3530#[serde(rename_all = "camelCase")]
3531#[non_exhaustive]
3532pub struct SessionCapabilities {
3533 #[serde(skip_serializing_if = "Option::is_none")]
3535 pub list: Option<SessionListCapabilities>,
3536 #[cfg(feature = "unstable_session_additional_directories")]
3542 #[serde(skip_serializing_if = "Option::is_none")]
3543 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
3544 #[cfg(feature = "unstable_session_fork")]
3550 #[serde(skip_serializing_if = "Option::is_none")]
3551 pub fork: Option<SessionForkCapabilities>,
3552 #[cfg(feature = "unstable_session_resume")]
3558 #[serde(skip_serializing_if = "Option::is_none")]
3559 pub resume: Option<SessionResumeCapabilities>,
3560 #[cfg(feature = "unstable_session_close")]
3566 #[serde(skip_serializing_if = "Option::is_none")]
3567 pub close: Option<SessionCloseCapabilities>,
3568 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3574 pub meta: Option<Meta>,
3575}
3576
3577impl SessionCapabilities {
3578 #[must_use]
3579 pub fn new() -> Self {
3580 Self::default()
3581 }
3582
3583 #[must_use]
3585 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3586 self.list = list.into_option();
3587 self
3588 }
3589
3590 #[cfg(feature = "unstable_session_additional_directories")]
3596 #[must_use]
3597 pub fn additional_directories(
3598 mut self,
3599 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
3600 ) -> Self {
3601 self.additional_directories = additional_directories.into_option();
3602 self
3603 }
3604
3605 #[cfg(feature = "unstable_session_fork")]
3606 #[must_use]
3608 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
3609 self.fork = fork.into_option();
3610 self
3611 }
3612
3613 #[cfg(feature = "unstable_session_resume")]
3614 #[must_use]
3616 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
3617 self.resume = resume.into_option();
3618 self
3619 }
3620
3621 #[cfg(feature = "unstable_session_close")]
3622 #[must_use]
3624 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
3625 self.close = close.into_option();
3626 self
3627 }
3628
3629 #[must_use]
3635 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3636 self.meta = meta.into_option();
3637 self
3638 }
3639}
3640
3641#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3645#[non_exhaustive]
3646pub struct SessionListCapabilities {
3647 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3653 pub meta: Option<Meta>,
3654}
3655
3656impl SessionListCapabilities {
3657 #[must_use]
3658 pub fn new() -> Self {
3659 Self::default()
3660 }
3661
3662 #[must_use]
3668 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3669 self.meta = meta.into_option();
3670 self
3671 }
3672}
3673
3674#[cfg(feature = "unstable_session_additional_directories")]
3683#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3684#[non_exhaustive]
3685pub struct SessionAdditionalDirectoriesCapabilities {
3686 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3692 pub meta: Option<Meta>,
3693}
3694
3695#[cfg(feature = "unstable_session_additional_directories")]
3696impl SessionAdditionalDirectoriesCapabilities {
3697 #[must_use]
3698 pub fn new() -> Self {
3699 Self::default()
3700 }
3701
3702 #[must_use]
3708 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3709 self.meta = meta.into_option();
3710 self
3711 }
3712}
3713
3714#[cfg(feature = "unstable_session_fork")]
3722#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3723#[non_exhaustive]
3724pub struct SessionForkCapabilities {
3725 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3731 pub meta: Option<Meta>,
3732}
3733
3734#[cfg(feature = "unstable_session_fork")]
3735impl SessionForkCapabilities {
3736 #[must_use]
3737 pub fn new() -> Self {
3738 Self::default()
3739 }
3740
3741 #[must_use]
3747 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3748 self.meta = meta.into_option();
3749 self
3750 }
3751}
3752
3753#[cfg(feature = "unstable_session_resume")]
3761#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3762#[non_exhaustive]
3763pub struct SessionResumeCapabilities {
3764 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3770 pub meta: Option<Meta>,
3771}
3772
3773#[cfg(feature = "unstable_session_resume")]
3774impl SessionResumeCapabilities {
3775 #[must_use]
3776 pub fn new() -> Self {
3777 Self::default()
3778 }
3779
3780 #[must_use]
3786 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3787 self.meta = meta.into_option();
3788 self
3789 }
3790}
3791
3792#[cfg(feature = "unstable_session_close")]
3800#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3801#[non_exhaustive]
3802pub struct SessionCloseCapabilities {
3803 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3809 pub meta: Option<Meta>,
3810}
3811
3812#[cfg(feature = "unstable_session_close")]
3813impl SessionCloseCapabilities {
3814 #[must_use]
3815 pub fn new() -> Self {
3816 Self::default()
3817 }
3818
3819 #[must_use]
3825 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3826 self.meta = meta.into_option();
3827 self
3828 }
3829}
3830
3831#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3844#[serde(rename_all = "camelCase")]
3845#[non_exhaustive]
3846pub struct PromptCapabilities {
3847 #[serde(default)]
3849 pub image: bool,
3850 #[serde(default)]
3852 pub audio: bool,
3853 #[serde(default)]
3858 pub embedded_context: bool,
3859 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3865 pub meta: Option<Meta>,
3866}
3867
3868impl PromptCapabilities {
3869 #[must_use]
3870 pub fn new() -> Self {
3871 Self::default()
3872 }
3873
3874 #[must_use]
3876 pub fn image(mut self, image: bool) -> Self {
3877 self.image = image;
3878 self
3879 }
3880
3881 #[must_use]
3883 pub fn audio(mut self, audio: bool) -> Self {
3884 self.audio = audio;
3885 self
3886 }
3887
3888 #[must_use]
3893 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
3894 self.embedded_context = embedded_context;
3895 self
3896 }
3897
3898 #[must_use]
3904 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3905 self.meta = meta.into_option();
3906 self
3907 }
3908}
3909
3910#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3912#[serde(rename_all = "camelCase")]
3913#[non_exhaustive]
3914pub struct McpCapabilities {
3915 #[serde(default)]
3917 pub http: bool,
3918 #[serde(default)]
3920 pub sse: bool,
3921 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3927 pub meta: Option<Meta>,
3928}
3929
3930impl McpCapabilities {
3931 #[must_use]
3932 pub fn new() -> Self {
3933 Self::default()
3934 }
3935
3936 #[must_use]
3938 pub fn http(mut self, http: bool) -> Self {
3939 self.http = http;
3940 self
3941 }
3942
3943 #[must_use]
3945 pub fn sse(mut self, sse: bool) -> Self {
3946 self.sse = sse;
3947 self
3948 }
3949
3950 #[must_use]
3956 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3957 self.meta = meta.into_option();
3958 self
3959 }
3960}
3961
3962#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3968#[non_exhaustive]
3969pub struct AgentMethodNames {
3970 pub initialize: &'static str,
3972 pub authenticate: &'static str,
3974 pub session_new: &'static str,
3976 pub session_load: &'static str,
3978 pub session_set_mode: &'static str,
3980 pub session_set_config_option: &'static str,
3982 pub session_prompt: &'static str,
3984 pub session_cancel: &'static str,
3986 #[cfg(feature = "unstable_session_model")]
3988 pub session_set_model: &'static str,
3989 pub session_list: &'static str,
3991 #[cfg(feature = "unstable_session_fork")]
3993 pub session_fork: &'static str,
3994 #[cfg(feature = "unstable_session_resume")]
3996 pub session_resume: &'static str,
3997 #[cfg(feature = "unstable_session_close")]
3999 pub session_close: &'static str,
4000 #[cfg(feature = "unstable_logout")]
4002 pub logout: &'static str,
4003 #[cfg(feature = "unstable_nes")]
4005 pub nes_start: &'static str,
4006 #[cfg(feature = "unstable_nes")]
4008 pub nes_suggest: &'static str,
4009 #[cfg(feature = "unstable_nes")]
4011 pub nes_accept: &'static str,
4012 #[cfg(feature = "unstable_nes")]
4014 pub nes_reject: &'static str,
4015 #[cfg(feature = "unstable_nes")]
4017 pub nes_close: &'static str,
4018 #[cfg(feature = "unstable_nes")]
4020 pub document_did_open: &'static str,
4021 #[cfg(feature = "unstable_nes")]
4023 pub document_did_change: &'static str,
4024 #[cfg(feature = "unstable_nes")]
4026 pub document_did_close: &'static str,
4027 #[cfg(feature = "unstable_nes")]
4029 pub document_did_save: &'static str,
4030 #[cfg(feature = "unstable_nes")]
4032 pub document_did_focus: &'static str,
4033}
4034
4035pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4037 initialize: INITIALIZE_METHOD_NAME,
4038 authenticate: AUTHENTICATE_METHOD_NAME,
4039 session_new: SESSION_NEW_METHOD_NAME,
4040 session_load: SESSION_LOAD_METHOD_NAME,
4041 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4042 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4043 session_prompt: SESSION_PROMPT_METHOD_NAME,
4044 session_cancel: SESSION_CANCEL_METHOD_NAME,
4045 #[cfg(feature = "unstable_session_model")]
4046 session_set_model: SESSION_SET_MODEL_METHOD_NAME,
4047 session_list: SESSION_LIST_METHOD_NAME,
4048 #[cfg(feature = "unstable_session_fork")]
4049 session_fork: SESSION_FORK_METHOD_NAME,
4050 #[cfg(feature = "unstable_session_resume")]
4051 session_resume: SESSION_RESUME_METHOD_NAME,
4052 #[cfg(feature = "unstable_session_close")]
4053 session_close: SESSION_CLOSE_METHOD_NAME,
4054 #[cfg(feature = "unstable_logout")]
4055 logout: LOGOUT_METHOD_NAME,
4056 #[cfg(feature = "unstable_nes")]
4057 nes_start: NES_START_METHOD_NAME,
4058 #[cfg(feature = "unstable_nes")]
4059 nes_suggest: NES_SUGGEST_METHOD_NAME,
4060 #[cfg(feature = "unstable_nes")]
4061 nes_accept: NES_ACCEPT_METHOD_NAME,
4062 #[cfg(feature = "unstable_nes")]
4063 nes_reject: NES_REJECT_METHOD_NAME,
4064 #[cfg(feature = "unstable_nes")]
4065 nes_close: NES_CLOSE_METHOD_NAME,
4066 #[cfg(feature = "unstable_nes")]
4067 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4068 #[cfg(feature = "unstable_nes")]
4069 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4070 #[cfg(feature = "unstable_nes")]
4071 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4072 #[cfg(feature = "unstable_nes")]
4073 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4074 #[cfg(feature = "unstable_nes")]
4075 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4076};
4077
4078pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4080pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4082pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4084pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4086pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4088pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4090pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4092pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4094#[cfg(feature = "unstable_session_model")]
4096pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
4097pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4099#[cfg(feature = "unstable_session_fork")]
4101pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4102#[cfg(feature = "unstable_session_resume")]
4104pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4105#[cfg(feature = "unstable_session_close")]
4107pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4108#[cfg(feature = "unstable_logout")]
4110pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4111
4112#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4119#[serde(untagged)]
4120#[schemars(inline)]
4121#[non_exhaustive]
4122#[allow(clippy::large_enum_variant)]
4123pub enum ClientRequest {
4124 InitializeRequest(InitializeRequest),
4135 AuthenticateRequest(AuthenticateRequest),
4145 #[cfg(feature = "unstable_logout")]
4154 LogoutRequest(LogoutRequest),
4155 NewSessionRequest(NewSessionRequest),
4168 LoadSessionRequest(LoadSessionRequest),
4179 ListSessionsRequest(ListSessionsRequest),
4185 #[cfg(feature = "unstable_session_fork")]
4186 ForkSessionRequest(ForkSessionRequest),
4198 #[cfg(feature = "unstable_session_resume")]
4199 ResumeSessionRequest(ResumeSessionRequest),
4210 #[cfg(feature = "unstable_session_close")]
4211 CloseSessionRequest(CloseSessionRequest),
4222 SetSessionModeRequest(SetSessionModeRequest),
4236 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4238 PromptRequest(PromptRequest),
4250 #[cfg(feature = "unstable_session_model")]
4251 SetSessionModelRequest(SetSessionModelRequest),
4257 #[cfg(feature = "unstable_nes")]
4258 StartNesRequest(StartNesRequest),
4264 #[cfg(feature = "unstable_nes")]
4265 SuggestNesRequest(SuggestNesRequest),
4271 #[cfg(feature = "unstable_nes")]
4272 CloseNesRequest(CloseNesRequest),
4281 ExtMethodRequest(ExtRequest),
4288}
4289
4290impl ClientRequest {
4291 #[must_use]
4293 pub fn method(&self) -> &str {
4294 match self {
4295 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4296 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4297 #[cfg(feature = "unstable_logout")]
4298 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4299 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4300 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4301 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4302 #[cfg(feature = "unstable_session_fork")]
4303 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
4304 #[cfg(feature = "unstable_session_resume")]
4305 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
4306 #[cfg(feature = "unstable_session_close")]
4307 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
4308 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
4309 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
4310 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
4311 #[cfg(feature = "unstable_session_model")]
4312 Self::SetSessionModelRequest(_) => AGENT_METHOD_NAMES.session_set_model,
4313 #[cfg(feature = "unstable_nes")]
4314 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
4315 #[cfg(feature = "unstable_nes")]
4316 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
4317 #[cfg(feature = "unstable_nes")]
4318 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
4319 Self::ExtMethodRequest(ext_request) => &ext_request.method,
4320 }
4321 }
4322}
4323
4324#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4331#[serde(untagged)]
4332#[schemars(inline)]
4333#[non_exhaustive]
4334#[allow(clippy::large_enum_variant)]
4335pub enum AgentResponse {
4336 InitializeResponse(InitializeResponse),
4337 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
4338 #[cfg(feature = "unstable_logout")]
4339 LogoutResponse(#[serde(default)] LogoutResponse),
4340 NewSessionResponse(NewSessionResponse),
4341 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
4342 ListSessionsResponse(ListSessionsResponse),
4343 #[cfg(feature = "unstable_session_fork")]
4344 ForkSessionResponse(ForkSessionResponse),
4345 #[cfg(feature = "unstable_session_resume")]
4346 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
4347 #[cfg(feature = "unstable_session_close")]
4348 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
4349 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
4350 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
4351 PromptResponse(PromptResponse),
4352 #[cfg(feature = "unstable_session_model")]
4353 SetSessionModelResponse(#[serde(default)] SetSessionModelResponse),
4354 #[cfg(feature = "unstable_nes")]
4355 StartNesResponse(StartNesResponse),
4356 #[cfg(feature = "unstable_nes")]
4357 SuggestNesResponse(SuggestNesResponse),
4358 #[cfg(feature = "unstable_nes")]
4359 CloseNesResponse(#[serde(default)] CloseNesResponse),
4360 ExtMethodResponse(ExtResponse),
4361}
4362
4363#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4370#[serde(untagged)]
4371#[schemars(inline)]
4372#[non_exhaustive]
4373pub enum ClientNotification {
4374 CancelNotification(CancelNotification),
4386 #[cfg(feature = "unstable_nes")]
4387 DidOpenDocumentNotification(DidOpenDocumentNotification),
4391 #[cfg(feature = "unstable_nes")]
4392 DidChangeDocumentNotification(DidChangeDocumentNotification),
4396 #[cfg(feature = "unstable_nes")]
4397 DidCloseDocumentNotification(DidCloseDocumentNotification),
4401 #[cfg(feature = "unstable_nes")]
4402 DidSaveDocumentNotification(DidSaveDocumentNotification),
4406 #[cfg(feature = "unstable_nes")]
4407 DidFocusDocumentNotification(DidFocusDocumentNotification),
4411 #[cfg(feature = "unstable_nes")]
4412 AcceptNesNotification(AcceptNesNotification),
4416 #[cfg(feature = "unstable_nes")]
4417 RejectNesNotification(RejectNesNotification),
4421 ExtNotification(ExtNotification),
4428}
4429
4430impl ClientNotification {
4431 #[must_use]
4433 pub fn method(&self) -> &str {
4434 match self {
4435 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
4436 #[cfg(feature = "unstable_nes")]
4437 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
4438 #[cfg(feature = "unstable_nes")]
4439 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
4440 #[cfg(feature = "unstable_nes")]
4441 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
4442 #[cfg(feature = "unstable_nes")]
4443 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
4444 #[cfg(feature = "unstable_nes")]
4445 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
4446 #[cfg(feature = "unstable_nes")]
4447 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
4448 #[cfg(feature = "unstable_nes")]
4449 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
4450 Self::ExtNotification(ext_notification) => &ext_notification.method,
4451 }
4452 }
4453}
4454
4455#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4459#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
4460#[serde(rename_all = "camelCase")]
4461#[non_exhaustive]
4462pub struct CancelNotification {
4463 pub session_id: SessionId,
4465 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
4471 pub meta: Option<Meta>,
4472}
4473
4474impl CancelNotification {
4475 #[must_use]
4476 pub fn new(session_id: impl Into<SessionId>) -> Self {
4477 Self {
4478 session_id: session_id.into(),
4479 meta: None,
4480 }
4481 }
4482
4483 #[must_use]
4489 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4490 self.meta = meta.into_option();
4491 self
4492 }
4493}
4494
4495#[cfg(test)]
4496mod test_serialization {
4497 use super::*;
4498 use serde_json::json;
4499
4500 #[test]
4501 fn test_mcp_server_stdio_serialization() {
4502 let server = McpServer::Stdio(
4503 McpServerStdio::new("test-server", "/usr/bin/server")
4504 .args(vec!["--port".to_string(), "3000".to_string()])
4505 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
4506 );
4507
4508 let json = serde_json::to_value(&server).unwrap();
4509 assert_eq!(
4510 json,
4511 json!({
4512 "name": "test-server",
4513 "command": "/usr/bin/server",
4514 "args": ["--port", "3000"],
4515 "env": [
4516 {
4517 "name": "API_KEY",
4518 "value": "secret123"
4519 }
4520 ]
4521 })
4522 );
4523
4524 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4525 match deserialized {
4526 McpServer::Stdio(McpServerStdio {
4527 name,
4528 command,
4529 args,
4530 env,
4531 meta: _,
4532 }) => {
4533 assert_eq!(name, "test-server");
4534 assert_eq!(command, PathBuf::from("/usr/bin/server"));
4535 assert_eq!(args, vec!["--port", "3000"]);
4536 assert_eq!(env.len(), 1);
4537 assert_eq!(env[0].name, "API_KEY");
4538 assert_eq!(env[0].value, "secret123");
4539 }
4540 _ => panic!("Expected Stdio variant"),
4541 }
4542 }
4543
4544 #[test]
4545 fn test_mcp_server_http_serialization() {
4546 let server = McpServer::Http(
4547 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
4548 HttpHeader::new("Authorization", "Bearer token123"),
4549 HttpHeader::new("Content-Type", "application/json"),
4550 ]),
4551 );
4552
4553 let json = serde_json::to_value(&server).unwrap();
4554 assert_eq!(
4555 json,
4556 json!({
4557 "type": "http",
4558 "name": "http-server",
4559 "url": "https://api.example.com",
4560 "headers": [
4561 {
4562 "name": "Authorization",
4563 "value": "Bearer token123"
4564 },
4565 {
4566 "name": "Content-Type",
4567 "value": "application/json"
4568 }
4569 ]
4570 })
4571 );
4572
4573 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4574 match deserialized {
4575 McpServer::Http(McpServerHttp {
4576 name,
4577 url,
4578 headers,
4579 meta: _,
4580 }) => {
4581 assert_eq!(name, "http-server");
4582 assert_eq!(url, "https://api.example.com");
4583 assert_eq!(headers.len(), 2);
4584 assert_eq!(headers[0].name, "Authorization");
4585 assert_eq!(headers[0].value, "Bearer token123");
4586 assert_eq!(headers[1].name, "Content-Type");
4587 assert_eq!(headers[1].value, "application/json");
4588 }
4589 _ => panic!("Expected Http variant"),
4590 }
4591 }
4592
4593 #[test]
4594 fn test_mcp_server_sse_serialization() {
4595 let server = McpServer::Sse(
4596 McpServerSse::new("sse-server", "https://sse.example.com/events")
4597 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
4598 );
4599
4600 let json = serde_json::to_value(&server).unwrap();
4601 assert_eq!(
4602 json,
4603 json!({
4604 "type": "sse",
4605 "name": "sse-server",
4606 "url": "https://sse.example.com/events",
4607 "headers": [
4608 {
4609 "name": "X-API-Key",
4610 "value": "apikey456"
4611 }
4612 ]
4613 })
4614 );
4615
4616 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4617 match deserialized {
4618 McpServer::Sse(McpServerSse {
4619 name,
4620 url,
4621 headers,
4622 meta: _,
4623 }) => {
4624 assert_eq!(name, "sse-server");
4625 assert_eq!(url, "https://sse.example.com/events");
4626 assert_eq!(headers.len(), 1);
4627 assert_eq!(headers[0].name, "X-API-Key");
4628 assert_eq!(headers[0].value, "apikey456");
4629 }
4630 _ => panic!("Expected Sse variant"),
4631 }
4632 }
4633
4634 #[test]
4635 fn test_session_config_option_category_known_variants() {
4636 assert_eq!(
4638 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
4639 json!("mode")
4640 );
4641 assert_eq!(
4642 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
4643 json!("model")
4644 );
4645 assert_eq!(
4646 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
4647 json!("thought_level")
4648 );
4649
4650 assert_eq!(
4652 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
4653 SessionConfigOptionCategory::Mode
4654 );
4655 assert_eq!(
4656 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
4657 SessionConfigOptionCategory::Model
4658 );
4659 assert_eq!(
4660 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
4661 SessionConfigOptionCategory::ThoughtLevel
4662 );
4663 }
4664
4665 #[test]
4666 fn test_session_config_option_category_unknown_variants() {
4667 let unknown: SessionConfigOptionCategory =
4669 serde_json::from_str("\"some_future_category\"").unwrap();
4670 assert_eq!(
4671 unknown,
4672 SessionConfigOptionCategory::Other("some_future_category".to_string())
4673 );
4674
4675 let json = serde_json::to_value(&unknown).unwrap();
4677 assert_eq!(json, json!("some_future_category"));
4678 }
4679
4680 #[test]
4681 fn test_session_config_option_category_custom_categories() {
4682 let custom: SessionConfigOptionCategory =
4684 serde_json::from_str("\"_my_custom_category\"").unwrap();
4685 assert_eq!(
4686 custom,
4687 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
4688 );
4689
4690 let json = serde_json::to_value(&custom).unwrap();
4692 assert_eq!(json, json!("_my_custom_category"));
4693
4694 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
4696 assert_eq!(
4697 deserialized,
4698 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
4699 );
4700 }
4701
4702 #[test]
4703 fn test_auth_method_agent_serialization() {
4704 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
4705
4706 let json = serde_json::to_value(&method).unwrap();
4707 assert_eq!(
4708 json,
4709 json!({
4710 "id": "default-auth",
4711 "name": "Default Auth"
4712 })
4713 );
4714 assert!(!json.as_object().unwrap().contains_key("description"));
4716 assert!(!json.as_object().unwrap().contains_key("type"));
4718
4719 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4720 match deserialized {
4721 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
4722 assert_eq!(id.0.as_ref(), "default-auth");
4723 assert_eq!(name, "Default Auth");
4724 }
4725 #[cfg(feature = "unstable_auth_methods")]
4726 _ => panic!("Expected Agent variant"),
4727 }
4728 }
4729
4730 #[test]
4731 fn test_auth_method_explicit_agent_deserialization() {
4732 let json = json!({
4734 "id": "agent-auth",
4735 "name": "Agent Auth",
4736 "type": "agent"
4737 });
4738
4739 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4740 assert!(matches!(deserialized, AuthMethod::Agent(_)));
4741 }
4742
4743 #[cfg(feature = "unstable_session_additional_directories")]
4744 #[test]
4745 fn test_session_additional_directories_serialization() {
4746 assert_eq!(
4747 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
4748 json!({
4749 "cwd": "/home/user/project",
4750 "mcpServers": []
4751 })
4752 );
4753 assert_eq!(
4754 serde_json::to_value(
4755 NewSessionRequest::new("/home/user/project").additional_directories(vec![
4756 PathBuf::from("/home/user/shared-lib"),
4757 PathBuf::from("/home/user/product-docs"),
4758 ])
4759 )
4760 .unwrap(),
4761 json!({
4762 "cwd": "/home/user/project",
4763 "additionalDirectories": [
4764 "/home/user/shared-lib",
4765 "/home/user/product-docs"
4766 ],
4767 "mcpServers": []
4768 })
4769 );
4770 assert_eq!(
4771 serde_json::to_value(
4772 ListSessionsRequest::new().additional_directories(Vec::<PathBuf>::new())
4773 )
4774 .unwrap(),
4775 json!({})
4776 );
4777 assert_eq!(
4778 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
4779 json!({
4780 "sessionId": "sess_abc123",
4781 "cwd": "/home/user/project"
4782 })
4783 );
4784 assert_eq!(
4785 serde_json::to_value(
4786 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
4787 PathBuf::from("/home/user/shared-lib"),
4788 PathBuf::from("/home/user/product-docs"),
4789 ])
4790 )
4791 .unwrap(),
4792 json!({
4793 "sessionId": "sess_abc123",
4794 "cwd": "/home/user/project",
4795 "additionalDirectories": [
4796 "/home/user/shared-lib",
4797 "/home/user/product-docs"
4798 ]
4799 })
4800 );
4801 assert_eq!(
4802 serde_json::from_value::<SessionInfo>(json!({
4803 "sessionId": "sess_abc123",
4804 "cwd": "/home/user/project"
4805 }))
4806 .unwrap()
4807 .additional_directories,
4808 Vec::<PathBuf>::new()
4809 );
4810
4811 assert_eq!(
4812 serde_json::from_value::<ListSessionsRequest>(json!({}))
4813 .unwrap()
4814 .additional_directories,
4815 Vec::<PathBuf>::new()
4816 );
4817
4818 assert_eq!(
4819 serde_json::from_value::<ListSessionsRequest>(json!({
4820 "additionalDirectories": []
4821 }))
4822 .unwrap()
4823 .additional_directories,
4824 Vec::<PathBuf>::new()
4825 );
4826 }
4827
4828 #[cfg(feature = "unstable_session_additional_directories")]
4829 #[test]
4830 fn test_session_additional_directories_capabilities_serialization() {
4831 assert_eq!(
4832 serde_json::to_value(
4833 SessionCapabilities::new()
4834 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
4835 )
4836 .unwrap(),
4837 json!({
4838 "additionalDirectories": {}
4839 })
4840 );
4841 }
4842
4843 #[cfg(feature = "unstable_auth_methods")]
4844 #[test]
4845 fn test_auth_method_env_var_serialization() {
4846 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
4847 "api-key",
4848 "API Key",
4849 vec![AuthEnvVar::new("API_KEY")],
4850 ));
4851
4852 let json = serde_json::to_value(&method).unwrap();
4853 assert_eq!(
4854 json,
4855 json!({
4856 "id": "api-key",
4857 "name": "API Key",
4858 "type": "env_var",
4859 "vars": [{"name": "API_KEY"}]
4860 })
4861 );
4862 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
4864 assert!(
4865 !json["vars"][0]
4866 .as_object()
4867 .unwrap()
4868 .contains_key("optional")
4869 );
4870
4871 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4872 match deserialized {
4873 AuthMethod::EnvVar(AuthMethodEnvVar {
4874 id,
4875 name: method_name,
4876 vars,
4877 link,
4878 ..
4879 }) => {
4880 assert_eq!(id.0.as_ref(), "api-key");
4881 assert_eq!(method_name, "API Key");
4882 assert_eq!(vars.len(), 1);
4883 assert_eq!(vars[0].name, "API_KEY");
4884 assert!(vars[0].secret);
4885 assert!(!vars[0].optional);
4886 assert!(link.is_none());
4887 }
4888 _ => panic!("Expected EnvVar variant"),
4889 }
4890 }
4891
4892 #[cfg(feature = "unstable_auth_methods")]
4893 #[test]
4894 fn test_auth_method_env_var_with_link_serialization() {
4895 let method = AuthMethod::EnvVar(
4896 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
4897 .link("https://example.com/keys"),
4898 );
4899
4900 let json = serde_json::to_value(&method).unwrap();
4901 assert_eq!(
4902 json,
4903 json!({
4904 "id": "api-key",
4905 "name": "API Key",
4906 "type": "env_var",
4907 "vars": [{"name": "API_KEY"}],
4908 "link": "https://example.com/keys"
4909 })
4910 );
4911
4912 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4913 match deserialized {
4914 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
4915 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
4916 }
4917 _ => panic!("Expected EnvVar variant"),
4918 }
4919 }
4920
4921 #[cfg(feature = "unstable_auth_methods")]
4922 #[test]
4923 fn test_auth_method_env_var_multiple_vars() {
4924 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
4925 "azure-openai",
4926 "Azure OpenAI",
4927 vec![
4928 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
4929 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
4930 .label("Endpoint URL")
4931 .secret(false),
4932 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
4933 .label("API Version")
4934 .secret(false)
4935 .optional(true),
4936 ],
4937 ));
4938
4939 let json = serde_json::to_value(&method).unwrap();
4940 assert_eq!(
4941 json,
4942 json!({
4943 "id": "azure-openai",
4944 "name": "Azure OpenAI",
4945 "type": "env_var",
4946 "vars": [
4947 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
4948 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
4949 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
4950 ]
4951 })
4952 );
4953
4954 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4955 match deserialized {
4956 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
4957 assert_eq!(vars.len(), 3);
4958 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
4960 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
4961 assert!(vars[0].secret);
4962 assert!(!vars[0].optional);
4963 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
4965 assert!(!vars[1].secret);
4966 assert!(!vars[1].optional);
4967 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
4969 assert!(!vars[2].secret);
4970 assert!(vars[2].optional);
4971 }
4972 _ => panic!("Expected EnvVar variant"),
4973 }
4974 }
4975
4976 #[cfg(feature = "unstable_auth_methods")]
4977 #[test]
4978 fn test_auth_method_terminal_serialization() {
4979 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
4980
4981 let json = serde_json::to_value(&method).unwrap();
4982 assert_eq!(
4983 json,
4984 json!({
4985 "id": "tui-auth",
4986 "name": "Terminal Auth",
4987 "type": "terminal"
4988 })
4989 );
4990 assert!(!json.as_object().unwrap().contains_key("args"));
4992 assert!(!json.as_object().unwrap().contains_key("env"));
4993
4994 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4995 match deserialized {
4996 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
4997 assert!(args.is_empty());
4998 assert!(env.is_empty());
4999 }
5000 _ => panic!("Expected Terminal variant"),
5001 }
5002 }
5003
5004 #[cfg(feature = "unstable_auth_methods")]
5005 #[test]
5006 fn test_auth_method_terminal_with_args_and_env_serialization() {
5007 use std::collections::HashMap;
5008
5009 let mut env = HashMap::new();
5010 env.insert("TERM".to_string(), "xterm-256color".to_string());
5011
5012 let method = AuthMethod::Terminal(
5013 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5014 .args(vec!["--interactive".to_string(), "--color".to_string()])
5015 .env(env),
5016 );
5017
5018 let json = serde_json::to_value(&method).unwrap();
5019 assert_eq!(
5020 json,
5021 json!({
5022 "id": "tui-auth",
5023 "name": "Terminal Auth",
5024 "type": "terminal",
5025 "args": ["--interactive", "--color"],
5026 "env": {
5027 "TERM": "xterm-256color"
5028 }
5029 })
5030 );
5031
5032 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5033 match deserialized {
5034 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5035 assert_eq!(args, vec!["--interactive", "--color"]);
5036 assert_eq!(env.len(), 1);
5037 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5038 }
5039 _ => panic!("Expected Terminal variant"),
5040 }
5041 }
5042
5043 #[cfg(feature = "unstable_boolean_config")]
5044 #[test]
5045 fn test_session_config_option_value_id_serialize() {
5046 let val = SessionConfigOptionValue::value_id("model-1");
5047 let json = serde_json::to_value(&val).unwrap();
5048 assert_eq!(json, json!({ "value": "model-1" }));
5050 assert!(!json.as_object().unwrap().contains_key("type"));
5051 }
5052
5053 #[cfg(feature = "unstable_boolean_config")]
5054 #[test]
5055 fn test_session_config_option_value_boolean_serialize() {
5056 let val = SessionConfigOptionValue::boolean(true);
5057 let json = serde_json::to_value(&val).unwrap();
5058 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5059 }
5060
5061 #[cfg(feature = "unstable_boolean_config")]
5062 #[test]
5063 fn test_session_config_option_value_deserialize_no_type() {
5064 let json = json!({ "value": "model-1" });
5066 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5067 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5068 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5069 }
5070
5071 #[cfg(feature = "unstable_boolean_config")]
5072 #[test]
5073 fn test_session_config_option_value_deserialize_boolean() {
5074 let json = json!({ "type": "boolean", "value": true });
5075 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5076 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5077 assert_eq!(val.as_bool(), Some(true));
5078 }
5079
5080 #[cfg(feature = "unstable_boolean_config")]
5081 #[test]
5082 fn test_session_config_option_value_deserialize_boolean_false() {
5083 let json = json!({ "type": "boolean", "value": false });
5084 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5085 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5086 assert_eq!(val.as_bool(), Some(false));
5087 }
5088
5089 #[cfg(feature = "unstable_boolean_config")]
5090 #[test]
5091 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5092 let json = json!({ "type": "text", "value": "freeform input" });
5094 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5095 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5096 }
5097
5098 #[cfg(feature = "unstable_boolean_config")]
5099 #[test]
5100 fn test_session_config_option_value_roundtrip_value_id() {
5101 let original = SessionConfigOptionValue::value_id("option-a");
5102 let json = serde_json::to_value(&original).unwrap();
5103 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5104 assert_eq!(original, roundtripped);
5105 }
5106
5107 #[cfg(feature = "unstable_boolean_config")]
5108 #[test]
5109 fn test_session_config_option_value_roundtrip_boolean() {
5110 let original = SessionConfigOptionValue::boolean(false);
5111 let json = serde_json::to_value(&original).unwrap();
5112 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5113 assert_eq!(original, roundtripped);
5114 }
5115
5116 #[cfg(feature = "unstable_boolean_config")]
5117 #[test]
5118 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5119 let json = json!({ "type": "boolean", "value": "not a bool" });
5121 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5122 assert!(result.is_ok());
5124 assert_eq!(
5125 result.unwrap().as_value_id().unwrap().to_string(),
5126 "not a bool"
5127 );
5128 }
5129
5130 #[cfg(feature = "unstable_boolean_config")]
5131 #[test]
5132 fn test_session_config_option_value_from_impls() {
5133 let from_str: SessionConfigOptionValue = "model-1".into();
5134 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5135
5136 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5137 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5138
5139 let from_bool: SessionConfigOptionValue = true.into();
5140 assert_eq!(from_bool.as_bool(), Some(true));
5141 }
5142
5143 #[cfg(feature = "unstable_boolean_config")]
5144 #[test]
5145 fn test_set_session_config_option_request_value_id() {
5146 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5147 let json = serde_json::to_value(&req).unwrap();
5148 assert_eq!(
5149 json,
5150 json!({
5151 "sessionId": "sess_1",
5152 "configId": "model",
5153 "value": "model-1"
5154 })
5155 );
5156 assert!(!json.as_object().unwrap().contains_key("type"));
5158 }
5159
5160 #[cfg(feature = "unstable_boolean_config")]
5161 #[test]
5162 fn test_set_session_config_option_request_boolean() {
5163 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5164 let json = serde_json::to_value(&req).unwrap();
5165 assert_eq!(
5166 json,
5167 json!({
5168 "sessionId": "sess_1",
5169 "configId": "brave_mode",
5170 "type": "boolean",
5171 "value": true
5172 })
5173 );
5174 }
5175
5176 #[cfg(feature = "unstable_boolean_config")]
5177 #[test]
5178 fn test_set_session_config_option_request_deserialize_no_type() {
5179 let json = json!({
5181 "sessionId": "sess_1",
5182 "configId": "model",
5183 "value": "model-1"
5184 });
5185 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5186 assert_eq!(req.session_id.to_string(), "sess_1");
5187 assert_eq!(req.config_id.to_string(), "model");
5188 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5189 }
5190
5191 #[cfg(feature = "unstable_boolean_config")]
5192 #[test]
5193 fn test_set_session_config_option_request_deserialize_boolean() {
5194 let json = json!({
5195 "sessionId": "sess_1",
5196 "configId": "brave_mode",
5197 "type": "boolean",
5198 "value": true
5199 });
5200 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5201 assert_eq!(req.value.as_bool(), Some(true));
5202 }
5203
5204 #[cfg(feature = "unstable_boolean_config")]
5205 #[test]
5206 fn test_set_session_config_option_request_roundtrip_value_id() {
5207 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5208 let json = serde_json::to_value(&original).unwrap();
5209 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5210 assert_eq!(original, roundtripped);
5211 }
5212
5213 #[cfg(feature = "unstable_boolean_config")]
5214 #[test]
5215 fn test_set_session_config_option_request_roundtrip_boolean() {
5216 let original = SetSessionConfigOptionRequest::new("s", "c", false);
5217 let json = serde_json::to_value(&original).unwrap();
5218 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5219 assert_eq!(original, roundtripped);
5220 }
5221
5222 #[cfg(feature = "unstable_boolean_config")]
5223 #[test]
5224 fn test_session_config_boolean_serialization() {
5225 let cfg = SessionConfigBoolean::new(true);
5226 let json = serde_json::to_value(&cfg).unwrap();
5227 assert_eq!(json, json!({ "currentValue": true }));
5228
5229 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
5230 assert!(deserialized.current_value);
5231 }
5232
5233 #[cfg(feature = "unstable_boolean_config")]
5234 #[test]
5235 fn test_session_config_option_boolean_variant() {
5236 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
5237 .description("Skip confirmation prompts");
5238 let json = serde_json::to_value(&opt).unwrap();
5239 assert_eq!(
5240 json,
5241 json!({
5242 "id": "brave_mode",
5243 "name": "Brave Mode",
5244 "description": "Skip confirmation prompts",
5245 "type": "boolean",
5246 "currentValue": false
5247 })
5248 );
5249
5250 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5251 assert_eq!(deserialized.id.to_string(), "brave_mode");
5252 assert_eq!(deserialized.name, "Brave Mode");
5253 match deserialized.kind {
5254 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
5255 _ => panic!("Expected Boolean kind"),
5256 }
5257 }
5258
5259 #[cfg(feature = "unstable_boolean_config")]
5260 #[test]
5261 fn test_session_config_option_select_still_works() {
5262 let opt = SessionConfigOption::select(
5264 "model",
5265 "Model",
5266 "model-1",
5267 vec![
5268 SessionConfigSelectOption::new("model-1", "Model 1"),
5269 SessionConfigSelectOption::new("model-2", "Model 2"),
5270 ],
5271 );
5272 let json = serde_json::to_value(&opt).unwrap();
5273 assert_eq!(json["type"], "select");
5274 assert_eq!(json["currentValue"], "model-1");
5275 assert_eq!(json["options"].as_array().unwrap().len(), 2);
5276
5277 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5278 match deserialized.kind {
5279 SessionConfigKind::Select(ref s) => {
5280 assert_eq!(s.current_value.to_string(), "model-1");
5281 }
5282 _ => panic!("Expected Select kind"),
5283 }
5284 }
5285}