1use std::{path::PathBuf, sync::Arc};
7
8#[cfg(any(feature = "unstable_auth_methods", feature = "unstable_llm_providers"))]
9use std::collections::HashMap;
10
11use derive_more::{Display, From};
12use schemars::JsonSchema;
13use serde::{Deserialize, Serialize};
14use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
15
16use crate::{
17 ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta,
18 ProtocolVersion, SessionId, SkipListener,
19};
20
21#[cfg(feature = "unstable_mcp_over_acp")]
22use super::mcp::{
23 MCP_MESSAGE_METHOD_NAME, MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
24};
25
26#[cfg(feature = "unstable_nes")]
27use crate::{
28 AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
29 DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
30 DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
31 StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
32};
33
34#[cfg(feature = "unstable_nes")]
35use crate::{
36 DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
37 DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
38 NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
39 NES_SUGGEST_METHOD_NAME,
40};
41
42#[serde_as]
50#[skip_serializing_none]
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
52#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
53#[serde(rename_all = "camelCase")]
54#[non_exhaustive]
55pub struct InitializeRequest {
56 pub protocol_version: ProtocolVersion,
58 #[serde(default)]
60 pub client_capabilities: ClientCapabilities,
61 #[serde_as(deserialize_as = "DefaultOnError")]
65 #[serde(default)]
66 pub client_info: Option<Implementation>,
67 #[serde(rename = "_meta")]
73 pub meta: Option<Meta>,
74}
75
76impl InitializeRequest {
77 #[must_use]
78 pub fn new(protocol_version: ProtocolVersion) -> Self {
79 Self {
80 protocol_version,
81 client_capabilities: ClientCapabilities::default(),
82 client_info: None,
83 meta: None,
84 }
85 }
86
87 #[must_use]
89 pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
90 self.client_capabilities = client_capabilities;
91 self
92 }
93
94 #[must_use]
96 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
97 self.client_info = client_info.into_option();
98 self
99 }
100
101 #[must_use]
107 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
108 self.meta = meta.into_option();
109 self
110 }
111}
112
113#[serde_as]
119#[skip_serializing_none]
120#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
121#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
122#[serde(rename_all = "camelCase")]
123#[non_exhaustive]
124pub struct InitializeResponse {
125 pub protocol_version: ProtocolVersion,
130 #[serde(default)]
132 pub agent_capabilities: AgentCapabilities,
133 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
135 #[serde(default)]
136 pub auth_methods: Vec<AuthMethod>,
137 #[serde_as(deserialize_as = "DefaultOnError")]
141 #[serde(default)]
142 pub agent_info: Option<Implementation>,
143 #[serde(rename = "_meta")]
149 pub meta: Option<Meta>,
150}
151
152impl InitializeResponse {
153 #[must_use]
154 pub fn new(protocol_version: ProtocolVersion) -> Self {
155 Self {
156 protocol_version,
157 agent_capabilities: AgentCapabilities::default(),
158 auth_methods: vec![],
159 agent_info: None,
160 meta: None,
161 }
162 }
163
164 #[must_use]
166 pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
167 self.agent_capabilities = agent_capabilities;
168 self
169 }
170
171 #[must_use]
173 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
174 self.auth_methods = auth_methods;
175 self
176 }
177
178 #[must_use]
180 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
181 self.agent_info = agent_info.into_option();
182 self
183 }
184
185 #[must_use]
191 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
192 self.meta = meta.into_option();
193 self
194 }
195}
196
197#[skip_serializing_none]
201#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
202#[serde(rename_all = "camelCase")]
203#[non_exhaustive]
204pub struct Implementation {
205 pub name: String,
208 pub title: Option<String>,
213 pub version: String,
216 #[serde(rename = "_meta")]
222 pub meta: Option<Meta>,
223}
224
225impl Implementation {
226 #[must_use]
227 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
228 Self {
229 name: name.into(),
230 title: None,
231 version: version.into(),
232 meta: None,
233 }
234 }
235
236 #[must_use]
241 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
242 self.title = title.into_option();
243 self
244 }
245
246 #[must_use]
252 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
253 self.meta = meta.into_option();
254 self
255 }
256}
257
258#[skip_serializing_none]
264#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
265#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
266#[serde(rename_all = "camelCase")]
267#[non_exhaustive]
268pub struct AuthenticateRequest {
269 pub method_id: AuthMethodId,
272 #[serde(rename = "_meta")]
278 pub meta: Option<Meta>,
279}
280
281impl AuthenticateRequest {
282 #[must_use]
283 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
284 Self {
285 method_id: method_id.into(),
286 meta: None,
287 }
288 }
289
290 #[must_use]
296 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
297 self.meta = meta.into_option();
298 self
299 }
300}
301
302#[skip_serializing_none]
304#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
305#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
306#[serde(rename_all = "camelCase")]
307#[non_exhaustive]
308pub struct AuthenticateResponse {
309 #[serde(rename = "_meta")]
315 pub meta: Option<Meta>,
316}
317
318impl AuthenticateResponse {
319 #[must_use]
320 pub fn new() -> Self {
321 Self::default()
322 }
323
324 #[must_use]
330 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
331 self.meta = meta.into_option();
332 self
333 }
334}
335
336#[cfg(feature = "unstable_logout")]
346#[skip_serializing_none]
347#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
348#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
349#[serde(rename_all = "camelCase")]
350#[non_exhaustive]
351pub struct LogoutRequest {
352 #[serde(rename = "_meta")]
358 pub meta: Option<Meta>,
359}
360
361#[cfg(feature = "unstable_logout")]
362impl LogoutRequest {
363 #[must_use]
364 pub fn new() -> Self {
365 Self::default()
366 }
367
368 #[must_use]
374 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
375 self.meta = meta.into_option();
376 self
377 }
378}
379
380#[cfg(feature = "unstable_logout")]
386#[skip_serializing_none]
387#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
388#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
389#[serde(rename_all = "camelCase")]
390#[non_exhaustive]
391pub struct LogoutResponse {
392 #[serde(rename = "_meta")]
398 pub meta: Option<Meta>,
399}
400
401#[cfg(feature = "unstable_logout")]
402impl LogoutResponse {
403 #[must_use]
404 pub fn new() -> Self {
405 Self::default()
406 }
407
408 #[must_use]
414 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
415 self.meta = meta.into_option();
416 self
417 }
418}
419
420#[cfg(feature = "unstable_logout")]
426#[serde_as]
427#[skip_serializing_none]
428#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
429#[serde(rename_all = "camelCase")]
430#[non_exhaustive]
431pub struct AgentAuthCapabilities {
432 #[serde_as(deserialize_as = "DefaultOnError")]
436 #[serde(default)]
437 pub logout: Option<LogoutCapabilities>,
438 #[serde(rename = "_meta")]
444 pub meta: Option<Meta>,
445}
446
447#[cfg(feature = "unstable_logout")]
448impl AgentAuthCapabilities {
449 #[must_use]
450 pub fn new() -> Self {
451 Self::default()
452 }
453
454 #[must_use]
456 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
457 self.logout = logout.into_option();
458 self
459 }
460
461 #[must_use]
467 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
468 self.meta = meta.into_option();
469 self
470 }
471}
472
473#[cfg(feature = "unstable_logout")]
481#[skip_serializing_none]
482#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
483#[non_exhaustive]
484pub struct LogoutCapabilities {
485 #[serde(rename = "_meta")]
491 pub meta: Option<Meta>,
492}
493
494#[cfg(feature = "unstable_logout")]
495impl LogoutCapabilities {
496 #[must_use]
497 pub fn new() -> Self {
498 Self::default()
499 }
500
501 #[must_use]
507 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
508 self.meta = meta.into_option();
509 self
510 }
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
514#[serde(transparent)]
515#[from(Arc<str>, String, &'static str)]
516#[non_exhaustive]
517pub struct AuthMethodId(pub Arc<str>);
518
519impl AuthMethodId {
520 #[must_use]
521 pub fn new(id: impl Into<Arc<str>>) -> Self {
522 Self(id.into())
523 }
524}
525
526#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
531#[serde(tag = "type", rename_all = "snake_case")]
532#[non_exhaustive]
533pub enum AuthMethod {
534 #[cfg(feature = "unstable_auth_methods")]
540 EnvVar(AuthMethodEnvVar),
541 #[cfg(feature = "unstable_auth_methods")]
547 Terminal(AuthMethodTerminal),
548 #[serde(untagged)]
552 Agent(AuthMethodAgent),
553}
554
555impl AuthMethod {
556 #[must_use]
558 pub fn id(&self) -> &AuthMethodId {
559 match self {
560 Self::Agent(a) => &a.id,
561 #[cfg(feature = "unstable_auth_methods")]
562 Self::EnvVar(e) => &e.id,
563 #[cfg(feature = "unstable_auth_methods")]
564 Self::Terminal(t) => &t.id,
565 }
566 }
567
568 #[must_use]
570 pub fn name(&self) -> &str {
571 match self {
572 Self::Agent(a) => &a.name,
573 #[cfg(feature = "unstable_auth_methods")]
574 Self::EnvVar(e) => &e.name,
575 #[cfg(feature = "unstable_auth_methods")]
576 Self::Terminal(t) => &t.name,
577 }
578 }
579
580 #[must_use]
582 pub fn description(&self) -> Option<&str> {
583 match self {
584 Self::Agent(a) => a.description.as_deref(),
585 #[cfg(feature = "unstable_auth_methods")]
586 Self::EnvVar(e) => e.description.as_deref(),
587 #[cfg(feature = "unstable_auth_methods")]
588 Self::Terminal(t) => t.description.as_deref(),
589 }
590 }
591
592 #[must_use]
598 pub fn meta(&self) -> Option<&Meta> {
599 match self {
600 Self::Agent(a) => a.meta.as_ref(),
601 #[cfg(feature = "unstable_auth_methods")]
602 Self::EnvVar(e) => e.meta.as_ref(),
603 #[cfg(feature = "unstable_auth_methods")]
604 Self::Terminal(t) => t.meta.as_ref(),
605 }
606 }
607}
608
609#[skip_serializing_none]
613#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
614#[serde(rename_all = "camelCase")]
615#[non_exhaustive]
616pub struct AuthMethodAgent {
617 pub id: AuthMethodId,
619 pub name: String,
621 pub description: Option<String>,
623 #[serde(rename = "_meta")]
629 pub meta: Option<Meta>,
630}
631
632impl AuthMethodAgent {
633 #[must_use]
634 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
635 Self {
636 id: id.into(),
637 name: name.into(),
638 description: None,
639 meta: None,
640 }
641 }
642
643 #[must_use]
645 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
646 self.description = description.into_option();
647 self
648 }
649
650 #[must_use]
656 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
657 self.meta = meta.into_option();
658 self
659 }
660}
661
662#[cfg(feature = "unstable_auth_methods")]
670#[skip_serializing_none]
671#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
672#[serde(rename_all = "camelCase")]
673#[non_exhaustive]
674pub struct AuthMethodEnvVar {
675 pub id: AuthMethodId,
677 pub name: String,
679 pub description: Option<String>,
681 pub vars: Vec<AuthEnvVar>,
683 pub link: Option<String>,
685 #[serde(rename = "_meta")]
691 pub meta: Option<Meta>,
692}
693
694#[cfg(feature = "unstable_auth_methods")]
695impl AuthMethodEnvVar {
696 #[must_use]
697 pub fn new(
698 id: impl Into<AuthMethodId>,
699 name: impl Into<String>,
700 vars: Vec<AuthEnvVar>,
701 ) -> Self {
702 Self {
703 id: id.into(),
704 name: name.into(),
705 description: None,
706 vars,
707 link: None,
708 meta: None,
709 }
710 }
711
712 #[must_use]
714 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
715 self.link = link.into_option();
716 self
717 }
718
719 #[must_use]
721 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
722 self.description = description.into_option();
723 self
724 }
725
726 #[must_use]
732 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
733 self.meta = meta.into_option();
734 self
735 }
736}
737
738#[cfg(feature = "unstable_auth_methods")]
744#[skip_serializing_none]
745#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
746#[serde(rename_all = "camelCase")]
747#[non_exhaustive]
748pub struct AuthEnvVar {
749 pub name: String,
751 pub label: Option<String>,
753 #[serde(default = "default_true", skip_serializing_if = "is_true")]
758 #[schemars(extend("default" = true))]
759 pub secret: bool,
760 #[serde(default, skip_serializing_if = "is_false")]
764 #[schemars(extend("default" = false))]
765 pub optional: bool,
766 #[serde(rename = "_meta")]
772 pub meta: Option<Meta>,
773}
774
775#[cfg(feature = "unstable_auth_methods")]
776fn default_true() -> bool {
777 true
778}
779
780#[cfg(feature = "unstable_auth_methods")]
781#[expect(clippy::trivially_copy_pass_by_ref)]
782fn is_true(v: &bool) -> bool {
783 *v
784}
785
786#[cfg(feature = "unstable_auth_methods")]
787#[expect(clippy::trivially_copy_pass_by_ref)]
788fn is_false(v: &bool) -> bool {
789 !*v
790}
791
792#[cfg(feature = "unstable_auth_methods")]
793impl AuthEnvVar {
794 #[must_use]
796 pub fn new(name: impl Into<String>) -> Self {
797 Self {
798 name: name.into(),
799 label: None,
800 secret: true,
801 optional: false,
802 meta: None,
803 }
804 }
805
806 #[must_use]
808 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
809 self.label = label.into_option();
810 self
811 }
812
813 #[must_use]
816 pub fn secret(mut self, secret: bool) -> Self {
817 self.secret = secret;
818 self
819 }
820
821 #[must_use]
823 pub fn optional(mut self, optional: bool) -> Self {
824 self.optional = optional;
825 self
826 }
827
828 #[must_use]
834 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
835 self.meta = meta.into_option();
836 self
837 }
838}
839
840#[cfg(feature = "unstable_auth_methods")]
848#[skip_serializing_none]
849#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
850#[serde(rename_all = "camelCase")]
851#[non_exhaustive]
852pub struct AuthMethodTerminal {
853 pub id: AuthMethodId,
855 pub name: String,
857 pub description: Option<String>,
859 #[serde(default, skip_serializing_if = "Vec::is_empty")]
861 pub args: Vec<String>,
862 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
864 pub env: HashMap<String, String>,
865 #[serde(rename = "_meta")]
871 pub meta: Option<Meta>,
872}
873
874#[cfg(feature = "unstable_auth_methods")]
875impl AuthMethodTerminal {
876 #[must_use]
877 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
878 Self {
879 id: id.into(),
880 name: name.into(),
881 description: None,
882 args: Vec::new(),
883 env: HashMap::new(),
884 meta: None,
885 }
886 }
887
888 #[must_use]
890 pub fn args(mut self, args: Vec<String>) -> Self {
891 self.args = args;
892 self
893 }
894
895 #[must_use]
897 pub fn env(mut self, env: HashMap<String, String>) -> Self {
898 self.env = env;
899 self
900 }
901
902 #[must_use]
904 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
905 self.description = description.into_option();
906 self
907 }
908
909 #[must_use]
915 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
916 self.meta = meta.into_option();
917 self
918 }
919}
920
921#[skip_serializing_none]
927#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
928#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
929#[serde(rename_all = "camelCase")]
930#[non_exhaustive]
931pub struct NewSessionRequest {
932 pub cwd: PathBuf,
934 #[cfg(feature = "unstable_session_additional_directories")]
944 #[serde(default, skip_serializing_if = "Vec::is_empty")]
945 pub additional_directories: Vec<PathBuf>,
946 pub mcp_servers: Vec<McpServer>,
948 #[serde(rename = "_meta")]
954 pub meta: Option<Meta>,
955}
956
957impl NewSessionRequest {
958 #[must_use]
959 pub fn new(cwd: impl Into<PathBuf>) -> Self {
960 Self {
961 cwd: cwd.into(),
962 #[cfg(feature = "unstable_session_additional_directories")]
963 additional_directories: vec![],
964 mcp_servers: vec![],
965 meta: None,
966 }
967 }
968
969 #[cfg(feature = "unstable_session_additional_directories")]
975 #[must_use]
976 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
977 self.additional_directories = additional_directories;
978 self
979 }
980
981 #[must_use]
983 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
984 self.mcp_servers = mcp_servers;
985 self
986 }
987
988 #[must_use]
994 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
995 self.meta = meta.into_option();
996 self
997 }
998}
999
1000#[serde_as]
1004#[skip_serializing_none]
1005#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1006#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1007#[serde(rename_all = "camelCase")]
1008#[non_exhaustive]
1009pub struct NewSessionResponse {
1010 pub session_id: SessionId,
1014 #[serde_as(deserialize_as = "DefaultOnError")]
1018 #[serde(default)]
1019 pub modes: Option<SessionModeState>,
1020 #[cfg(feature = "unstable_session_model")]
1026 #[serde_as(deserialize_as = "DefaultOnError")]
1027 #[serde(default)]
1028 pub models: Option<SessionModelState>,
1029 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1031 #[serde(default)]
1032 pub config_options: Option<Vec<SessionConfigOption>>,
1033 #[serde(rename = "_meta")]
1039 pub meta: Option<Meta>,
1040}
1041
1042impl NewSessionResponse {
1043 #[must_use]
1044 pub fn new(session_id: impl Into<SessionId>) -> Self {
1045 Self {
1046 session_id: session_id.into(),
1047 modes: None,
1048 #[cfg(feature = "unstable_session_model")]
1049 models: None,
1050 config_options: None,
1051 meta: None,
1052 }
1053 }
1054
1055 #[must_use]
1059 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1060 self.modes = modes.into_option();
1061 self
1062 }
1063
1064 #[cfg(feature = "unstable_session_model")]
1070 #[must_use]
1071 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1072 self.models = models.into_option();
1073 self
1074 }
1075
1076 #[must_use]
1078 pub fn config_options(
1079 mut self,
1080 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1081 ) -> Self {
1082 self.config_options = config_options.into_option();
1083 self
1084 }
1085
1086 #[must_use]
1092 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1093 self.meta = meta.into_option();
1094 self
1095 }
1096}
1097
1098#[skip_serializing_none]
1106#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1107#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1108#[serde(rename_all = "camelCase")]
1109#[non_exhaustive]
1110pub struct LoadSessionRequest {
1111 pub mcp_servers: Vec<McpServer>,
1113 pub cwd: PathBuf,
1115 #[cfg(feature = "unstable_session_additional_directories")]
1125 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1126 pub additional_directories: Vec<PathBuf>,
1127 pub session_id: SessionId,
1129 #[serde(rename = "_meta")]
1135 pub meta: Option<Meta>,
1136}
1137
1138impl LoadSessionRequest {
1139 #[must_use]
1140 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1141 Self {
1142 mcp_servers: vec![],
1143 cwd: cwd.into(),
1144 #[cfg(feature = "unstable_session_additional_directories")]
1145 additional_directories: vec![],
1146 session_id: session_id.into(),
1147 meta: None,
1148 }
1149 }
1150
1151 #[cfg(feature = "unstable_session_additional_directories")]
1157 #[must_use]
1158 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1159 self.additional_directories = additional_directories;
1160 self
1161 }
1162
1163 #[must_use]
1165 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1166 self.mcp_servers = mcp_servers;
1167 self
1168 }
1169
1170 #[must_use]
1176 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1177 self.meta = meta.into_option();
1178 self
1179 }
1180}
1181
1182#[serde_as]
1184#[skip_serializing_none]
1185#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1186#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1187#[serde(rename_all = "camelCase")]
1188#[non_exhaustive]
1189pub struct LoadSessionResponse {
1190 #[serde_as(deserialize_as = "DefaultOnError")]
1194 #[serde(default)]
1195 pub modes: Option<SessionModeState>,
1196 #[cfg(feature = "unstable_session_model")]
1202 #[serde_as(deserialize_as = "DefaultOnError")]
1203 #[serde(default)]
1204 pub models: Option<SessionModelState>,
1205 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1207 #[serde(default)]
1208 pub config_options: Option<Vec<SessionConfigOption>>,
1209 #[serde(rename = "_meta")]
1215 pub meta: Option<Meta>,
1216}
1217
1218impl LoadSessionResponse {
1219 #[must_use]
1220 pub fn new() -> Self {
1221 Self::default()
1222 }
1223
1224 #[must_use]
1228 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1229 self.modes = modes.into_option();
1230 self
1231 }
1232
1233 #[cfg(feature = "unstable_session_model")]
1239 #[must_use]
1240 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1241 self.models = models.into_option();
1242 self
1243 }
1244
1245 #[must_use]
1247 pub fn config_options(
1248 mut self,
1249 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1250 ) -> Self {
1251 self.config_options = config_options.into_option();
1252 self
1253 }
1254
1255 #[must_use]
1261 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1262 self.meta = meta.into_option();
1263 self
1264 }
1265}
1266
1267#[cfg(feature = "unstable_session_fork")]
1280#[skip_serializing_none]
1281#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1282#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1283#[serde(rename_all = "camelCase")]
1284#[non_exhaustive]
1285pub struct ForkSessionRequest {
1286 pub session_id: SessionId,
1288 pub cwd: PathBuf,
1290 #[cfg(feature = "unstable_session_additional_directories")]
1300 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1301 pub additional_directories: Vec<PathBuf>,
1302 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1304 pub mcp_servers: Vec<McpServer>,
1305 #[serde(rename = "_meta")]
1311 pub meta: Option<Meta>,
1312}
1313
1314#[cfg(feature = "unstable_session_fork")]
1315impl ForkSessionRequest {
1316 #[must_use]
1317 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1318 Self {
1319 session_id: session_id.into(),
1320 cwd: cwd.into(),
1321 #[cfg(feature = "unstable_session_additional_directories")]
1322 additional_directories: vec![],
1323 mcp_servers: vec![],
1324 meta: None,
1325 }
1326 }
1327
1328 #[cfg(feature = "unstable_session_additional_directories")]
1334 #[must_use]
1335 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1336 self.additional_directories = additional_directories;
1337 self
1338 }
1339
1340 #[must_use]
1342 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1343 self.mcp_servers = mcp_servers;
1344 self
1345 }
1346
1347 #[must_use]
1353 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1354 self.meta = meta.into_option();
1355 self
1356 }
1357}
1358
1359#[cfg(feature = "unstable_session_fork")]
1365#[serde_as]
1366#[skip_serializing_none]
1367#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1368#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1369#[serde(rename_all = "camelCase")]
1370#[non_exhaustive]
1371pub struct ForkSessionResponse {
1372 pub session_id: SessionId,
1374 #[serde_as(deserialize_as = "DefaultOnError")]
1378 #[serde(default)]
1379 pub modes: Option<SessionModeState>,
1380 #[cfg(feature = "unstable_session_model")]
1386 #[serde_as(deserialize_as = "DefaultOnError")]
1387 #[serde(default)]
1388 pub models: Option<SessionModelState>,
1389 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1391 #[serde(default)]
1392 pub config_options: Option<Vec<SessionConfigOption>>,
1393 #[serde(rename = "_meta")]
1399 pub meta: Option<Meta>,
1400}
1401
1402#[cfg(feature = "unstable_session_fork")]
1403impl ForkSessionResponse {
1404 #[must_use]
1405 pub fn new(session_id: impl Into<SessionId>) -> Self {
1406 Self {
1407 session_id: session_id.into(),
1408 modes: None,
1409 #[cfg(feature = "unstable_session_model")]
1410 models: None,
1411 config_options: None,
1412 meta: None,
1413 }
1414 }
1415
1416 #[must_use]
1420 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1421 self.modes = modes.into_option();
1422 self
1423 }
1424
1425 #[cfg(feature = "unstable_session_model")]
1431 #[must_use]
1432 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1433 self.models = models.into_option();
1434 self
1435 }
1436
1437 #[must_use]
1439 pub fn config_options(
1440 mut self,
1441 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1442 ) -> Self {
1443 self.config_options = config_options.into_option();
1444 self
1445 }
1446
1447 #[must_use]
1453 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1454 self.meta = meta.into_option();
1455 self
1456 }
1457}
1458
1459#[skip_serializing_none]
1468#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1469#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1470#[serde(rename_all = "camelCase")]
1471#[non_exhaustive]
1472pub struct ResumeSessionRequest {
1473 pub session_id: SessionId,
1475 pub cwd: PathBuf,
1477 #[cfg(feature = "unstable_session_additional_directories")]
1487 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1488 pub additional_directories: Vec<PathBuf>,
1489 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1491 pub mcp_servers: Vec<McpServer>,
1492 #[serde(rename = "_meta")]
1498 pub meta: Option<Meta>,
1499}
1500
1501impl ResumeSessionRequest {
1502 #[must_use]
1503 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1504 Self {
1505 session_id: session_id.into(),
1506 cwd: cwd.into(),
1507 #[cfg(feature = "unstable_session_additional_directories")]
1508 additional_directories: vec![],
1509 mcp_servers: vec![],
1510 meta: None,
1511 }
1512 }
1513
1514 #[cfg(feature = "unstable_session_additional_directories")]
1520 #[must_use]
1521 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1522 self.additional_directories = additional_directories;
1523 self
1524 }
1525
1526 #[must_use]
1528 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1529 self.mcp_servers = mcp_servers;
1530 self
1531 }
1532
1533 #[must_use]
1539 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1540 self.meta = meta.into_option();
1541 self
1542 }
1543}
1544
1545#[serde_as]
1547#[skip_serializing_none]
1548#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1549#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1550#[serde(rename_all = "camelCase")]
1551#[non_exhaustive]
1552pub struct ResumeSessionResponse {
1553 #[serde_as(deserialize_as = "DefaultOnError")]
1557 #[serde(default)]
1558 pub modes: Option<SessionModeState>,
1559 #[cfg(feature = "unstable_session_model")]
1565 #[serde_as(deserialize_as = "DefaultOnError")]
1566 #[serde(default)]
1567 pub models: Option<SessionModelState>,
1568 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1570 #[serde(default)]
1571 pub config_options: Option<Vec<SessionConfigOption>>,
1572 #[serde(rename = "_meta")]
1578 pub meta: Option<Meta>,
1579}
1580
1581impl ResumeSessionResponse {
1582 #[must_use]
1583 pub fn new() -> Self {
1584 Self::default()
1585 }
1586
1587 #[must_use]
1591 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1592 self.modes = modes.into_option();
1593 self
1594 }
1595
1596 #[cfg(feature = "unstable_session_model")]
1602 #[must_use]
1603 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1604 self.models = models.into_option();
1605 self
1606 }
1607
1608 #[must_use]
1610 pub fn config_options(
1611 mut self,
1612 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1613 ) -> Self {
1614 self.config_options = config_options.into_option();
1615 self
1616 }
1617
1618 #[must_use]
1624 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1625 self.meta = meta.into_option();
1626 self
1627 }
1628}
1629
1630#[skip_serializing_none]
1640#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1641#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1642#[serde(rename_all = "camelCase")]
1643#[non_exhaustive]
1644pub struct CloseSessionRequest {
1645 pub session_id: SessionId,
1647 #[serde(rename = "_meta")]
1653 pub meta: Option<Meta>,
1654}
1655
1656impl CloseSessionRequest {
1657 #[must_use]
1658 pub fn new(session_id: impl Into<SessionId>) -> Self {
1659 Self {
1660 session_id: session_id.into(),
1661 meta: None,
1662 }
1663 }
1664
1665 #[must_use]
1671 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1672 self.meta = meta.into_option();
1673 self
1674 }
1675}
1676
1677#[skip_serializing_none]
1679#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1680#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1681#[serde(rename_all = "camelCase")]
1682#[non_exhaustive]
1683pub struct CloseSessionResponse {
1684 #[serde(rename = "_meta")]
1690 pub meta: Option<Meta>,
1691}
1692
1693impl CloseSessionResponse {
1694 #[must_use]
1695 pub fn new() -> Self {
1696 Self::default()
1697 }
1698
1699 #[must_use]
1705 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1706 self.meta = meta.into_option();
1707 self
1708 }
1709}
1710
1711#[skip_serializing_none]
1717#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1718#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1719#[serde(rename_all = "camelCase")]
1720#[non_exhaustive]
1721pub struct ListSessionsRequest {
1722 pub cwd: Option<PathBuf>,
1724 #[cfg(feature = "unstable_session_additional_directories")]
1733 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1734 pub additional_directories: Vec<PathBuf>,
1735 pub cursor: Option<String>,
1737 #[serde(rename = "_meta")]
1743 pub meta: Option<Meta>,
1744}
1745
1746impl ListSessionsRequest {
1747 #[must_use]
1748 pub fn new() -> Self {
1749 Self::default()
1750 }
1751
1752 #[must_use]
1754 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1755 self.cwd = cwd.into_option();
1756 self
1757 }
1758
1759 #[cfg(feature = "unstable_session_additional_directories")]
1765 #[must_use]
1766 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1767 self.additional_directories = additional_directories;
1768 self
1769 }
1770
1771 #[must_use]
1773 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1774 self.cursor = cursor.into_option();
1775 self
1776 }
1777
1778 #[must_use]
1784 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1785 self.meta = meta.into_option();
1786 self
1787 }
1788}
1789
1790#[serde_as]
1792#[skip_serializing_none]
1793#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1794#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1795#[serde(rename_all = "camelCase")]
1796#[non_exhaustive]
1797pub struct ListSessionsResponse {
1798 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1800 pub sessions: Vec<SessionInfo>,
1801 pub next_cursor: Option<String>,
1804 #[serde(rename = "_meta")]
1810 pub meta: Option<Meta>,
1811}
1812
1813impl ListSessionsResponse {
1814 #[must_use]
1815 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1816 Self {
1817 sessions,
1818 next_cursor: None,
1819 meta: None,
1820 }
1821 }
1822
1823 #[must_use]
1824 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1825 self.next_cursor = next_cursor.into_option();
1826 self
1827 }
1828
1829 #[must_use]
1835 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1836 self.meta = meta.into_option();
1837 self
1838 }
1839}
1840
1841#[serde_as]
1843#[skip_serializing_none]
1844#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1845#[serde(rename_all = "camelCase")]
1846#[non_exhaustive]
1847pub struct SessionInfo {
1848 pub session_id: SessionId,
1850 pub cwd: PathBuf,
1852 #[cfg(feature = "unstable_session_additional_directories")]
1860 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1861 pub additional_directories: Vec<PathBuf>,
1862
1863 #[serde_as(deserialize_as = "DefaultOnError")]
1865 #[serde(default)]
1866 pub title: Option<String>,
1867 #[serde_as(deserialize_as = "DefaultOnError")]
1869 #[serde(default)]
1870 pub updated_at: Option<String>,
1871 #[serde(rename = "_meta")]
1877 pub meta: Option<Meta>,
1878}
1879
1880impl SessionInfo {
1881 #[must_use]
1882 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1883 Self {
1884 session_id: session_id.into(),
1885 cwd: cwd.into(),
1886 #[cfg(feature = "unstable_session_additional_directories")]
1887 additional_directories: vec![],
1888 title: None,
1889 updated_at: None,
1890 meta: None,
1891 }
1892 }
1893
1894 #[cfg(feature = "unstable_session_additional_directories")]
1900 #[must_use]
1901 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1902 self.additional_directories = additional_directories;
1903 self
1904 }
1905
1906 #[must_use]
1908 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1909 self.title = title.into_option();
1910 self
1911 }
1912
1913 #[must_use]
1915 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1916 self.updated_at = updated_at.into_option();
1917 self
1918 }
1919
1920 #[must_use]
1926 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1927 self.meta = meta.into_option();
1928 self
1929 }
1930}
1931
1932#[serde_as]
1936#[skip_serializing_none]
1937#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1938#[serde(rename_all = "camelCase")]
1939#[non_exhaustive]
1940pub struct SessionModeState {
1941 pub current_mode_id: SessionModeId,
1943 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1945 pub available_modes: Vec<SessionMode>,
1946 #[serde(rename = "_meta")]
1952 pub meta: Option<Meta>,
1953}
1954
1955impl SessionModeState {
1956 #[must_use]
1957 pub fn new(
1958 current_mode_id: impl Into<SessionModeId>,
1959 available_modes: Vec<SessionMode>,
1960 ) -> Self {
1961 Self {
1962 current_mode_id: current_mode_id.into(),
1963 available_modes,
1964 meta: None,
1965 }
1966 }
1967
1968 #[must_use]
1974 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1975 self.meta = meta.into_option();
1976 self
1977 }
1978}
1979
1980#[skip_serializing_none]
1984#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1985#[serde(rename_all = "camelCase")]
1986#[non_exhaustive]
1987pub struct SessionMode {
1988 pub id: SessionModeId,
1989 pub name: String,
1990 #[serde(default)]
1991 pub description: Option<String>,
1992 #[serde(rename = "_meta")]
1998 pub meta: Option<Meta>,
1999}
2000
2001impl SessionMode {
2002 #[must_use]
2003 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
2004 Self {
2005 id: id.into(),
2006 name: name.into(),
2007 description: None,
2008 meta: None,
2009 }
2010 }
2011
2012 #[must_use]
2013 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2014 self.description = description.into_option();
2015 self
2016 }
2017
2018 #[must_use]
2024 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2025 self.meta = meta.into_option();
2026 self
2027 }
2028}
2029
2030#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2032#[serde(transparent)]
2033#[from(Arc<str>, String, &'static str)]
2034#[non_exhaustive]
2035pub struct SessionModeId(pub Arc<str>);
2036
2037impl SessionModeId {
2038 #[must_use]
2039 pub fn new(id: impl Into<Arc<str>>) -> Self {
2040 Self(id.into())
2041 }
2042}
2043
2044#[skip_serializing_none]
2046#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2047#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2048#[serde(rename_all = "camelCase")]
2049#[non_exhaustive]
2050pub struct SetSessionModeRequest {
2051 pub session_id: SessionId,
2053 pub mode_id: SessionModeId,
2055 #[serde(rename = "_meta")]
2061 pub meta: Option<Meta>,
2062}
2063
2064impl SetSessionModeRequest {
2065 #[must_use]
2066 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
2067 Self {
2068 session_id: session_id.into(),
2069 mode_id: mode_id.into(),
2070 meta: None,
2071 }
2072 }
2073
2074 #[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#[skip_serializing_none]
2083#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2084#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2085#[serde(rename_all = "camelCase")]
2086#[non_exhaustive]
2087pub struct SetSessionModeResponse {
2088 #[serde(rename = "_meta")]
2094 pub meta: Option<Meta>,
2095}
2096
2097impl SetSessionModeResponse {
2098 #[must_use]
2099 pub fn new() -> Self {
2100 Self::default()
2101 }
2102
2103 #[must_use]
2109 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2110 self.meta = meta.into_option();
2111 self
2112 }
2113}
2114
2115#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2119#[serde(transparent)]
2120#[from(Arc<str>, String, &'static str)]
2121#[non_exhaustive]
2122pub struct SessionConfigId(pub Arc<str>);
2123
2124impl SessionConfigId {
2125 #[must_use]
2126 pub fn new(id: impl Into<Arc<str>>) -> Self {
2127 Self(id.into())
2128 }
2129}
2130
2131#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2133#[serde(transparent)]
2134#[from(Arc<str>, String, &'static str)]
2135#[non_exhaustive]
2136pub struct SessionConfigValueId(pub Arc<str>);
2137
2138impl SessionConfigValueId {
2139 #[must_use]
2140 pub fn new(id: impl Into<Arc<str>>) -> Self {
2141 Self(id.into())
2142 }
2143}
2144
2145#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2147#[serde(transparent)]
2148#[from(Arc<str>, String, &'static str)]
2149#[non_exhaustive]
2150pub struct SessionConfigGroupId(pub Arc<str>);
2151
2152impl SessionConfigGroupId {
2153 #[must_use]
2154 pub fn new(id: impl Into<Arc<str>>) -> Self {
2155 Self(id.into())
2156 }
2157}
2158
2159#[skip_serializing_none]
2161#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2162#[serde(rename_all = "camelCase")]
2163#[non_exhaustive]
2164pub struct SessionConfigSelectOption {
2165 pub value: SessionConfigValueId,
2167 pub name: String,
2169 #[serde(default)]
2171 pub description: Option<String>,
2172 #[serde(rename = "_meta")]
2178 pub meta: Option<Meta>,
2179}
2180
2181impl SessionConfigSelectOption {
2182 #[must_use]
2183 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2184 Self {
2185 value: value.into(),
2186 name: name.into(),
2187 description: None,
2188 meta: None,
2189 }
2190 }
2191
2192 #[must_use]
2193 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2194 self.description = description.into_option();
2195 self
2196 }
2197
2198 #[must_use]
2204 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2205 self.meta = meta.into_option();
2206 self
2207 }
2208}
2209
2210#[skip_serializing_none]
2212#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2213#[serde(rename_all = "camelCase")]
2214#[non_exhaustive]
2215pub struct SessionConfigSelectGroup {
2216 pub group: SessionConfigGroupId,
2218 pub name: String,
2220 pub options: Vec<SessionConfigSelectOption>,
2222 #[serde(rename = "_meta")]
2228 pub meta: Option<Meta>,
2229}
2230
2231impl SessionConfigSelectGroup {
2232 #[must_use]
2233 pub fn new(
2234 group: impl Into<SessionConfigGroupId>,
2235 name: impl Into<String>,
2236 options: Vec<SessionConfigSelectOption>,
2237 ) -> Self {
2238 Self {
2239 group: group.into(),
2240 name: name.into(),
2241 options,
2242 meta: None,
2243 }
2244 }
2245
2246 #[must_use]
2252 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2253 self.meta = meta.into_option();
2254 self
2255 }
2256}
2257
2258#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2260#[serde(untagged)]
2261#[non_exhaustive]
2262pub enum SessionConfigSelectOptions {
2263 Ungrouped(Vec<SessionConfigSelectOption>),
2265 Grouped(Vec<SessionConfigSelectGroup>),
2267}
2268
2269impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2270 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2271 SessionConfigSelectOptions::Ungrouped(options)
2272 }
2273}
2274
2275impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2276 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2277 SessionConfigSelectOptions::Grouped(groups)
2278 }
2279}
2280
2281#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2283#[serde(rename_all = "camelCase")]
2284#[non_exhaustive]
2285pub struct SessionConfigSelect {
2286 pub current_value: SessionConfigValueId,
2288 pub options: SessionConfigSelectOptions,
2290}
2291
2292impl SessionConfigSelect {
2293 #[must_use]
2294 pub fn new(
2295 current_value: impl Into<SessionConfigValueId>,
2296 options: impl Into<SessionConfigSelectOptions>,
2297 ) -> Self {
2298 Self {
2299 current_value: current_value.into(),
2300 options: options.into(),
2301 }
2302 }
2303}
2304
2305#[cfg(feature = "unstable_boolean_config")]
2311#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2312#[serde(rename_all = "camelCase")]
2313#[non_exhaustive]
2314pub struct SessionConfigBoolean {
2315 pub current_value: bool,
2317}
2318
2319#[cfg(feature = "unstable_boolean_config")]
2320impl SessionConfigBoolean {
2321 #[must_use]
2322 pub fn new(current_value: bool) -> Self {
2323 Self { current_value }
2324 }
2325}
2326
2327#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2337#[serde(rename_all = "snake_case")]
2338#[non_exhaustive]
2339pub enum SessionConfigOptionCategory {
2340 Mode,
2342 Model,
2344 ThoughtLevel,
2346 #[serde(untagged)]
2348 Other(String),
2349}
2350
2351#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2353#[serde(tag = "type", rename_all = "snake_case")]
2354#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2355#[non_exhaustive]
2356pub enum SessionConfigKind {
2357 Select(SessionConfigSelect),
2359 #[cfg(feature = "unstable_boolean_config")]
2365 Boolean(SessionConfigBoolean),
2366}
2367
2368#[serde_as]
2370#[skip_serializing_none]
2371#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2372#[serde(rename_all = "camelCase")]
2373#[non_exhaustive]
2374pub struct SessionConfigOption {
2375 pub id: SessionConfigId,
2377 pub name: String,
2379 #[serde(default)]
2381 pub description: Option<String>,
2382 #[serde_as(deserialize_as = "DefaultOnError")]
2384 #[serde(default)]
2385 pub category: Option<SessionConfigOptionCategory>,
2386 #[serde(flatten)]
2388 pub kind: SessionConfigKind,
2389 #[serde(rename = "_meta")]
2395 pub meta: Option<Meta>,
2396}
2397
2398impl SessionConfigOption {
2399 #[must_use]
2400 pub fn new(
2401 id: impl Into<SessionConfigId>,
2402 name: impl Into<String>,
2403 kind: SessionConfigKind,
2404 ) -> Self {
2405 Self {
2406 id: id.into(),
2407 name: name.into(),
2408 description: None,
2409 category: None,
2410 kind,
2411 meta: None,
2412 }
2413 }
2414
2415 #[must_use]
2416 pub fn select(
2417 id: impl Into<SessionConfigId>,
2418 name: impl Into<String>,
2419 current_value: impl Into<SessionConfigValueId>,
2420 options: impl Into<SessionConfigSelectOptions>,
2421 ) -> Self {
2422 Self::new(
2423 id,
2424 name,
2425 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2426 )
2427 }
2428
2429 #[cfg(feature = "unstable_boolean_config")]
2433 #[must_use]
2434 pub fn boolean(
2435 id: impl Into<SessionConfigId>,
2436 name: impl Into<String>,
2437 current_value: bool,
2438 ) -> Self {
2439 Self::new(
2440 id,
2441 name,
2442 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2443 )
2444 }
2445
2446 #[must_use]
2447 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2448 self.description = description.into_option();
2449 self
2450 }
2451
2452 #[must_use]
2453 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2454 self.category = category.into_option();
2455 self
2456 }
2457
2458 #[must_use]
2464 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2465 self.meta = meta.into_option();
2466 self
2467 }
2468}
2469
2470#[cfg(feature = "unstable_boolean_config")]
2485#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2486#[serde(tag = "type", rename_all = "snake_case")]
2487#[non_exhaustive]
2488pub enum SessionConfigOptionValue {
2489 Boolean {
2491 value: bool,
2493 },
2494 #[serde(untagged)]
2500 ValueId {
2501 value: SessionConfigValueId,
2503 },
2504}
2505
2506#[cfg(feature = "unstable_boolean_config")]
2507impl SessionConfigOptionValue {
2508 #[must_use]
2510 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2511 Self::ValueId { value: id.into() }
2512 }
2513
2514 #[must_use]
2516 pub fn boolean(val: bool) -> Self {
2517 Self::Boolean { value: val }
2518 }
2519
2520 #[must_use]
2523 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2524 match self {
2525 Self::ValueId { value } => Some(value),
2526 _ => None,
2527 }
2528 }
2529
2530 #[must_use]
2532 pub fn as_bool(&self) -> Option<bool> {
2533 match self {
2534 Self::Boolean { value } => Some(*value),
2535 _ => None,
2536 }
2537 }
2538}
2539
2540#[cfg(feature = "unstable_boolean_config")]
2541impl From<SessionConfigValueId> for SessionConfigOptionValue {
2542 fn from(value: SessionConfigValueId) -> Self {
2543 Self::ValueId { value }
2544 }
2545}
2546
2547#[cfg(feature = "unstable_boolean_config")]
2548impl From<bool> for SessionConfigOptionValue {
2549 fn from(value: bool) -> Self {
2550 Self::Boolean { value }
2551 }
2552}
2553
2554#[cfg(feature = "unstable_boolean_config")]
2555impl From<&str> for SessionConfigOptionValue {
2556 fn from(value: &str) -> Self {
2557 Self::ValueId {
2558 value: SessionConfigValueId::new(value),
2559 }
2560 }
2561}
2562
2563#[skip_serializing_none]
2565#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2566#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2567#[serde(rename_all = "camelCase")]
2568#[non_exhaustive]
2569pub struct SetSessionConfigOptionRequest {
2570 pub session_id: SessionId,
2572 pub config_id: SessionConfigId,
2574 #[cfg(feature = "unstable_boolean_config")]
2579 #[serde(flatten)]
2580 pub value: SessionConfigOptionValue,
2581 #[cfg(not(feature = "unstable_boolean_config"))]
2583 pub value: SessionConfigValueId,
2584 #[serde(rename = "_meta")]
2590 pub meta: Option<Meta>,
2591}
2592
2593impl SetSessionConfigOptionRequest {
2594 #[cfg(feature = "unstable_boolean_config")]
2595 #[must_use]
2596 pub fn new(
2597 session_id: impl Into<SessionId>,
2598 config_id: impl Into<SessionConfigId>,
2599 value: impl Into<SessionConfigOptionValue>,
2600 ) -> Self {
2601 Self {
2602 session_id: session_id.into(),
2603 config_id: config_id.into(),
2604 value: value.into(),
2605 meta: None,
2606 }
2607 }
2608
2609 #[cfg(not(feature = "unstable_boolean_config"))]
2610 #[must_use]
2611 pub fn new(
2612 session_id: impl Into<SessionId>,
2613 config_id: impl Into<SessionConfigId>,
2614 value: impl Into<SessionConfigValueId>,
2615 ) -> Self {
2616 Self {
2617 session_id: session_id.into(),
2618 config_id: config_id.into(),
2619 value: value.into(),
2620 meta: None,
2621 }
2622 }
2623
2624 #[must_use]
2630 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2631 self.meta = meta.into_option();
2632 self
2633 }
2634}
2635
2636#[serde_as]
2638#[skip_serializing_none]
2639#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2640#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2641#[serde(rename_all = "camelCase")]
2642#[non_exhaustive]
2643pub struct SetSessionConfigOptionResponse {
2644 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2646 pub config_options: Vec<SessionConfigOption>,
2647 #[serde(rename = "_meta")]
2653 pub meta: Option<Meta>,
2654}
2655
2656impl SetSessionConfigOptionResponse {
2657 #[must_use]
2658 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2659 Self {
2660 config_options,
2661 meta: None,
2662 }
2663 }
2664
2665 #[must_use]
2671 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2672 self.meta = meta.into_option();
2673 self
2674 }
2675}
2676
2677#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2686#[serde(tag = "type", rename_all = "snake_case")]
2687#[non_exhaustive]
2688pub enum McpServer {
2689 Http(McpServerHttp),
2693 Sse(McpServerSse),
2697 #[cfg(feature = "unstable_mcp_over_acp")]
2706 Acp(McpServerAcp),
2707 #[serde(untagged)]
2711 Stdio(McpServerStdio),
2712}
2713
2714#[skip_serializing_none]
2716#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2717#[serde(rename_all = "camelCase")]
2718#[non_exhaustive]
2719pub struct McpServerHttp {
2720 pub name: String,
2722 pub url: String,
2724 pub headers: Vec<HttpHeader>,
2726 #[serde(rename = "_meta")]
2732 pub meta: Option<Meta>,
2733}
2734
2735impl McpServerHttp {
2736 #[must_use]
2737 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2738 Self {
2739 name: name.into(),
2740 url: url.into(),
2741 headers: Vec::new(),
2742 meta: None,
2743 }
2744 }
2745
2746 #[must_use]
2748 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2749 self.headers = headers;
2750 self
2751 }
2752
2753 #[must_use]
2759 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2760 self.meta = meta.into_option();
2761 self
2762 }
2763}
2764
2765#[skip_serializing_none]
2767#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2768#[serde(rename_all = "camelCase")]
2769#[non_exhaustive]
2770pub struct McpServerSse {
2771 pub name: String,
2773 pub url: String,
2775 pub headers: Vec<HttpHeader>,
2777 #[serde(rename = "_meta")]
2783 pub meta: Option<Meta>,
2784}
2785
2786impl McpServerSse {
2787 #[must_use]
2788 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2789 Self {
2790 name: name.into(),
2791 url: url.into(),
2792 headers: Vec::new(),
2793 meta: None,
2794 }
2795 }
2796
2797 #[must_use]
2799 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2800 self.headers = headers;
2801 self
2802 }
2803
2804 #[must_use]
2810 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2811 self.meta = meta.into_option();
2812 self
2813 }
2814}
2815
2816#[cfg(feature = "unstable_mcp_over_acp")]
2826#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2827#[serde(transparent)]
2828#[from(Arc<str>, String, &'static str)]
2829#[non_exhaustive]
2830pub struct McpServerAcpId(pub Arc<str>);
2831
2832#[cfg(feature = "unstable_mcp_over_acp")]
2833impl McpServerAcpId {
2834 #[must_use]
2835 pub fn new(id: impl Into<Arc<str>>) -> Self {
2836 Self(id.into())
2837 }
2838}
2839
2840#[skip_serializing_none]
2849#[cfg(feature = "unstable_mcp_over_acp")]
2850#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2851#[serde(rename_all = "camelCase")]
2852#[non_exhaustive]
2853pub struct McpServerAcp {
2854 pub name: String,
2856 pub id: McpServerAcpId,
2861 #[serde(rename = "_meta")]
2867 pub meta: Option<Meta>,
2868}
2869
2870#[cfg(feature = "unstable_mcp_over_acp")]
2871impl McpServerAcp {
2872 #[must_use]
2873 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2874 Self {
2875 name: name.into(),
2876 id: id.into(),
2877 meta: None,
2878 }
2879 }
2880
2881 #[must_use]
2887 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2888 self.meta = meta.into_option();
2889 self
2890 }
2891}
2892
2893#[skip_serializing_none]
2895#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2896#[serde(rename_all = "camelCase")]
2897#[non_exhaustive]
2898pub struct McpServerStdio {
2899 pub name: String,
2901 pub command: PathBuf,
2903 pub args: Vec<String>,
2905 pub env: Vec<EnvVariable>,
2907 #[serde(rename = "_meta")]
2913 pub meta: Option<Meta>,
2914}
2915
2916impl McpServerStdio {
2917 #[must_use]
2918 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2919 Self {
2920 name: name.into(),
2921 command: command.into(),
2922 args: Vec::new(),
2923 env: Vec::new(),
2924 meta: None,
2925 }
2926 }
2927
2928 #[must_use]
2930 pub fn args(mut self, args: Vec<String>) -> Self {
2931 self.args = args;
2932 self
2933 }
2934
2935 #[must_use]
2937 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2938 self.env = env;
2939 self
2940 }
2941
2942 #[must_use]
2948 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2949 self.meta = meta.into_option();
2950 self
2951 }
2952}
2953
2954#[skip_serializing_none]
2956#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2957#[serde(rename_all = "camelCase")]
2958#[non_exhaustive]
2959pub struct EnvVariable {
2960 pub name: String,
2962 pub value: String,
2964 #[serde(rename = "_meta")]
2970 pub meta: Option<Meta>,
2971}
2972
2973impl EnvVariable {
2974 #[must_use]
2975 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2976 Self {
2977 name: name.into(),
2978 value: value.into(),
2979 meta: None,
2980 }
2981 }
2982
2983 #[must_use]
2989 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2990 self.meta = meta.into_option();
2991 self
2992 }
2993}
2994
2995#[skip_serializing_none]
2997#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2998#[serde(rename_all = "camelCase")]
2999#[non_exhaustive]
3000pub struct HttpHeader {
3001 pub name: String,
3003 pub value: String,
3005 #[serde(rename = "_meta")]
3011 pub meta: Option<Meta>,
3012}
3013
3014impl HttpHeader {
3015 #[must_use]
3016 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3017 Self {
3018 name: name.into(),
3019 value: value.into(),
3020 meta: None,
3021 }
3022 }
3023
3024 #[must_use]
3030 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3031 self.meta = meta.into_option();
3032 self
3033 }
3034}
3035
3036#[skip_serializing_none]
3044#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
3045#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3046#[serde(rename_all = "camelCase")]
3047#[non_exhaustive]
3048pub struct PromptRequest {
3049 pub session_id: SessionId,
3051 #[cfg(feature = "unstable_message_id")]
3061 pub message_id: Option<String>,
3062 pub prompt: Vec<ContentBlock>,
3076 #[serde(rename = "_meta")]
3082 pub meta: Option<Meta>,
3083}
3084
3085impl PromptRequest {
3086 #[must_use]
3087 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3088 Self {
3089 session_id: session_id.into(),
3090 #[cfg(feature = "unstable_message_id")]
3091 message_id: None,
3092 prompt,
3093 meta: None,
3094 }
3095 }
3096
3097 #[cfg(feature = "unstable_message_id")]
3107 #[must_use]
3108 pub fn message_id(mut self, message_id: impl IntoOption<String>) -> Self {
3109 self.message_id = message_id.into_option();
3110 self
3111 }
3112
3113 #[must_use]
3119 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3120 self.meta = meta.into_option();
3121 self
3122 }
3123}
3124
3125#[serde_as]
3129#[skip_serializing_none]
3130#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3131#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3132#[serde(rename_all = "camelCase")]
3133#[non_exhaustive]
3134pub struct PromptResponse {
3135 #[cfg(feature = "unstable_message_id")]
3145 pub user_message_id: Option<String>,
3146 pub stop_reason: StopReason,
3148 #[cfg(feature = "unstable_session_usage")]
3154 #[serde_as(deserialize_as = "DefaultOnError")]
3155 #[serde(default)]
3156 pub usage: Option<Usage>,
3157 #[serde(rename = "_meta")]
3163 pub meta: Option<Meta>,
3164}
3165
3166impl PromptResponse {
3167 #[must_use]
3168 pub fn new(stop_reason: StopReason) -> Self {
3169 Self {
3170 #[cfg(feature = "unstable_message_id")]
3171 user_message_id: None,
3172 stop_reason,
3173 #[cfg(feature = "unstable_session_usage")]
3174 usage: None,
3175 meta: None,
3176 }
3177 }
3178
3179 #[cfg(feature = "unstable_message_id")]
3189 #[must_use]
3190 pub fn user_message_id(mut self, user_message_id: impl IntoOption<String>) -> Self {
3191 self.user_message_id = user_message_id.into_option();
3192 self
3193 }
3194
3195 #[cfg(feature = "unstable_session_usage")]
3201 #[must_use]
3202 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3203 self.usage = usage.into_option();
3204 self
3205 }
3206
3207 #[must_use]
3213 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3214 self.meta = meta.into_option();
3215 self
3216 }
3217}
3218
3219#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3223#[serde(rename_all = "snake_case")]
3224#[non_exhaustive]
3225pub enum StopReason {
3226 EndTurn,
3228 MaxTokens,
3230 MaxTurnRequests,
3233 Refusal,
3237 Cancelled,
3244}
3245
3246#[cfg(feature = "unstable_session_usage")]
3252#[skip_serializing_none]
3253#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3254#[serde(rename_all = "camelCase")]
3255#[non_exhaustive]
3256pub struct Usage {
3257 pub total_tokens: u64,
3259 pub input_tokens: u64,
3261 pub output_tokens: u64,
3263 pub thought_tokens: Option<u64>,
3265 pub cached_read_tokens: Option<u64>,
3267 pub cached_write_tokens: Option<u64>,
3269}
3270
3271#[cfg(feature = "unstable_session_usage")]
3272impl Usage {
3273 #[must_use]
3274 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3275 Self {
3276 total_tokens,
3277 input_tokens,
3278 output_tokens,
3279 thought_tokens: None,
3280 cached_read_tokens: None,
3281 cached_write_tokens: None,
3282 }
3283 }
3284
3285 #[must_use]
3287 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3288 self.thought_tokens = thought_tokens.into_option();
3289 self
3290 }
3291
3292 #[must_use]
3294 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3295 self.cached_read_tokens = cached_read_tokens.into_option();
3296 self
3297 }
3298
3299 #[must_use]
3301 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3302 self.cached_write_tokens = cached_write_tokens.into_option();
3303 self
3304 }
3305}
3306
3307#[cfg(feature = "unstable_session_model")]
3315#[serde_as]
3316#[skip_serializing_none]
3317#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3318#[serde(rename_all = "camelCase")]
3319#[non_exhaustive]
3320pub struct SessionModelState {
3321 pub current_model_id: ModelId,
3323 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3325 pub available_models: Vec<ModelInfo>,
3326 #[serde(rename = "_meta")]
3332 pub meta: Option<Meta>,
3333}
3334
3335#[cfg(feature = "unstable_session_model")]
3336impl SessionModelState {
3337 #[must_use]
3338 pub fn new(current_model_id: impl Into<ModelId>, available_models: Vec<ModelInfo>) -> Self {
3339 Self {
3340 current_model_id: current_model_id.into(),
3341 available_models,
3342 meta: None,
3343 }
3344 }
3345
3346 #[must_use]
3352 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3353 self.meta = meta.into_option();
3354 self
3355 }
3356}
3357
3358#[cfg(feature = "unstable_session_model")]
3364#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
3365#[serde(transparent)]
3366#[from(Arc<str>, String, &'static str)]
3367#[non_exhaustive]
3368pub struct ModelId(pub Arc<str>);
3369
3370#[cfg(feature = "unstable_session_model")]
3371impl ModelId {
3372 #[must_use]
3373 pub fn new(id: impl Into<Arc<str>>) -> Self {
3374 Self(id.into())
3375 }
3376}
3377
3378#[cfg(feature = "unstable_session_model")]
3384#[skip_serializing_none]
3385#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3386#[serde(rename_all = "camelCase")]
3387#[non_exhaustive]
3388pub struct ModelInfo {
3389 pub model_id: ModelId,
3391 pub name: String,
3393 #[serde(default)]
3395 pub description: Option<String>,
3396 #[serde(rename = "_meta")]
3402 pub meta: Option<Meta>,
3403}
3404
3405#[cfg(feature = "unstable_session_model")]
3406impl ModelInfo {
3407 #[must_use]
3408 pub fn new(model_id: impl Into<ModelId>, name: impl Into<String>) -> Self {
3409 Self {
3410 model_id: model_id.into(),
3411 name: name.into(),
3412 description: None,
3413 meta: None,
3414 }
3415 }
3416
3417 #[must_use]
3419 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
3420 self.description = description.into_option();
3421 self
3422 }
3423
3424 #[must_use]
3430 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3431 self.meta = meta.into_option();
3432 self
3433 }
3434}
3435
3436#[cfg(feature = "unstable_session_model")]
3442#[skip_serializing_none]
3443#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3444#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3445#[serde(rename_all = "camelCase")]
3446#[non_exhaustive]
3447pub struct SetSessionModelRequest {
3448 pub session_id: SessionId,
3450 pub model_id: ModelId,
3452 #[serde(rename = "_meta")]
3458 pub meta: Option<Meta>,
3459}
3460
3461#[cfg(feature = "unstable_session_model")]
3462impl SetSessionModelRequest {
3463 #[must_use]
3464 pub fn new(session_id: impl Into<SessionId>, model_id: impl Into<ModelId>) -> Self {
3465 Self {
3466 session_id: session_id.into(),
3467 model_id: model_id.into(),
3468 meta: None,
3469 }
3470 }
3471
3472 #[must_use]
3478 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3479 self.meta = meta.into_option();
3480 self
3481 }
3482}
3483
3484#[cfg(feature = "unstable_session_model")]
3490#[skip_serializing_none]
3491#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3492#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3493#[serde(rename_all = "camelCase")]
3494#[non_exhaustive]
3495pub struct SetSessionModelResponse {
3496 #[serde(rename = "_meta")]
3502 pub meta: Option<Meta>,
3503}
3504
3505#[cfg(feature = "unstable_session_model")]
3506impl SetSessionModelResponse {
3507 #[must_use]
3508 pub fn new() -> Self {
3509 Self::default()
3510 }
3511
3512 #[must_use]
3518 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3519 self.meta = meta.into_option();
3520 self
3521 }
3522}
3523
3524#[cfg(feature = "unstable_llm_providers")]
3537#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3538#[serde(rename_all = "snake_case")]
3539#[non_exhaustive]
3540#[expect(clippy::doc_markdown)]
3541pub enum LlmProtocol {
3542 Anthropic,
3544 #[serde(rename = "openai")]
3546 OpenAi,
3547 Azure,
3549 Vertex,
3551 Bedrock,
3553 #[serde(untagged)]
3555 Other(String),
3556}
3557
3558#[cfg(feature = "unstable_llm_providers")]
3564#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3565#[serde(rename_all = "camelCase")]
3566#[non_exhaustive]
3567pub struct ProviderCurrentConfig {
3568 pub api_type: LlmProtocol,
3570 pub base_url: String,
3572}
3573
3574#[cfg(feature = "unstable_llm_providers")]
3575impl ProviderCurrentConfig {
3576 #[must_use]
3577 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3578 Self {
3579 api_type,
3580 base_url: base_url.into(),
3581 }
3582 }
3583}
3584
3585#[cfg(feature = "unstable_llm_providers")]
3591#[serde_as]
3592#[skip_serializing_none]
3593#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3594#[serde(rename_all = "camelCase")]
3595#[non_exhaustive]
3596pub struct ProviderInfo {
3597 pub id: String,
3599 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3601 pub supported: Vec<LlmProtocol>,
3602 pub required: bool,
3605 pub current: Option<ProviderCurrentConfig>,
3608 #[serde(rename = "_meta")]
3614 pub meta: Option<Meta>,
3615}
3616
3617#[cfg(feature = "unstable_llm_providers")]
3618impl ProviderInfo {
3619 #[must_use]
3620 pub fn new(
3621 id: impl Into<String>,
3622 supported: Vec<LlmProtocol>,
3623 required: bool,
3624 current: impl IntoOption<ProviderCurrentConfig>,
3625 ) -> Self {
3626 Self {
3627 id: id.into(),
3628 supported,
3629 required,
3630 current: current.into_option(),
3631 meta: None,
3632 }
3633 }
3634
3635 #[must_use]
3641 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3642 self.meta = meta.into_option();
3643 self
3644 }
3645}
3646
3647#[cfg(feature = "unstable_llm_providers")]
3653#[skip_serializing_none]
3654#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3655#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3656#[serde(rename_all = "camelCase")]
3657#[non_exhaustive]
3658pub struct ListProvidersRequest {
3659 #[serde(rename = "_meta")]
3665 pub meta: Option<Meta>,
3666}
3667
3668#[cfg(feature = "unstable_llm_providers")]
3669impl ListProvidersRequest {
3670 #[must_use]
3671 pub fn new() -> Self {
3672 Self::default()
3673 }
3674
3675 #[must_use]
3681 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3682 self.meta = meta.into_option();
3683 self
3684 }
3685}
3686
3687#[cfg(feature = "unstable_llm_providers")]
3693#[serde_as]
3694#[skip_serializing_none]
3695#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3696#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3697#[serde(rename_all = "camelCase")]
3698#[non_exhaustive]
3699pub struct ListProvidersResponse {
3700 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3702 pub providers: Vec<ProviderInfo>,
3703 #[serde(rename = "_meta")]
3709 pub meta: Option<Meta>,
3710}
3711
3712#[cfg(feature = "unstable_llm_providers")]
3713impl ListProvidersResponse {
3714 #[must_use]
3715 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3716 Self {
3717 providers,
3718 meta: None,
3719 }
3720 }
3721
3722 #[must_use]
3728 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3729 self.meta = meta.into_option();
3730 self
3731 }
3732}
3733
3734#[cfg(feature = "unstable_llm_providers")]
3742#[skip_serializing_none]
3743#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3744#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3745#[serde(rename_all = "camelCase")]
3746#[non_exhaustive]
3747pub struct SetProvidersRequest {
3748 pub id: String,
3750 pub api_type: LlmProtocol,
3752 pub base_url: String,
3754 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3757 pub headers: HashMap<String, String>,
3758 #[serde(rename = "_meta")]
3764 pub meta: Option<Meta>,
3765}
3766
3767#[cfg(feature = "unstable_llm_providers")]
3768impl SetProvidersRequest {
3769 #[must_use]
3770 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3771 Self {
3772 id: id.into(),
3773 api_type,
3774 base_url: base_url.into(),
3775 headers: HashMap::new(),
3776 meta: None,
3777 }
3778 }
3779
3780 #[must_use]
3783 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3784 self.headers = headers;
3785 self
3786 }
3787
3788 #[must_use]
3794 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3795 self.meta = meta.into_option();
3796 self
3797 }
3798}
3799
3800#[cfg(feature = "unstable_llm_providers")]
3806#[skip_serializing_none]
3807#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3808#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3809#[serde(rename_all = "camelCase")]
3810#[non_exhaustive]
3811pub struct SetProvidersResponse {
3812 #[serde(rename = "_meta")]
3818 pub meta: Option<Meta>,
3819}
3820
3821#[cfg(feature = "unstable_llm_providers")]
3822impl SetProvidersResponse {
3823 #[must_use]
3824 pub fn new() -> Self {
3825 Self::default()
3826 }
3827
3828 #[must_use]
3834 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3835 self.meta = meta.into_option();
3836 self
3837 }
3838}
3839
3840#[cfg(feature = "unstable_llm_providers")]
3846#[skip_serializing_none]
3847#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3848#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3849#[serde(rename_all = "camelCase")]
3850#[non_exhaustive]
3851pub struct DisableProvidersRequest {
3852 pub id: String,
3854 #[serde(rename = "_meta")]
3860 pub meta: Option<Meta>,
3861}
3862
3863#[cfg(feature = "unstable_llm_providers")]
3864impl DisableProvidersRequest {
3865 #[must_use]
3866 pub fn new(id: impl Into<String>) -> Self {
3867 Self {
3868 id: id.into(),
3869 meta: None,
3870 }
3871 }
3872
3873 #[must_use]
3879 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3880 self.meta = meta.into_option();
3881 self
3882 }
3883}
3884
3885#[cfg(feature = "unstable_llm_providers")]
3891#[skip_serializing_none]
3892#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3893#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3894#[serde(rename_all = "camelCase")]
3895#[non_exhaustive]
3896pub struct DisableProvidersResponse {
3897 #[serde(rename = "_meta")]
3903 pub meta: Option<Meta>,
3904}
3905
3906#[cfg(feature = "unstable_llm_providers")]
3907impl DisableProvidersResponse {
3908 #[must_use]
3909 pub fn new() -> Self {
3910 Self::default()
3911 }
3912
3913 #[must_use]
3919 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3920 self.meta = meta.into_option();
3921 self
3922 }
3923}
3924
3925#[serde_as]
3934#[skip_serializing_none]
3935#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3936#[serde(rename_all = "camelCase")]
3937#[non_exhaustive]
3938pub struct AgentCapabilities {
3939 #[serde(default)]
3941 pub load_session: bool,
3942 #[serde(default)]
3944 pub prompt_capabilities: PromptCapabilities,
3945 #[serde(default)]
3947 pub mcp_capabilities: McpCapabilities,
3948 #[serde(default)]
3949 pub session_capabilities: SessionCapabilities,
3950 #[cfg(feature = "unstable_logout")]
3956 #[serde(default)]
3957 pub auth: AgentAuthCapabilities,
3958 #[cfg(feature = "unstable_llm_providers")]
3966 #[serde_as(deserialize_as = "DefaultOnError")]
3967 #[serde(default)]
3968 pub providers: Option<ProvidersCapabilities>,
3969 #[cfg(feature = "unstable_nes")]
3975 #[serde_as(deserialize_as = "DefaultOnError")]
3976 #[serde(default)]
3977 pub nes: Option<NesCapabilities>,
3978 #[cfg(feature = "unstable_nes")]
3984 #[serde_as(deserialize_as = "DefaultOnError")]
3985 #[serde(default)]
3986 pub position_encoding: Option<PositionEncodingKind>,
3987 #[serde(rename = "_meta")]
3993 pub meta: Option<Meta>,
3994}
3995
3996impl AgentCapabilities {
3997 #[must_use]
3998 pub fn new() -> Self {
3999 Self::default()
4000 }
4001
4002 #[must_use]
4004 pub fn load_session(mut self, load_session: bool) -> Self {
4005 self.load_session = load_session;
4006 self
4007 }
4008
4009 #[must_use]
4011 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
4012 self.prompt_capabilities = prompt_capabilities;
4013 self
4014 }
4015
4016 #[must_use]
4018 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
4019 self.mcp_capabilities = mcp_capabilities;
4020 self
4021 }
4022
4023 #[must_use]
4025 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
4026 self.session_capabilities = session_capabilities;
4027 self
4028 }
4029
4030 #[cfg(feature = "unstable_logout")]
4036 #[must_use]
4037 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
4038 self.auth = auth;
4039 self
4040 }
4041
4042 #[cfg(feature = "unstable_llm_providers")]
4048 #[must_use]
4049 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
4050 self.providers = providers.into_option();
4051 self
4052 }
4053
4054 #[cfg(feature = "unstable_nes")]
4060 #[must_use]
4061 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
4062 self.nes = nes.into_option();
4063 self
4064 }
4065
4066 #[cfg(feature = "unstable_nes")]
4070 #[must_use]
4071 pub fn position_encoding(
4072 mut self,
4073 position_encoding: impl IntoOption<PositionEncodingKind>,
4074 ) -> Self {
4075 self.position_encoding = position_encoding.into_option();
4076 self
4077 }
4078
4079 #[must_use]
4085 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4086 self.meta = meta.into_option();
4087 self
4088 }
4089}
4090
4091#[cfg(feature = "unstable_llm_providers")]
4099#[skip_serializing_none]
4100#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4101#[non_exhaustive]
4102pub struct ProvidersCapabilities {
4103 #[serde(rename = "_meta")]
4109 pub meta: Option<Meta>,
4110}
4111
4112#[cfg(feature = "unstable_llm_providers")]
4113impl ProvidersCapabilities {
4114 #[must_use]
4115 pub fn new() -> Self {
4116 Self::default()
4117 }
4118
4119 #[must_use]
4125 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4126 self.meta = meta.into_option();
4127 self
4128 }
4129}
4130
4131#[serde_as]
4141#[skip_serializing_none]
4142#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4143#[serde(rename_all = "camelCase")]
4144#[non_exhaustive]
4145pub struct SessionCapabilities {
4146 #[serde_as(deserialize_as = "DefaultOnError")]
4148 #[serde(default)]
4149 pub list: Option<SessionListCapabilities>,
4150 #[cfg(feature = "unstable_session_additional_directories")]
4156 #[serde_as(deserialize_as = "DefaultOnError")]
4157 #[serde(default)]
4158 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
4159 #[cfg(feature = "unstable_session_fork")]
4165 #[serde_as(deserialize_as = "DefaultOnError")]
4166 #[serde(default)]
4167 pub fork: Option<SessionForkCapabilities>,
4168 #[serde_as(deserialize_as = "DefaultOnError")]
4170 #[serde(default)]
4171 pub resume: Option<SessionResumeCapabilities>,
4172 #[serde_as(deserialize_as = "DefaultOnError")]
4174 #[serde(default)]
4175 pub close: Option<SessionCloseCapabilities>,
4176 #[serde(rename = "_meta")]
4182 pub meta: Option<Meta>,
4183}
4184
4185impl SessionCapabilities {
4186 #[must_use]
4187 pub fn new() -> Self {
4188 Self::default()
4189 }
4190
4191 #[must_use]
4193 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
4194 self.list = list.into_option();
4195 self
4196 }
4197
4198 #[cfg(feature = "unstable_session_additional_directories")]
4204 #[must_use]
4205 pub fn additional_directories(
4206 mut self,
4207 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4208 ) -> Self {
4209 self.additional_directories = additional_directories.into_option();
4210 self
4211 }
4212
4213 #[cfg(feature = "unstable_session_fork")]
4214 #[must_use]
4216 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4217 self.fork = fork.into_option();
4218 self
4219 }
4220
4221 #[must_use]
4223 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4224 self.resume = resume.into_option();
4225 self
4226 }
4227
4228 #[must_use]
4230 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4231 self.close = close.into_option();
4232 self
4233 }
4234
4235 #[must_use]
4241 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4242 self.meta = meta.into_option();
4243 self
4244 }
4245}
4246
4247#[skip_serializing_none]
4251#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4252#[non_exhaustive]
4253pub struct SessionListCapabilities {
4254 #[serde(rename = "_meta")]
4260 pub meta: Option<Meta>,
4261}
4262
4263impl SessionListCapabilities {
4264 #[must_use]
4265 pub fn new() -> Self {
4266 Self::default()
4267 }
4268
4269 #[must_use]
4275 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4276 self.meta = meta.into_option();
4277 self
4278 }
4279}
4280
4281#[cfg(feature = "unstable_session_additional_directories")]
4290#[skip_serializing_none]
4291#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4292#[non_exhaustive]
4293pub struct SessionAdditionalDirectoriesCapabilities {
4294 #[serde(rename = "_meta")]
4300 pub meta: Option<Meta>,
4301}
4302
4303#[cfg(feature = "unstable_session_additional_directories")]
4304impl SessionAdditionalDirectoriesCapabilities {
4305 #[must_use]
4306 pub fn new() -> Self {
4307 Self::default()
4308 }
4309
4310 #[must_use]
4316 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4317 self.meta = meta.into_option();
4318 self
4319 }
4320}
4321
4322#[cfg(feature = "unstable_session_fork")]
4330#[skip_serializing_none]
4331#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4332#[non_exhaustive]
4333pub struct SessionForkCapabilities {
4334 #[serde(rename = "_meta")]
4340 pub meta: Option<Meta>,
4341}
4342
4343#[cfg(feature = "unstable_session_fork")]
4344impl SessionForkCapabilities {
4345 #[must_use]
4346 pub fn new() -> Self {
4347 Self::default()
4348 }
4349
4350 #[must_use]
4356 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4357 self.meta = meta.into_option();
4358 self
4359 }
4360}
4361
4362#[skip_serializing_none]
4366#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4367#[non_exhaustive]
4368pub struct SessionResumeCapabilities {
4369 #[serde(rename = "_meta")]
4375 pub meta: Option<Meta>,
4376}
4377
4378impl SessionResumeCapabilities {
4379 #[must_use]
4380 pub fn new() -> Self {
4381 Self::default()
4382 }
4383
4384 #[must_use]
4390 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4391 self.meta = meta.into_option();
4392 self
4393 }
4394}
4395
4396#[skip_serializing_none]
4400#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4401#[non_exhaustive]
4402pub struct SessionCloseCapabilities {
4403 #[serde(rename = "_meta")]
4409 pub meta: Option<Meta>,
4410}
4411
4412impl SessionCloseCapabilities {
4413 #[must_use]
4414 pub fn new() -> Self {
4415 Self::default()
4416 }
4417
4418 #[must_use]
4424 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4425 self.meta = meta.into_option();
4426 self
4427 }
4428}
4429
4430#[skip_serializing_none]
4443#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4444#[serde(rename_all = "camelCase")]
4445#[non_exhaustive]
4446pub struct PromptCapabilities {
4447 #[serde(default)]
4449 pub image: bool,
4450 #[serde(default)]
4452 pub audio: bool,
4453 #[serde(default)]
4458 pub embedded_context: bool,
4459 #[serde(rename = "_meta")]
4465 pub meta: Option<Meta>,
4466}
4467
4468impl PromptCapabilities {
4469 #[must_use]
4470 pub fn new() -> Self {
4471 Self::default()
4472 }
4473
4474 #[must_use]
4476 pub fn image(mut self, image: bool) -> Self {
4477 self.image = image;
4478 self
4479 }
4480
4481 #[must_use]
4483 pub fn audio(mut self, audio: bool) -> Self {
4484 self.audio = audio;
4485 self
4486 }
4487
4488 #[must_use]
4493 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4494 self.embedded_context = embedded_context;
4495 self
4496 }
4497
4498 #[must_use]
4504 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4505 self.meta = meta.into_option();
4506 self
4507 }
4508}
4509
4510#[skip_serializing_none]
4512#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4513#[serde(rename_all = "camelCase")]
4514#[non_exhaustive]
4515pub struct McpCapabilities {
4516 #[serde(default)]
4518 pub http: bool,
4519 #[serde(default)]
4521 pub sse: bool,
4522 #[cfg(feature = "unstable_mcp_over_acp")]
4528 #[serde(default)]
4529 pub acp: bool,
4530 #[serde(rename = "_meta")]
4536 pub meta: Option<Meta>,
4537}
4538
4539impl McpCapabilities {
4540 #[must_use]
4541 pub fn new() -> Self {
4542 Self::default()
4543 }
4544
4545 #[must_use]
4547 pub fn http(mut self, http: bool) -> Self {
4548 self.http = http;
4549 self
4550 }
4551
4552 #[must_use]
4554 pub fn sse(mut self, sse: bool) -> Self {
4555 self.sse = sse;
4556 self
4557 }
4558
4559 #[cfg(feature = "unstable_mcp_over_acp")]
4565 #[must_use]
4566 pub fn acp(mut self, acp: bool) -> Self {
4567 self.acp = acp;
4568 self
4569 }
4570
4571 #[must_use]
4577 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4578 self.meta = meta.into_option();
4579 self
4580 }
4581}
4582
4583#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4589#[non_exhaustive]
4590pub struct AgentMethodNames {
4591 pub initialize: &'static str,
4593 pub authenticate: &'static str,
4595 #[cfg(feature = "unstable_llm_providers")]
4597 pub providers_list: &'static str,
4598 #[cfg(feature = "unstable_llm_providers")]
4600 pub providers_set: &'static str,
4601 #[cfg(feature = "unstable_llm_providers")]
4603 pub providers_disable: &'static str,
4604 pub session_new: &'static str,
4606 pub session_load: &'static str,
4608 pub session_set_mode: &'static str,
4610 pub session_set_config_option: &'static str,
4612 pub session_prompt: &'static str,
4614 pub session_cancel: &'static str,
4616 #[cfg(feature = "unstable_mcp_over_acp")]
4618 pub mcp_message: &'static str,
4619 #[cfg(feature = "unstable_session_model")]
4621 pub session_set_model: &'static str,
4622 pub session_list: &'static str,
4624 #[cfg(feature = "unstable_session_fork")]
4626 pub session_fork: &'static str,
4627 pub session_resume: &'static str,
4629 pub session_close: &'static str,
4631 #[cfg(feature = "unstable_logout")]
4633 pub logout: &'static str,
4634 #[cfg(feature = "unstable_nes")]
4636 pub nes_start: &'static str,
4637 #[cfg(feature = "unstable_nes")]
4639 pub nes_suggest: &'static str,
4640 #[cfg(feature = "unstable_nes")]
4642 pub nes_accept: &'static str,
4643 #[cfg(feature = "unstable_nes")]
4645 pub nes_reject: &'static str,
4646 #[cfg(feature = "unstable_nes")]
4648 pub nes_close: &'static str,
4649 #[cfg(feature = "unstable_nes")]
4651 pub document_did_open: &'static str,
4652 #[cfg(feature = "unstable_nes")]
4654 pub document_did_change: &'static str,
4655 #[cfg(feature = "unstable_nes")]
4657 pub document_did_close: &'static str,
4658 #[cfg(feature = "unstable_nes")]
4660 pub document_did_save: &'static str,
4661 #[cfg(feature = "unstable_nes")]
4663 pub document_did_focus: &'static str,
4664}
4665
4666pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4668 initialize: INITIALIZE_METHOD_NAME,
4669 authenticate: AUTHENTICATE_METHOD_NAME,
4670 #[cfg(feature = "unstable_llm_providers")]
4671 providers_list: PROVIDERS_LIST_METHOD_NAME,
4672 #[cfg(feature = "unstable_llm_providers")]
4673 providers_set: PROVIDERS_SET_METHOD_NAME,
4674 #[cfg(feature = "unstable_llm_providers")]
4675 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4676 session_new: SESSION_NEW_METHOD_NAME,
4677 session_load: SESSION_LOAD_METHOD_NAME,
4678 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4679 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4680 session_prompt: SESSION_PROMPT_METHOD_NAME,
4681 session_cancel: SESSION_CANCEL_METHOD_NAME,
4682 #[cfg(feature = "unstable_mcp_over_acp")]
4683 mcp_message: MCP_MESSAGE_METHOD_NAME,
4684 #[cfg(feature = "unstable_session_model")]
4685 session_set_model: SESSION_SET_MODEL_METHOD_NAME,
4686 session_list: SESSION_LIST_METHOD_NAME,
4687 #[cfg(feature = "unstable_session_fork")]
4688 session_fork: SESSION_FORK_METHOD_NAME,
4689 session_resume: SESSION_RESUME_METHOD_NAME,
4690 session_close: SESSION_CLOSE_METHOD_NAME,
4691 #[cfg(feature = "unstable_logout")]
4692 logout: LOGOUT_METHOD_NAME,
4693 #[cfg(feature = "unstable_nes")]
4694 nes_start: NES_START_METHOD_NAME,
4695 #[cfg(feature = "unstable_nes")]
4696 nes_suggest: NES_SUGGEST_METHOD_NAME,
4697 #[cfg(feature = "unstable_nes")]
4698 nes_accept: NES_ACCEPT_METHOD_NAME,
4699 #[cfg(feature = "unstable_nes")]
4700 nes_reject: NES_REJECT_METHOD_NAME,
4701 #[cfg(feature = "unstable_nes")]
4702 nes_close: NES_CLOSE_METHOD_NAME,
4703 #[cfg(feature = "unstable_nes")]
4704 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4705 #[cfg(feature = "unstable_nes")]
4706 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4707 #[cfg(feature = "unstable_nes")]
4708 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4709 #[cfg(feature = "unstable_nes")]
4710 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4711 #[cfg(feature = "unstable_nes")]
4712 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4713};
4714
4715pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4717pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4719#[cfg(feature = "unstable_llm_providers")]
4721pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4722#[cfg(feature = "unstable_llm_providers")]
4724pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4725#[cfg(feature = "unstable_llm_providers")]
4727pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4728pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4730pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4732pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4734pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4736pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4738pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4740#[cfg(feature = "unstable_session_model")]
4742pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
4743pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4745#[cfg(feature = "unstable_session_fork")]
4747pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4748pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4750pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4752#[cfg(feature = "unstable_logout")]
4754pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4755
4756#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4763#[serde(untagged)]
4764#[schemars(inline)]
4765#[non_exhaustive]
4766#[allow(clippy::large_enum_variant)]
4767pub enum ClientRequest {
4768 InitializeRequest(InitializeRequest),
4779 AuthenticateRequest(AuthenticateRequest),
4789 #[cfg(feature = "unstable_llm_providers")]
4795 ListProvidersRequest(ListProvidersRequest),
4796 #[cfg(feature = "unstable_llm_providers")]
4802 SetProvidersRequest(SetProvidersRequest),
4803 #[cfg(feature = "unstable_llm_providers")]
4809 DisableProvidersRequest(DisableProvidersRequest),
4810 #[cfg(feature = "unstable_logout")]
4819 LogoutRequest(LogoutRequest),
4820 NewSessionRequest(NewSessionRequest),
4833 LoadSessionRequest(LoadSessionRequest),
4844 ListSessionsRequest(ListSessionsRequest),
4850 #[cfg(feature = "unstable_session_fork")]
4851 ForkSessionRequest(ForkSessionRequest),
4863 ResumeSessionRequest(ResumeSessionRequest),
4870 CloseSessionRequest(CloseSessionRequest),
4877 SetSessionModeRequest(SetSessionModeRequest),
4891 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4893 PromptRequest(PromptRequest),
4905 #[cfg(feature = "unstable_session_model")]
4906 SetSessionModelRequest(SetSessionModelRequest),
4912 #[cfg(feature = "unstable_nes")]
4913 StartNesRequest(StartNesRequest),
4919 #[cfg(feature = "unstable_nes")]
4920 SuggestNesRequest(SuggestNesRequest),
4926 #[cfg(feature = "unstable_nes")]
4927 CloseNesRequest(CloseNesRequest),
4936 #[cfg(feature = "unstable_mcp_over_acp")]
4942 MessageMcpRequest(MessageMcpRequest),
4943 ExtMethodRequest(ExtRequest),
4950}
4951
4952impl ClientRequest {
4953 #[must_use]
4955 pub fn method(&self) -> &str {
4956 match self {
4957 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4958 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4959 #[cfg(feature = "unstable_llm_providers")]
4960 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4961 #[cfg(feature = "unstable_llm_providers")]
4962 Self::SetProvidersRequest(_) => AGENT_METHOD_NAMES.providers_set,
4963 #[cfg(feature = "unstable_llm_providers")]
4964 Self::DisableProvidersRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4965 #[cfg(feature = "unstable_logout")]
4966 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4967 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4968 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4969 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4970 #[cfg(feature = "unstable_session_fork")]
4971 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
4972 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
4973 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
4974 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
4975 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
4976 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
4977 #[cfg(feature = "unstable_session_model")]
4978 Self::SetSessionModelRequest(_) => AGENT_METHOD_NAMES.session_set_model,
4979 #[cfg(feature = "unstable_nes")]
4980 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
4981 #[cfg(feature = "unstable_nes")]
4982 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
4983 #[cfg(feature = "unstable_nes")]
4984 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
4985 #[cfg(feature = "unstable_mcp_over_acp")]
4986 Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
4987 Self::ExtMethodRequest(ext_request) => &ext_request.method,
4988 }
4989 }
4990}
4991
4992#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4999#[serde(untagged)]
5000#[schemars(inline)]
5001#[non_exhaustive]
5002#[allow(clippy::large_enum_variant)]
5003pub enum AgentResponse {
5004 InitializeResponse(InitializeResponse),
5005 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
5006 #[cfg(feature = "unstable_llm_providers")]
5007 ListProvidersResponse(ListProvidersResponse),
5008 #[cfg(feature = "unstable_llm_providers")]
5009 SetProvidersResponse(#[serde(default)] SetProvidersResponse),
5010 #[cfg(feature = "unstable_llm_providers")]
5011 DisableProvidersResponse(#[serde(default)] DisableProvidersResponse),
5012 #[cfg(feature = "unstable_logout")]
5013 LogoutResponse(#[serde(default)] LogoutResponse),
5014 NewSessionResponse(NewSessionResponse),
5015 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5016 ListSessionsResponse(ListSessionsResponse),
5017 #[cfg(feature = "unstable_session_fork")]
5018 ForkSessionResponse(ForkSessionResponse),
5019 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5020 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5021 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
5022 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5023 PromptResponse(PromptResponse),
5024 #[cfg(feature = "unstable_session_model")]
5025 SetSessionModelResponse(#[serde(default)] SetSessionModelResponse),
5026 #[cfg(feature = "unstable_nes")]
5027 StartNesResponse(StartNesResponse),
5028 #[cfg(feature = "unstable_nes")]
5029 SuggestNesResponse(SuggestNesResponse),
5030 #[cfg(feature = "unstable_nes")]
5031 CloseNesResponse(#[serde(default)] CloseNesResponse),
5032 ExtMethodResponse(ExtResponse),
5033 #[cfg(feature = "unstable_mcp_over_acp")]
5034 MessageMcpResponse(MessageMcpResponse),
5035}
5036
5037#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5044#[serde(untagged)]
5045#[schemars(inline)]
5046#[non_exhaustive]
5047pub enum ClientNotification {
5048 CancelNotification(CancelNotification),
5060 #[cfg(feature = "unstable_nes")]
5061 DidOpenDocumentNotification(DidOpenDocumentNotification),
5065 #[cfg(feature = "unstable_nes")]
5066 DidChangeDocumentNotification(DidChangeDocumentNotification),
5070 #[cfg(feature = "unstable_nes")]
5071 DidCloseDocumentNotification(DidCloseDocumentNotification),
5075 #[cfg(feature = "unstable_nes")]
5076 DidSaveDocumentNotification(DidSaveDocumentNotification),
5080 #[cfg(feature = "unstable_nes")]
5081 DidFocusDocumentNotification(DidFocusDocumentNotification),
5085 #[cfg(feature = "unstable_nes")]
5086 AcceptNesNotification(AcceptNesNotification),
5090 #[cfg(feature = "unstable_nes")]
5091 RejectNesNotification(RejectNesNotification),
5095 #[cfg(feature = "unstable_mcp_over_acp")]
5101 MessageMcpNotification(MessageMcpNotification),
5102 ExtNotification(ExtNotification),
5109}
5110
5111impl ClientNotification {
5112 #[must_use]
5114 pub fn method(&self) -> &str {
5115 match self {
5116 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5117 #[cfg(feature = "unstable_nes")]
5118 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5119 #[cfg(feature = "unstable_nes")]
5120 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5121 #[cfg(feature = "unstable_nes")]
5122 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5123 #[cfg(feature = "unstable_nes")]
5124 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5125 #[cfg(feature = "unstable_nes")]
5126 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5127 #[cfg(feature = "unstable_nes")]
5128 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5129 #[cfg(feature = "unstable_nes")]
5130 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5131 #[cfg(feature = "unstable_mcp_over_acp")]
5132 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5133 Self::ExtNotification(ext_notification) => &ext_notification.method,
5134 }
5135 }
5136}
5137
5138#[skip_serializing_none]
5142#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5143#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5144#[serde(rename_all = "camelCase")]
5145#[non_exhaustive]
5146pub struct CancelNotification {
5147 pub session_id: SessionId,
5149 #[serde(rename = "_meta")]
5155 pub meta: Option<Meta>,
5156}
5157
5158impl CancelNotification {
5159 #[must_use]
5160 pub fn new(session_id: impl Into<SessionId>) -> Self {
5161 Self {
5162 session_id: session_id.into(),
5163 meta: None,
5164 }
5165 }
5166
5167 #[must_use]
5173 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5174 self.meta = meta.into_option();
5175 self
5176 }
5177}
5178
5179#[cfg(test)]
5180mod test_serialization {
5181 use super::*;
5182 use serde_json::json;
5183
5184 #[test]
5185 fn test_mcp_server_stdio_serialization() {
5186 let server = McpServer::Stdio(
5187 McpServerStdio::new("test-server", "/usr/bin/server")
5188 .args(vec!["--port".to_string(), "3000".to_string()])
5189 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5190 );
5191
5192 let json = serde_json::to_value(&server).unwrap();
5193 assert_eq!(
5194 json,
5195 json!({
5196 "name": "test-server",
5197 "command": "/usr/bin/server",
5198 "args": ["--port", "3000"],
5199 "env": [
5200 {
5201 "name": "API_KEY",
5202 "value": "secret123"
5203 }
5204 ]
5205 })
5206 );
5207
5208 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5209 match deserialized {
5210 McpServer::Stdio(McpServerStdio {
5211 name,
5212 command,
5213 args,
5214 env,
5215 meta: _,
5216 }) => {
5217 assert_eq!(name, "test-server");
5218 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5219 assert_eq!(args, vec!["--port", "3000"]);
5220 assert_eq!(env.len(), 1);
5221 assert_eq!(env[0].name, "API_KEY");
5222 assert_eq!(env[0].value, "secret123");
5223 }
5224 _ => panic!("Expected Stdio variant"),
5225 }
5226 }
5227
5228 #[test]
5229 fn test_mcp_server_http_serialization() {
5230 let server = McpServer::Http(
5231 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5232 HttpHeader::new("Authorization", "Bearer token123"),
5233 HttpHeader::new("Content-Type", "application/json"),
5234 ]),
5235 );
5236
5237 let json = serde_json::to_value(&server).unwrap();
5238 assert_eq!(
5239 json,
5240 json!({
5241 "type": "http",
5242 "name": "http-server",
5243 "url": "https://api.example.com",
5244 "headers": [
5245 {
5246 "name": "Authorization",
5247 "value": "Bearer token123"
5248 },
5249 {
5250 "name": "Content-Type",
5251 "value": "application/json"
5252 }
5253 ]
5254 })
5255 );
5256
5257 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5258 match deserialized {
5259 McpServer::Http(McpServerHttp {
5260 name,
5261 url,
5262 headers,
5263 meta: _,
5264 }) => {
5265 assert_eq!(name, "http-server");
5266 assert_eq!(url, "https://api.example.com");
5267 assert_eq!(headers.len(), 2);
5268 assert_eq!(headers[0].name, "Authorization");
5269 assert_eq!(headers[0].value, "Bearer token123");
5270 assert_eq!(headers[1].name, "Content-Type");
5271 assert_eq!(headers[1].value, "application/json");
5272 }
5273 _ => panic!("Expected Http variant"),
5274 }
5275 }
5276
5277 #[cfg(feature = "unstable_mcp_over_acp")]
5278 #[test]
5279 fn test_mcp_server_acp_serialization() {
5280 let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id"));
5281
5282 let json = serde_json::to_value(&server).unwrap();
5283 assert_eq!(
5284 json,
5285 json!({
5286 "type": "acp",
5287 "name": "project-tools",
5288 "id": "project-tools-id"
5289 })
5290 );
5291
5292 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5293 match deserialized {
5294 McpServer::Acp(McpServerAcp { name, id, meta: _ }) => {
5295 assert_eq!(name, "project-tools");
5296 assert_eq!(id, McpServerAcpId::new("project-tools-id"));
5297 }
5298 _ => panic!("Expected Acp variant"),
5299 }
5300 }
5301
5302 #[cfg(feature = "unstable_mcp_over_acp")]
5303 #[test]
5304 fn test_client_mcp_message_method_names() {
5305 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5306
5307 assert_eq!(
5308 ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
5309 .method(),
5310 "mcp/message"
5311 );
5312 assert_eq!(
5313 ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
5314 "conn-1",
5315 "notifications/progress"
5316 ))
5317 .method(),
5318 "mcp/message"
5319 );
5320 }
5321
5322 #[cfg(feature = "unstable_mcp_over_acp")]
5323 #[test]
5324 fn test_mcp_server_acp_schema() {
5325 let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap();
5326 assert!(json_contains_entry(
5327 &mcp_server_schema,
5328 "const",
5329 &json!("acp")
5330 ));
5331 assert!(json_contains_entry(
5332 &mcp_server_schema,
5333 "$ref",
5334 &json!("#/$defs/McpServerAcp")
5335 ));
5336
5337 let capabilities_schema =
5338 serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap();
5339 assert!(json_contains_key(&capabilities_schema, "acp"));
5340 }
5341
5342 #[cfg(feature = "unstable_mcp_over_acp")]
5343 fn json_contains_entry(
5344 value: &serde_json::Value,
5345 key: &str,
5346 expected: &serde_json::Value,
5347 ) -> bool {
5348 match value {
5349 serde_json::Value::Object(map) => {
5350 map.get(key) == Some(expected)
5351 || map
5352 .values()
5353 .any(|value| json_contains_entry(value, key, expected))
5354 }
5355 serde_json::Value::Array(values) => values
5356 .iter()
5357 .any(|value| json_contains_entry(value, key, expected)),
5358 _ => false,
5359 }
5360 }
5361
5362 #[cfg(feature = "unstable_mcp_over_acp")]
5363 fn json_contains_key(value: &serde_json::Value, key: &str) -> bool {
5364 match value {
5365 serde_json::Value::Object(map) => {
5366 map.contains_key(key) || map.values().any(|value| json_contains_key(value, key))
5367 }
5368 serde_json::Value::Array(values) => {
5369 values.iter().any(|value| json_contains_key(value, key))
5370 }
5371 _ => false,
5372 }
5373 }
5374
5375 #[test]
5376 fn test_mcp_server_sse_serialization() {
5377 let server = McpServer::Sse(
5378 McpServerSse::new("sse-server", "https://sse.example.com/events")
5379 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5380 );
5381
5382 let json = serde_json::to_value(&server).unwrap();
5383 assert_eq!(
5384 json,
5385 json!({
5386 "type": "sse",
5387 "name": "sse-server",
5388 "url": "https://sse.example.com/events",
5389 "headers": [
5390 {
5391 "name": "X-API-Key",
5392 "value": "apikey456"
5393 }
5394 ]
5395 })
5396 );
5397
5398 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5399 match deserialized {
5400 McpServer::Sse(McpServerSse {
5401 name,
5402 url,
5403 headers,
5404 meta: _,
5405 }) => {
5406 assert_eq!(name, "sse-server");
5407 assert_eq!(url, "https://sse.example.com/events");
5408 assert_eq!(headers.len(), 1);
5409 assert_eq!(headers[0].name, "X-API-Key");
5410 assert_eq!(headers[0].value, "apikey456");
5411 }
5412 _ => panic!("Expected Sse variant"),
5413 }
5414 }
5415
5416 #[test]
5417 fn test_session_config_option_category_known_variants() {
5418 assert_eq!(
5420 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5421 json!("mode")
5422 );
5423 assert_eq!(
5424 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5425 json!("model")
5426 );
5427 assert_eq!(
5428 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5429 json!("thought_level")
5430 );
5431
5432 assert_eq!(
5434 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5435 SessionConfigOptionCategory::Mode
5436 );
5437 assert_eq!(
5438 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5439 SessionConfigOptionCategory::Model
5440 );
5441 assert_eq!(
5442 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5443 SessionConfigOptionCategory::ThoughtLevel
5444 );
5445 }
5446
5447 #[test]
5448 fn test_session_config_option_category_unknown_variants() {
5449 let unknown: SessionConfigOptionCategory =
5451 serde_json::from_str("\"some_future_category\"").unwrap();
5452 assert_eq!(
5453 unknown,
5454 SessionConfigOptionCategory::Other("some_future_category".to_string())
5455 );
5456
5457 let json = serde_json::to_value(&unknown).unwrap();
5459 assert_eq!(json, json!("some_future_category"));
5460 }
5461
5462 #[test]
5463 fn test_session_config_option_category_custom_categories() {
5464 let custom: SessionConfigOptionCategory =
5466 serde_json::from_str("\"_my_custom_category\"").unwrap();
5467 assert_eq!(
5468 custom,
5469 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5470 );
5471
5472 let json = serde_json::to_value(&custom).unwrap();
5474 assert_eq!(json, json!("_my_custom_category"));
5475
5476 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5478 assert_eq!(
5479 deserialized,
5480 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5481 );
5482 }
5483
5484 #[test]
5485 fn test_auth_method_agent_serialization() {
5486 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5487
5488 let json = serde_json::to_value(&method).unwrap();
5489 assert_eq!(
5490 json,
5491 json!({
5492 "id": "default-auth",
5493 "name": "Default Auth"
5494 })
5495 );
5496 assert!(!json.as_object().unwrap().contains_key("description"));
5498 assert!(!json.as_object().unwrap().contains_key("type"));
5500
5501 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5502 match deserialized {
5503 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5504 assert_eq!(id.0.as_ref(), "default-auth");
5505 assert_eq!(name, "Default Auth");
5506 }
5507 #[cfg(feature = "unstable_auth_methods")]
5508 _ => panic!("Expected Agent variant"),
5509 }
5510 }
5511
5512 #[test]
5513 fn test_auth_method_explicit_agent_deserialization() {
5514 let json = json!({
5516 "id": "agent-auth",
5517 "name": "Agent Auth",
5518 "type": "agent"
5519 });
5520
5521 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5522 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5523 }
5524
5525 #[cfg(feature = "unstable_session_additional_directories")]
5526 #[test]
5527 fn test_session_additional_directories_serialization() {
5528 assert_eq!(
5529 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5530 json!({
5531 "cwd": "/home/user/project",
5532 "mcpServers": []
5533 })
5534 );
5535 assert_eq!(
5536 serde_json::to_value(
5537 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5538 PathBuf::from("/home/user/shared-lib"),
5539 PathBuf::from("/home/user/product-docs"),
5540 ])
5541 )
5542 .unwrap(),
5543 json!({
5544 "cwd": "/home/user/project",
5545 "additionalDirectories": [
5546 "/home/user/shared-lib",
5547 "/home/user/product-docs"
5548 ],
5549 "mcpServers": []
5550 })
5551 );
5552 assert_eq!(
5553 serde_json::to_value(
5554 ListSessionsRequest::new().additional_directories(Vec::<PathBuf>::new())
5555 )
5556 .unwrap(),
5557 json!({})
5558 );
5559 assert_eq!(
5560 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5561 json!({
5562 "sessionId": "sess_abc123",
5563 "cwd": "/home/user/project"
5564 })
5565 );
5566 assert_eq!(
5567 serde_json::to_value(
5568 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5569 PathBuf::from("/home/user/shared-lib"),
5570 PathBuf::from("/home/user/product-docs"),
5571 ])
5572 )
5573 .unwrap(),
5574 json!({
5575 "sessionId": "sess_abc123",
5576 "cwd": "/home/user/project",
5577 "additionalDirectories": [
5578 "/home/user/shared-lib",
5579 "/home/user/product-docs"
5580 ]
5581 })
5582 );
5583 assert_eq!(
5584 serde_json::from_value::<SessionInfo>(json!({
5585 "sessionId": "sess_abc123",
5586 "cwd": "/home/user/project"
5587 }))
5588 .unwrap()
5589 .additional_directories,
5590 Vec::<PathBuf>::new()
5591 );
5592
5593 assert_eq!(
5594 serde_json::from_value::<ListSessionsRequest>(json!({}))
5595 .unwrap()
5596 .additional_directories,
5597 Vec::<PathBuf>::new()
5598 );
5599
5600 assert_eq!(
5601 serde_json::from_value::<ListSessionsRequest>(json!({
5602 "additionalDirectories": []
5603 }))
5604 .unwrap()
5605 .additional_directories,
5606 Vec::<PathBuf>::new()
5607 );
5608 }
5609
5610 #[cfg(feature = "unstable_session_additional_directories")]
5611 #[test]
5612 fn test_session_additional_directories_capabilities_serialization() {
5613 assert_eq!(
5614 serde_json::to_value(
5615 SessionCapabilities::new()
5616 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5617 )
5618 .unwrap(),
5619 json!({
5620 "additionalDirectories": {}
5621 })
5622 );
5623 }
5624
5625 #[cfg(feature = "unstable_auth_methods")]
5626 #[test]
5627 fn test_auth_method_env_var_serialization() {
5628 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5629 "api-key",
5630 "API Key",
5631 vec![AuthEnvVar::new("API_KEY")],
5632 ));
5633
5634 let json = serde_json::to_value(&method).unwrap();
5635 assert_eq!(
5636 json,
5637 json!({
5638 "id": "api-key",
5639 "name": "API Key",
5640 "type": "env_var",
5641 "vars": [{"name": "API_KEY"}]
5642 })
5643 );
5644 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5646 assert!(
5647 !json["vars"][0]
5648 .as_object()
5649 .unwrap()
5650 .contains_key("optional")
5651 );
5652
5653 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5654 match deserialized {
5655 AuthMethod::EnvVar(AuthMethodEnvVar {
5656 id,
5657 name: method_name,
5658 vars,
5659 link,
5660 ..
5661 }) => {
5662 assert_eq!(id.0.as_ref(), "api-key");
5663 assert_eq!(method_name, "API Key");
5664 assert_eq!(vars.len(), 1);
5665 assert_eq!(vars[0].name, "API_KEY");
5666 assert!(vars[0].secret);
5667 assert!(!vars[0].optional);
5668 assert!(link.is_none());
5669 }
5670 _ => panic!("Expected EnvVar variant"),
5671 }
5672 }
5673
5674 #[cfg(feature = "unstable_auth_methods")]
5675 #[test]
5676 fn test_auth_method_env_var_with_link_serialization() {
5677 let method = AuthMethod::EnvVar(
5678 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5679 .link("https://example.com/keys"),
5680 );
5681
5682 let json = serde_json::to_value(&method).unwrap();
5683 assert_eq!(
5684 json,
5685 json!({
5686 "id": "api-key",
5687 "name": "API Key",
5688 "type": "env_var",
5689 "vars": [{"name": "API_KEY"}],
5690 "link": "https://example.com/keys"
5691 })
5692 );
5693
5694 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5695 match deserialized {
5696 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5697 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5698 }
5699 _ => panic!("Expected EnvVar variant"),
5700 }
5701 }
5702
5703 #[cfg(feature = "unstable_auth_methods")]
5704 #[test]
5705 fn test_auth_method_env_var_multiple_vars() {
5706 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5707 "azure-openai",
5708 "Azure OpenAI",
5709 vec![
5710 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5711 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5712 .label("Endpoint URL")
5713 .secret(false),
5714 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5715 .label("API Version")
5716 .secret(false)
5717 .optional(true),
5718 ],
5719 ));
5720
5721 let json = serde_json::to_value(&method).unwrap();
5722 assert_eq!(
5723 json,
5724 json!({
5725 "id": "azure-openai",
5726 "name": "Azure OpenAI",
5727 "type": "env_var",
5728 "vars": [
5729 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5730 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5731 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5732 ]
5733 })
5734 );
5735
5736 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5737 match deserialized {
5738 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5739 assert_eq!(vars.len(), 3);
5740 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5742 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5743 assert!(vars[0].secret);
5744 assert!(!vars[0].optional);
5745 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5747 assert!(!vars[1].secret);
5748 assert!(!vars[1].optional);
5749 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5751 assert!(!vars[2].secret);
5752 assert!(vars[2].optional);
5753 }
5754 _ => panic!("Expected EnvVar variant"),
5755 }
5756 }
5757
5758 #[cfg(feature = "unstable_auth_methods")]
5759 #[test]
5760 fn test_auth_method_terminal_serialization() {
5761 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5762
5763 let json = serde_json::to_value(&method).unwrap();
5764 assert_eq!(
5765 json,
5766 json!({
5767 "id": "tui-auth",
5768 "name": "Terminal Auth",
5769 "type": "terminal"
5770 })
5771 );
5772 assert!(!json.as_object().unwrap().contains_key("args"));
5774 assert!(!json.as_object().unwrap().contains_key("env"));
5775
5776 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5777 match deserialized {
5778 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5779 assert!(args.is_empty());
5780 assert!(env.is_empty());
5781 }
5782 _ => panic!("Expected Terminal variant"),
5783 }
5784 }
5785
5786 #[cfg(feature = "unstable_auth_methods")]
5787 #[test]
5788 fn test_auth_method_terminal_with_args_and_env_serialization() {
5789 use std::collections::HashMap;
5790
5791 let mut env = HashMap::new();
5792 env.insert("TERM".to_string(), "xterm-256color".to_string());
5793
5794 let method = AuthMethod::Terminal(
5795 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5796 .args(vec!["--interactive".to_string(), "--color".to_string()])
5797 .env(env),
5798 );
5799
5800 let json = serde_json::to_value(&method).unwrap();
5801 assert_eq!(
5802 json,
5803 json!({
5804 "id": "tui-auth",
5805 "name": "Terminal Auth",
5806 "type": "terminal",
5807 "args": ["--interactive", "--color"],
5808 "env": {
5809 "TERM": "xterm-256color"
5810 }
5811 })
5812 );
5813
5814 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5815 match deserialized {
5816 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5817 assert_eq!(args, vec!["--interactive", "--color"]);
5818 assert_eq!(env.len(), 1);
5819 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5820 }
5821 _ => panic!("Expected Terminal variant"),
5822 }
5823 }
5824
5825 #[cfg(feature = "unstable_boolean_config")]
5826 #[test]
5827 fn test_session_config_option_value_id_serialize() {
5828 let val = SessionConfigOptionValue::value_id("model-1");
5829 let json = serde_json::to_value(&val).unwrap();
5830 assert_eq!(json, json!({ "value": "model-1" }));
5832 assert!(!json.as_object().unwrap().contains_key("type"));
5833 }
5834
5835 #[cfg(feature = "unstable_boolean_config")]
5836 #[test]
5837 fn test_session_config_option_value_boolean_serialize() {
5838 let val = SessionConfigOptionValue::boolean(true);
5839 let json = serde_json::to_value(&val).unwrap();
5840 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5841 }
5842
5843 #[cfg(feature = "unstable_boolean_config")]
5844 #[test]
5845 fn test_session_config_option_value_deserialize_no_type() {
5846 let json = json!({ "value": "model-1" });
5848 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5849 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5850 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5851 }
5852
5853 #[cfg(feature = "unstable_boolean_config")]
5854 #[test]
5855 fn test_session_config_option_value_deserialize_boolean() {
5856 let json = json!({ "type": "boolean", "value": true });
5857 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5858 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5859 assert_eq!(val.as_bool(), Some(true));
5860 }
5861
5862 #[cfg(feature = "unstable_boolean_config")]
5863 #[test]
5864 fn test_session_config_option_value_deserialize_boolean_false() {
5865 let json = json!({ "type": "boolean", "value": false });
5866 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5867 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5868 assert_eq!(val.as_bool(), Some(false));
5869 }
5870
5871 #[cfg(feature = "unstable_boolean_config")]
5872 #[test]
5873 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5874 let json = json!({ "type": "text", "value": "freeform input" });
5876 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5877 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5878 }
5879
5880 #[cfg(feature = "unstable_boolean_config")]
5881 #[test]
5882 fn test_session_config_option_value_roundtrip_value_id() {
5883 let original = SessionConfigOptionValue::value_id("option-a");
5884 let json = serde_json::to_value(&original).unwrap();
5885 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5886 assert_eq!(original, roundtripped);
5887 }
5888
5889 #[cfg(feature = "unstable_boolean_config")]
5890 #[test]
5891 fn test_session_config_option_value_roundtrip_boolean() {
5892 let original = SessionConfigOptionValue::boolean(false);
5893 let json = serde_json::to_value(&original).unwrap();
5894 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5895 assert_eq!(original, roundtripped);
5896 }
5897
5898 #[cfg(feature = "unstable_boolean_config")]
5899 #[test]
5900 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5901 let json = json!({ "type": "boolean", "value": "not a bool" });
5903 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5904 assert!(result.is_ok());
5906 assert_eq!(
5907 result.unwrap().as_value_id().unwrap().to_string(),
5908 "not a bool"
5909 );
5910 }
5911
5912 #[cfg(feature = "unstable_boolean_config")]
5913 #[test]
5914 fn test_session_config_option_value_from_impls() {
5915 let from_str: SessionConfigOptionValue = "model-1".into();
5916 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5917
5918 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5919 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5920
5921 let from_bool: SessionConfigOptionValue = true.into();
5922 assert_eq!(from_bool.as_bool(), Some(true));
5923 }
5924
5925 #[cfg(feature = "unstable_boolean_config")]
5926 #[test]
5927 fn test_set_session_config_option_request_value_id() {
5928 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5929 let json = serde_json::to_value(&req).unwrap();
5930 assert_eq!(
5931 json,
5932 json!({
5933 "sessionId": "sess_1",
5934 "configId": "model",
5935 "value": "model-1"
5936 })
5937 );
5938 assert!(!json.as_object().unwrap().contains_key("type"));
5940 }
5941
5942 #[cfg(feature = "unstable_boolean_config")]
5943 #[test]
5944 fn test_set_session_config_option_request_boolean() {
5945 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5946 let json = serde_json::to_value(&req).unwrap();
5947 assert_eq!(
5948 json,
5949 json!({
5950 "sessionId": "sess_1",
5951 "configId": "brave_mode",
5952 "type": "boolean",
5953 "value": true
5954 })
5955 );
5956 }
5957
5958 #[cfg(feature = "unstable_boolean_config")]
5959 #[test]
5960 fn test_set_session_config_option_request_deserialize_no_type() {
5961 let json = json!({
5963 "sessionId": "sess_1",
5964 "configId": "model",
5965 "value": "model-1"
5966 });
5967 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5968 assert_eq!(req.session_id.to_string(), "sess_1");
5969 assert_eq!(req.config_id.to_string(), "model");
5970 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5971 }
5972
5973 #[cfg(feature = "unstable_boolean_config")]
5974 #[test]
5975 fn test_set_session_config_option_request_deserialize_boolean() {
5976 let json = json!({
5977 "sessionId": "sess_1",
5978 "configId": "brave_mode",
5979 "type": "boolean",
5980 "value": true
5981 });
5982 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5983 assert_eq!(req.value.as_bool(), Some(true));
5984 }
5985
5986 #[cfg(feature = "unstable_boolean_config")]
5987 #[test]
5988 fn test_set_session_config_option_request_roundtrip_value_id() {
5989 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5990 let json = serde_json::to_value(&original).unwrap();
5991 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5992 assert_eq!(original, roundtripped);
5993 }
5994
5995 #[cfg(feature = "unstable_boolean_config")]
5996 #[test]
5997 fn test_set_session_config_option_request_roundtrip_boolean() {
5998 let original = SetSessionConfigOptionRequest::new("s", "c", false);
5999 let json = serde_json::to_value(&original).unwrap();
6000 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6001 assert_eq!(original, roundtripped);
6002 }
6003
6004 #[cfg(feature = "unstable_boolean_config")]
6005 #[test]
6006 fn test_session_config_boolean_serialization() {
6007 let cfg = SessionConfigBoolean::new(true);
6008 let json = serde_json::to_value(&cfg).unwrap();
6009 assert_eq!(json, json!({ "currentValue": true }));
6010
6011 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6012 assert!(deserialized.current_value);
6013 }
6014
6015 #[cfg(feature = "unstable_boolean_config")]
6016 #[test]
6017 fn test_session_config_option_boolean_variant() {
6018 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6019 .description("Skip confirmation prompts");
6020 let json = serde_json::to_value(&opt).unwrap();
6021 assert_eq!(
6022 json,
6023 json!({
6024 "id": "brave_mode",
6025 "name": "Brave Mode",
6026 "description": "Skip confirmation prompts",
6027 "type": "boolean",
6028 "currentValue": false
6029 })
6030 );
6031
6032 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6033 assert_eq!(deserialized.id.to_string(), "brave_mode");
6034 assert_eq!(deserialized.name, "Brave Mode");
6035 match deserialized.kind {
6036 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6037 _ => panic!("Expected Boolean kind"),
6038 }
6039 }
6040
6041 #[cfg(feature = "unstable_boolean_config")]
6042 #[test]
6043 fn test_session_config_option_select_still_works() {
6044 let opt = SessionConfigOption::select(
6046 "model",
6047 "Model",
6048 "model-1",
6049 vec![
6050 SessionConfigSelectOption::new("model-1", "Model 1"),
6051 SessionConfigSelectOption::new("model-2", "Model 2"),
6052 ],
6053 );
6054 let json = serde_json::to_value(&opt).unwrap();
6055 assert_eq!(json["type"], "select");
6056 assert_eq!(json["currentValue"], "model-1");
6057 assert_eq!(json["options"].as_array().unwrap().len(), 2);
6058
6059 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6060 match deserialized.kind {
6061 SessionConfigKind::Select(ref s) => {
6062 assert_eq!(s.current_value.to_string(), "model-1");
6063 }
6064 _ => panic!("Expected Select kind"),
6065 }
6066 }
6067
6068 #[cfg(feature = "unstable_llm_providers")]
6069 #[test]
6070 fn test_llm_protocol_known_variants() {
6071 assert_eq!(
6072 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6073 json!("anthropic")
6074 );
6075 assert_eq!(
6076 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6077 json!("openai")
6078 );
6079 assert_eq!(
6080 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6081 json!("azure")
6082 );
6083 assert_eq!(
6084 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6085 json!("vertex")
6086 );
6087 assert_eq!(
6088 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6089 json!("bedrock")
6090 );
6091
6092 assert_eq!(
6093 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6094 LlmProtocol::Anthropic
6095 );
6096 assert_eq!(
6097 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6098 LlmProtocol::OpenAi
6099 );
6100 assert_eq!(
6101 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6102 LlmProtocol::Azure
6103 );
6104 assert_eq!(
6105 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6106 LlmProtocol::Vertex
6107 );
6108 assert_eq!(
6109 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6110 LlmProtocol::Bedrock
6111 );
6112 }
6113
6114 #[cfg(feature = "unstable_llm_providers")]
6115 #[test]
6116 fn test_llm_protocol_unknown_variant() {
6117 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6118 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6119
6120 let json = serde_json::to_value(&unknown).unwrap();
6121 assert_eq!(json, json!("cohere"));
6122 }
6123
6124 #[cfg(feature = "unstable_llm_providers")]
6125 #[test]
6126 fn test_provider_current_config_serialization() {
6127 let config =
6128 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6129
6130 let json = serde_json::to_value(&config).unwrap();
6131 assert_eq!(
6132 json,
6133 json!({
6134 "apiType": "anthropic",
6135 "baseUrl": "https://api.anthropic.com"
6136 })
6137 );
6138
6139 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6140 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6141 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6142 }
6143
6144 #[cfg(feature = "unstable_llm_providers")]
6145 #[test]
6146 fn test_provider_info_with_current_config() {
6147 let info = ProviderInfo::new(
6148 "main",
6149 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6150 true,
6151 Some(ProviderCurrentConfig::new(
6152 LlmProtocol::Anthropic,
6153 "https://api.anthropic.com",
6154 )),
6155 );
6156
6157 let json = serde_json::to_value(&info).unwrap();
6158 assert_eq!(
6159 json,
6160 json!({
6161 "id": "main",
6162 "supported": ["anthropic", "openai"],
6163 "required": true,
6164 "current": {
6165 "apiType": "anthropic",
6166 "baseUrl": "https://api.anthropic.com"
6167 }
6168 })
6169 );
6170
6171 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6172 assert_eq!(deserialized.id, "main");
6173 assert_eq!(deserialized.supported.len(), 2);
6174 assert!(deserialized.required);
6175 assert!(deserialized.current.is_some());
6176 assert_eq!(
6177 deserialized.current.as_ref().unwrap().api_type,
6178 LlmProtocol::Anthropic
6179 );
6180 }
6181
6182 #[cfg(feature = "unstable_llm_providers")]
6183 #[test]
6184 fn test_provider_info_disabled() {
6185 let info = ProviderInfo::new(
6186 "secondary",
6187 vec![LlmProtocol::OpenAi],
6188 false,
6189 None::<ProviderCurrentConfig>,
6190 );
6191
6192 let json = serde_json::to_value(&info).unwrap();
6193 assert_eq!(
6194 json,
6195 json!({
6196 "id": "secondary",
6197 "supported": ["openai"],
6198 "required": false
6199 })
6200 );
6201
6202 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6203 assert_eq!(deserialized.id, "secondary");
6204 assert!(!deserialized.required);
6205 assert!(deserialized.current.is_none());
6206 }
6207
6208 #[cfg(feature = "unstable_llm_providers")]
6209 #[test]
6210 fn test_provider_info_missing_current_defaults_to_none() {
6211 let json = json!({
6213 "id": "main",
6214 "supported": ["anthropic"],
6215 "required": true
6216 });
6217 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6218 assert!(deserialized.current.is_none());
6219 }
6220
6221 #[cfg(feature = "unstable_llm_providers")]
6222 #[test]
6223 fn test_provider_info_explicit_null_current_decodes_to_none() {
6224 let json = json!({
6228 "id": "main",
6229 "supported": ["anthropic"],
6230 "required": true,
6231 "current": null
6232 });
6233 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6234 assert!(deserialized.current.is_none());
6235 }
6236
6237 #[cfg(feature = "unstable_llm_providers")]
6238 #[test]
6239 fn test_list_providers_response_serialization() {
6240 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6241 "main",
6242 vec![LlmProtocol::Anthropic],
6243 true,
6244 Some(ProviderCurrentConfig::new(
6245 LlmProtocol::Anthropic,
6246 "https://api.anthropic.com",
6247 )),
6248 )]);
6249
6250 let json = serde_json::to_value(&response).unwrap();
6251 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6252 assert_eq!(json["providers"][0]["id"], "main");
6253
6254 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6255 assert_eq!(deserialized.providers.len(), 1);
6256 }
6257
6258 #[cfg(feature = "unstable_llm_providers")]
6259 #[test]
6260 fn test_set_providers_request_serialization() {
6261 use std::collections::HashMap;
6262
6263 let mut headers = HashMap::new();
6264 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6265
6266 let request =
6267 SetProvidersRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6268 .headers(headers);
6269
6270 let json = serde_json::to_value(&request).unwrap();
6271 assert_eq!(
6272 json,
6273 json!({
6274 "id": "main",
6275 "apiType": "openai",
6276 "baseUrl": "https://api.openai.com/v1",
6277 "headers": {
6278 "Authorization": "Bearer sk-test"
6279 }
6280 })
6281 );
6282
6283 let deserialized: SetProvidersRequest = serde_json::from_value(json).unwrap();
6284 assert_eq!(deserialized.id, "main");
6285 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6286 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6287 assert_eq!(deserialized.headers.len(), 1);
6288 assert_eq!(
6289 deserialized.headers.get("Authorization").unwrap(),
6290 "Bearer sk-test"
6291 );
6292 }
6293
6294 #[cfg(feature = "unstable_llm_providers")]
6295 #[test]
6296 fn test_set_providers_request_omits_empty_headers() {
6297 let request =
6298 SetProvidersRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6299
6300 let json = serde_json::to_value(&request).unwrap();
6301 assert!(!json.as_object().unwrap().contains_key("headers"));
6303 }
6304
6305 #[cfg(feature = "unstable_llm_providers")]
6306 #[test]
6307 fn test_disable_providers_request_serialization() {
6308 let request = DisableProvidersRequest::new("secondary");
6309
6310 let json = serde_json::to_value(&request).unwrap();
6311 assert_eq!(json, json!({ "id": "secondary" }));
6312
6313 let deserialized: DisableProvidersRequest = serde_json::from_value(json).unwrap();
6314 assert_eq!(deserialized.id, "secondary");
6315 }
6316
6317 #[cfg(feature = "unstable_llm_providers")]
6318 #[test]
6319 fn test_providers_capabilities_serialization() {
6320 let caps = ProvidersCapabilities::new();
6321
6322 let json = serde_json::to_value(&caps).unwrap();
6323 assert_eq!(json, json!({}));
6324
6325 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6326 assert!(deserialized.meta.is_none());
6327 }
6328
6329 #[cfg(feature = "unstable_llm_providers")]
6330 #[test]
6331 fn test_agent_capabilities_with_providers() {
6332 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6333
6334 let json = serde_json::to_value(&caps).unwrap();
6335 assert_eq!(json["providers"], json!({}));
6336
6337 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6338 assert!(deserialized.providers.is_some());
6339 }
6340}