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 #[schemars(extend("x-deserialize-default-on-error" = true))]
66 #[serde(default)]
67 pub client_info: Option<Implementation>,
68 #[serde(rename = "_meta")]
74 pub meta: Option<Meta>,
75}
76
77impl InitializeRequest {
78 #[must_use]
79 pub fn new(protocol_version: ProtocolVersion) -> Self {
80 Self {
81 protocol_version,
82 client_capabilities: ClientCapabilities::default(),
83 client_info: None,
84 meta: None,
85 }
86 }
87
88 #[must_use]
90 pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
91 self.client_capabilities = client_capabilities;
92 self
93 }
94
95 #[must_use]
97 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
98 self.client_info = client_info.into_option();
99 self
100 }
101
102 #[must_use]
108 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
109 self.meta = meta.into_option();
110 self
111 }
112}
113
114#[serde_as]
120#[skip_serializing_none]
121#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
122#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
123#[serde(rename_all = "camelCase")]
124#[non_exhaustive]
125pub struct InitializeResponse {
126 pub protocol_version: ProtocolVersion,
131 #[serde(default)]
133 pub agent_capabilities: AgentCapabilities,
134 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
136 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
137 #[serde(default)]
138 pub auth_methods: Vec<AuthMethod>,
139 #[serde_as(deserialize_as = "DefaultOnError")]
143 #[schemars(extend("x-deserialize-default-on-error" = true))]
144 #[serde(default)]
145 pub agent_info: Option<Implementation>,
146 #[serde(rename = "_meta")]
152 pub meta: Option<Meta>,
153}
154
155impl InitializeResponse {
156 #[must_use]
157 pub fn new(protocol_version: ProtocolVersion) -> Self {
158 Self {
159 protocol_version,
160 agent_capabilities: AgentCapabilities::default(),
161 auth_methods: vec![],
162 agent_info: None,
163 meta: None,
164 }
165 }
166
167 #[must_use]
169 pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
170 self.agent_capabilities = agent_capabilities;
171 self
172 }
173
174 #[must_use]
176 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
177 self.auth_methods = auth_methods;
178 self
179 }
180
181 #[must_use]
183 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
184 self.agent_info = agent_info.into_option();
185 self
186 }
187
188 #[must_use]
194 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
195 self.meta = meta.into_option();
196 self
197 }
198}
199
200#[skip_serializing_none]
204#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
205#[serde(rename_all = "camelCase")]
206#[non_exhaustive]
207pub struct Implementation {
208 pub name: String,
211 pub title: Option<String>,
216 pub version: String,
219 #[serde(rename = "_meta")]
225 pub meta: Option<Meta>,
226}
227
228impl Implementation {
229 #[must_use]
230 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
231 Self {
232 name: name.into(),
233 title: None,
234 version: version.into(),
235 meta: None,
236 }
237 }
238
239 #[must_use]
244 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
245 self.title = title.into_option();
246 self
247 }
248
249 #[must_use]
255 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
256 self.meta = meta.into_option();
257 self
258 }
259}
260
261#[skip_serializing_none]
267#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
268#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
269#[serde(rename_all = "camelCase")]
270#[non_exhaustive]
271pub struct AuthenticateRequest {
272 pub method_id: AuthMethodId,
275 #[serde(rename = "_meta")]
281 pub meta: Option<Meta>,
282}
283
284impl AuthenticateRequest {
285 #[must_use]
286 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
287 Self {
288 method_id: method_id.into(),
289 meta: None,
290 }
291 }
292
293 #[must_use]
299 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
300 self.meta = meta.into_option();
301 self
302 }
303}
304
305#[skip_serializing_none]
307#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
308#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
309#[serde(rename_all = "camelCase")]
310#[non_exhaustive]
311pub struct AuthenticateResponse {
312 #[serde(rename = "_meta")]
318 pub meta: Option<Meta>,
319}
320
321impl AuthenticateResponse {
322 #[must_use]
323 pub fn new() -> Self {
324 Self::default()
325 }
326
327 #[must_use]
333 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
334 self.meta = meta.into_option();
335 self
336 }
337}
338
339#[skip_serializing_none]
345#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
346#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
347#[serde(rename_all = "camelCase")]
348#[non_exhaustive]
349pub struct LogoutRequest {
350 #[serde(rename = "_meta")]
356 pub meta: Option<Meta>,
357}
358
359impl LogoutRequest {
360 #[must_use]
361 pub fn new() -> Self {
362 Self::default()
363 }
364
365 #[must_use]
371 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
372 self.meta = meta.into_option();
373 self
374 }
375}
376
377#[skip_serializing_none]
379#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
380#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
381#[serde(rename_all = "camelCase")]
382#[non_exhaustive]
383pub struct LogoutResponse {
384 #[serde(rename = "_meta")]
390 pub meta: Option<Meta>,
391}
392
393impl LogoutResponse {
394 #[must_use]
395 pub fn new() -> Self {
396 Self::default()
397 }
398
399 #[must_use]
405 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
406 self.meta = meta.into_option();
407 self
408 }
409}
410
411#[serde_as]
413#[skip_serializing_none]
414#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
415#[serde(rename_all = "camelCase")]
416#[non_exhaustive]
417pub struct AgentAuthCapabilities {
418 #[serde_as(deserialize_as = "DefaultOnError")]
422 #[schemars(extend("x-deserialize-default-on-error" = true))]
423 #[serde(default)]
424 pub logout: Option<LogoutCapabilities>,
425 #[serde(rename = "_meta")]
431 pub meta: Option<Meta>,
432}
433
434impl AgentAuthCapabilities {
435 #[must_use]
436 pub fn new() -> Self {
437 Self::default()
438 }
439
440 #[must_use]
442 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
443 self.logout = logout.into_option();
444 self
445 }
446
447 #[must_use]
453 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
454 self.meta = meta.into_option();
455 self
456 }
457}
458
459#[skip_serializing_none]
463#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
464#[non_exhaustive]
465pub struct LogoutCapabilities {
466 #[serde(rename = "_meta")]
472 pub meta: Option<Meta>,
473}
474
475impl LogoutCapabilities {
476 #[must_use]
477 pub fn new() -> Self {
478 Self::default()
479 }
480
481 #[must_use]
487 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
488 self.meta = meta.into_option();
489 self
490 }
491}
492
493#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
494#[serde(transparent)]
495#[from(Arc<str>, String, &'static str)]
496#[non_exhaustive]
497pub struct AuthMethodId(pub Arc<str>);
498
499impl AuthMethodId {
500 #[must_use]
501 pub fn new(id: impl Into<Arc<str>>) -> Self {
502 Self(id.into())
503 }
504}
505
506#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
511#[serde(tag = "type", rename_all = "snake_case")]
512#[non_exhaustive]
513pub enum AuthMethod {
514 #[cfg(feature = "unstable_auth_methods")]
520 EnvVar(AuthMethodEnvVar),
521 #[cfg(feature = "unstable_auth_methods")]
527 Terminal(AuthMethodTerminal),
528 #[serde(untagged)]
532 Agent(AuthMethodAgent),
533}
534
535impl AuthMethod {
536 #[must_use]
538 pub fn id(&self) -> &AuthMethodId {
539 match self {
540 Self::Agent(a) => &a.id,
541 #[cfg(feature = "unstable_auth_methods")]
542 Self::EnvVar(e) => &e.id,
543 #[cfg(feature = "unstable_auth_methods")]
544 Self::Terminal(t) => &t.id,
545 }
546 }
547
548 #[must_use]
550 pub fn name(&self) -> &str {
551 match self {
552 Self::Agent(a) => &a.name,
553 #[cfg(feature = "unstable_auth_methods")]
554 Self::EnvVar(e) => &e.name,
555 #[cfg(feature = "unstable_auth_methods")]
556 Self::Terminal(t) => &t.name,
557 }
558 }
559
560 #[must_use]
562 pub fn description(&self) -> Option<&str> {
563 match self {
564 Self::Agent(a) => a.description.as_deref(),
565 #[cfg(feature = "unstable_auth_methods")]
566 Self::EnvVar(e) => e.description.as_deref(),
567 #[cfg(feature = "unstable_auth_methods")]
568 Self::Terminal(t) => t.description.as_deref(),
569 }
570 }
571
572 #[must_use]
578 pub fn meta(&self) -> Option<&Meta> {
579 match self {
580 Self::Agent(a) => a.meta.as_ref(),
581 #[cfg(feature = "unstable_auth_methods")]
582 Self::EnvVar(e) => e.meta.as_ref(),
583 #[cfg(feature = "unstable_auth_methods")]
584 Self::Terminal(t) => t.meta.as_ref(),
585 }
586 }
587}
588
589#[skip_serializing_none]
593#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
594#[serde(rename_all = "camelCase")]
595#[non_exhaustive]
596pub struct AuthMethodAgent {
597 pub id: AuthMethodId,
599 pub name: String,
601 pub description: Option<String>,
603 #[serde(rename = "_meta")]
609 pub meta: Option<Meta>,
610}
611
612impl AuthMethodAgent {
613 #[must_use]
614 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
615 Self {
616 id: id.into(),
617 name: name.into(),
618 description: None,
619 meta: None,
620 }
621 }
622
623 #[must_use]
625 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
626 self.description = description.into_option();
627 self
628 }
629
630 #[must_use]
636 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
637 self.meta = meta.into_option();
638 self
639 }
640}
641
642#[cfg(feature = "unstable_auth_methods")]
650#[skip_serializing_none]
651#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
652#[serde(rename_all = "camelCase")]
653#[non_exhaustive]
654pub struct AuthMethodEnvVar {
655 pub id: AuthMethodId,
657 pub name: String,
659 pub description: Option<String>,
661 pub vars: Vec<AuthEnvVar>,
663 pub link: Option<String>,
665 #[serde(rename = "_meta")]
671 pub meta: Option<Meta>,
672}
673
674#[cfg(feature = "unstable_auth_methods")]
675impl AuthMethodEnvVar {
676 #[must_use]
677 pub fn new(
678 id: impl Into<AuthMethodId>,
679 name: impl Into<String>,
680 vars: Vec<AuthEnvVar>,
681 ) -> Self {
682 Self {
683 id: id.into(),
684 name: name.into(),
685 description: None,
686 vars,
687 link: None,
688 meta: None,
689 }
690 }
691
692 #[must_use]
694 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
695 self.link = link.into_option();
696 self
697 }
698
699 #[must_use]
701 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
702 self.description = description.into_option();
703 self
704 }
705
706 #[must_use]
712 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
713 self.meta = meta.into_option();
714 self
715 }
716}
717
718#[cfg(feature = "unstable_auth_methods")]
724#[skip_serializing_none]
725#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
726#[serde(rename_all = "camelCase")]
727#[non_exhaustive]
728pub struct AuthEnvVar {
729 pub name: String,
731 pub label: Option<String>,
733 #[serde(default = "default_true", skip_serializing_if = "is_true")]
738 #[schemars(extend("default" = true))]
739 pub secret: bool,
740 #[serde(default, skip_serializing_if = "is_false")]
744 #[schemars(extend("default" = false))]
745 pub optional: bool,
746 #[serde(rename = "_meta")]
752 pub meta: Option<Meta>,
753}
754
755#[cfg(feature = "unstable_auth_methods")]
756fn default_true() -> bool {
757 true
758}
759
760#[cfg(feature = "unstable_auth_methods")]
761#[expect(clippy::trivially_copy_pass_by_ref)]
762fn is_true(v: &bool) -> bool {
763 *v
764}
765
766#[cfg(feature = "unstable_auth_methods")]
767#[expect(clippy::trivially_copy_pass_by_ref)]
768fn is_false(v: &bool) -> bool {
769 !*v
770}
771
772#[cfg(feature = "unstable_auth_methods")]
773impl AuthEnvVar {
774 #[must_use]
776 pub fn new(name: impl Into<String>) -> Self {
777 Self {
778 name: name.into(),
779 label: None,
780 secret: true,
781 optional: false,
782 meta: None,
783 }
784 }
785
786 #[must_use]
788 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
789 self.label = label.into_option();
790 self
791 }
792
793 #[must_use]
796 pub fn secret(mut self, secret: bool) -> Self {
797 self.secret = secret;
798 self
799 }
800
801 #[must_use]
803 pub fn optional(mut self, optional: bool) -> Self {
804 self.optional = optional;
805 self
806 }
807
808 #[must_use]
814 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
815 self.meta = meta.into_option();
816 self
817 }
818}
819
820#[cfg(feature = "unstable_auth_methods")]
828#[skip_serializing_none]
829#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
830#[serde(rename_all = "camelCase")]
831#[non_exhaustive]
832pub struct AuthMethodTerminal {
833 pub id: AuthMethodId,
835 pub name: String,
837 pub description: Option<String>,
839 #[serde(default, skip_serializing_if = "Vec::is_empty")]
841 pub args: Vec<String>,
842 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
844 pub env: HashMap<String, String>,
845 #[serde(rename = "_meta")]
851 pub meta: Option<Meta>,
852}
853
854#[cfg(feature = "unstable_auth_methods")]
855impl AuthMethodTerminal {
856 #[must_use]
857 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
858 Self {
859 id: id.into(),
860 name: name.into(),
861 description: None,
862 args: Vec::new(),
863 env: HashMap::new(),
864 meta: None,
865 }
866 }
867
868 #[must_use]
870 pub fn args(mut self, args: Vec<String>) -> Self {
871 self.args = args;
872 self
873 }
874
875 #[must_use]
877 pub fn env(mut self, env: HashMap<String, String>) -> Self {
878 self.env = env;
879 self
880 }
881
882 #[must_use]
884 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
885 self.description = description.into_option();
886 self
887 }
888
889 #[must_use]
895 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
896 self.meta = meta.into_option();
897 self
898 }
899}
900
901#[skip_serializing_none]
907#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
908#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
909#[serde(rename_all = "camelCase")]
910#[non_exhaustive]
911pub struct NewSessionRequest {
912 pub cwd: PathBuf,
914 #[serde(default, skip_serializing_if = "Vec::is_empty")]
920 pub additional_directories: Vec<PathBuf>,
921 pub mcp_servers: Vec<McpServer>,
923 #[serde(rename = "_meta")]
929 pub meta: Option<Meta>,
930}
931
932impl NewSessionRequest {
933 #[must_use]
934 pub fn new(cwd: impl Into<PathBuf>) -> Self {
935 Self {
936 cwd: cwd.into(),
937 additional_directories: vec![],
938 mcp_servers: vec![],
939 meta: None,
940 }
941 }
942
943 #[must_use]
945 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
946 self.additional_directories = additional_directories;
947 self
948 }
949
950 #[must_use]
952 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
953 self.mcp_servers = mcp_servers;
954 self
955 }
956
957 #[must_use]
963 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
964 self.meta = meta.into_option();
965 self
966 }
967}
968
969#[serde_as]
973#[skip_serializing_none]
974#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
975#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
976#[serde(rename_all = "camelCase")]
977#[non_exhaustive]
978pub struct NewSessionResponse {
979 pub session_id: SessionId,
983 #[serde_as(deserialize_as = "DefaultOnError")]
987 #[schemars(extend("x-deserialize-default-on-error" = true))]
988 #[serde(default)]
989 pub modes: Option<SessionModeState>,
990 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
992 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
993 #[serde(default)]
994 pub config_options: Option<Vec<SessionConfigOption>>,
995 #[serde(rename = "_meta")]
1001 pub meta: Option<Meta>,
1002}
1003
1004impl NewSessionResponse {
1005 #[must_use]
1006 pub fn new(session_id: impl Into<SessionId>) -> Self {
1007 Self {
1008 session_id: session_id.into(),
1009 modes: None,
1010 config_options: None,
1011 meta: None,
1012 }
1013 }
1014
1015 #[must_use]
1019 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1020 self.modes = modes.into_option();
1021 self
1022 }
1023
1024 #[must_use]
1026 pub fn config_options(
1027 mut self,
1028 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1029 ) -> Self {
1030 self.config_options = config_options.into_option();
1031 self
1032 }
1033
1034 #[must_use]
1040 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1041 self.meta = meta.into_option();
1042 self
1043 }
1044}
1045
1046#[skip_serializing_none]
1054#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1055#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1056#[serde(rename_all = "camelCase")]
1057#[non_exhaustive]
1058pub struct LoadSessionRequest {
1059 pub mcp_servers: Vec<McpServer>,
1061 pub cwd: PathBuf,
1063 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1070 pub additional_directories: Vec<PathBuf>,
1071 pub session_id: SessionId,
1073 #[serde(rename = "_meta")]
1079 pub meta: Option<Meta>,
1080}
1081
1082impl LoadSessionRequest {
1083 #[must_use]
1084 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1085 Self {
1086 mcp_servers: vec![],
1087 cwd: cwd.into(),
1088 additional_directories: vec![],
1089 session_id: session_id.into(),
1090 meta: None,
1091 }
1092 }
1093
1094 #[must_use]
1096 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1097 self.additional_directories = additional_directories;
1098 self
1099 }
1100
1101 #[must_use]
1103 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1104 self.mcp_servers = mcp_servers;
1105 self
1106 }
1107
1108 #[must_use]
1114 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1115 self.meta = meta.into_option();
1116 self
1117 }
1118}
1119
1120#[serde_as]
1122#[skip_serializing_none]
1123#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1124#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1125#[serde(rename_all = "camelCase")]
1126#[non_exhaustive]
1127pub struct LoadSessionResponse {
1128 #[serde_as(deserialize_as = "DefaultOnError")]
1132 #[schemars(extend("x-deserialize-default-on-error" = true))]
1133 #[serde(default)]
1134 pub modes: Option<SessionModeState>,
1135 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1137 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1138 #[serde(default)]
1139 pub config_options: Option<Vec<SessionConfigOption>>,
1140 #[serde(rename = "_meta")]
1146 pub meta: Option<Meta>,
1147}
1148
1149impl LoadSessionResponse {
1150 #[must_use]
1151 pub fn new() -> Self {
1152 Self::default()
1153 }
1154
1155 #[must_use]
1159 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1160 self.modes = modes.into_option();
1161 self
1162 }
1163
1164 #[must_use]
1166 pub fn config_options(
1167 mut self,
1168 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1169 ) -> Self {
1170 self.config_options = config_options.into_option();
1171 self
1172 }
1173
1174 #[must_use]
1180 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1181 self.meta = meta.into_option();
1182 self
1183 }
1184}
1185
1186#[cfg(feature = "unstable_session_fork")]
1199#[skip_serializing_none]
1200#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1201#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1202#[serde(rename_all = "camelCase")]
1203#[non_exhaustive]
1204pub struct ForkSessionRequest {
1205 pub session_id: SessionId,
1207 pub cwd: PathBuf,
1209 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1215 pub additional_directories: Vec<PathBuf>,
1216 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1218 pub mcp_servers: Vec<McpServer>,
1219 #[serde(rename = "_meta")]
1225 pub meta: Option<Meta>,
1226}
1227
1228#[cfg(feature = "unstable_session_fork")]
1229impl ForkSessionRequest {
1230 #[must_use]
1231 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1232 Self {
1233 session_id: session_id.into(),
1234 cwd: cwd.into(),
1235 additional_directories: vec![],
1236 mcp_servers: vec![],
1237 meta: None,
1238 }
1239 }
1240
1241 #[must_use]
1243 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1244 self.additional_directories = additional_directories;
1245 self
1246 }
1247
1248 #[must_use]
1250 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1251 self.mcp_servers = mcp_servers;
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")]
1273#[serde_as]
1274#[skip_serializing_none]
1275#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1276#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1277#[serde(rename_all = "camelCase")]
1278#[non_exhaustive]
1279pub struct ForkSessionResponse {
1280 pub session_id: SessionId,
1282 #[serde_as(deserialize_as = "DefaultOnError")]
1286 #[schemars(extend("x-deserialize-default-on-error" = true))]
1287 #[serde(default)]
1288 pub modes: Option<SessionModeState>,
1289 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1291 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1292 #[serde(default)]
1293 pub config_options: Option<Vec<SessionConfigOption>>,
1294 #[serde(rename = "_meta")]
1300 pub meta: Option<Meta>,
1301}
1302
1303#[cfg(feature = "unstable_session_fork")]
1304impl ForkSessionResponse {
1305 #[must_use]
1306 pub fn new(session_id: impl Into<SessionId>) -> Self {
1307 Self {
1308 session_id: session_id.into(),
1309 modes: None,
1310 config_options: None,
1311 meta: None,
1312 }
1313 }
1314
1315 #[must_use]
1319 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1320 self.modes = modes.into_option();
1321 self
1322 }
1323
1324 #[must_use]
1326 pub fn config_options(
1327 mut self,
1328 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1329 ) -> Self {
1330 self.config_options = config_options.into_option();
1331 self
1332 }
1333
1334 #[must_use]
1340 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1341 self.meta = meta.into_option();
1342 self
1343 }
1344}
1345
1346#[skip_serializing_none]
1355#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1356#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1357#[serde(rename_all = "camelCase")]
1358#[non_exhaustive]
1359pub struct ResumeSessionRequest {
1360 pub session_id: SessionId,
1362 pub cwd: PathBuf,
1364 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1371 pub additional_directories: Vec<PathBuf>,
1372 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1374 pub mcp_servers: Vec<McpServer>,
1375 #[serde(rename = "_meta")]
1381 pub meta: Option<Meta>,
1382}
1383
1384impl ResumeSessionRequest {
1385 #[must_use]
1386 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1387 Self {
1388 session_id: session_id.into(),
1389 cwd: cwd.into(),
1390 additional_directories: vec![],
1391 mcp_servers: vec![],
1392 meta: None,
1393 }
1394 }
1395
1396 #[must_use]
1398 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1399 self.additional_directories = additional_directories;
1400 self
1401 }
1402
1403 #[must_use]
1405 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1406 self.mcp_servers = mcp_servers;
1407 self
1408 }
1409
1410 #[must_use]
1416 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1417 self.meta = meta.into_option();
1418 self
1419 }
1420}
1421
1422#[serde_as]
1424#[skip_serializing_none]
1425#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1426#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1427#[serde(rename_all = "camelCase")]
1428#[non_exhaustive]
1429pub struct ResumeSessionResponse {
1430 #[serde_as(deserialize_as = "DefaultOnError")]
1434 #[schemars(extend("x-deserialize-default-on-error" = true))]
1435 #[serde(default)]
1436 pub modes: Option<SessionModeState>,
1437 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1439 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1440 #[serde(default)]
1441 pub config_options: Option<Vec<SessionConfigOption>>,
1442 #[serde(rename = "_meta")]
1448 pub meta: Option<Meta>,
1449}
1450
1451impl ResumeSessionResponse {
1452 #[must_use]
1453 pub fn new() -> Self {
1454 Self::default()
1455 }
1456
1457 #[must_use]
1461 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1462 self.modes = modes.into_option();
1463 self
1464 }
1465
1466 #[must_use]
1468 pub fn config_options(
1469 mut self,
1470 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1471 ) -> Self {
1472 self.config_options = config_options.into_option();
1473 self
1474 }
1475
1476 #[must_use]
1482 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1483 self.meta = meta.into_option();
1484 self
1485 }
1486}
1487
1488#[skip_serializing_none]
1498#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1499#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1500#[serde(rename_all = "camelCase")]
1501#[non_exhaustive]
1502pub struct CloseSessionRequest {
1503 pub session_id: SessionId,
1505 #[serde(rename = "_meta")]
1511 pub meta: Option<Meta>,
1512}
1513
1514impl CloseSessionRequest {
1515 #[must_use]
1516 pub fn new(session_id: impl Into<SessionId>) -> Self {
1517 Self {
1518 session_id: session_id.into(),
1519 meta: None,
1520 }
1521 }
1522
1523 #[must_use]
1529 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1530 self.meta = meta.into_option();
1531 self
1532 }
1533}
1534
1535#[skip_serializing_none]
1537#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1538#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1539#[serde(rename_all = "camelCase")]
1540#[non_exhaustive]
1541pub struct CloseSessionResponse {
1542 #[serde(rename = "_meta")]
1548 pub meta: Option<Meta>,
1549}
1550
1551impl CloseSessionResponse {
1552 #[must_use]
1553 pub fn new() -> Self {
1554 Self::default()
1555 }
1556
1557 #[must_use]
1563 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1564 self.meta = meta.into_option();
1565 self
1566 }
1567}
1568
1569#[skip_serializing_none]
1575#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1576#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1577#[serde(rename_all = "camelCase")]
1578#[non_exhaustive]
1579pub struct ListSessionsRequest {
1580 pub cwd: Option<PathBuf>,
1582 pub cursor: Option<String>,
1584 #[serde(rename = "_meta")]
1590 pub meta: Option<Meta>,
1591}
1592
1593impl ListSessionsRequest {
1594 #[must_use]
1595 pub fn new() -> Self {
1596 Self::default()
1597 }
1598
1599 #[must_use]
1601 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1602 self.cwd = cwd.into_option();
1603 self
1604 }
1605
1606 #[must_use]
1608 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1609 self.cursor = cursor.into_option();
1610 self
1611 }
1612
1613 #[must_use]
1619 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1620 self.meta = meta.into_option();
1621 self
1622 }
1623}
1624
1625#[serde_as]
1627#[skip_serializing_none]
1628#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1629#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1630#[serde(rename_all = "camelCase")]
1631#[non_exhaustive]
1632pub struct ListSessionsResponse {
1633 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1635 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1636 pub sessions: Vec<SessionInfo>,
1637 pub next_cursor: Option<String>,
1640 #[serde(rename = "_meta")]
1646 pub meta: Option<Meta>,
1647}
1648
1649impl ListSessionsResponse {
1650 #[must_use]
1651 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1652 Self {
1653 sessions,
1654 next_cursor: None,
1655 meta: None,
1656 }
1657 }
1658
1659 #[must_use]
1660 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1661 self.next_cursor = next_cursor.into_option();
1662 self
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#[cfg(feature = "unstable_session_delete")]
1687#[skip_serializing_none]
1688#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1689#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1690#[serde(rename_all = "camelCase")]
1691#[non_exhaustive]
1692pub struct DeleteSessionRequest {
1693 pub session_id: SessionId,
1695 #[serde(rename = "_meta")]
1701 pub meta: Option<Meta>,
1702}
1703
1704#[cfg(feature = "unstable_session_delete")]
1705impl DeleteSessionRequest {
1706 #[must_use]
1707 pub fn new(session_id: impl Into<SessionId>) -> Self {
1708 Self {
1709 session_id: session_id.into(),
1710 meta: None,
1711 }
1712 }
1713
1714 #[must_use]
1720 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1721 self.meta = meta.into_option();
1722 self
1723 }
1724}
1725
1726#[cfg(feature = "unstable_session_delete")]
1732#[skip_serializing_none]
1733#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1734#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1735#[serde(rename_all = "camelCase")]
1736#[non_exhaustive]
1737pub struct DeleteSessionResponse {
1738 #[serde(rename = "_meta")]
1744 pub meta: Option<Meta>,
1745}
1746
1747#[cfg(feature = "unstable_session_delete")]
1748impl DeleteSessionResponse {
1749 #[must_use]
1750 pub fn new() -> Self {
1751 Self::default()
1752 }
1753
1754 #[must_use]
1760 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1761 self.meta = meta.into_option();
1762 self
1763 }
1764}
1765
1766#[serde_as]
1768#[skip_serializing_none]
1769#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1770#[serde(rename_all = "camelCase")]
1771#[non_exhaustive]
1772pub struct SessionInfo {
1773 pub session_id: SessionId,
1775 pub cwd: PathBuf,
1777 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1783 pub additional_directories: Vec<PathBuf>,
1784
1785 #[serde_as(deserialize_as = "DefaultOnError")]
1787 #[schemars(extend("x-deserialize-default-on-error" = true))]
1788 #[serde(default)]
1789 pub title: Option<String>,
1790 #[serde_as(deserialize_as = "DefaultOnError")]
1792 #[schemars(extend("x-deserialize-default-on-error" = true))]
1793 #[serde(default)]
1794 pub updated_at: Option<String>,
1795 #[serde(rename = "_meta")]
1801 pub meta: Option<Meta>,
1802}
1803
1804impl SessionInfo {
1805 #[must_use]
1806 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1807 Self {
1808 session_id: session_id.into(),
1809 cwd: cwd.into(),
1810 additional_directories: vec![],
1811 title: None,
1812 updated_at: None,
1813 meta: None,
1814 }
1815 }
1816
1817 #[must_use]
1819 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1820 self.additional_directories = additional_directories;
1821 self
1822 }
1823
1824 #[must_use]
1826 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1827 self.title = title.into_option();
1828 self
1829 }
1830
1831 #[must_use]
1833 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1834 self.updated_at = updated_at.into_option();
1835 self
1836 }
1837
1838 #[must_use]
1844 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1845 self.meta = meta.into_option();
1846 self
1847 }
1848}
1849
1850#[serde_as]
1854#[skip_serializing_none]
1855#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1856#[serde(rename_all = "camelCase")]
1857#[non_exhaustive]
1858pub struct SessionModeState {
1859 pub current_mode_id: SessionModeId,
1861 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1863 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1864 pub available_modes: Vec<SessionMode>,
1865 #[serde(rename = "_meta")]
1871 pub meta: Option<Meta>,
1872}
1873
1874impl SessionModeState {
1875 #[must_use]
1876 pub fn new(
1877 current_mode_id: impl Into<SessionModeId>,
1878 available_modes: Vec<SessionMode>,
1879 ) -> Self {
1880 Self {
1881 current_mode_id: current_mode_id.into(),
1882 available_modes,
1883 meta: None,
1884 }
1885 }
1886
1887 #[must_use]
1893 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1894 self.meta = meta.into_option();
1895 self
1896 }
1897}
1898
1899#[skip_serializing_none]
1903#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1904#[serde(rename_all = "camelCase")]
1905#[non_exhaustive]
1906pub struct SessionMode {
1907 pub id: SessionModeId,
1908 pub name: String,
1909 #[serde(default)]
1910 pub description: Option<String>,
1911 #[serde(rename = "_meta")]
1917 pub meta: Option<Meta>,
1918}
1919
1920impl SessionMode {
1921 #[must_use]
1922 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
1923 Self {
1924 id: id.into(),
1925 name: name.into(),
1926 description: None,
1927 meta: None,
1928 }
1929 }
1930
1931 #[must_use]
1932 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1933 self.description = description.into_option();
1934 self
1935 }
1936
1937 #[must_use]
1943 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1944 self.meta = meta.into_option();
1945 self
1946 }
1947}
1948
1949#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1951#[serde(transparent)]
1952#[from(Arc<str>, String, &'static str)]
1953#[non_exhaustive]
1954pub struct SessionModeId(pub Arc<str>);
1955
1956impl SessionModeId {
1957 #[must_use]
1958 pub fn new(id: impl Into<Arc<str>>) -> Self {
1959 Self(id.into())
1960 }
1961}
1962
1963#[skip_serializing_none]
1965#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1966#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
1967#[serde(rename_all = "camelCase")]
1968#[non_exhaustive]
1969pub struct SetSessionModeRequest {
1970 pub session_id: SessionId,
1972 pub mode_id: SessionModeId,
1974 #[serde(rename = "_meta")]
1980 pub meta: Option<Meta>,
1981}
1982
1983impl SetSessionModeRequest {
1984 #[must_use]
1985 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
1986 Self {
1987 session_id: session_id.into(),
1988 mode_id: mode_id.into(),
1989 meta: None,
1990 }
1991 }
1992
1993 #[must_use]
1994 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1995 self.meta = meta.into_option();
1996 self
1997 }
1998}
1999
2000#[skip_serializing_none]
2002#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2003#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
2004#[serde(rename_all = "camelCase")]
2005#[non_exhaustive]
2006pub struct SetSessionModeResponse {
2007 #[serde(rename = "_meta")]
2013 pub meta: Option<Meta>,
2014}
2015
2016impl SetSessionModeResponse {
2017 #[must_use]
2018 pub fn new() -> Self {
2019 Self::default()
2020 }
2021
2022 #[must_use]
2028 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2029 self.meta = meta.into_option();
2030 self
2031 }
2032}
2033
2034#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2038#[serde(transparent)]
2039#[from(Arc<str>, String, &'static str)]
2040#[non_exhaustive]
2041pub struct SessionConfigId(pub Arc<str>);
2042
2043impl SessionConfigId {
2044 #[must_use]
2045 pub fn new(id: impl Into<Arc<str>>) -> Self {
2046 Self(id.into())
2047 }
2048}
2049
2050#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2052#[serde(transparent)]
2053#[from(Arc<str>, String, &'static str)]
2054#[non_exhaustive]
2055pub struct SessionConfigValueId(pub Arc<str>);
2056
2057impl SessionConfigValueId {
2058 #[must_use]
2059 pub fn new(id: impl Into<Arc<str>>) -> Self {
2060 Self(id.into())
2061 }
2062}
2063
2064#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2066#[serde(transparent)]
2067#[from(Arc<str>, String, &'static str)]
2068#[non_exhaustive]
2069pub struct SessionConfigGroupId(pub Arc<str>);
2070
2071impl SessionConfigGroupId {
2072 #[must_use]
2073 pub fn new(id: impl Into<Arc<str>>) -> Self {
2074 Self(id.into())
2075 }
2076}
2077
2078#[skip_serializing_none]
2080#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2081#[serde(rename_all = "camelCase")]
2082#[non_exhaustive]
2083pub struct SessionConfigSelectOption {
2084 pub value: SessionConfigValueId,
2086 pub name: String,
2088 #[serde(default)]
2090 pub description: Option<String>,
2091 #[serde(rename = "_meta")]
2097 pub meta: Option<Meta>,
2098}
2099
2100impl SessionConfigSelectOption {
2101 #[must_use]
2102 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2103 Self {
2104 value: value.into(),
2105 name: name.into(),
2106 description: None,
2107 meta: None,
2108 }
2109 }
2110
2111 #[must_use]
2112 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2113 self.description = description.into_option();
2114 self
2115 }
2116
2117 #[must_use]
2123 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2124 self.meta = meta.into_option();
2125 self
2126 }
2127}
2128
2129#[skip_serializing_none]
2131#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2132#[serde(rename_all = "camelCase")]
2133#[non_exhaustive]
2134pub struct SessionConfigSelectGroup {
2135 pub group: SessionConfigGroupId,
2137 pub name: String,
2139 pub options: Vec<SessionConfigSelectOption>,
2141 #[serde(rename = "_meta")]
2147 pub meta: Option<Meta>,
2148}
2149
2150impl SessionConfigSelectGroup {
2151 #[must_use]
2152 pub fn new(
2153 group: impl Into<SessionConfigGroupId>,
2154 name: impl Into<String>,
2155 options: Vec<SessionConfigSelectOption>,
2156 ) -> Self {
2157 Self {
2158 group: group.into(),
2159 name: name.into(),
2160 options,
2161 meta: None,
2162 }
2163 }
2164
2165 #[must_use]
2171 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2172 self.meta = meta.into_option();
2173 self
2174 }
2175}
2176
2177#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2179#[serde(untagged)]
2180#[non_exhaustive]
2181pub enum SessionConfigSelectOptions {
2182 Ungrouped(Vec<SessionConfigSelectOption>),
2184 Grouped(Vec<SessionConfigSelectGroup>),
2186}
2187
2188impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2189 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2190 SessionConfigSelectOptions::Ungrouped(options)
2191 }
2192}
2193
2194impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2195 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2196 SessionConfigSelectOptions::Grouped(groups)
2197 }
2198}
2199
2200#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2202#[serde(rename_all = "camelCase")]
2203#[non_exhaustive]
2204pub struct SessionConfigSelect {
2205 pub current_value: SessionConfigValueId,
2207 pub options: SessionConfigSelectOptions,
2209}
2210
2211impl SessionConfigSelect {
2212 #[must_use]
2213 pub fn new(
2214 current_value: impl Into<SessionConfigValueId>,
2215 options: impl Into<SessionConfigSelectOptions>,
2216 ) -> Self {
2217 Self {
2218 current_value: current_value.into(),
2219 options: options.into(),
2220 }
2221 }
2222}
2223
2224#[cfg(feature = "unstable_boolean_config")]
2230#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2231#[serde(rename_all = "camelCase")]
2232#[non_exhaustive]
2233pub struct SessionConfigBoolean {
2234 pub current_value: bool,
2236}
2237
2238#[cfg(feature = "unstable_boolean_config")]
2239impl SessionConfigBoolean {
2240 #[must_use]
2241 pub fn new(current_value: bool) -> Self {
2242 Self { current_value }
2243 }
2244}
2245
2246#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2256#[serde(rename_all = "snake_case")]
2257#[non_exhaustive]
2258pub enum SessionConfigOptionCategory {
2259 Mode,
2261 Model,
2263 ThoughtLevel,
2265 #[serde(untagged)]
2267 Other(String),
2268}
2269
2270#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2272#[serde(tag = "type", rename_all = "snake_case")]
2273#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2274#[non_exhaustive]
2275pub enum SessionConfigKind {
2276 Select(SessionConfigSelect),
2278 #[cfg(feature = "unstable_boolean_config")]
2284 Boolean(SessionConfigBoolean),
2285}
2286
2287#[serde_as]
2289#[skip_serializing_none]
2290#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2291#[serde(rename_all = "camelCase")]
2292#[non_exhaustive]
2293pub struct SessionConfigOption {
2294 pub id: SessionConfigId,
2296 pub name: String,
2298 #[serde(default)]
2300 pub description: Option<String>,
2301 #[serde_as(deserialize_as = "DefaultOnError")]
2303 #[schemars(extend("x-deserialize-default-on-error" = true))]
2304 #[serde(default)]
2305 pub category: Option<SessionConfigOptionCategory>,
2306 #[serde(flatten)]
2308 pub kind: SessionConfigKind,
2309 #[serde(rename = "_meta")]
2315 pub meta: Option<Meta>,
2316}
2317
2318impl SessionConfigOption {
2319 #[must_use]
2320 pub fn new(
2321 id: impl Into<SessionConfigId>,
2322 name: impl Into<String>,
2323 kind: SessionConfigKind,
2324 ) -> Self {
2325 Self {
2326 id: id.into(),
2327 name: name.into(),
2328 description: None,
2329 category: None,
2330 kind,
2331 meta: None,
2332 }
2333 }
2334
2335 #[must_use]
2336 pub fn select(
2337 id: impl Into<SessionConfigId>,
2338 name: impl Into<String>,
2339 current_value: impl Into<SessionConfigValueId>,
2340 options: impl Into<SessionConfigSelectOptions>,
2341 ) -> Self {
2342 Self::new(
2343 id,
2344 name,
2345 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2346 )
2347 }
2348
2349 #[cfg(feature = "unstable_boolean_config")]
2353 #[must_use]
2354 pub fn boolean(
2355 id: impl Into<SessionConfigId>,
2356 name: impl Into<String>,
2357 current_value: bool,
2358 ) -> Self {
2359 Self::new(
2360 id,
2361 name,
2362 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2363 )
2364 }
2365
2366 #[must_use]
2367 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2368 self.description = description.into_option();
2369 self
2370 }
2371
2372 #[must_use]
2373 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2374 self.category = category.into_option();
2375 self
2376 }
2377
2378 #[must_use]
2384 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2385 self.meta = meta.into_option();
2386 self
2387 }
2388}
2389
2390#[cfg(feature = "unstable_boolean_config")]
2405#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2406#[serde(tag = "type", rename_all = "snake_case")]
2407#[non_exhaustive]
2408pub enum SessionConfigOptionValue {
2409 Boolean {
2411 value: bool,
2413 },
2414 #[serde(untagged)]
2420 ValueId {
2421 value: SessionConfigValueId,
2423 },
2424}
2425
2426#[cfg(feature = "unstable_boolean_config")]
2427impl SessionConfigOptionValue {
2428 #[must_use]
2430 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2431 Self::ValueId { value: id.into() }
2432 }
2433
2434 #[must_use]
2436 pub fn boolean(val: bool) -> Self {
2437 Self::Boolean { value: val }
2438 }
2439
2440 #[must_use]
2443 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2444 match self {
2445 Self::ValueId { value } => Some(value),
2446 _ => None,
2447 }
2448 }
2449
2450 #[must_use]
2452 pub fn as_bool(&self) -> Option<bool> {
2453 match self {
2454 Self::Boolean { value } => Some(*value),
2455 _ => None,
2456 }
2457 }
2458}
2459
2460#[cfg(feature = "unstable_boolean_config")]
2461impl From<SessionConfigValueId> for SessionConfigOptionValue {
2462 fn from(value: SessionConfigValueId) -> Self {
2463 Self::ValueId { value }
2464 }
2465}
2466
2467#[cfg(feature = "unstable_boolean_config")]
2468impl From<bool> for SessionConfigOptionValue {
2469 fn from(value: bool) -> Self {
2470 Self::Boolean { value }
2471 }
2472}
2473
2474#[cfg(feature = "unstable_boolean_config")]
2475impl From<&str> for SessionConfigOptionValue {
2476 fn from(value: &str) -> Self {
2477 Self::ValueId {
2478 value: SessionConfigValueId::new(value),
2479 }
2480 }
2481}
2482
2483#[skip_serializing_none]
2485#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2486#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2487#[serde(rename_all = "camelCase")]
2488#[non_exhaustive]
2489pub struct SetSessionConfigOptionRequest {
2490 pub session_id: SessionId,
2492 pub config_id: SessionConfigId,
2494 #[cfg(feature = "unstable_boolean_config")]
2499 #[serde(flatten)]
2500 pub value: SessionConfigOptionValue,
2501 #[cfg(not(feature = "unstable_boolean_config"))]
2503 pub value: SessionConfigValueId,
2504 #[serde(rename = "_meta")]
2510 pub meta: Option<Meta>,
2511}
2512
2513impl SetSessionConfigOptionRequest {
2514 #[cfg(feature = "unstable_boolean_config")]
2515 #[must_use]
2516 pub fn new(
2517 session_id: impl Into<SessionId>,
2518 config_id: impl Into<SessionConfigId>,
2519 value: impl Into<SessionConfigOptionValue>,
2520 ) -> Self {
2521 Self {
2522 session_id: session_id.into(),
2523 config_id: config_id.into(),
2524 value: value.into(),
2525 meta: None,
2526 }
2527 }
2528
2529 #[cfg(not(feature = "unstable_boolean_config"))]
2530 #[must_use]
2531 pub fn new(
2532 session_id: impl Into<SessionId>,
2533 config_id: impl Into<SessionConfigId>,
2534 value: impl Into<SessionConfigValueId>,
2535 ) -> Self {
2536 Self {
2537 session_id: session_id.into(),
2538 config_id: config_id.into(),
2539 value: value.into(),
2540 meta: None,
2541 }
2542 }
2543
2544 #[must_use]
2550 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2551 self.meta = meta.into_option();
2552 self
2553 }
2554}
2555
2556#[serde_as]
2558#[skip_serializing_none]
2559#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2560#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2561#[serde(rename_all = "camelCase")]
2562#[non_exhaustive]
2563pub struct SetSessionConfigOptionResponse {
2564 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2566 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2567 pub config_options: Vec<SessionConfigOption>,
2568 #[serde(rename = "_meta")]
2574 pub meta: Option<Meta>,
2575}
2576
2577impl SetSessionConfigOptionResponse {
2578 #[must_use]
2579 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2580 Self {
2581 config_options,
2582 meta: None,
2583 }
2584 }
2585
2586 #[must_use]
2592 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2593 self.meta = meta.into_option();
2594 self
2595 }
2596}
2597
2598#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2607#[serde(tag = "type", rename_all = "snake_case")]
2608#[non_exhaustive]
2609pub enum McpServer {
2610 Http(McpServerHttp),
2614 Sse(McpServerSse),
2618 #[cfg(feature = "unstable_mcp_over_acp")]
2627 Acp(McpServerAcp),
2628 #[serde(untagged)]
2632 Stdio(McpServerStdio),
2633}
2634
2635#[skip_serializing_none]
2637#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2638#[serde(rename_all = "camelCase")]
2639#[non_exhaustive]
2640pub struct McpServerHttp {
2641 pub name: String,
2643 pub url: String,
2645 pub headers: Vec<HttpHeader>,
2647 #[serde(rename = "_meta")]
2653 pub meta: Option<Meta>,
2654}
2655
2656impl McpServerHttp {
2657 #[must_use]
2658 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2659 Self {
2660 name: name.into(),
2661 url: url.into(),
2662 headers: Vec::new(),
2663 meta: None,
2664 }
2665 }
2666
2667 #[must_use]
2669 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2670 self.headers = headers;
2671 self
2672 }
2673
2674 #[must_use]
2680 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2681 self.meta = meta.into_option();
2682 self
2683 }
2684}
2685
2686#[skip_serializing_none]
2688#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2689#[serde(rename_all = "camelCase")]
2690#[non_exhaustive]
2691pub struct McpServerSse {
2692 pub name: String,
2694 pub url: String,
2696 pub headers: Vec<HttpHeader>,
2698 #[serde(rename = "_meta")]
2704 pub meta: Option<Meta>,
2705}
2706
2707impl McpServerSse {
2708 #[must_use]
2709 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2710 Self {
2711 name: name.into(),
2712 url: url.into(),
2713 headers: Vec::new(),
2714 meta: None,
2715 }
2716 }
2717
2718 #[must_use]
2720 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2721 self.headers = headers;
2722 self
2723 }
2724
2725 #[must_use]
2731 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2732 self.meta = meta.into_option();
2733 self
2734 }
2735}
2736
2737#[cfg(feature = "unstable_mcp_over_acp")]
2747#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2748#[serde(transparent)]
2749#[from(Arc<str>, String, &'static str)]
2750#[non_exhaustive]
2751pub struct McpServerAcpId(pub Arc<str>);
2752
2753#[cfg(feature = "unstable_mcp_over_acp")]
2754impl McpServerAcpId {
2755 #[must_use]
2756 pub fn new(id: impl Into<Arc<str>>) -> Self {
2757 Self(id.into())
2758 }
2759}
2760
2761#[skip_serializing_none]
2770#[cfg(feature = "unstable_mcp_over_acp")]
2771#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2772#[serde(rename_all = "camelCase")]
2773#[non_exhaustive]
2774pub struct McpServerAcp {
2775 pub name: String,
2777 pub id: McpServerAcpId,
2782 #[serde(rename = "_meta")]
2788 pub meta: Option<Meta>,
2789}
2790
2791#[cfg(feature = "unstable_mcp_over_acp")]
2792impl McpServerAcp {
2793 #[must_use]
2794 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2795 Self {
2796 name: name.into(),
2797 id: id.into(),
2798 meta: None,
2799 }
2800 }
2801
2802 #[must_use]
2808 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2809 self.meta = meta.into_option();
2810 self
2811 }
2812}
2813
2814#[skip_serializing_none]
2816#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2817#[serde(rename_all = "camelCase")]
2818#[non_exhaustive]
2819pub struct McpServerStdio {
2820 pub name: String,
2822 pub command: PathBuf,
2824 pub args: Vec<String>,
2826 pub env: Vec<EnvVariable>,
2828 #[serde(rename = "_meta")]
2834 pub meta: Option<Meta>,
2835}
2836
2837impl McpServerStdio {
2838 #[must_use]
2839 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2840 Self {
2841 name: name.into(),
2842 command: command.into(),
2843 args: Vec::new(),
2844 env: Vec::new(),
2845 meta: None,
2846 }
2847 }
2848
2849 #[must_use]
2851 pub fn args(mut self, args: Vec<String>) -> Self {
2852 self.args = args;
2853 self
2854 }
2855
2856 #[must_use]
2858 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2859 self.env = env;
2860 self
2861 }
2862
2863 #[must_use]
2869 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2870 self.meta = meta.into_option();
2871 self
2872 }
2873}
2874
2875#[skip_serializing_none]
2877#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2878#[serde(rename_all = "camelCase")]
2879#[non_exhaustive]
2880pub struct EnvVariable {
2881 pub name: String,
2883 pub value: String,
2885 #[serde(rename = "_meta")]
2891 pub meta: Option<Meta>,
2892}
2893
2894impl EnvVariable {
2895 #[must_use]
2896 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2897 Self {
2898 name: name.into(),
2899 value: value.into(),
2900 meta: None,
2901 }
2902 }
2903
2904 #[must_use]
2910 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2911 self.meta = meta.into_option();
2912 self
2913 }
2914}
2915
2916#[skip_serializing_none]
2918#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2919#[serde(rename_all = "camelCase")]
2920#[non_exhaustive]
2921pub struct HttpHeader {
2922 pub name: String,
2924 pub value: String,
2926 #[serde(rename = "_meta")]
2932 pub meta: Option<Meta>,
2933}
2934
2935impl HttpHeader {
2936 #[must_use]
2937 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2938 Self {
2939 name: name.into(),
2940 value: value.into(),
2941 meta: None,
2942 }
2943 }
2944
2945 #[must_use]
2951 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2952 self.meta = meta.into_option();
2953 self
2954 }
2955}
2956
2957#[skip_serializing_none]
2965#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
2966#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2967#[serde(rename_all = "camelCase")]
2968#[non_exhaustive]
2969pub struct PromptRequest {
2970 pub session_id: SessionId,
2972 #[cfg(feature = "unstable_message_id")]
2982 pub message_id: Option<String>,
2983 pub prompt: Vec<ContentBlock>,
2997 #[serde(rename = "_meta")]
3003 pub meta: Option<Meta>,
3004}
3005
3006impl PromptRequest {
3007 #[must_use]
3008 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3009 Self {
3010 session_id: session_id.into(),
3011 #[cfg(feature = "unstable_message_id")]
3012 message_id: None,
3013 prompt,
3014 meta: None,
3015 }
3016 }
3017
3018 #[cfg(feature = "unstable_message_id")]
3028 #[must_use]
3029 pub fn message_id(mut self, message_id: impl IntoOption<String>) -> Self {
3030 self.message_id = message_id.into_option();
3031 self
3032 }
3033
3034 #[must_use]
3040 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3041 self.meta = meta.into_option();
3042 self
3043 }
3044}
3045
3046#[serde_as]
3050#[skip_serializing_none]
3051#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3052#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3053#[serde(rename_all = "camelCase")]
3054#[non_exhaustive]
3055pub struct PromptResponse {
3056 #[cfg(feature = "unstable_message_id")]
3066 pub user_message_id: Option<String>,
3067 pub stop_reason: StopReason,
3069 #[cfg(feature = "unstable_session_usage")]
3075 #[serde_as(deserialize_as = "DefaultOnError")]
3076 #[schemars(extend("x-deserialize-default-on-error" = true))]
3077 #[serde(default)]
3078 pub usage: Option<Usage>,
3079 #[serde(rename = "_meta")]
3085 pub meta: Option<Meta>,
3086}
3087
3088impl PromptResponse {
3089 #[must_use]
3090 pub fn new(stop_reason: StopReason) -> Self {
3091 Self {
3092 #[cfg(feature = "unstable_message_id")]
3093 user_message_id: None,
3094 stop_reason,
3095 #[cfg(feature = "unstable_session_usage")]
3096 usage: None,
3097 meta: None,
3098 }
3099 }
3100
3101 #[cfg(feature = "unstable_message_id")]
3111 #[must_use]
3112 pub fn user_message_id(mut self, user_message_id: impl IntoOption<String>) -> Self {
3113 self.user_message_id = user_message_id.into_option();
3114 self
3115 }
3116
3117 #[cfg(feature = "unstable_session_usage")]
3123 #[must_use]
3124 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3125 self.usage = usage.into_option();
3126 self
3127 }
3128
3129 #[must_use]
3135 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3136 self.meta = meta.into_option();
3137 self
3138 }
3139}
3140
3141#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3145#[serde(rename_all = "snake_case")]
3146#[non_exhaustive]
3147pub enum StopReason {
3148 EndTurn,
3150 MaxTokens,
3152 MaxTurnRequests,
3155 Refusal,
3159 Cancelled,
3166}
3167
3168#[cfg(feature = "unstable_session_usage")]
3174#[skip_serializing_none]
3175#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3176#[serde(rename_all = "camelCase")]
3177#[non_exhaustive]
3178pub struct Usage {
3179 pub total_tokens: u64,
3181 pub input_tokens: u64,
3183 pub output_tokens: u64,
3185 pub thought_tokens: Option<u64>,
3187 pub cached_read_tokens: Option<u64>,
3189 pub cached_write_tokens: Option<u64>,
3191}
3192
3193#[cfg(feature = "unstable_session_usage")]
3194impl Usage {
3195 #[must_use]
3196 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3197 Self {
3198 total_tokens,
3199 input_tokens,
3200 output_tokens,
3201 thought_tokens: None,
3202 cached_read_tokens: None,
3203 cached_write_tokens: None,
3204 }
3205 }
3206
3207 #[must_use]
3209 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3210 self.thought_tokens = thought_tokens.into_option();
3211 self
3212 }
3213
3214 #[must_use]
3216 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3217 self.cached_read_tokens = cached_read_tokens.into_option();
3218 self
3219 }
3220
3221 #[must_use]
3223 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3224 self.cached_write_tokens = cached_write_tokens.into_option();
3225 self
3226 }
3227}
3228
3229#[cfg(feature = "unstable_llm_providers")]
3242#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3243#[serde(rename_all = "snake_case")]
3244#[non_exhaustive]
3245#[expect(clippy::doc_markdown)]
3246pub enum LlmProtocol {
3247 Anthropic,
3249 #[serde(rename = "openai")]
3251 OpenAi,
3252 Azure,
3254 Vertex,
3256 Bedrock,
3258 #[serde(untagged)]
3260 Other(String),
3261}
3262
3263#[cfg(feature = "unstable_llm_providers")]
3269#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3270#[serde(rename_all = "camelCase")]
3271#[non_exhaustive]
3272pub struct ProviderCurrentConfig {
3273 pub api_type: LlmProtocol,
3275 pub base_url: String,
3277}
3278
3279#[cfg(feature = "unstable_llm_providers")]
3280impl ProviderCurrentConfig {
3281 #[must_use]
3282 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3283 Self {
3284 api_type,
3285 base_url: base_url.into(),
3286 }
3287 }
3288}
3289
3290#[cfg(feature = "unstable_llm_providers")]
3296#[serde_as]
3297#[skip_serializing_none]
3298#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3299#[serde(rename_all = "camelCase")]
3300#[non_exhaustive]
3301pub struct ProviderInfo {
3302 pub id: String,
3304 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3306 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3307 pub supported: Vec<LlmProtocol>,
3308 pub required: bool,
3311 pub current: Option<ProviderCurrentConfig>,
3314 #[serde(rename = "_meta")]
3320 pub meta: Option<Meta>,
3321}
3322
3323#[cfg(feature = "unstable_llm_providers")]
3324impl ProviderInfo {
3325 #[must_use]
3326 pub fn new(
3327 id: impl Into<String>,
3328 supported: Vec<LlmProtocol>,
3329 required: bool,
3330 current: impl IntoOption<ProviderCurrentConfig>,
3331 ) -> Self {
3332 Self {
3333 id: id.into(),
3334 supported,
3335 required,
3336 current: current.into_option(),
3337 meta: None,
3338 }
3339 }
3340
3341 #[must_use]
3347 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3348 self.meta = meta.into_option();
3349 self
3350 }
3351}
3352
3353#[cfg(feature = "unstable_llm_providers")]
3359#[skip_serializing_none]
3360#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3361#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3362#[serde(rename_all = "camelCase")]
3363#[non_exhaustive]
3364pub struct ListProvidersRequest {
3365 #[serde(rename = "_meta")]
3371 pub meta: Option<Meta>,
3372}
3373
3374#[cfg(feature = "unstable_llm_providers")]
3375impl ListProvidersRequest {
3376 #[must_use]
3377 pub fn new() -> Self {
3378 Self::default()
3379 }
3380
3381 #[must_use]
3387 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3388 self.meta = meta.into_option();
3389 self
3390 }
3391}
3392
3393#[cfg(feature = "unstable_llm_providers")]
3399#[serde_as]
3400#[skip_serializing_none]
3401#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3402#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3403#[serde(rename_all = "camelCase")]
3404#[non_exhaustive]
3405pub struct ListProvidersResponse {
3406 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3408 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3409 pub providers: Vec<ProviderInfo>,
3410 #[serde(rename = "_meta")]
3416 pub meta: Option<Meta>,
3417}
3418
3419#[cfg(feature = "unstable_llm_providers")]
3420impl ListProvidersResponse {
3421 #[must_use]
3422 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3423 Self {
3424 providers,
3425 meta: None,
3426 }
3427 }
3428
3429 #[must_use]
3435 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3436 self.meta = meta.into_option();
3437 self
3438 }
3439}
3440
3441#[cfg(feature = "unstable_llm_providers")]
3449#[skip_serializing_none]
3450#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3451#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3452#[serde(rename_all = "camelCase")]
3453#[non_exhaustive]
3454pub struct SetProviderRequest {
3455 pub id: String,
3457 pub api_type: LlmProtocol,
3459 pub base_url: String,
3461 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3464 pub headers: HashMap<String, String>,
3465 #[serde(rename = "_meta")]
3471 pub meta: Option<Meta>,
3472}
3473
3474#[cfg(feature = "unstable_llm_providers")]
3475impl SetProviderRequest {
3476 #[must_use]
3477 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3478 Self {
3479 id: id.into(),
3480 api_type,
3481 base_url: base_url.into(),
3482 headers: HashMap::new(),
3483 meta: None,
3484 }
3485 }
3486
3487 #[must_use]
3490 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3491 self.headers = headers;
3492 self
3493 }
3494
3495 #[must_use]
3501 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3502 self.meta = meta.into_option();
3503 self
3504 }
3505}
3506
3507#[cfg(feature = "unstable_llm_providers")]
3513#[skip_serializing_none]
3514#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3515#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3516#[serde(rename_all = "camelCase")]
3517#[non_exhaustive]
3518pub struct SetProviderResponse {
3519 #[serde(rename = "_meta")]
3525 pub meta: Option<Meta>,
3526}
3527
3528#[cfg(feature = "unstable_llm_providers")]
3529impl SetProviderResponse {
3530 #[must_use]
3531 pub fn new() -> Self {
3532 Self::default()
3533 }
3534
3535 #[must_use]
3541 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3542 self.meta = meta.into_option();
3543 self
3544 }
3545}
3546
3547#[cfg(feature = "unstable_llm_providers")]
3553#[skip_serializing_none]
3554#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3555#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3556#[serde(rename_all = "camelCase")]
3557#[non_exhaustive]
3558pub struct DisableProviderRequest {
3559 pub id: String,
3561 #[serde(rename = "_meta")]
3567 pub meta: Option<Meta>,
3568}
3569
3570#[cfg(feature = "unstable_llm_providers")]
3571impl DisableProviderRequest {
3572 #[must_use]
3573 pub fn new(id: impl Into<String>) -> Self {
3574 Self {
3575 id: id.into(),
3576 meta: None,
3577 }
3578 }
3579
3580 #[must_use]
3586 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3587 self.meta = meta.into_option();
3588 self
3589 }
3590}
3591
3592#[cfg(feature = "unstable_llm_providers")]
3598#[skip_serializing_none]
3599#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3600#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3601#[serde(rename_all = "camelCase")]
3602#[non_exhaustive]
3603pub struct DisableProviderResponse {
3604 #[serde(rename = "_meta")]
3610 pub meta: Option<Meta>,
3611}
3612
3613#[cfg(feature = "unstable_llm_providers")]
3614impl DisableProviderResponse {
3615 #[must_use]
3616 pub fn new() -> Self {
3617 Self::default()
3618 }
3619
3620 #[must_use]
3626 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3627 self.meta = meta.into_option();
3628 self
3629 }
3630}
3631
3632#[serde_as]
3641#[skip_serializing_none]
3642#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3643#[serde(rename_all = "camelCase")]
3644#[non_exhaustive]
3645pub struct AgentCapabilities {
3646 #[serde(default)]
3648 pub load_session: bool,
3649 #[serde(default)]
3651 pub prompt_capabilities: PromptCapabilities,
3652 #[serde(default)]
3654 pub mcp_capabilities: McpCapabilities,
3655 #[serde(default)]
3656 pub session_capabilities: SessionCapabilities,
3657 #[serde(default)]
3659 pub auth: AgentAuthCapabilities,
3660 #[cfg(feature = "unstable_llm_providers")]
3668 #[serde_as(deserialize_as = "DefaultOnError")]
3669 #[schemars(extend("x-deserialize-default-on-error" = true))]
3670 #[serde(default)]
3671 pub providers: Option<ProvidersCapabilities>,
3672 #[cfg(feature = "unstable_nes")]
3678 #[serde_as(deserialize_as = "DefaultOnError")]
3679 #[schemars(extend("x-deserialize-default-on-error" = true))]
3680 #[serde(default)]
3681 pub nes: Option<NesCapabilities>,
3682 #[cfg(feature = "unstable_nes")]
3688 #[serde_as(deserialize_as = "DefaultOnError")]
3689 #[schemars(extend("x-deserialize-default-on-error" = true))]
3690 #[serde(default)]
3691 pub position_encoding: Option<PositionEncodingKind>,
3692 #[serde(rename = "_meta")]
3698 pub meta: Option<Meta>,
3699}
3700
3701impl AgentCapabilities {
3702 #[must_use]
3703 pub fn new() -> Self {
3704 Self::default()
3705 }
3706
3707 #[must_use]
3709 pub fn load_session(mut self, load_session: bool) -> Self {
3710 self.load_session = load_session;
3711 self
3712 }
3713
3714 #[must_use]
3716 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3717 self.prompt_capabilities = prompt_capabilities;
3718 self
3719 }
3720
3721 #[must_use]
3723 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3724 self.mcp_capabilities = mcp_capabilities;
3725 self
3726 }
3727
3728 #[must_use]
3730 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3731 self.session_capabilities = session_capabilities;
3732 self
3733 }
3734
3735 #[must_use]
3737 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3738 self.auth = auth;
3739 self
3740 }
3741
3742 #[cfg(feature = "unstable_llm_providers")]
3748 #[must_use]
3749 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3750 self.providers = providers.into_option();
3751 self
3752 }
3753
3754 #[cfg(feature = "unstable_nes")]
3760 #[must_use]
3761 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3762 self.nes = nes.into_option();
3763 self
3764 }
3765
3766 #[cfg(feature = "unstable_nes")]
3770 #[must_use]
3771 pub fn position_encoding(
3772 mut self,
3773 position_encoding: impl IntoOption<PositionEncodingKind>,
3774 ) -> Self {
3775 self.position_encoding = position_encoding.into_option();
3776 self
3777 }
3778
3779 #[must_use]
3785 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3786 self.meta = meta.into_option();
3787 self
3788 }
3789}
3790
3791#[cfg(feature = "unstable_llm_providers")]
3799#[skip_serializing_none]
3800#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3801#[non_exhaustive]
3802pub struct ProvidersCapabilities {
3803 #[serde(rename = "_meta")]
3809 pub meta: Option<Meta>,
3810}
3811
3812#[cfg(feature = "unstable_llm_providers")]
3813impl ProvidersCapabilities {
3814 #[must_use]
3815 pub fn new() -> Self {
3816 Self::default()
3817 }
3818
3819 #[must_use]
3825 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3826 self.meta = meta.into_option();
3827 self
3828 }
3829}
3830
3831#[serde_as]
3841#[skip_serializing_none]
3842#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3843#[serde(rename_all = "camelCase")]
3844#[non_exhaustive]
3845pub struct SessionCapabilities {
3846 #[serde_as(deserialize_as = "DefaultOnError")]
3848 #[schemars(extend("x-deserialize-default-on-error" = true))]
3849 #[serde(default)]
3850 pub list: Option<SessionListCapabilities>,
3851 #[cfg(feature = "unstable_session_delete")]
3860 #[serde_as(deserialize_as = "DefaultOnError")]
3861 #[schemars(extend("x-deserialize-default-on-error" = true))]
3862 #[serde(default)]
3863 pub delete: Option<SessionDeleteCapabilities>,
3864 #[serde_as(deserialize_as = "DefaultOnError")]
3870 #[schemars(extend("x-deserialize-default-on-error" = true))]
3871 #[serde(default)]
3872 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
3873 #[cfg(feature = "unstable_session_fork")]
3879 #[serde_as(deserialize_as = "DefaultOnError")]
3880 #[schemars(extend("x-deserialize-default-on-error" = true))]
3881 #[serde(default)]
3882 pub fork: Option<SessionForkCapabilities>,
3883 #[serde_as(deserialize_as = "DefaultOnError")]
3885 #[schemars(extend("x-deserialize-default-on-error" = true))]
3886 #[serde(default)]
3887 pub resume: Option<SessionResumeCapabilities>,
3888 #[serde_as(deserialize_as = "DefaultOnError")]
3890 #[schemars(extend("x-deserialize-default-on-error" = true))]
3891 #[serde(default)]
3892 pub close: Option<SessionCloseCapabilities>,
3893 #[serde(rename = "_meta")]
3899 pub meta: Option<Meta>,
3900}
3901
3902impl SessionCapabilities {
3903 #[must_use]
3904 pub fn new() -> Self {
3905 Self::default()
3906 }
3907
3908 #[must_use]
3910 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3911 self.list = list.into_option();
3912 self
3913 }
3914
3915 #[cfg(feature = "unstable_session_delete")]
3924 #[must_use]
3925 pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
3926 self.delete = delete.into_option();
3927 self
3928 }
3929
3930 #[must_use]
3936 pub fn additional_directories(
3937 mut self,
3938 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
3939 ) -> Self {
3940 self.additional_directories = additional_directories.into_option();
3941 self
3942 }
3943
3944 #[cfg(feature = "unstable_session_fork")]
3945 #[must_use]
3947 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
3948 self.fork = fork.into_option();
3949 self
3950 }
3951
3952 #[must_use]
3954 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
3955 self.resume = resume.into_option();
3956 self
3957 }
3958
3959 #[must_use]
3961 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
3962 self.close = close.into_option();
3963 self
3964 }
3965
3966 #[must_use]
3972 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3973 self.meta = meta.into_option();
3974 self
3975 }
3976}
3977
3978#[skip_serializing_none]
3982#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3983#[non_exhaustive]
3984pub struct SessionListCapabilities {
3985 #[serde(rename = "_meta")]
3991 pub meta: Option<Meta>,
3992}
3993
3994impl SessionListCapabilities {
3995 #[must_use]
3996 pub fn new() -> Self {
3997 Self::default()
3998 }
3999
4000 #[must_use]
4006 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4007 self.meta = meta.into_option();
4008 self
4009 }
4010}
4011
4012#[cfg(feature = "unstable_session_delete")]
4020#[skip_serializing_none]
4021#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4022#[non_exhaustive]
4023pub struct SessionDeleteCapabilities {
4024 #[serde(rename = "_meta")]
4030 pub meta: Option<Meta>,
4031}
4032
4033#[cfg(feature = "unstable_session_delete")]
4034impl SessionDeleteCapabilities {
4035 #[must_use]
4036 pub fn new() -> Self {
4037 Self::default()
4038 }
4039
4040 #[must_use]
4046 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4047 self.meta = meta.into_option();
4048 self
4049 }
4050}
4051
4052#[skip_serializing_none]
4059#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4060#[non_exhaustive]
4061pub struct SessionAdditionalDirectoriesCapabilities {
4062 #[serde(rename = "_meta")]
4068 pub meta: Option<Meta>,
4069}
4070
4071impl SessionAdditionalDirectoriesCapabilities {
4072 #[must_use]
4073 pub fn new() -> Self {
4074 Self::default()
4075 }
4076
4077 #[must_use]
4083 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4084 self.meta = meta.into_option();
4085 self
4086 }
4087}
4088
4089#[cfg(feature = "unstable_session_fork")]
4097#[skip_serializing_none]
4098#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4099#[non_exhaustive]
4100pub struct SessionForkCapabilities {
4101 #[serde(rename = "_meta")]
4107 pub meta: Option<Meta>,
4108}
4109
4110#[cfg(feature = "unstable_session_fork")]
4111impl SessionForkCapabilities {
4112 #[must_use]
4113 pub fn new() -> Self {
4114 Self::default()
4115 }
4116
4117 #[must_use]
4123 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4124 self.meta = meta.into_option();
4125 self
4126 }
4127}
4128
4129#[skip_serializing_none]
4133#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4134#[non_exhaustive]
4135pub struct SessionResumeCapabilities {
4136 #[serde(rename = "_meta")]
4142 pub meta: Option<Meta>,
4143}
4144
4145impl SessionResumeCapabilities {
4146 #[must_use]
4147 pub fn new() -> Self {
4148 Self::default()
4149 }
4150
4151 #[must_use]
4157 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4158 self.meta = meta.into_option();
4159 self
4160 }
4161}
4162
4163#[skip_serializing_none]
4167#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4168#[non_exhaustive]
4169pub struct SessionCloseCapabilities {
4170 #[serde(rename = "_meta")]
4176 pub meta: Option<Meta>,
4177}
4178
4179impl SessionCloseCapabilities {
4180 #[must_use]
4181 pub fn new() -> Self {
4182 Self::default()
4183 }
4184
4185 #[must_use]
4191 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4192 self.meta = meta.into_option();
4193 self
4194 }
4195}
4196
4197#[skip_serializing_none]
4210#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4211#[serde(rename_all = "camelCase")]
4212#[non_exhaustive]
4213pub struct PromptCapabilities {
4214 #[serde(default)]
4216 pub image: bool,
4217 #[serde(default)]
4219 pub audio: bool,
4220 #[serde(default)]
4225 pub embedded_context: bool,
4226 #[serde(rename = "_meta")]
4232 pub meta: Option<Meta>,
4233}
4234
4235impl PromptCapabilities {
4236 #[must_use]
4237 pub fn new() -> Self {
4238 Self::default()
4239 }
4240
4241 #[must_use]
4243 pub fn image(mut self, image: bool) -> Self {
4244 self.image = image;
4245 self
4246 }
4247
4248 #[must_use]
4250 pub fn audio(mut self, audio: bool) -> Self {
4251 self.audio = audio;
4252 self
4253 }
4254
4255 #[must_use]
4260 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4261 self.embedded_context = embedded_context;
4262 self
4263 }
4264
4265 #[must_use]
4271 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4272 self.meta = meta.into_option();
4273 self
4274 }
4275}
4276
4277#[skip_serializing_none]
4279#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4280#[serde(rename_all = "camelCase")]
4281#[non_exhaustive]
4282pub struct McpCapabilities {
4283 #[serde(default)]
4285 pub http: bool,
4286 #[serde(default)]
4288 pub sse: bool,
4289 #[cfg(feature = "unstable_mcp_over_acp")]
4295 #[serde(default)]
4296 pub acp: bool,
4297 #[serde(rename = "_meta")]
4303 pub meta: Option<Meta>,
4304}
4305
4306impl McpCapabilities {
4307 #[must_use]
4308 pub fn new() -> Self {
4309 Self::default()
4310 }
4311
4312 #[must_use]
4314 pub fn http(mut self, http: bool) -> Self {
4315 self.http = http;
4316 self
4317 }
4318
4319 #[must_use]
4321 pub fn sse(mut self, sse: bool) -> Self {
4322 self.sse = sse;
4323 self
4324 }
4325
4326 #[cfg(feature = "unstable_mcp_over_acp")]
4332 #[must_use]
4333 pub fn acp(mut self, acp: bool) -> Self {
4334 self.acp = acp;
4335 self
4336 }
4337
4338 #[must_use]
4344 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4345 self.meta = meta.into_option();
4346 self
4347 }
4348}
4349
4350#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4356#[non_exhaustive]
4357pub struct AgentMethodNames {
4358 pub initialize: &'static str,
4360 pub authenticate: &'static str,
4362 #[cfg(feature = "unstable_llm_providers")]
4364 pub providers_list: &'static str,
4365 #[cfg(feature = "unstable_llm_providers")]
4367 pub providers_set: &'static str,
4368 #[cfg(feature = "unstable_llm_providers")]
4370 pub providers_disable: &'static str,
4371 pub session_new: &'static str,
4373 pub session_load: &'static str,
4375 pub session_set_mode: &'static str,
4377 pub session_set_config_option: &'static str,
4379 pub session_prompt: &'static str,
4381 pub session_cancel: &'static str,
4383 #[cfg(feature = "unstable_mcp_over_acp")]
4385 pub mcp_message: &'static str,
4386 pub session_list: &'static str,
4388 #[cfg(feature = "unstable_session_delete")]
4390 pub session_delete: &'static str,
4391 #[cfg(feature = "unstable_session_fork")]
4393 pub session_fork: &'static str,
4394 pub session_resume: &'static str,
4396 pub session_close: &'static str,
4398 pub logout: &'static str,
4400 #[cfg(feature = "unstable_nes")]
4402 pub nes_start: &'static str,
4403 #[cfg(feature = "unstable_nes")]
4405 pub nes_suggest: &'static str,
4406 #[cfg(feature = "unstable_nes")]
4408 pub nes_accept: &'static str,
4409 #[cfg(feature = "unstable_nes")]
4411 pub nes_reject: &'static str,
4412 #[cfg(feature = "unstable_nes")]
4414 pub nes_close: &'static str,
4415 #[cfg(feature = "unstable_nes")]
4417 pub document_did_open: &'static str,
4418 #[cfg(feature = "unstable_nes")]
4420 pub document_did_change: &'static str,
4421 #[cfg(feature = "unstable_nes")]
4423 pub document_did_close: &'static str,
4424 #[cfg(feature = "unstable_nes")]
4426 pub document_did_save: &'static str,
4427 #[cfg(feature = "unstable_nes")]
4429 pub document_did_focus: &'static str,
4430}
4431
4432pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4434 initialize: INITIALIZE_METHOD_NAME,
4435 authenticate: AUTHENTICATE_METHOD_NAME,
4436 #[cfg(feature = "unstable_llm_providers")]
4437 providers_list: PROVIDERS_LIST_METHOD_NAME,
4438 #[cfg(feature = "unstable_llm_providers")]
4439 providers_set: PROVIDERS_SET_METHOD_NAME,
4440 #[cfg(feature = "unstable_llm_providers")]
4441 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4442 session_new: SESSION_NEW_METHOD_NAME,
4443 session_load: SESSION_LOAD_METHOD_NAME,
4444 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4445 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4446 session_prompt: SESSION_PROMPT_METHOD_NAME,
4447 session_cancel: SESSION_CANCEL_METHOD_NAME,
4448 #[cfg(feature = "unstable_mcp_over_acp")]
4449 mcp_message: MCP_MESSAGE_METHOD_NAME,
4450 session_list: SESSION_LIST_METHOD_NAME,
4451 #[cfg(feature = "unstable_session_delete")]
4452 session_delete: SESSION_DELETE_METHOD_NAME,
4453 #[cfg(feature = "unstable_session_fork")]
4454 session_fork: SESSION_FORK_METHOD_NAME,
4455 session_resume: SESSION_RESUME_METHOD_NAME,
4456 session_close: SESSION_CLOSE_METHOD_NAME,
4457 logout: LOGOUT_METHOD_NAME,
4458 #[cfg(feature = "unstable_nes")]
4459 nes_start: NES_START_METHOD_NAME,
4460 #[cfg(feature = "unstable_nes")]
4461 nes_suggest: NES_SUGGEST_METHOD_NAME,
4462 #[cfg(feature = "unstable_nes")]
4463 nes_accept: NES_ACCEPT_METHOD_NAME,
4464 #[cfg(feature = "unstable_nes")]
4465 nes_reject: NES_REJECT_METHOD_NAME,
4466 #[cfg(feature = "unstable_nes")]
4467 nes_close: NES_CLOSE_METHOD_NAME,
4468 #[cfg(feature = "unstable_nes")]
4469 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4470 #[cfg(feature = "unstable_nes")]
4471 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4472 #[cfg(feature = "unstable_nes")]
4473 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4474 #[cfg(feature = "unstable_nes")]
4475 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4476 #[cfg(feature = "unstable_nes")]
4477 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4478};
4479
4480pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4482pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4484#[cfg(feature = "unstable_llm_providers")]
4486pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4487#[cfg(feature = "unstable_llm_providers")]
4489pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4490#[cfg(feature = "unstable_llm_providers")]
4492pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4493pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4495pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4497pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4499pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4501pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4503pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4505pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4507#[cfg(feature = "unstable_session_delete")]
4509pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
4510#[cfg(feature = "unstable_session_fork")]
4512pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4513pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4515pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4517pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4519
4520#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4527#[serde(untagged)]
4528#[schemars(inline)]
4529#[non_exhaustive]
4530#[allow(clippy::large_enum_variant)]
4531pub enum ClientRequest {
4532 InitializeRequest(InitializeRequest),
4543 AuthenticateRequest(AuthenticateRequest),
4553 #[cfg(feature = "unstable_llm_providers")]
4559 ListProvidersRequest(ListProvidersRequest),
4560 #[cfg(feature = "unstable_llm_providers")]
4566 SetProviderRequest(SetProviderRequest),
4567 #[cfg(feature = "unstable_llm_providers")]
4573 DisableProviderRequest(DisableProviderRequest),
4574 LogoutRequest(LogoutRequest),
4579 NewSessionRequest(NewSessionRequest),
4592 LoadSessionRequest(LoadSessionRequest),
4603 ListSessionsRequest(ListSessionsRequest),
4609 #[cfg(feature = "unstable_session_delete")]
4617 DeleteSessionRequest(DeleteSessionRequest),
4618 #[cfg(feature = "unstable_session_fork")]
4619 ForkSessionRequest(ForkSessionRequest),
4631 ResumeSessionRequest(ResumeSessionRequest),
4638 CloseSessionRequest(CloseSessionRequest),
4645 SetSessionModeRequest(SetSessionModeRequest),
4659 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4661 PromptRequest(PromptRequest),
4673 #[cfg(feature = "unstable_nes")]
4674 StartNesRequest(StartNesRequest),
4680 #[cfg(feature = "unstable_nes")]
4681 SuggestNesRequest(SuggestNesRequest),
4687 #[cfg(feature = "unstable_nes")]
4688 CloseNesRequest(CloseNesRequest),
4697 #[cfg(feature = "unstable_mcp_over_acp")]
4703 MessageMcpRequest(MessageMcpRequest),
4704 ExtMethodRequest(ExtRequest),
4711}
4712
4713impl ClientRequest {
4714 #[must_use]
4716 pub fn method(&self) -> &str {
4717 match self {
4718 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4719 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4720 #[cfg(feature = "unstable_llm_providers")]
4721 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4722 #[cfg(feature = "unstable_llm_providers")]
4723 Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
4724 #[cfg(feature = "unstable_llm_providers")]
4725 Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4726 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4727 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4728 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4729 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4730 #[cfg(feature = "unstable_session_delete")]
4731 Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
4732 #[cfg(feature = "unstable_session_fork")]
4733 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
4734 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
4735 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
4736 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
4737 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
4738 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
4739 #[cfg(feature = "unstable_nes")]
4740 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
4741 #[cfg(feature = "unstable_nes")]
4742 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
4743 #[cfg(feature = "unstable_nes")]
4744 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
4745 #[cfg(feature = "unstable_mcp_over_acp")]
4746 Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
4747 Self::ExtMethodRequest(ext_request) => &ext_request.method,
4748 }
4749 }
4750}
4751
4752#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4759#[serde(untagged)]
4760#[schemars(inline)]
4761#[non_exhaustive]
4762#[allow(clippy::large_enum_variant)]
4763pub enum AgentResponse {
4764 InitializeResponse(InitializeResponse),
4765 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
4766 #[cfg(feature = "unstable_llm_providers")]
4767 ListProvidersResponse(ListProvidersResponse),
4768 #[cfg(feature = "unstable_llm_providers")]
4769 SetProviderResponse(#[serde(default)] SetProviderResponse),
4770 #[cfg(feature = "unstable_llm_providers")]
4771 DisableProviderResponse(#[serde(default)] DisableProviderResponse),
4772 LogoutResponse(#[serde(default)] LogoutResponse),
4773 NewSessionResponse(NewSessionResponse),
4774 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
4775 ListSessionsResponse(ListSessionsResponse),
4776 #[cfg(feature = "unstable_session_delete")]
4777 DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
4778 #[cfg(feature = "unstable_session_fork")]
4779 ForkSessionResponse(ForkSessionResponse),
4780 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
4781 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
4782 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
4783 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
4784 PromptResponse(PromptResponse),
4785 #[cfg(feature = "unstable_nes")]
4786 StartNesResponse(StartNesResponse),
4787 #[cfg(feature = "unstable_nes")]
4788 SuggestNesResponse(SuggestNesResponse),
4789 #[cfg(feature = "unstable_nes")]
4790 CloseNesResponse(#[serde(default)] CloseNesResponse),
4791 ExtMethodResponse(ExtResponse),
4792 #[cfg(feature = "unstable_mcp_over_acp")]
4793 MessageMcpResponse(MessageMcpResponse),
4794}
4795
4796#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4803#[serde(untagged)]
4804#[schemars(inline)]
4805#[non_exhaustive]
4806pub enum ClientNotification {
4807 CancelNotification(CancelNotification),
4819 #[cfg(feature = "unstable_nes")]
4820 DidOpenDocumentNotification(DidOpenDocumentNotification),
4824 #[cfg(feature = "unstable_nes")]
4825 DidChangeDocumentNotification(DidChangeDocumentNotification),
4829 #[cfg(feature = "unstable_nes")]
4830 DidCloseDocumentNotification(DidCloseDocumentNotification),
4834 #[cfg(feature = "unstable_nes")]
4835 DidSaveDocumentNotification(DidSaveDocumentNotification),
4839 #[cfg(feature = "unstable_nes")]
4840 DidFocusDocumentNotification(DidFocusDocumentNotification),
4844 #[cfg(feature = "unstable_nes")]
4845 AcceptNesNotification(AcceptNesNotification),
4849 #[cfg(feature = "unstable_nes")]
4850 RejectNesNotification(RejectNesNotification),
4854 #[cfg(feature = "unstable_mcp_over_acp")]
4860 MessageMcpNotification(MessageMcpNotification),
4861 ExtNotification(ExtNotification),
4868}
4869
4870impl ClientNotification {
4871 #[must_use]
4873 pub fn method(&self) -> &str {
4874 match self {
4875 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
4876 #[cfg(feature = "unstable_nes")]
4877 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
4878 #[cfg(feature = "unstable_nes")]
4879 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
4880 #[cfg(feature = "unstable_nes")]
4881 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
4882 #[cfg(feature = "unstable_nes")]
4883 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
4884 #[cfg(feature = "unstable_nes")]
4885 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
4886 #[cfg(feature = "unstable_nes")]
4887 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
4888 #[cfg(feature = "unstable_nes")]
4889 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
4890 #[cfg(feature = "unstable_mcp_over_acp")]
4891 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
4892 Self::ExtNotification(ext_notification) => &ext_notification.method,
4893 }
4894 }
4895}
4896
4897#[skip_serializing_none]
4901#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4902#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
4903#[serde(rename_all = "camelCase")]
4904#[non_exhaustive]
4905pub struct CancelNotification {
4906 pub session_id: SessionId,
4908 #[serde(rename = "_meta")]
4914 pub meta: Option<Meta>,
4915}
4916
4917impl CancelNotification {
4918 #[must_use]
4919 pub fn new(session_id: impl Into<SessionId>) -> Self {
4920 Self {
4921 session_id: session_id.into(),
4922 meta: None,
4923 }
4924 }
4925
4926 #[must_use]
4932 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4933 self.meta = meta.into_option();
4934 self
4935 }
4936}
4937
4938#[cfg(test)]
4939mod test_serialization {
4940 use super::*;
4941 use serde_json::json;
4942
4943 #[test]
4944 fn test_mcp_server_stdio_serialization() {
4945 let server = McpServer::Stdio(
4946 McpServerStdio::new("test-server", "/usr/bin/server")
4947 .args(vec!["--port".to_string(), "3000".to_string()])
4948 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
4949 );
4950
4951 let json = serde_json::to_value(&server).unwrap();
4952 assert_eq!(
4953 json,
4954 json!({
4955 "name": "test-server",
4956 "command": "/usr/bin/server",
4957 "args": ["--port", "3000"],
4958 "env": [
4959 {
4960 "name": "API_KEY",
4961 "value": "secret123"
4962 }
4963 ]
4964 })
4965 );
4966
4967 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4968 match deserialized {
4969 McpServer::Stdio(McpServerStdio {
4970 name,
4971 command,
4972 args,
4973 env,
4974 meta: _,
4975 }) => {
4976 assert_eq!(name, "test-server");
4977 assert_eq!(command, PathBuf::from("/usr/bin/server"));
4978 assert_eq!(args, vec!["--port", "3000"]);
4979 assert_eq!(env.len(), 1);
4980 assert_eq!(env[0].name, "API_KEY");
4981 assert_eq!(env[0].value, "secret123");
4982 }
4983 _ => panic!("Expected Stdio variant"),
4984 }
4985 }
4986
4987 #[test]
4988 fn test_mcp_server_http_serialization() {
4989 let server = McpServer::Http(
4990 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
4991 HttpHeader::new("Authorization", "Bearer token123"),
4992 HttpHeader::new("Content-Type", "application/json"),
4993 ]),
4994 );
4995
4996 let json = serde_json::to_value(&server).unwrap();
4997 assert_eq!(
4998 json,
4999 json!({
5000 "type": "http",
5001 "name": "http-server",
5002 "url": "https://api.example.com",
5003 "headers": [
5004 {
5005 "name": "Authorization",
5006 "value": "Bearer token123"
5007 },
5008 {
5009 "name": "Content-Type",
5010 "value": "application/json"
5011 }
5012 ]
5013 })
5014 );
5015
5016 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5017 match deserialized {
5018 McpServer::Http(McpServerHttp {
5019 name,
5020 url,
5021 headers,
5022 meta: _,
5023 }) => {
5024 assert_eq!(name, "http-server");
5025 assert_eq!(url, "https://api.example.com");
5026 assert_eq!(headers.len(), 2);
5027 assert_eq!(headers[0].name, "Authorization");
5028 assert_eq!(headers[0].value, "Bearer token123");
5029 assert_eq!(headers[1].name, "Content-Type");
5030 assert_eq!(headers[1].value, "application/json");
5031 }
5032 _ => panic!("Expected Http variant"),
5033 }
5034 }
5035
5036 #[cfg(feature = "unstable_mcp_over_acp")]
5037 #[test]
5038 fn test_mcp_server_acp_serialization() {
5039 let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id"));
5040
5041 let json = serde_json::to_value(&server).unwrap();
5042 assert_eq!(
5043 json,
5044 json!({
5045 "type": "acp",
5046 "name": "project-tools",
5047 "id": "project-tools-id"
5048 })
5049 );
5050
5051 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5052 match deserialized {
5053 McpServer::Acp(McpServerAcp { name, id, meta: _ }) => {
5054 assert_eq!(name, "project-tools");
5055 assert_eq!(id, McpServerAcpId::new("project-tools-id"));
5056 }
5057 _ => panic!("Expected Acp variant"),
5058 }
5059 }
5060
5061 #[cfg(feature = "unstable_mcp_over_acp")]
5062 #[test]
5063 fn test_client_mcp_message_method_names() {
5064 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5065
5066 assert_eq!(
5067 ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
5068 .method(),
5069 "mcp/message"
5070 );
5071 assert_eq!(
5072 ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
5073 "conn-1",
5074 "notifications/progress"
5075 ))
5076 .method(),
5077 "mcp/message"
5078 );
5079 }
5080
5081 #[cfg(feature = "unstable_mcp_over_acp")]
5082 #[test]
5083 fn test_mcp_server_acp_schema() {
5084 let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap();
5085 assert!(json_contains_entry(
5086 &mcp_server_schema,
5087 "const",
5088 &json!("acp")
5089 ));
5090 assert!(json_contains_entry(
5091 &mcp_server_schema,
5092 "$ref",
5093 &json!("#/$defs/McpServerAcp")
5094 ));
5095
5096 let capabilities_schema =
5097 serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap();
5098 assert!(json_contains_key(&capabilities_schema, "acp"));
5099 }
5100
5101 #[cfg(feature = "unstable_mcp_over_acp")]
5102 fn json_contains_entry(
5103 value: &serde_json::Value,
5104 key: &str,
5105 expected: &serde_json::Value,
5106 ) -> bool {
5107 match value {
5108 serde_json::Value::Object(map) => {
5109 map.get(key) == Some(expected)
5110 || map
5111 .values()
5112 .any(|value| json_contains_entry(value, key, expected))
5113 }
5114 serde_json::Value::Array(values) => values
5115 .iter()
5116 .any(|value| json_contains_entry(value, key, expected)),
5117 _ => false,
5118 }
5119 }
5120
5121 #[cfg(feature = "unstable_mcp_over_acp")]
5122 fn json_contains_key(value: &serde_json::Value, key: &str) -> bool {
5123 match value {
5124 serde_json::Value::Object(map) => {
5125 map.contains_key(key) || map.values().any(|value| json_contains_key(value, key))
5126 }
5127 serde_json::Value::Array(values) => {
5128 values.iter().any(|value| json_contains_key(value, key))
5129 }
5130 _ => false,
5131 }
5132 }
5133
5134 #[test]
5135 fn test_mcp_server_sse_serialization() {
5136 let server = McpServer::Sse(
5137 McpServerSse::new("sse-server", "https://sse.example.com/events")
5138 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5139 );
5140
5141 let json = serde_json::to_value(&server).unwrap();
5142 assert_eq!(
5143 json,
5144 json!({
5145 "type": "sse",
5146 "name": "sse-server",
5147 "url": "https://sse.example.com/events",
5148 "headers": [
5149 {
5150 "name": "X-API-Key",
5151 "value": "apikey456"
5152 }
5153 ]
5154 })
5155 );
5156
5157 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5158 match deserialized {
5159 McpServer::Sse(McpServerSse {
5160 name,
5161 url,
5162 headers,
5163 meta: _,
5164 }) => {
5165 assert_eq!(name, "sse-server");
5166 assert_eq!(url, "https://sse.example.com/events");
5167 assert_eq!(headers.len(), 1);
5168 assert_eq!(headers[0].name, "X-API-Key");
5169 assert_eq!(headers[0].value, "apikey456");
5170 }
5171 _ => panic!("Expected Sse variant"),
5172 }
5173 }
5174
5175 #[test]
5176 fn test_session_config_option_category_known_variants() {
5177 assert_eq!(
5179 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5180 json!("mode")
5181 );
5182 assert_eq!(
5183 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5184 json!("model")
5185 );
5186 assert_eq!(
5187 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5188 json!("thought_level")
5189 );
5190
5191 assert_eq!(
5193 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5194 SessionConfigOptionCategory::Mode
5195 );
5196 assert_eq!(
5197 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5198 SessionConfigOptionCategory::Model
5199 );
5200 assert_eq!(
5201 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5202 SessionConfigOptionCategory::ThoughtLevel
5203 );
5204 }
5205
5206 #[test]
5207 fn test_session_config_option_category_unknown_variants() {
5208 let unknown: SessionConfigOptionCategory =
5210 serde_json::from_str("\"some_future_category\"").unwrap();
5211 assert_eq!(
5212 unknown,
5213 SessionConfigOptionCategory::Other("some_future_category".to_string())
5214 );
5215
5216 let json = serde_json::to_value(&unknown).unwrap();
5218 assert_eq!(json, json!("some_future_category"));
5219 }
5220
5221 #[test]
5222 fn test_session_config_option_category_custom_categories() {
5223 let custom: SessionConfigOptionCategory =
5225 serde_json::from_str("\"_my_custom_category\"").unwrap();
5226 assert_eq!(
5227 custom,
5228 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5229 );
5230
5231 let json = serde_json::to_value(&custom).unwrap();
5233 assert_eq!(json, json!("_my_custom_category"));
5234
5235 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5237 assert_eq!(
5238 deserialized,
5239 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5240 );
5241 }
5242
5243 #[test]
5244 fn test_auth_method_agent_serialization() {
5245 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5246
5247 let json = serde_json::to_value(&method).unwrap();
5248 assert_eq!(
5249 json,
5250 json!({
5251 "id": "default-auth",
5252 "name": "Default Auth"
5253 })
5254 );
5255 assert!(!json.as_object().unwrap().contains_key("description"));
5257 assert!(!json.as_object().unwrap().contains_key("type"));
5259
5260 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5261 match deserialized {
5262 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5263 assert_eq!(id.0.as_ref(), "default-auth");
5264 assert_eq!(name, "Default Auth");
5265 }
5266 #[cfg(feature = "unstable_auth_methods")]
5267 _ => panic!("Expected Agent variant"),
5268 }
5269 }
5270
5271 #[test]
5272 fn test_auth_method_explicit_agent_deserialization() {
5273 let json = json!({
5275 "id": "agent-auth",
5276 "name": "Agent Auth",
5277 "type": "agent"
5278 });
5279
5280 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5281 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5282 }
5283
5284 #[cfg(feature = "unstable_session_delete")]
5285 #[test]
5286 fn test_session_delete_serialization() {
5287 assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5288 assert_eq!(
5289 ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5290 "session/delete"
5291 );
5292 assert_eq!(
5293 serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5294 json!({
5295 "sessionId": "sess_abc123"
5296 })
5297 );
5298 assert_eq!(
5299 serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5300 json!({})
5301 );
5302 assert_eq!(
5303 serde_json::to_value(
5304 SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5305 )
5306 .unwrap(),
5307 json!({
5308 "delete": {}
5309 })
5310 );
5311 }
5312 #[test]
5313 fn test_session_additional_directories_serialization() {
5314 assert_eq!(
5315 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5316 json!({
5317 "cwd": "/home/user/project",
5318 "mcpServers": []
5319 })
5320 );
5321 assert_eq!(
5322 serde_json::to_value(
5323 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5324 PathBuf::from("/home/user/shared-lib"),
5325 PathBuf::from("/home/user/product-docs"),
5326 ])
5327 )
5328 .unwrap(),
5329 json!({
5330 "cwd": "/home/user/project",
5331 "additionalDirectories": [
5332 "/home/user/shared-lib",
5333 "/home/user/product-docs"
5334 ],
5335 "mcpServers": []
5336 })
5337 );
5338 assert_eq!(
5339 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5340 json!({
5341 "sessionId": "sess_abc123",
5342 "cwd": "/home/user/project"
5343 })
5344 );
5345 assert_eq!(
5346 serde_json::to_value(
5347 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5348 PathBuf::from("/home/user/shared-lib"),
5349 PathBuf::from("/home/user/product-docs"),
5350 ])
5351 )
5352 .unwrap(),
5353 json!({
5354 "sessionId": "sess_abc123",
5355 "cwd": "/home/user/project",
5356 "additionalDirectories": [
5357 "/home/user/shared-lib",
5358 "/home/user/product-docs"
5359 ]
5360 })
5361 );
5362 assert_eq!(
5363 serde_json::from_value::<SessionInfo>(json!({
5364 "sessionId": "sess_abc123",
5365 "cwd": "/home/user/project"
5366 }))
5367 .unwrap()
5368 .additional_directories,
5369 Vec::<PathBuf>::new()
5370 );
5371 }
5372 #[test]
5373 fn test_session_additional_directories_capabilities_serialization() {
5374 assert_eq!(
5375 serde_json::to_value(
5376 SessionCapabilities::new()
5377 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5378 )
5379 .unwrap(),
5380 json!({
5381 "additionalDirectories": {}
5382 })
5383 );
5384 }
5385
5386 #[cfg(feature = "unstable_auth_methods")]
5387 #[test]
5388 fn test_auth_method_env_var_serialization() {
5389 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5390 "api-key",
5391 "API Key",
5392 vec![AuthEnvVar::new("API_KEY")],
5393 ));
5394
5395 let json = serde_json::to_value(&method).unwrap();
5396 assert_eq!(
5397 json,
5398 json!({
5399 "id": "api-key",
5400 "name": "API Key",
5401 "type": "env_var",
5402 "vars": [{"name": "API_KEY"}]
5403 })
5404 );
5405 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5407 assert!(
5408 !json["vars"][0]
5409 .as_object()
5410 .unwrap()
5411 .contains_key("optional")
5412 );
5413
5414 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5415 match deserialized {
5416 AuthMethod::EnvVar(AuthMethodEnvVar {
5417 id,
5418 name: method_name,
5419 vars,
5420 link,
5421 ..
5422 }) => {
5423 assert_eq!(id.0.as_ref(), "api-key");
5424 assert_eq!(method_name, "API Key");
5425 assert_eq!(vars.len(), 1);
5426 assert_eq!(vars[0].name, "API_KEY");
5427 assert!(vars[0].secret);
5428 assert!(!vars[0].optional);
5429 assert!(link.is_none());
5430 }
5431 _ => panic!("Expected EnvVar variant"),
5432 }
5433 }
5434
5435 #[cfg(feature = "unstable_auth_methods")]
5436 #[test]
5437 fn test_auth_method_env_var_with_link_serialization() {
5438 let method = AuthMethod::EnvVar(
5439 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5440 .link("https://example.com/keys"),
5441 );
5442
5443 let json = serde_json::to_value(&method).unwrap();
5444 assert_eq!(
5445 json,
5446 json!({
5447 "id": "api-key",
5448 "name": "API Key",
5449 "type": "env_var",
5450 "vars": [{"name": "API_KEY"}],
5451 "link": "https://example.com/keys"
5452 })
5453 );
5454
5455 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5456 match deserialized {
5457 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5458 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5459 }
5460 _ => panic!("Expected EnvVar variant"),
5461 }
5462 }
5463
5464 #[cfg(feature = "unstable_auth_methods")]
5465 #[test]
5466 fn test_auth_method_env_var_multiple_vars() {
5467 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5468 "azure-openai",
5469 "Azure OpenAI",
5470 vec![
5471 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5472 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5473 .label("Endpoint URL")
5474 .secret(false),
5475 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5476 .label("API Version")
5477 .secret(false)
5478 .optional(true),
5479 ],
5480 ));
5481
5482 let json = serde_json::to_value(&method).unwrap();
5483 assert_eq!(
5484 json,
5485 json!({
5486 "id": "azure-openai",
5487 "name": "Azure OpenAI",
5488 "type": "env_var",
5489 "vars": [
5490 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5491 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5492 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5493 ]
5494 })
5495 );
5496
5497 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5498 match deserialized {
5499 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5500 assert_eq!(vars.len(), 3);
5501 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5503 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5504 assert!(vars[0].secret);
5505 assert!(!vars[0].optional);
5506 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5508 assert!(!vars[1].secret);
5509 assert!(!vars[1].optional);
5510 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5512 assert!(!vars[2].secret);
5513 assert!(vars[2].optional);
5514 }
5515 _ => panic!("Expected EnvVar variant"),
5516 }
5517 }
5518
5519 #[cfg(feature = "unstable_auth_methods")]
5520 #[test]
5521 fn test_auth_method_terminal_serialization() {
5522 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5523
5524 let json = serde_json::to_value(&method).unwrap();
5525 assert_eq!(
5526 json,
5527 json!({
5528 "id": "tui-auth",
5529 "name": "Terminal Auth",
5530 "type": "terminal"
5531 })
5532 );
5533 assert!(!json.as_object().unwrap().contains_key("args"));
5535 assert!(!json.as_object().unwrap().contains_key("env"));
5536
5537 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5538 match deserialized {
5539 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5540 assert!(args.is_empty());
5541 assert!(env.is_empty());
5542 }
5543 _ => panic!("Expected Terminal variant"),
5544 }
5545 }
5546
5547 #[cfg(feature = "unstable_auth_methods")]
5548 #[test]
5549 fn test_auth_method_terminal_with_args_and_env_serialization() {
5550 use std::collections::HashMap;
5551
5552 let mut env = HashMap::new();
5553 env.insert("TERM".to_string(), "xterm-256color".to_string());
5554
5555 let method = AuthMethod::Terminal(
5556 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5557 .args(vec!["--interactive".to_string(), "--color".to_string()])
5558 .env(env),
5559 );
5560
5561 let json = serde_json::to_value(&method).unwrap();
5562 assert_eq!(
5563 json,
5564 json!({
5565 "id": "tui-auth",
5566 "name": "Terminal Auth",
5567 "type": "terminal",
5568 "args": ["--interactive", "--color"],
5569 "env": {
5570 "TERM": "xterm-256color"
5571 }
5572 })
5573 );
5574
5575 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5576 match deserialized {
5577 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5578 assert_eq!(args, vec!["--interactive", "--color"]);
5579 assert_eq!(env.len(), 1);
5580 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5581 }
5582 _ => panic!("Expected Terminal variant"),
5583 }
5584 }
5585
5586 #[cfg(feature = "unstable_boolean_config")]
5587 #[test]
5588 fn test_session_config_option_value_id_serialize() {
5589 let val = SessionConfigOptionValue::value_id("model-1");
5590 let json = serde_json::to_value(&val).unwrap();
5591 assert_eq!(json, json!({ "value": "model-1" }));
5593 assert!(!json.as_object().unwrap().contains_key("type"));
5594 }
5595
5596 #[cfg(feature = "unstable_boolean_config")]
5597 #[test]
5598 fn test_session_config_option_value_boolean_serialize() {
5599 let val = SessionConfigOptionValue::boolean(true);
5600 let json = serde_json::to_value(&val).unwrap();
5601 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5602 }
5603
5604 #[cfg(feature = "unstable_boolean_config")]
5605 #[test]
5606 fn test_session_config_option_value_deserialize_no_type() {
5607 let json = json!({ "value": "model-1" });
5609 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5610 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5611 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5612 }
5613
5614 #[cfg(feature = "unstable_boolean_config")]
5615 #[test]
5616 fn test_session_config_option_value_deserialize_boolean() {
5617 let json = json!({ "type": "boolean", "value": true });
5618 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5619 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5620 assert_eq!(val.as_bool(), Some(true));
5621 }
5622
5623 #[cfg(feature = "unstable_boolean_config")]
5624 #[test]
5625 fn test_session_config_option_value_deserialize_boolean_false() {
5626 let json = json!({ "type": "boolean", "value": false });
5627 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5628 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5629 assert_eq!(val.as_bool(), Some(false));
5630 }
5631
5632 #[cfg(feature = "unstable_boolean_config")]
5633 #[test]
5634 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5635 let json = json!({ "type": "text", "value": "freeform input" });
5637 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5638 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5639 }
5640
5641 #[cfg(feature = "unstable_boolean_config")]
5642 #[test]
5643 fn test_session_config_option_value_roundtrip_value_id() {
5644 let original = SessionConfigOptionValue::value_id("option-a");
5645 let json = serde_json::to_value(&original).unwrap();
5646 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5647 assert_eq!(original, roundtripped);
5648 }
5649
5650 #[cfg(feature = "unstable_boolean_config")]
5651 #[test]
5652 fn test_session_config_option_value_roundtrip_boolean() {
5653 let original = SessionConfigOptionValue::boolean(false);
5654 let json = serde_json::to_value(&original).unwrap();
5655 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5656 assert_eq!(original, roundtripped);
5657 }
5658
5659 #[cfg(feature = "unstable_boolean_config")]
5660 #[test]
5661 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5662 let json = json!({ "type": "boolean", "value": "not a bool" });
5664 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5665 assert!(result.is_ok());
5667 assert_eq!(
5668 result.unwrap().as_value_id().unwrap().to_string(),
5669 "not a bool"
5670 );
5671 }
5672
5673 #[cfg(feature = "unstable_boolean_config")]
5674 #[test]
5675 fn test_session_config_option_value_from_impls() {
5676 let from_str: SessionConfigOptionValue = "model-1".into();
5677 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5678
5679 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5680 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5681
5682 let from_bool: SessionConfigOptionValue = true.into();
5683 assert_eq!(from_bool.as_bool(), Some(true));
5684 }
5685
5686 #[cfg(feature = "unstable_boolean_config")]
5687 #[test]
5688 fn test_set_session_config_option_request_value_id() {
5689 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5690 let json = serde_json::to_value(&req).unwrap();
5691 assert_eq!(
5692 json,
5693 json!({
5694 "sessionId": "sess_1",
5695 "configId": "model",
5696 "value": "model-1"
5697 })
5698 );
5699 assert!(!json.as_object().unwrap().contains_key("type"));
5701 }
5702
5703 #[cfg(feature = "unstable_boolean_config")]
5704 #[test]
5705 fn test_set_session_config_option_request_boolean() {
5706 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5707 let json = serde_json::to_value(&req).unwrap();
5708 assert_eq!(
5709 json,
5710 json!({
5711 "sessionId": "sess_1",
5712 "configId": "brave_mode",
5713 "type": "boolean",
5714 "value": true
5715 })
5716 );
5717 }
5718
5719 #[cfg(feature = "unstable_boolean_config")]
5720 #[test]
5721 fn test_set_session_config_option_request_deserialize_no_type() {
5722 let json = json!({
5724 "sessionId": "sess_1",
5725 "configId": "model",
5726 "value": "model-1"
5727 });
5728 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5729 assert_eq!(req.session_id.to_string(), "sess_1");
5730 assert_eq!(req.config_id.to_string(), "model");
5731 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5732 }
5733
5734 #[cfg(feature = "unstable_boolean_config")]
5735 #[test]
5736 fn test_set_session_config_option_request_deserialize_boolean() {
5737 let json = json!({
5738 "sessionId": "sess_1",
5739 "configId": "brave_mode",
5740 "type": "boolean",
5741 "value": true
5742 });
5743 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5744 assert_eq!(req.value.as_bool(), Some(true));
5745 }
5746
5747 #[cfg(feature = "unstable_boolean_config")]
5748 #[test]
5749 fn test_set_session_config_option_request_roundtrip_value_id() {
5750 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5751 let json = serde_json::to_value(&original).unwrap();
5752 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5753 assert_eq!(original, roundtripped);
5754 }
5755
5756 #[cfg(feature = "unstable_boolean_config")]
5757 #[test]
5758 fn test_set_session_config_option_request_roundtrip_boolean() {
5759 let original = SetSessionConfigOptionRequest::new("s", "c", false);
5760 let json = serde_json::to_value(&original).unwrap();
5761 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5762 assert_eq!(original, roundtripped);
5763 }
5764
5765 #[cfg(feature = "unstable_boolean_config")]
5766 #[test]
5767 fn test_session_config_boolean_serialization() {
5768 let cfg = SessionConfigBoolean::new(true);
5769 let json = serde_json::to_value(&cfg).unwrap();
5770 assert_eq!(json, json!({ "currentValue": true }));
5771
5772 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
5773 assert!(deserialized.current_value);
5774 }
5775
5776 #[cfg(feature = "unstable_boolean_config")]
5777 #[test]
5778 fn test_session_config_option_boolean_variant() {
5779 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
5780 .description("Skip confirmation prompts");
5781 let json = serde_json::to_value(&opt).unwrap();
5782 assert_eq!(
5783 json,
5784 json!({
5785 "id": "brave_mode",
5786 "name": "Brave Mode",
5787 "description": "Skip confirmation prompts",
5788 "type": "boolean",
5789 "currentValue": false
5790 })
5791 );
5792
5793 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5794 assert_eq!(deserialized.id.to_string(), "brave_mode");
5795 assert_eq!(deserialized.name, "Brave Mode");
5796 match deserialized.kind {
5797 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
5798 _ => panic!("Expected Boolean kind"),
5799 }
5800 }
5801
5802 #[cfg(feature = "unstable_boolean_config")]
5803 #[test]
5804 fn test_session_config_option_select_still_works() {
5805 let opt = SessionConfigOption::select(
5807 "model",
5808 "Model",
5809 "model-1",
5810 vec![
5811 SessionConfigSelectOption::new("model-1", "Model 1"),
5812 SessionConfigSelectOption::new("model-2", "Model 2"),
5813 ],
5814 );
5815 let json = serde_json::to_value(&opt).unwrap();
5816 assert_eq!(json["type"], "select");
5817 assert_eq!(json["currentValue"], "model-1");
5818 assert_eq!(json["options"].as_array().unwrap().len(), 2);
5819
5820 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5821 match deserialized.kind {
5822 SessionConfigKind::Select(ref s) => {
5823 assert_eq!(s.current_value.to_string(), "model-1");
5824 }
5825 _ => panic!("Expected Select kind"),
5826 }
5827 }
5828
5829 #[cfg(feature = "unstable_llm_providers")]
5830 #[test]
5831 fn test_llm_protocol_known_variants() {
5832 assert_eq!(
5833 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
5834 json!("anthropic")
5835 );
5836 assert_eq!(
5837 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
5838 json!("openai")
5839 );
5840 assert_eq!(
5841 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
5842 json!("azure")
5843 );
5844 assert_eq!(
5845 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
5846 json!("vertex")
5847 );
5848 assert_eq!(
5849 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
5850 json!("bedrock")
5851 );
5852
5853 assert_eq!(
5854 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
5855 LlmProtocol::Anthropic
5856 );
5857 assert_eq!(
5858 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
5859 LlmProtocol::OpenAi
5860 );
5861 assert_eq!(
5862 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
5863 LlmProtocol::Azure
5864 );
5865 assert_eq!(
5866 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
5867 LlmProtocol::Vertex
5868 );
5869 assert_eq!(
5870 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
5871 LlmProtocol::Bedrock
5872 );
5873 }
5874
5875 #[cfg(feature = "unstable_llm_providers")]
5876 #[test]
5877 fn test_llm_protocol_unknown_variant() {
5878 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
5879 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
5880
5881 let json = serde_json::to_value(&unknown).unwrap();
5882 assert_eq!(json, json!("cohere"));
5883 }
5884
5885 #[cfg(feature = "unstable_llm_providers")]
5886 #[test]
5887 fn test_provider_current_config_serialization() {
5888 let config =
5889 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
5890
5891 let json = serde_json::to_value(&config).unwrap();
5892 assert_eq!(
5893 json,
5894 json!({
5895 "apiType": "anthropic",
5896 "baseUrl": "https://api.anthropic.com"
5897 })
5898 );
5899
5900 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
5901 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
5902 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
5903 }
5904
5905 #[cfg(feature = "unstable_llm_providers")]
5906 #[test]
5907 fn test_provider_info_with_current_config() {
5908 let info = ProviderInfo::new(
5909 "main",
5910 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
5911 true,
5912 Some(ProviderCurrentConfig::new(
5913 LlmProtocol::Anthropic,
5914 "https://api.anthropic.com",
5915 )),
5916 );
5917
5918 let json = serde_json::to_value(&info).unwrap();
5919 assert_eq!(
5920 json,
5921 json!({
5922 "id": "main",
5923 "supported": ["anthropic", "openai"],
5924 "required": true,
5925 "current": {
5926 "apiType": "anthropic",
5927 "baseUrl": "https://api.anthropic.com"
5928 }
5929 })
5930 );
5931
5932 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5933 assert_eq!(deserialized.id, "main");
5934 assert_eq!(deserialized.supported.len(), 2);
5935 assert!(deserialized.required);
5936 assert!(deserialized.current.is_some());
5937 assert_eq!(
5938 deserialized.current.as_ref().unwrap().api_type,
5939 LlmProtocol::Anthropic
5940 );
5941 }
5942
5943 #[cfg(feature = "unstable_llm_providers")]
5944 #[test]
5945 fn test_provider_info_disabled() {
5946 let info = ProviderInfo::new(
5947 "secondary",
5948 vec![LlmProtocol::OpenAi],
5949 false,
5950 None::<ProviderCurrentConfig>,
5951 );
5952
5953 let json = serde_json::to_value(&info).unwrap();
5954 assert_eq!(
5955 json,
5956 json!({
5957 "id": "secondary",
5958 "supported": ["openai"],
5959 "required": false
5960 })
5961 );
5962
5963 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5964 assert_eq!(deserialized.id, "secondary");
5965 assert!(!deserialized.required);
5966 assert!(deserialized.current.is_none());
5967 }
5968
5969 #[cfg(feature = "unstable_llm_providers")]
5970 #[test]
5971 fn test_provider_info_missing_current_defaults_to_none() {
5972 let json = json!({
5974 "id": "main",
5975 "supported": ["anthropic"],
5976 "required": true
5977 });
5978 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5979 assert!(deserialized.current.is_none());
5980 }
5981
5982 #[cfg(feature = "unstable_llm_providers")]
5983 #[test]
5984 fn test_provider_info_explicit_null_current_decodes_to_none() {
5985 let json = json!({
5989 "id": "main",
5990 "supported": ["anthropic"],
5991 "required": true,
5992 "current": null
5993 });
5994 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5995 assert!(deserialized.current.is_none());
5996 }
5997
5998 #[cfg(feature = "unstable_llm_providers")]
5999 #[test]
6000 fn test_list_providers_response_serialization() {
6001 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6002 "main",
6003 vec![LlmProtocol::Anthropic],
6004 true,
6005 Some(ProviderCurrentConfig::new(
6006 LlmProtocol::Anthropic,
6007 "https://api.anthropic.com",
6008 )),
6009 )]);
6010
6011 let json = serde_json::to_value(&response).unwrap();
6012 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6013 assert_eq!(json["providers"][0]["id"], "main");
6014
6015 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6016 assert_eq!(deserialized.providers.len(), 1);
6017 }
6018
6019 #[cfg(feature = "unstable_llm_providers")]
6020 #[test]
6021 fn test_set_provider_request_serialization() {
6022 use std::collections::HashMap;
6023
6024 let mut headers = HashMap::new();
6025 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6026
6027 let request =
6028 SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6029 .headers(headers);
6030
6031 let json = serde_json::to_value(&request).unwrap();
6032 assert_eq!(
6033 json,
6034 json!({
6035 "id": "main",
6036 "apiType": "openai",
6037 "baseUrl": "https://api.openai.com/v1",
6038 "headers": {
6039 "Authorization": "Bearer sk-test"
6040 }
6041 })
6042 );
6043
6044 let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6045 assert_eq!(deserialized.id, "main");
6046 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6047 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6048 assert_eq!(deserialized.headers.len(), 1);
6049 assert_eq!(
6050 deserialized.headers.get("Authorization").unwrap(),
6051 "Bearer sk-test"
6052 );
6053 }
6054
6055 #[cfg(feature = "unstable_llm_providers")]
6056 #[test]
6057 fn test_set_provider_request_omits_empty_headers() {
6058 let request =
6059 SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6060
6061 let json = serde_json::to_value(&request).unwrap();
6062 assert!(!json.as_object().unwrap().contains_key("headers"));
6064 }
6065
6066 #[cfg(feature = "unstable_llm_providers")]
6067 #[test]
6068 fn test_disable_provider_request_serialization() {
6069 let request = DisableProviderRequest::new("secondary");
6070
6071 let json = serde_json::to_value(&request).unwrap();
6072 assert_eq!(json, json!({ "id": "secondary" }));
6073
6074 let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6075 assert_eq!(deserialized.id, "secondary");
6076 }
6077
6078 #[cfg(feature = "unstable_llm_providers")]
6079 #[test]
6080 fn test_providers_capabilities_serialization() {
6081 let caps = ProvidersCapabilities::new();
6082
6083 let json = serde_json::to_value(&caps).unwrap();
6084 assert_eq!(json, json!({}));
6085
6086 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6087 assert!(deserialized.meta.is_none());
6088 }
6089
6090 #[cfg(feature = "unstable_llm_providers")]
6091 #[test]
6092 fn test_agent_capabilities_with_providers() {
6093 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6094
6095 let json = serde_json::to_value(&caps).unwrap();
6096 assert_eq!(json["providers"], json!({}));
6097
6098 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6099 assert!(deserialized.providers.is_some());
6100 }
6101}