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#[skip_serializing_none]
1683#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1684#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1685#[serde(rename_all = "camelCase")]
1686#[non_exhaustive]
1687pub struct DeleteSessionRequest {
1688 pub session_id: SessionId,
1690 #[serde(rename = "_meta")]
1696 pub meta: Option<Meta>,
1697}
1698
1699impl DeleteSessionRequest {
1700 #[must_use]
1701 pub fn new(session_id: impl Into<SessionId>) -> Self {
1702 Self {
1703 session_id: session_id.into(),
1704 meta: None,
1705 }
1706 }
1707
1708 #[must_use]
1714 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1715 self.meta = meta.into_option();
1716 self
1717 }
1718}
1719
1720#[skip_serializing_none]
1722#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1723#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1724#[serde(rename_all = "camelCase")]
1725#[non_exhaustive]
1726pub struct DeleteSessionResponse {
1727 #[serde(rename = "_meta")]
1733 pub meta: Option<Meta>,
1734}
1735
1736impl DeleteSessionResponse {
1737 #[must_use]
1738 pub fn new() -> Self {
1739 Self::default()
1740 }
1741
1742 #[must_use]
1748 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1749 self.meta = meta.into_option();
1750 self
1751 }
1752}
1753
1754#[serde_as]
1756#[skip_serializing_none]
1757#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1758#[serde(rename_all = "camelCase")]
1759#[non_exhaustive]
1760pub struct SessionInfo {
1761 pub session_id: SessionId,
1763 pub cwd: PathBuf,
1765 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1771 pub additional_directories: Vec<PathBuf>,
1772
1773 #[serde_as(deserialize_as = "DefaultOnError")]
1775 #[schemars(extend("x-deserialize-default-on-error" = true))]
1776 #[serde(default)]
1777 pub title: Option<String>,
1778 #[serde_as(deserialize_as = "DefaultOnError")]
1780 #[schemars(extend("x-deserialize-default-on-error" = true))]
1781 #[serde(default)]
1782 pub updated_at: Option<String>,
1783 #[serde(rename = "_meta")]
1789 pub meta: Option<Meta>,
1790}
1791
1792impl SessionInfo {
1793 #[must_use]
1794 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1795 Self {
1796 session_id: session_id.into(),
1797 cwd: cwd.into(),
1798 additional_directories: vec![],
1799 title: None,
1800 updated_at: None,
1801 meta: None,
1802 }
1803 }
1804
1805 #[must_use]
1807 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1808 self.additional_directories = additional_directories;
1809 self
1810 }
1811
1812 #[must_use]
1814 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1815 self.title = title.into_option();
1816 self
1817 }
1818
1819 #[must_use]
1821 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1822 self.updated_at = updated_at.into_option();
1823 self
1824 }
1825
1826 #[must_use]
1832 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1833 self.meta = meta.into_option();
1834 self
1835 }
1836}
1837
1838#[serde_as]
1842#[skip_serializing_none]
1843#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1844#[serde(rename_all = "camelCase")]
1845#[non_exhaustive]
1846pub struct SessionModeState {
1847 pub current_mode_id: SessionModeId,
1849 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1851 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1852 pub available_modes: Vec<SessionMode>,
1853 #[serde(rename = "_meta")]
1859 pub meta: Option<Meta>,
1860}
1861
1862impl SessionModeState {
1863 #[must_use]
1864 pub fn new(
1865 current_mode_id: impl Into<SessionModeId>,
1866 available_modes: Vec<SessionMode>,
1867 ) -> Self {
1868 Self {
1869 current_mode_id: current_mode_id.into(),
1870 available_modes,
1871 meta: None,
1872 }
1873 }
1874
1875 #[must_use]
1881 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1882 self.meta = meta.into_option();
1883 self
1884 }
1885}
1886
1887#[skip_serializing_none]
1891#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1892#[serde(rename_all = "camelCase")]
1893#[non_exhaustive]
1894pub struct SessionMode {
1895 pub id: SessionModeId,
1896 pub name: String,
1897 #[serde(default)]
1898 pub description: Option<String>,
1899 #[serde(rename = "_meta")]
1905 pub meta: Option<Meta>,
1906}
1907
1908impl SessionMode {
1909 #[must_use]
1910 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
1911 Self {
1912 id: id.into(),
1913 name: name.into(),
1914 description: None,
1915 meta: None,
1916 }
1917 }
1918
1919 #[must_use]
1920 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1921 self.description = description.into_option();
1922 self
1923 }
1924
1925 #[must_use]
1931 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1932 self.meta = meta.into_option();
1933 self
1934 }
1935}
1936
1937#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1939#[serde(transparent)]
1940#[from(Arc<str>, String, &'static str)]
1941#[non_exhaustive]
1942pub struct SessionModeId(pub Arc<str>);
1943
1944impl SessionModeId {
1945 #[must_use]
1946 pub fn new(id: impl Into<Arc<str>>) -> Self {
1947 Self(id.into())
1948 }
1949}
1950
1951#[skip_serializing_none]
1953#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1954#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
1955#[serde(rename_all = "camelCase")]
1956#[non_exhaustive]
1957pub struct SetSessionModeRequest {
1958 pub session_id: SessionId,
1960 pub mode_id: SessionModeId,
1962 #[serde(rename = "_meta")]
1968 pub meta: Option<Meta>,
1969}
1970
1971impl SetSessionModeRequest {
1972 #[must_use]
1973 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
1974 Self {
1975 session_id: session_id.into(),
1976 mode_id: mode_id.into(),
1977 meta: None,
1978 }
1979 }
1980
1981 #[must_use]
1982 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1983 self.meta = meta.into_option();
1984 self
1985 }
1986}
1987
1988#[skip_serializing_none]
1990#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1991#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
1992#[serde(rename_all = "camelCase")]
1993#[non_exhaustive]
1994pub struct SetSessionModeResponse {
1995 #[serde(rename = "_meta")]
2001 pub meta: Option<Meta>,
2002}
2003
2004impl SetSessionModeResponse {
2005 #[must_use]
2006 pub fn new() -> Self {
2007 Self::default()
2008 }
2009
2010 #[must_use]
2016 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2017 self.meta = meta.into_option();
2018 self
2019 }
2020}
2021
2022#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2026#[serde(transparent)]
2027#[from(Arc<str>, String, &'static str)]
2028#[non_exhaustive]
2029pub struct SessionConfigId(pub Arc<str>);
2030
2031impl SessionConfigId {
2032 #[must_use]
2033 pub fn new(id: impl Into<Arc<str>>) -> Self {
2034 Self(id.into())
2035 }
2036}
2037
2038#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2040#[serde(transparent)]
2041#[from(Arc<str>, String, &'static str)]
2042#[non_exhaustive]
2043pub struct SessionConfigValueId(pub Arc<str>);
2044
2045impl SessionConfigValueId {
2046 #[must_use]
2047 pub fn new(id: impl Into<Arc<str>>) -> Self {
2048 Self(id.into())
2049 }
2050}
2051
2052#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
2054#[serde(transparent)]
2055#[from(Arc<str>, String, &'static str)]
2056#[non_exhaustive]
2057pub struct SessionConfigGroupId(pub Arc<str>);
2058
2059impl SessionConfigGroupId {
2060 #[must_use]
2061 pub fn new(id: impl Into<Arc<str>>) -> Self {
2062 Self(id.into())
2063 }
2064}
2065
2066#[skip_serializing_none]
2068#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2069#[serde(rename_all = "camelCase")]
2070#[non_exhaustive]
2071pub struct SessionConfigSelectOption {
2072 pub value: SessionConfigValueId,
2074 pub name: String,
2076 #[serde(default)]
2078 pub description: Option<String>,
2079 #[serde(rename = "_meta")]
2085 pub meta: Option<Meta>,
2086}
2087
2088impl SessionConfigSelectOption {
2089 #[must_use]
2090 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2091 Self {
2092 value: value.into(),
2093 name: name.into(),
2094 description: None,
2095 meta: None,
2096 }
2097 }
2098
2099 #[must_use]
2100 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2101 self.description = description.into_option();
2102 self
2103 }
2104
2105 #[must_use]
2111 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2112 self.meta = meta.into_option();
2113 self
2114 }
2115}
2116
2117#[skip_serializing_none]
2119#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2120#[serde(rename_all = "camelCase")]
2121#[non_exhaustive]
2122pub struct SessionConfigSelectGroup {
2123 pub group: SessionConfigGroupId,
2125 pub name: String,
2127 pub options: Vec<SessionConfigSelectOption>,
2129 #[serde(rename = "_meta")]
2135 pub meta: Option<Meta>,
2136}
2137
2138impl SessionConfigSelectGroup {
2139 #[must_use]
2140 pub fn new(
2141 group: impl Into<SessionConfigGroupId>,
2142 name: impl Into<String>,
2143 options: Vec<SessionConfigSelectOption>,
2144 ) -> Self {
2145 Self {
2146 group: group.into(),
2147 name: name.into(),
2148 options,
2149 meta: None,
2150 }
2151 }
2152
2153 #[must_use]
2159 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2160 self.meta = meta.into_option();
2161 self
2162 }
2163}
2164
2165#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2167#[serde(untagged)]
2168#[non_exhaustive]
2169pub enum SessionConfigSelectOptions {
2170 Ungrouped(Vec<SessionConfigSelectOption>),
2172 Grouped(Vec<SessionConfigSelectGroup>),
2174}
2175
2176impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2177 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2178 SessionConfigSelectOptions::Ungrouped(options)
2179 }
2180}
2181
2182impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2183 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2184 SessionConfigSelectOptions::Grouped(groups)
2185 }
2186}
2187
2188#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2190#[serde(rename_all = "camelCase")]
2191#[non_exhaustive]
2192pub struct SessionConfigSelect {
2193 pub current_value: SessionConfigValueId,
2195 pub options: SessionConfigSelectOptions,
2197}
2198
2199impl SessionConfigSelect {
2200 #[must_use]
2201 pub fn new(
2202 current_value: impl Into<SessionConfigValueId>,
2203 options: impl Into<SessionConfigSelectOptions>,
2204 ) -> Self {
2205 Self {
2206 current_value: current_value.into(),
2207 options: options.into(),
2208 }
2209 }
2210}
2211
2212#[cfg(feature = "unstable_boolean_config")]
2218#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2219#[serde(rename_all = "camelCase")]
2220#[non_exhaustive]
2221pub struct SessionConfigBoolean {
2222 pub current_value: bool,
2224}
2225
2226#[cfg(feature = "unstable_boolean_config")]
2227impl SessionConfigBoolean {
2228 #[must_use]
2229 pub fn new(current_value: bool) -> Self {
2230 Self { current_value }
2231 }
2232}
2233
2234#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2244#[serde(rename_all = "snake_case")]
2245#[non_exhaustive]
2246pub enum SessionConfigOptionCategory {
2247 Mode,
2249 Model,
2251 ThoughtLevel,
2253 #[serde(untagged)]
2255 Other(String),
2256}
2257
2258#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2260#[serde(tag = "type", rename_all = "snake_case")]
2261#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2262#[non_exhaustive]
2263pub enum SessionConfigKind {
2264 Select(SessionConfigSelect),
2266 #[cfg(feature = "unstable_boolean_config")]
2272 Boolean(SessionConfigBoolean),
2273}
2274
2275#[serde_as]
2277#[skip_serializing_none]
2278#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2279#[serde(rename_all = "camelCase")]
2280#[non_exhaustive]
2281pub struct SessionConfigOption {
2282 pub id: SessionConfigId,
2284 pub name: String,
2286 #[serde(default)]
2288 pub description: Option<String>,
2289 #[serde_as(deserialize_as = "DefaultOnError")]
2291 #[schemars(extend("x-deserialize-default-on-error" = true))]
2292 #[serde(default)]
2293 pub category: Option<SessionConfigOptionCategory>,
2294 #[serde(flatten)]
2296 pub kind: SessionConfigKind,
2297 #[serde(rename = "_meta")]
2303 pub meta: Option<Meta>,
2304}
2305
2306impl SessionConfigOption {
2307 #[must_use]
2308 pub fn new(
2309 id: impl Into<SessionConfigId>,
2310 name: impl Into<String>,
2311 kind: SessionConfigKind,
2312 ) -> Self {
2313 Self {
2314 id: id.into(),
2315 name: name.into(),
2316 description: None,
2317 category: None,
2318 kind,
2319 meta: None,
2320 }
2321 }
2322
2323 #[must_use]
2324 pub fn select(
2325 id: impl Into<SessionConfigId>,
2326 name: impl Into<String>,
2327 current_value: impl Into<SessionConfigValueId>,
2328 options: impl Into<SessionConfigSelectOptions>,
2329 ) -> Self {
2330 Self::new(
2331 id,
2332 name,
2333 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2334 )
2335 }
2336
2337 #[cfg(feature = "unstable_boolean_config")]
2341 #[must_use]
2342 pub fn boolean(
2343 id: impl Into<SessionConfigId>,
2344 name: impl Into<String>,
2345 current_value: bool,
2346 ) -> Self {
2347 Self::new(
2348 id,
2349 name,
2350 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2351 )
2352 }
2353
2354 #[must_use]
2355 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2356 self.description = description.into_option();
2357 self
2358 }
2359
2360 #[must_use]
2361 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2362 self.category = category.into_option();
2363 self
2364 }
2365
2366 #[must_use]
2372 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2373 self.meta = meta.into_option();
2374 self
2375 }
2376}
2377
2378#[cfg(feature = "unstable_boolean_config")]
2393#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2394#[serde(tag = "type", rename_all = "snake_case")]
2395#[non_exhaustive]
2396pub enum SessionConfigOptionValue {
2397 Boolean {
2399 value: bool,
2401 },
2402 #[serde(untagged)]
2408 ValueId {
2409 value: SessionConfigValueId,
2411 },
2412}
2413
2414#[cfg(feature = "unstable_boolean_config")]
2415impl SessionConfigOptionValue {
2416 #[must_use]
2418 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2419 Self::ValueId { value: id.into() }
2420 }
2421
2422 #[must_use]
2424 pub fn boolean(val: bool) -> Self {
2425 Self::Boolean { value: val }
2426 }
2427
2428 #[must_use]
2431 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2432 match self {
2433 Self::ValueId { value } => Some(value),
2434 _ => None,
2435 }
2436 }
2437
2438 #[must_use]
2440 pub fn as_bool(&self) -> Option<bool> {
2441 match self {
2442 Self::Boolean { value } => Some(*value),
2443 _ => None,
2444 }
2445 }
2446}
2447
2448#[cfg(feature = "unstable_boolean_config")]
2449impl From<SessionConfigValueId> for SessionConfigOptionValue {
2450 fn from(value: SessionConfigValueId) -> Self {
2451 Self::ValueId { value }
2452 }
2453}
2454
2455#[cfg(feature = "unstable_boolean_config")]
2456impl From<bool> for SessionConfigOptionValue {
2457 fn from(value: bool) -> Self {
2458 Self::Boolean { value }
2459 }
2460}
2461
2462#[cfg(feature = "unstable_boolean_config")]
2463impl From<&str> for SessionConfigOptionValue {
2464 fn from(value: &str) -> Self {
2465 Self::ValueId {
2466 value: SessionConfigValueId::new(value),
2467 }
2468 }
2469}
2470
2471#[skip_serializing_none]
2473#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2474#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2475#[serde(rename_all = "camelCase")]
2476#[non_exhaustive]
2477pub struct SetSessionConfigOptionRequest {
2478 pub session_id: SessionId,
2480 pub config_id: SessionConfigId,
2482 #[cfg(feature = "unstable_boolean_config")]
2487 #[serde(flatten)]
2488 pub value: SessionConfigOptionValue,
2489 #[cfg(not(feature = "unstable_boolean_config"))]
2491 pub value: SessionConfigValueId,
2492 #[serde(rename = "_meta")]
2498 pub meta: Option<Meta>,
2499}
2500
2501impl SetSessionConfigOptionRequest {
2502 #[cfg(feature = "unstable_boolean_config")]
2503 #[must_use]
2504 pub fn new(
2505 session_id: impl Into<SessionId>,
2506 config_id: impl Into<SessionConfigId>,
2507 value: impl Into<SessionConfigOptionValue>,
2508 ) -> Self {
2509 Self {
2510 session_id: session_id.into(),
2511 config_id: config_id.into(),
2512 value: value.into(),
2513 meta: None,
2514 }
2515 }
2516
2517 #[cfg(not(feature = "unstable_boolean_config"))]
2518 #[must_use]
2519 pub fn new(
2520 session_id: impl Into<SessionId>,
2521 config_id: impl Into<SessionConfigId>,
2522 value: impl Into<SessionConfigValueId>,
2523 ) -> Self {
2524 Self {
2525 session_id: session_id.into(),
2526 config_id: config_id.into(),
2527 value: value.into(),
2528 meta: None,
2529 }
2530 }
2531
2532 #[must_use]
2538 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2539 self.meta = meta.into_option();
2540 self
2541 }
2542}
2543
2544#[serde_as]
2546#[skip_serializing_none]
2547#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2548#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2549#[serde(rename_all = "camelCase")]
2550#[non_exhaustive]
2551pub struct SetSessionConfigOptionResponse {
2552 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2554 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2555 pub config_options: Vec<SessionConfigOption>,
2556 #[serde(rename = "_meta")]
2562 pub meta: Option<Meta>,
2563}
2564
2565impl SetSessionConfigOptionResponse {
2566 #[must_use]
2567 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2568 Self {
2569 config_options,
2570 meta: None,
2571 }
2572 }
2573
2574 #[must_use]
2580 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2581 self.meta = meta.into_option();
2582 self
2583 }
2584}
2585
2586#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2595#[serde(tag = "type", rename_all = "snake_case")]
2596#[non_exhaustive]
2597pub enum McpServer {
2598 Http(McpServerHttp),
2602 Sse(McpServerSse),
2606 #[cfg(feature = "unstable_mcp_over_acp")]
2615 Acp(McpServerAcp),
2616 #[serde(untagged)]
2620 Stdio(McpServerStdio),
2621}
2622
2623#[skip_serializing_none]
2625#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2626#[serde(rename_all = "camelCase")]
2627#[non_exhaustive]
2628pub struct McpServerHttp {
2629 pub name: String,
2631 pub url: String,
2633 pub headers: Vec<HttpHeader>,
2635 #[serde(rename = "_meta")]
2641 pub meta: Option<Meta>,
2642}
2643
2644impl McpServerHttp {
2645 #[must_use]
2646 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2647 Self {
2648 name: name.into(),
2649 url: url.into(),
2650 headers: Vec::new(),
2651 meta: None,
2652 }
2653 }
2654
2655 #[must_use]
2657 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2658 self.headers = headers;
2659 self
2660 }
2661
2662 #[must_use]
2668 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2669 self.meta = meta.into_option();
2670 self
2671 }
2672}
2673
2674#[skip_serializing_none]
2676#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2677#[serde(rename_all = "camelCase")]
2678#[non_exhaustive]
2679pub struct McpServerSse {
2680 pub name: String,
2682 pub url: String,
2684 pub headers: Vec<HttpHeader>,
2686 #[serde(rename = "_meta")]
2692 pub meta: Option<Meta>,
2693}
2694
2695impl McpServerSse {
2696 #[must_use]
2697 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2698 Self {
2699 name: name.into(),
2700 url: url.into(),
2701 headers: Vec::new(),
2702 meta: None,
2703 }
2704 }
2705
2706 #[must_use]
2708 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2709 self.headers = headers;
2710 self
2711 }
2712
2713 #[must_use]
2719 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2720 self.meta = meta.into_option();
2721 self
2722 }
2723}
2724
2725#[cfg(feature = "unstable_mcp_over_acp")]
2735#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2736#[serde(transparent)]
2737#[from(Arc<str>, String, &'static str)]
2738#[non_exhaustive]
2739pub struct McpServerAcpId(pub Arc<str>);
2740
2741#[cfg(feature = "unstable_mcp_over_acp")]
2742impl McpServerAcpId {
2743 #[must_use]
2744 pub fn new(id: impl Into<Arc<str>>) -> Self {
2745 Self(id.into())
2746 }
2747}
2748
2749#[skip_serializing_none]
2758#[cfg(feature = "unstable_mcp_over_acp")]
2759#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2760#[serde(rename_all = "camelCase")]
2761#[non_exhaustive]
2762pub struct McpServerAcp {
2763 pub name: String,
2765 pub id: McpServerAcpId,
2770 #[serde(rename = "_meta")]
2776 pub meta: Option<Meta>,
2777}
2778
2779#[cfg(feature = "unstable_mcp_over_acp")]
2780impl McpServerAcp {
2781 #[must_use]
2782 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2783 Self {
2784 name: name.into(),
2785 id: id.into(),
2786 meta: None,
2787 }
2788 }
2789
2790 #[must_use]
2796 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2797 self.meta = meta.into_option();
2798 self
2799 }
2800}
2801
2802#[skip_serializing_none]
2804#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2805#[serde(rename_all = "camelCase")]
2806#[non_exhaustive]
2807pub struct McpServerStdio {
2808 pub name: String,
2810 pub command: PathBuf,
2812 pub args: Vec<String>,
2814 pub env: Vec<EnvVariable>,
2816 #[serde(rename = "_meta")]
2822 pub meta: Option<Meta>,
2823}
2824
2825impl McpServerStdio {
2826 #[must_use]
2827 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2828 Self {
2829 name: name.into(),
2830 command: command.into(),
2831 args: Vec::new(),
2832 env: Vec::new(),
2833 meta: None,
2834 }
2835 }
2836
2837 #[must_use]
2839 pub fn args(mut self, args: Vec<String>) -> Self {
2840 self.args = args;
2841 self
2842 }
2843
2844 #[must_use]
2846 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2847 self.env = env;
2848 self
2849 }
2850
2851 #[must_use]
2857 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2858 self.meta = meta.into_option();
2859 self
2860 }
2861}
2862
2863#[skip_serializing_none]
2865#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2866#[serde(rename_all = "camelCase")]
2867#[non_exhaustive]
2868pub struct EnvVariable {
2869 pub name: String,
2871 pub value: String,
2873 #[serde(rename = "_meta")]
2879 pub meta: Option<Meta>,
2880}
2881
2882impl EnvVariable {
2883 #[must_use]
2884 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2885 Self {
2886 name: name.into(),
2887 value: value.into(),
2888 meta: None,
2889 }
2890 }
2891
2892 #[must_use]
2898 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2899 self.meta = meta.into_option();
2900 self
2901 }
2902}
2903
2904#[skip_serializing_none]
2906#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2907#[serde(rename_all = "camelCase")]
2908#[non_exhaustive]
2909pub struct HttpHeader {
2910 pub name: String,
2912 pub value: String,
2914 #[serde(rename = "_meta")]
2920 pub meta: Option<Meta>,
2921}
2922
2923impl HttpHeader {
2924 #[must_use]
2925 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2926 Self {
2927 name: name.into(),
2928 value: value.into(),
2929 meta: None,
2930 }
2931 }
2932
2933 #[must_use]
2939 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2940 self.meta = meta.into_option();
2941 self
2942 }
2943}
2944
2945#[skip_serializing_none]
2953#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
2954#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2955#[serde(rename_all = "camelCase")]
2956#[non_exhaustive]
2957pub struct PromptRequest {
2958 pub session_id: SessionId,
2960 pub prompt: Vec<ContentBlock>,
2974 #[serde(rename = "_meta")]
2980 pub meta: Option<Meta>,
2981}
2982
2983impl PromptRequest {
2984 #[must_use]
2985 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
2986 Self {
2987 session_id: session_id.into(),
2988 prompt,
2989 meta: None,
2990 }
2991 }
2992
2993 #[must_use]
2999 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3000 self.meta = meta.into_option();
3001 self
3002 }
3003}
3004
3005#[serde_as]
3009#[skip_serializing_none]
3010#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3011#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3012#[serde(rename_all = "camelCase")]
3013#[non_exhaustive]
3014pub struct PromptResponse {
3015 pub stop_reason: StopReason,
3017 #[cfg(feature = "unstable_end_turn_token_usage")]
3023 #[serde_as(deserialize_as = "DefaultOnError")]
3024 #[schemars(extend("x-deserialize-default-on-error" = true))]
3025 #[serde(default)]
3026 pub usage: Option<Usage>,
3027 #[serde(rename = "_meta")]
3033 pub meta: Option<Meta>,
3034}
3035
3036impl PromptResponse {
3037 #[must_use]
3038 pub fn new(stop_reason: StopReason) -> Self {
3039 Self {
3040 stop_reason,
3041 #[cfg(feature = "unstable_end_turn_token_usage")]
3042 usage: None,
3043 meta: None,
3044 }
3045 }
3046
3047 #[cfg(feature = "unstable_end_turn_token_usage")]
3053 #[must_use]
3054 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3055 self.usage = usage.into_option();
3056 self
3057 }
3058
3059 #[must_use]
3065 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3066 self.meta = meta.into_option();
3067 self
3068 }
3069}
3070
3071#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3075#[serde(rename_all = "snake_case")]
3076#[non_exhaustive]
3077pub enum StopReason {
3078 EndTurn,
3080 MaxTokens,
3082 MaxTurnRequests,
3085 Refusal,
3089 Cancelled,
3096}
3097
3098#[cfg(feature = "unstable_end_turn_token_usage")]
3104#[skip_serializing_none]
3105#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3106#[serde(rename_all = "camelCase")]
3107#[non_exhaustive]
3108pub struct Usage {
3109 pub total_tokens: u64,
3111 pub input_tokens: u64,
3113 pub output_tokens: u64,
3115 pub thought_tokens: Option<u64>,
3117 pub cached_read_tokens: Option<u64>,
3119 pub cached_write_tokens: Option<u64>,
3121}
3122
3123#[cfg(feature = "unstable_end_turn_token_usage")]
3124impl Usage {
3125 #[must_use]
3126 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3127 Self {
3128 total_tokens,
3129 input_tokens,
3130 output_tokens,
3131 thought_tokens: None,
3132 cached_read_tokens: None,
3133 cached_write_tokens: None,
3134 }
3135 }
3136
3137 #[must_use]
3139 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3140 self.thought_tokens = thought_tokens.into_option();
3141 self
3142 }
3143
3144 #[must_use]
3146 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3147 self.cached_read_tokens = cached_read_tokens.into_option();
3148 self
3149 }
3150
3151 #[must_use]
3153 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3154 self.cached_write_tokens = cached_write_tokens.into_option();
3155 self
3156 }
3157}
3158
3159#[cfg(feature = "unstable_llm_providers")]
3172#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3173#[serde(rename_all = "snake_case")]
3174#[non_exhaustive]
3175#[expect(clippy::doc_markdown)]
3176pub enum LlmProtocol {
3177 Anthropic,
3179 #[serde(rename = "openai")]
3181 OpenAi,
3182 Azure,
3184 Vertex,
3186 Bedrock,
3188 #[serde(untagged)]
3190 Other(String),
3191}
3192
3193#[cfg(feature = "unstable_llm_providers")]
3199#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3200#[serde(rename_all = "camelCase")]
3201#[non_exhaustive]
3202pub struct ProviderCurrentConfig {
3203 pub api_type: LlmProtocol,
3205 pub base_url: String,
3207}
3208
3209#[cfg(feature = "unstable_llm_providers")]
3210impl ProviderCurrentConfig {
3211 #[must_use]
3212 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3213 Self {
3214 api_type,
3215 base_url: base_url.into(),
3216 }
3217 }
3218}
3219
3220#[cfg(feature = "unstable_llm_providers")]
3226#[serde_as]
3227#[skip_serializing_none]
3228#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3229#[serde(rename_all = "camelCase")]
3230#[non_exhaustive]
3231pub struct ProviderInfo {
3232 pub id: String,
3234 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3236 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3237 pub supported: Vec<LlmProtocol>,
3238 pub required: bool,
3241 pub current: Option<ProviderCurrentConfig>,
3244 #[serde(rename = "_meta")]
3250 pub meta: Option<Meta>,
3251}
3252
3253#[cfg(feature = "unstable_llm_providers")]
3254impl ProviderInfo {
3255 #[must_use]
3256 pub fn new(
3257 id: impl Into<String>,
3258 supported: Vec<LlmProtocol>,
3259 required: bool,
3260 current: impl IntoOption<ProviderCurrentConfig>,
3261 ) -> Self {
3262 Self {
3263 id: id.into(),
3264 supported,
3265 required,
3266 current: current.into_option(),
3267 meta: None,
3268 }
3269 }
3270
3271 #[must_use]
3277 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3278 self.meta = meta.into_option();
3279 self
3280 }
3281}
3282
3283#[cfg(feature = "unstable_llm_providers")]
3289#[skip_serializing_none]
3290#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3291#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3292#[serde(rename_all = "camelCase")]
3293#[non_exhaustive]
3294pub struct ListProvidersRequest {
3295 #[serde(rename = "_meta")]
3301 pub meta: Option<Meta>,
3302}
3303
3304#[cfg(feature = "unstable_llm_providers")]
3305impl ListProvidersRequest {
3306 #[must_use]
3307 pub fn new() -> Self {
3308 Self::default()
3309 }
3310
3311 #[must_use]
3317 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3318 self.meta = meta.into_option();
3319 self
3320 }
3321}
3322
3323#[cfg(feature = "unstable_llm_providers")]
3329#[serde_as]
3330#[skip_serializing_none]
3331#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3332#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3333#[serde(rename_all = "camelCase")]
3334#[non_exhaustive]
3335pub struct ListProvidersResponse {
3336 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3338 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3339 pub providers: Vec<ProviderInfo>,
3340 #[serde(rename = "_meta")]
3346 pub meta: Option<Meta>,
3347}
3348
3349#[cfg(feature = "unstable_llm_providers")]
3350impl ListProvidersResponse {
3351 #[must_use]
3352 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3353 Self {
3354 providers,
3355 meta: None,
3356 }
3357 }
3358
3359 #[must_use]
3365 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3366 self.meta = meta.into_option();
3367 self
3368 }
3369}
3370
3371#[cfg(feature = "unstable_llm_providers")]
3379#[skip_serializing_none]
3380#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3381#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3382#[serde(rename_all = "camelCase")]
3383#[non_exhaustive]
3384pub struct SetProviderRequest {
3385 pub id: String,
3387 pub api_type: LlmProtocol,
3389 pub base_url: String,
3391 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3394 pub headers: HashMap<String, String>,
3395 #[serde(rename = "_meta")]
3401 pub meta: Option<Meta>,
3402}
3403
3404#[cfg(feature = "unstable_llm_providers")]
3405impl SetProviderRequest {
3406 #[must_use]
3407 pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3408 Self {
3409 id: id.into(),
3410 api_type,
3411 base_url: base_url.into(),
3412 headers: HashMap::new(),
3413 meta: None,
3414 }
3415 }
3416
3417 #[must_use]
3420 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3421 self.headers = headers;
3422 self
3423 }
3424
3425 #[must_use]
3431 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3432 self.meta = meta.into_option();
3433 self
3434 }
3435}
3436
3437#[cfg(feature = "unstable_llm_providers")]
3443#[skip_serializing_none]
3444#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3445#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3446#[serde(rename_all = "camelCase")]
3447#[non_exhaustive]
3448pub struct SetProviderResponse {
3449 #[serde(rename = "_meta")]
3455 pub meta: Option<Meta>,
3456}
3457
3458#[cfg(feature = "unstable_llm_providers")]
3459impl SetProviderResponse {
3460 #[must_use]
3461 pub fn new() -> Self {
3462 Self::default()
3463 }
3464
3465 #[must_use]
3471 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3472 self.meta = meta.into_option();
3473 self
3474 }
3475}
3476
3477#[cfg(feature = "unstable_llm_providers")]
3483#[skip_serializing_none]
3484#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3485#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3486#[serde(rename_all = "camelCase")]
3487#[non_exhaustive]
3488pub struct DisableProviderRequest {
3489 pub id: String,
3491 #[serde(rename = "_meta")]
3497 pub meta: Option<Meta>,
3498}
3499
3500#[cfg(feature = "unstable_llm_providers")]
3501impl DisableProviderRequest {
3502 #[must_use]
3503 pub fn new(id: impl Into<String>) -> Self {
3504 Self {
3505 id: id.into(),
3506 meta: None,
3507 }
3508 }
3509
3510 #[must_use]
3516 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3517 self.meta = meta.into_option();
3518 self
3519 }
3520}
3521
3522#[cfg(feature = "unstable_llm_providers")]
3528#[skip_serializing_none]
3529#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3530#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3531#[serde(rename_all = "camelCase")]
3532#[non_exhaustive]
3533pub struct DisableProviderResponse {
3534 #[serde(rename = "_meta")]
3540 pub meta: Option<Meta>,
3541}
3542
3543#[cfg(feature = "unstable_llm_providers")]
3544impl DisableProviderResponse {
3545 #[must_use]
3546 pub fn new() -> Self {
3547 Self::default()
3548 }
3549
3550 #[must_use]
3556 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3557 self.meta = meta.into_option();
3558 self
3559 }
3560}
3561
3562#[serde_as]
3571#[skip_serializing_none]
3572#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3573#[serde(rename_all = "camelCase")]
3574#[non_exhaustive]
3575pub struct AgentCapabilities {
3576 #[serde(default)]
3578 pub load_session: bool,
3579 #[serde(default)]
3581 pub prompt_capabilities: PromptCapabilities,
3582 #[serde(default)]
3584 pub mcp_capabilities: McpCapabilities,
3585 #[serde(default)]
3586 pub session_capabilities: SessionCapabilities,
3587 #[serde(default)]
3589 pub auth: AgentAuthCapabilities,
3590 #[cfg(feature = "unstable_llm_providers")]
3598 #[serde_as(deserialize_as = "DefaultOnError")]
3599 #[schemars(extend("x-deserialize-default-on-error" = true))]
3600 #[serde(default)]
3601 pub providers: Option<ProvidersCapabilities>,
3602 #[cfg(feature = "unstable_nes")]
3608 #[serde_as(deserialize_as = "DefaultOnError")]
3609 #[schemars(extend("x-deserialize-default-on-error" = true))]
3610 #[serde(default)]
3611 pub nes: Option<NesCapabilities>,
3612 #[cfg(feature = "unstable_nes")]
3618 #[serde_as(deserialize_as = "DefaultOnError")]
3619 #[schemars(extend("x-deserialize-default-on-error" = true))]
3620 #[serde(default)]
3621 pub position_encoding: Option<PositionEncodingKind>,
3622 #[serde(rename = "_meta")]
3628 pub meta: Option<Meta>,
3629}
3630
3631impl AgentCapabilities {
3632 #[must_use]
3633 pub fn new() -> Self {
3634 Self::default()
3635 }
3636
3637 #[must_use]
3639 pub fn load_session(mut self, load_session: bool) -> Self {
3640 self.load_session = load_session;
3641 self
3642 }
3643
3644 #[must_use]
3646 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3647 self.prompt_capabilities = prompt_capabilities;
3648 self
3649 }
3650
3651 #[must_use]
3653 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3654 self.mcp_capabilities = mcp_capabilities;
3655 self
3656 }
3657
3658 #[must_use]
3660 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3661 self.session_capabilities = session_capabilities;
3662 self
3663 }
3664
3665 #[must_use]
3667 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3668 self.auth = auth;
3669 self
3670 }
3671
3672 #[cfg(feature = "unstable_llm_providers")]
3678 #[must_use]
3679 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3680 self.providers = providers.into_option();
3681 self
3682 }
3683
3684 #[cfg(feature = "unstable_nes")]
3690 #[must_use]
3691 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3692 self.nes = nes.into_option();
3693 self
3694 }
3695
3696 #[cfg(feature = "unstable_nes")]
3700 #[must_use]
3701 pub fn position_encoding(
3702 mut self,
3703 position_encoding: impl IntoOption<PositionEncodingKind>,
3704 ) -> Self {
3705 self.position_encoding = position_encoding.into_option();
3706 self
3707 }
3708
3709 #[must_use]
3715 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3716 self.meta = meta.into_option();
3717 self
3718 }
3719}
3720
3721#[cfg(feature = "unstable_llm_providers")]
3729#[skip_serializing_none]
3730#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3731#[non_exhaustive]
3732pub struct ProvidersCapabilities {
3733 #[serde(rename = "_meta")]
3739 pub meta: Option<Meta>,
3740}
3741
3742#[cfg(feature = "unstable_llm_providers")]
3743impl ProvidersCapabilities {
3744 #[must_use]
3745 pub fn new() -> Self {
3746 Self::default()
3747 }
3748
3749 #[must_use]
3755 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3756 self.meta = meta.into_option();
3757 self
3758 }
3759}
3760
3761#[serde_as]
3771#[skip_serializing_none]
3772#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3773#[serde(rename_all = "camelCase")]
3774#[non_exhaustive]
3775pub struct SessionCapabilities {
3776 #[serde_as(deserialize_as = "DefaultOnError")]
3778 #[schemars(extend("x-deserialize-default-on-error" = true))]
3779 #[serde(default)]
3780 pub list: Option<SessionListCapabilities>,
3781 #[serde_as(deserialize_as = "DefaultOnError")]
3786 #[schemars(extend("x-deserialize-default-on-error" = true))]
3787 #[serde(default)]
3788 pub delete: Option<SessionDeleteCapabilities>,
3789 #[serde_as(deserialize_as = "DefaultOnError")]
3795 #[schemars(extend("x-deserialize-default-on-error" = true))]
3796 #[serde(default)]
3797 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
3798 #[cfg(feature = "unstable_session_fork")]
3804 #[serde_as(deserialize_as = "DefaultOnError")]
3805 #[schemars(extend("x-deserialize-default-on-error" = true))]
3806 #[serde(default)]
3807 pub fork: Option<SessionForkCapabilities>,
3808 #[serde_as(deserialize_as = "DefaultOnError")]
3810 #[schemars(extend("x-deserialize-default-on-error" = true))]
3811 #[serde(default)]
3812 pub resume: Option<SessionResumeCapabilities>,
3813 #[serde_as(deserialize_as = "DefaultOnError")]
3815 #[schemars(extend("x-deserialize-default-on-error" = true))]
3816 #[serde(default)]
3817 pub close: Option<SessionCloseCapabilities>,
3818 #[serde(rename = "_meta")]
3824 pub meta: Option<Meta>,
3825}
3826
3827impl SessionCapabilities {
3828 #[must_use]
3829 pub fn new() -> Self {
3830 Self::default()
3831 }
3832
3833 #[must_use]
3835 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3836 self.list = list.into_option();
3837 self
3838 }
3839
3840 #[must_use]
3845 pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
3846 self.delete = delete.into_option();
3847 self
3848 }
3849
3850 #[must_use]
3856 pub fn additional_directories(
3857 mut self,
3858 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
3859 ) -> Self {
3860 self.additional_directories = additional_directories.into_option();
3861 self
3862 }
3863
3864 #[cfg(feature = "unstable_session_fork")]
3865 #[must_use]
3867 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
3868 self.fork = fork.into_option();
3869 self
3870 }
3871
3872 #[must_use]
3874 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
3875 self.resume = resume.into_option();
3876 self
3877 }
3878
3879 #[must_use]
3881 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
3882 self.close = close.into_option();
3883 self
3884 }
3885
3886 #[must_use]
3892 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3893 self.meta = meta.into_option();
3894 self
3895 }
3896}
3897
3898#[skip_serializing_none]
3902#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3903#[non_exhaustive]
3904pub struct SessionListCapabilities {
3905 #[serde(rename = "_meta")]
3911 pub meta: Option<Meta>,
3912}
3913
3914impl SessionListCapabilities {
3915 #[must_use]
3916 pub fn new() -> Self {
3917 Self::default()
3918 }
3919
3920 #[must_use]
3926 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3927 self.meta = meta.into_option();
3928 self
3929 }
3930}
3931
3932#[skip_serializing_none]
3936#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3937#[non_exhaustive]
3938pub struct SessionDeleteCapabilities {
3939 #[serde(rename = "_meta")]
3945 pub meta: Option<Meta>,
3946}
3947
3948impl SessionDeleteCapabilities {
3949 #[must_use]
3950 pub fn new() -> Self {
3951 Self::default()
3952 }
3953
3954 #[must_use]
3960 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3961 self.meta = meta.into_option();
3962 self
3963 }
3964}
3965
3966#[skip_serializing_none]
3973#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3974#[non_exhaustive]
3975pub struct SessionAdditionalDirectoriesCapabilities {
3976 #[serde(rename = "_meta")]
3982 pub meta: Option<Meta>,
3983}
3984
3985impl SessionAdditionalDirectoriesCapabilities {
3986 #[must_use]
3987 pub fn new() -> Self {
3988 Self::default()
3989 }
3990
3991 #[must_use]
3997 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3998 self.meta = meta.into_option();
3999 self
4000 }
4001}
4002
4003#[cfg(feature = "unstable_session_fork")]
4011#[skip_serializing_none]
4012#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4013#[non_exhaustive]
4014pub struct SessionForkCapabilities {
4015 #[serde(rename = "_meta")]
4021 pub meta: Option<Meta>,
4022}
4023
4024#[cfg(feature = "unstable_session_fork")]
4025impl SessionForkCapabilities {
4026 #[must_use]
4027 pub fn new() -> Self {
4028 Self::default()
4029 }
4030
4031 #[must_use]
4037 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4038 self.meta = meta.into_option();
4039 self
4040 }
4041}
4042
4043#[skip_serializing_none]
4047#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4048#[non_exhaustive]
4049pub struct SessionResumeCapabilities {
4050 #[serde(rename = "_meta")]
4056 pub meta: Option<Meta>,
4057}
4058
4059impl SessionResumeCapabilities {
4060 #[must_use]
4061 pub fn new() -> Self {
4062 Self::default()
4063 }
4064
4065 #[must_use]
4071 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4072 self.meta = meta.into_option();
4073 self
4074 }
4075}
4076
4077#[skip_serializing_none]
4081#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4082#[non_exhaustive]
4083pub struct SessionCloseCapabilities {
4084 #[serde(rename = "_meta")]
4090 pub meta: Option<Meta>,
4091}
4092
4093impl SessionCloseCapabilities {
4094 #[must_use]
4095 pub fn new() -> Self {
4096 Self::default()
4097 }
4098
4099 #[must_use]
4105 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4106 self.meta = meta.into_option();
4107 self
4108 }
4109}
4110
4111#[skip_serializing_none]
4124#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4125#[serde(rename_all = "camelCase")]
4126#[non_exhaustive]
4127pub struct PromptCapabilities {
4128 #[serde(default)]
4130 pub image: bool,
4131 #[serde(default)]
4133 pub audio: bool,
4134 #[serde(default)]
4139 pub embedded_context: bool,
4140 #[serde(rename = "_meta")]
4146 pub meta: Option<Meta>,
4147}
4148
4149impl PromptCapabilities {
4150 #[must_use]
4151 pub fn new() -> Self {
4152 Self::default()
4153 }
4154
4155 #[must_use]
4157 pub fn image(mut self, image: bool) -> Self {
4158 self.image = image;
4159 self
4160 }
4161
4162 #[must_use]
4164 pub fn audio(mut self, audio: bool) -> Self {
4165 self.audio = audio;
4166 self
4167 }
4168
4169 #[must_use]
4174 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4175 self.embedded_context = embedded_context;
4176 self
4177 }
4178
4179 #[must_use]
4185 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4186 self.meta = meta.into_option();
4187 self
4188 }
4189}
4190
4191#[skip_serializing_none]
4193#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4194#[serde(rename_all = "camelCase")]
4195#[non_exhaustive]
4196pub struct McpCapabilities {
4197 #[serde(default)]
4199 pub http: bool,
4200 #[serde(default)]
4202 pub sse: bool,
4203 #[cfg(feature = "unstable_mcp_over_acp")]
4209 #[serde(default)]
4210 pub acp: bool,
4211 #[serde(rename = "_meta")]
4217 pub meta: Option<Meta>,
4218}
4219
4220impl McpCapabilities {
4221 #[must_use]
4222 pub fn new() -> Self {
4223 Self::default()
4224 }
4225
4226 #[must_use]
4228 pub fn http(mut self, http: bool) -> Self {
4229 self.http = http;
4230 self
4231 }
4232
4233 #[must_use]
4235 pub fn sse(mut self, sse: bool) -> Self {
4236 self.sse = sse;
4237 self
4238 }
4239
4240 #[cfg(feature = "unstable_mcp_over_acp")]
4246 #[must_use]
4247 pub fn acp(mut self, acp: bool) -> Self {
4248 self.acp = acp;
4249 self
4250 }
4251
4252 #[must_use]
4258 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4259 self.meta = meta.into_option();
4260 self
4261 }
4262}
4263
4264#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4270#[non_exhaustive]
4271pub struct AgentMethodNames {
4272 pub initialize: &'static str,
4274 pub authenticate: &'static str,
4276 #[cfg(feature = "unstable_llm_providers")]
4278 pub providers_list: &'static str,
4279 #[cfg(feature = "unstable_llm_providers")]
4281 pub providers_set: &'static str,
4282 #[cfg(feature = "unstable_llm_providers")]
4284 pub providers_disable: &'static str,
4285 pub session_new: &'static str,
4287 pub session_load: &'static str,
4289 pub session_set_mode: &'static str,
4291 pub session_set_config_option: &'static str,
4293 pub session_prompt: &'static str,
4295 pub session_cancel: &'static str,
4297 #[cfg(feature = "unstable_mcp_over_acp")]
4299 pub mcp_message: &'static str,
4300 pub session_list: &'static str,
4302 pub session_delete: &'static str,
4304 #[cfg(feature = "unstable_session_fork")]
4306 pub session_fork: &'static str,
4307 pub session_resume: &'static str,
4309 pub session_close: &'static str,
4311 pub logout: &'static str,
4313 #[cfg(feature = "unstable_nes")]
4315 pub nes_start: &'static str,
4316 #[cfg(feature = "unstable_nes")]
4318 pub nes_suggest: &'static str,
4319 #[cfg(feature = "unstable_nes")]
4321 pub nes_accept: &'static str,
4322 #[cfg(feature = "unstable_nes")]
4324 pub nes_reject: &'static str,
4325 #[cfg(feature = "unstable_nes")]
4327 pub nes_close: &'static str,
4328 #[cfg(feature = "unstable_nes")]
4330 pub document_did_open: &'static str,
4331 #[cfg(feature = "unstable_nes")]
4333 pub document_did_change: &'static str,
4334 #[cfg(feature = "unstable_nes")]
4336 pub document_did_close: &'static str,
4337 #[cfg(feature = "unstable_nes")]
4339 pub document_did_save: &'static str,
4340 #[cfg(feature = "unstable_nes")]
4342 pub document_did_focus: &'static str,
4343}
4344
4345pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4347 initialize: INITIALIZE_METHOD_NAME,
4348 authenticate: AUTHENTICATE_METHOD_NAME,
4349 #[cfg(feature = "unstable_llm_providers")]
4350 providers_list: PROVIDERS_LIST_METHOD_NAME,
4351 #[cfg(feature = "unstable_llm_providers")]
4352 providers_set: PROVIDERS_SET_METHOD_NAME,
4353 #[cfg(feature = "unstable_llm_providers")]
4354 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4355 session_new: SESSION_NEW_METHOD_NAME,
4356 session_load: SESSION_LOAD_METHOD_NAME,
4357 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4358 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4359 session_prompt: SESSION_PROMPT_METHOD_NAME,
4360 session_cancel: SESSION_CANCEL_METHOD_NAME,
4361 #[cfg(feature = "unstable_mcp_over_acp")]
4362 mcp_message: MCP_MESSAGE_METHOD_NAME,
4363 session_list: SESSION_LIST_METHOD_NAME,
4364 session_delete: SESSION_DELETE_METHOD_NAME,
4365 #[cfg(feature = "unstable_session_fork")]
4366 session_fork: SESSION_FORK_METHOD_NAME,
4367 session_resume: SESSION_RESUME_METHOD_NAME,
4368 session_close: SESSION_CLOSE_METHOD_NAME,
4369 logout: LOGOUT_METHOD_NAME,
4370 #[cfg(feature = "unstable_nes")]
4371 nes_start: NES_START_METHOD_NAME,
4372 #[cfg(feature = "unstable_nes")]
4373 nes_suggest: NES_SUGGEST_METHOD_NAME,
4374 #[cfg(feature = "unstable_nes")]
4375 nes_accept: NES_ACCEPT_METHOD_NAME,
4376 #[cfg(feature = "unstable_nes")]
4377 nes_reject: NES_REJECT_METHOD_NAME,
4378 #[cfg(feature = "unstable_nes")]
4379 nes_close: NES_CLOSE_METHOD_NAME,
4380 #[cfg(feature = "unstable_nes")]
4381 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4382 #[cfg(feature = "unstable_nes")]
4383 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4384 #[cfg(feature = "unstable_nes")]
4385 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4386 #[cfg(feature = "unstable_nes")]
4387 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4388 #[cfg(feature = "unstable_nes")]
4389 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4390};
4391
4392pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4394pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4396#[cfg(feature = "unstable_llm_providers")]
4398pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4399#[cfg(feature = "unstable_llm_providers")]
4401pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4402#[cfg(feature = "unstable_llm_providers")]
4404pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4405pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4407pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4409pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4411pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4413pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4415pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4417pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4419pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
4421#[cfg(feature = "unstable_session_fork")]
4423pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4424pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4426pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4428pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4430
4431#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4438#[serde(untagged)]
4439#[schemars(inline)]
4440#[non_exhaustive]
4441#[allow(clippy::large_enum_variant)]
4442pub enum ClientRequest {
4443 InitializeRequest(InitializeRequest),
4454 AuthenticateRequest(AuthenticateRequest),
4464 #[cfg(feature = "unstable_llm_providers")]
4470 ListProvidersRequest(ListProvidersRequest),
4471 #[cfg(feature = "unstable_llm_providers")]
4477 SetProviderRequest(SetProviderRequest),
4478 #[cfg(feature = "unstable_llm_providers")]
4484 DisableProviderRequest(DisableProviderRequest),
4485 LogoutRequest(LogoutRequest),
4490 NewSessionRequest(NewSessionRequest),
4503 LoadSessionRequest(LoadSessionRequest),
4514 ListSessionsRequest(ListSessionsRequest),
4520 DeleteSessionRequest(DeleteSessionRequest),
4524 #[cfg(feature = "unstable_session_fork")]
4525 ForkSessionRequest(ForkSessionRequest),
4537 ResumeSessionRequest(ResumeSessionRequest),
4544 CloseSessionRequest(CloseSessionRequest),
4551 SetSessionModeRequest(SetSessionModeRequest),
4565 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4567 PromptRequest(PromptRequest),
4579 #[cfg(feature = "unstable_nes")]
4580 StartNesRequest(StartNesRequest),
4586 #[cfg(feature = "unstable_nes")]
4587 SuggestNesRequest(SuggestNesRequest),
4593 #[cfg(feature = "unstable_nes")]
4594 CloseNesRequest(CloseNesRequest),
4603 #[cfg(feature = "unstable_mcp_over_acp")]
4609 MessageMcpRequest(MessageMcpRequest),
4610 ExtMethodRequest(ExtRequest),
4617}
4618
4619impl ClientRequest {
4620 #[must_use]
4622 pub fn method(&self) -> &str {
4623 match self {
4624 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4625 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4626 #[cfg(feature = "unstable_llm_providers")]
4627 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4628 #[cfg(feature = "unstable_llm_providers")]
4629 Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
4630 #[cfg(feature = "unstable_llm_providers")]
4631 Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4632 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4633 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4634 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4635 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4636 Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
4637 #[cfg(feature = "unstable_session_fork")]
4638 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
4639 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
4640 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
4641 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
4642 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
4643 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
4644 #[cfg(feature = "unstable_nes")]
4645 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
4646 #[cfg(feature = "unstable_nes")]
4647 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
4648 #[cfg(feature = "unstable_nes")]
4649 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
4650 #[cfg(feature = "unstable_mcp_over_acp")]
4651 Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
4652 Self::ExtMethodRequest(ext_request) => &ext_request.method,
4653 }
4654 }
4655}
4656
4657#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4664#[serde(untagged)]
4665#[schemars(inline)]
4666#[non_exhaustive]
4667#[allow(clippy::large_enum_variant)]
4668pub enum AgentResponse {
4669 InitializeResponse(InitializeResponse),
4670 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
4671 #[cfg(feature = "unstable_llm_providers")]
4672 ListProvidersResponse(ListProvidersResponse),
4673 #[cfg(feature = "unstable_llm_providers")]
4674 SetProviderResponse(#[serde(default)] SetProviderResponse),
4675 #[cfg(feature = "unstable_llm_providers")]
4676 DisableProviderResponse(#[serde(default)] DisableProviderResponse),
4677 LogoutResponse(#[serde(default)] LogoutResponse),
4678 NewSessionResponse(NewSessionResponse),
4679 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
4680 ListSessionsResponse(ListSessionsResponse),
4681 DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
4682 #[cfg(feature = "unstable_session_fork")]
4683 ForkSessionResponse(ForkSessionResponse),
4684 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
4685 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
4686 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
4687 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
4688 PromptResponse(PromptResponse),
4689 #[cfg(feature = "unstable_nes")]
4690 StartNesResponse(StartNesResponse),
4691 #[cfg(feature = "unstable_nes")]
4692 SuggestNesResponse(SuggestNesResponse),
4693 #[cfg(feature = "unstable_nes")]
4694 CloseNesResponse(#[serde(default)] CloseNesResponse),
4695 ExtMethodResponse(ExtResponse),
4696 #[cfg(feature = "unstable_mcp_over_acp")]
4697 MessageMcpResponse(MessageMcpResponse),
4698}
4699
4700#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4707#[serde(untagged)]
4708#[schemars(inline)]
4709#[non_exhaustive]
4710pub enum ClientNotification {
4711 CancelNotification(CancelNotification),
4723 #[cfg(feature = "unstable_nes")]
4724 DidOpenDocumentNotification(DidOpenDocumentNotification),
4728 #[cfg(feature = "unstable_nes")]
4729 DidChangeDocumentNotification(DidChangeDocumentNotification),
4733 #[cfg(feature = "unstable_nes")]
4734 DidCloseDocumentNotification(DidCloseDocumentNotification),
4738 #[cfg(feature = "unstable_nes")]
4739 DidSaveDocumentNotification(DidSaveDocumentNotification),
4743 #[cfg(feature = "unstable_nes")]
4744 DidFocusDocumentNotification(DidFocusDocumentNotification),
4748 #[cfg(feature = "unstable_nes")]
4749 AcceptNesNotification(AcceptNesNotification),
4753 #[cfg(feature = "unstable_nes")]
4754 RejectNesNotification(RejectNesNotification),
4758 #[cfg(feature = "unstable_mcp_over_acp")]
4764 MessageMcpNotification(MessageMcpNotification),
4765 ExtNotification(ExtNotification),
4772}
4773
4774impl ClientNotification {
4775 #[must_use]
4777 pub fn method(&self) -> &str {
4778 match self {
4779 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
4780 #[cfg(feature = "unstable_nes")]
4781 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
4782 #[cfg(feature = "unstable_nes")]
4783 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
4784 #[cfg(feature = "unstable_nes")]
4785 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
4786 #[cfg(feature = "unstable_nes")]
4787 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
4788 #[cfg(feature = "unstable_nes")]
4789 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
4790 #[cfg(feature = "unstable_nes")]
4791 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
4792 #[cfg(feature = "unstable_nes")]
4793 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
4794 #[cfg(feature = "unstable_mcp_over_acp")]
4795 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
4796 Self::ExtNotification(ext_notification) => &ext_notification.method,
4797 }
4798 }
4799}
4800
4801#[skip_serializing_none]
4805#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4806#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
4807#[serde(rename_all = "camelCase")]
4808#[non_exhaustive]
4809pub struct CancelNotification {
4810 pub session_id: SessionId,
4812 #[serde(rename = "_meta")]
4818 pub meta: Option<Meta>,
4819}
4820
4821impl CancelNotification {
4822 #[must_use]
4823 pub fn new(session_id: impl Into<SessionId>) -> Self {
4824 Self {
4825 session_id: session_id.into(),
4826 meta: None,
4827 }
4828 }
4829
4830 #[must_use]
4836 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4837 self.meta = meta.into_option();
4838 self
4839 }
4840}
4841
4842#[cfg(test)]
4843mod test_serialization {
4844 use super::*;
4845 use serde_json::json;
4846
4847 #[test]
4848 fn test_mcp_server_stdio_serialization() {
4849 let server = McpServer::Stdio(
4850 McpServerStdio::new("test-server", "/usr/bin/server")
4851 .args(vec!["--port".to_string(), "3000".to_string()])
4852 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
4853 );
4854
4855 let json = serde_json::to_value(&server).unwrap();
4856 assert_eq!(
4857 json,
4858 json!({
4859 "name": "test-server",
4860 "command": "/usr/bin/server",
4861 "args": ["--port", "3000"],
4862 "env": [
4863 {
4864 "name": "API_KEY",
4865 "value": "secret123"
4866 }
4867 ]
4868 })
4869 );
4870
4871 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4872 match deserialized {
4873 McpServer::Stdio(McpServerStdio {
4874 name,
4875 command,
4876 args,
4877 env,
4878 meta: _,
4879 }) => {
4880 assert_eq!(name, "test-server");
4881 assert_eq!(command, PathBuf::from("/usr/bin/server"));
4882 assert_eq!(args, vec!["--port", "3000"]);
4883 assert_eq!(env.len(), 1);
4884 assert_eq!(env[0].name, "API_KEY");
4885 assert_eq!(env[0].value, "secret123");
4886 }
4887 _ => panic!("Expected Stdio variant"),
4888 }
4889 }
4890
4891 #[test]
4892 fn test_mcp_server_http_serialization() {
4893 let server = McpServer::Http(
4894 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
4895 HttpHeader::new("Authorization", "Bearer token123"),
4896 HttpHeader::new("Content-Type", "application/json"),
4897 ]),
4898 );
4899
4900 let json = serde_json::to_value(&server).unwrap();
4901 assert_eq!(
4902 json,
4903 json!({
4904 "type": "http",
4905 "name": "http-server",
4906 "url": "https://api.example.com",
4907 "headers": [
4908 {
4909 "name": "Authorization",
4910 "value": "Bearer token123"
4911 },
4912 {
4913 "name": "Content-Type",
4914 "value": "application/json"
4915 }
4916 ]
4917 })
4918 );
4919
4920 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4921 match deserialized {
4922 McpServer::Http(McpServerHttp {
4923 name,
4924 url,
4925 headers,
4926 meta: _,
4927 }) => {
4928 assert_eq!(name, "http-server");
4929 assert_eq!(url, "https://api.example.com");
4930 assert_eq!(headers.len(), 2);
4931 assert_eq!(headers[0].name, "Authorization");
4932 assert_eq!(headers[0].value, "Bearer token123");
4933 assert_eq!(headers[1].name, "Content-Type");
4934 assert_eq!(headers[1].value, "application/json");
4935 }
4936 _ => panic!("Expected Http variant"),
4937 }
4938 }
4939
4940 #[cfg(feature = "unstable_mcp_over_acp")]
4941 #[test]
4942 fn test_mcp_server_acp_serialization() {
4943 let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id"));
4944
4945 let json = serde_json::to_value(&server).unwrap();
4946 assert_eq!(
4947 json,
4948 json!({
4949 "type": "acp",
4950 "name": "project-tools",
4951 "id": "project-tools-id"
4952 })
4953 );
4954
4955 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4956 match deserialized {
4957 McpServer::Acp(McpServerAcp { name, id, meta: _ }) => {
4958 assert_eq!(name, "project-tools");
4959 assert_eq!(id, McpServerAcpId::new("project-tools-id"));
4960 }
4961 _ => panic!("Expected Acp variant"),
4962 }
4963 }
4964
4965 #[cfg(feature = "unstable_mcp_over_acp")]
4966 #[test]
4967 fn test_client_mcp_message_method_names() {
4968 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
4969
4970 assert_eq!(
4971 ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
4972 .method(),
4973 "mcp/message"
4974 );
4975 assert_eq!(
4976 ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
4977 "conn-1",
4978 "notifications/progress"
4979 ))
4980 .method(),
4981 "mcp/message"
4982 );
4983 }
4984
4985 #[cfg(feature = "unstable_mcp_over_acp")]
4986 #[test]
4987 fn test_mcp_server_acp_schema() {
4988 let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap();
4989 assert!(json_contains_entry(
4990 &mcp_server_schema,
4991 "const",
4992 &json!("acp")
4993 ));
4994 assert!(json_contains_entry(
4995 &mcp_server_schema,
4996 "$ref",
4997 &json!("#/$defs/McpServerAcp")
4998 ));
4999
5000 let capabilities_schema =
5001 serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap();
5002 assert!(json_contains_key(&capabilities_schema, "acp"));
5003 }
5004
5005 #[cfg(feature = "unstable_mcp_over_acp")]
5006 fn json_contains_entry(
5007 value: &serde_json::Value,
5008 key: &str,
5009 expected: &serde_json::Value,
5010 ) -> bool {
5011 match value {
5012 serde_json::Value::Object(map) => {
5013 map.get(key) == Some(expected)
5014 || map
5015 .values()
5016 .any(|value| json_contains_entry(value, key, expected))
5017 }
5018 serde_json::Value::Array(values) => values
5019 .iter()
5020 .any(|value| json_contains_entry(value, key, expected)),
5021 _ => false,
5022 }
5023 }
5024
5025 #[cfg(feature = "unstable_mcp_over_acp")]
5026 fn json_contains_key(value: &serde_json::Value, key: &str) -> bool {
5027 match value {
5028 serde_json::Value::Object(map) => {
5029 map.contains_key(key) || map.values().any(|value| json_contains_key(value, key))
5030 }
5031 serde_json::Value::Array(values) => {
5032 values.iter().any(|value| json_contains_key(value, key))
5033 }
5034 _ => false,
5035 }
5036 }
5037
5038 #[test]
5039 fn test_mcp_server_sse_serialization() {
5040 let server = McpServer::Sse(
5041 McpServerSse::new("sse-server", "https://sse.example.com/events")
5042 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5043 );
5044
5045 let json = serde_json::to_value(&server).unwrap();
5046 assert_eq!(
5047 json,
5048 json!({
5049 "type": "sse",
5050 "name": "sse-server",
5051 "url": "https://sse.example.com/events",
5052 "headers": [
5053 {
5054 "name": "X-API-Key",
5055 "value": "apikey456"
5056 }
5057 ]
5058 })
5059 );
5060
5061 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5062 match deserialized {
5063 McpServer::Sse(McpServerSse {
5064 name,
5065 url,
5066 headers,
5067 meta: _,
5068 }) => {
5069 assert_eq!(name, "sse-server");
5070 assert_eq!(url, "https://sse.example.com/events");
5071 assert_eq!(headers.len(), 1);
5072 assert_eq!(headers[0].name, "X-API-Key");
5073 assert_eq!(headers[0].value, "apikey456");
5074 }
5075 _ => panic!("Expected Sse variant"),
5076 }
5077 }
5078
5079 #[test]
5080 fn test_session_config_option_category_known_variants() {
5081 assert_eq!(
5083 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5084 json!("mode")
5085 );
5086 assert_eq!(
5087 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5088 json!("model")
5089 );
5090 assert_eq!(
5091 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5092 json!("thought_level")
5093 );
5094
5095 assert_eq!(
5097 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5098 SessionConfigOptionCategory::Mode
5099 );
5100 assert_eq!(
5101 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5102 SessionConfigOptionCategory::Model
5103 );
5104 assert_eq!(
5105 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5106 SessionConfigOptionCategory::ThoughtLevel
5107 );
5108 }
5109
5110 #[test]
5111 fn test_session_config_option_category_unknown_variants() {
5112 let unknown: SessionConfigOptionCategory =
5114 serde_json::from_str("\"some_future_category\"").unwrap();
5115 assert_eq!(
5116 unknown,
5117 SessionConfigOptionCategory::Other("some_future_category".to_string())
5118 );
5119
5120 let json = serde_json::to_value(&unknown).unwrap();
5122 assert_eq!(json, json!("some_future_category"));
5123 }
5124
5125 #[test]
5126 fn test_session_config_option_category_custom_categories() {
5127 let custom: SessionConfigOptionCategory =
5129 serde_json::from_str("\"_my_custom_category\"").unwrap();
5130 assert_eq!(
5131 custom,
5132 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5133 );
5134
5135 let json = serde_json::to_value(&custom).unwrap();
5137 assert_eq!(json, json!("_my_custom_category"));
5138
5139 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5141 assert_eq!(
5142 deserialized,
5143 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5144 );
5145 }
5146
5147 #[test]
5148 fn test_auth_method_agent_serialization() {
5149 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5150
5151 let json = serde_json::to_value(&method).unwrap();
5152 assert_eq!(
5153 json,
5154 json!({
5155 "id": "default-auth",
5156 "name": "Default Auth"
5157 })
5158 );
5159 assert!(!json.as_object().unwrap().contains_key("description"));
5161 assert!(!json.as_object().unwrap().contains_key("type"));
5163
5164 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5165 match deserialized {
5166 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5167 assert_eq!(id.0.as_ref(), "default-auth");
5168 assert_eq!(name, "Default Auth");
5169 }
5170 #[cfg(feature = "unstable_auth_methods")]
5171 _ => panic!("Expected Agent variant"),
5172 }
5173 }
5174
5175 #[test]
5176 fn test_auth_method_explicit_agent_deserialization() {
5177 let json = json!({
5179 "id": "agent-auth",
5180 "name": "Agent Auth",
5181 "type": "agent"
5182 });
5183
5184 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5185 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5186 }
5187
5188 #[test]
5189 fn test_session_delete_serialization() {
5190 assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5191 assert_eq!(
5192 ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5193 "session/delete"
5194 );
5195 assert_eq!(
5196 serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5197 json!({
5198 "sessionId": "sess_abc123"
5199 })
5200 );
5201 assert_eq!(
5202 serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5203 json!({})
5204 );
5205 assert_eq!(
5206 serde_json::to_value(
5207 SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5208 )
5209 .unwrap(),
5210 json!({
5211 "delete": {}
5212 })
5213 );
5214 }
5215 #[test]
5216 fn test_session_additional_directories_serialization() {
5217 assert_eq!(
5218 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5219 json!({
5220 "cwd": "/home/user/project",
5221 "mcpServers": []
5222 })
5223 );
5224 assert_eq!(
5225 serde_json::to_value(
5226 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5227 PathBuf::from("/home/user/shared-lib"),
5228 PathBuf::from("/home/user/product-docs"),
5229 ])
5230 )
5231 .unwrap(),
5232 json!({
5233 "cwd": "/home/user/project",
5234 "additionalDirectories": [
5235 "/home/user/shared-lib",
5236 "/home/user/product-docs"
5237 ],
5238 "mcpServers": []
5239 })
5240 );
5241 assert_eq!(
5242 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5243 json!({
5244 "sessionId": "sess_abc123",
5245 "cwd": "/home/user/project"
5246 })
5247 );
5248 assert_eq!(
5249 serde_json::to_value(
5250 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5251 PathBuf::from("/home/user/shared-lib"),
5252 PathBuf::from("/home/user/product-docs"),
5253 ])
5254 )
5255 .unwrap(),
5256 json!({
5257 "sessionId": "sess_abc123",
5258 "cwd": "/home/user/project",
5259 "additionalDirectories": [
5260 "/home/user/shared-lib",
5261 "/home/user/product-docs"
5262 ]
5263 })
5264 );
5265 assert_eq!(
5266 serde_json::from_value::<SessionInfo>(json!({
5267 "sessionId": "sess_abc123",
5268 "cwd": "/home/user/project"
5269 }))
5270 .unwrap()
5271 .additional_directories,
5272 Vec::<PathBuf>::new()
5273 );
5274 }
5275 #[test]
5276 fn test_session_additional_directories_capabilities_serialization() {
5277 assert_eq!(
5278 serde_json::to_value(
5279 SessionCapabilities::new()
5280 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5281 )
5282 .unwrap(),
5283 json!({
5284 "additionalDirectories": {}
5285 })
5286 );
5287 }
5288
5289 #[cfg(feature = "unstable_auth_methods")]
5290 #[test]
5291 fn test_auth_method_env_var_serialization() {
5292 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5293 "api-key",
5294 "API Key",
5295 vec![AuthEnvVar::new("API_KEY")],
5296 ));
5297
5298 let json = serde_json::to_value(&method).unwrap();
5299 assert_eq!(
5300 json,
5301 json!({
5302 "id": "api-key",
5303 "name": "API Key",
5304 "type": "env_var",
5305 "vars": [{"name": "API_KEY"}]
5306 })
5307 );
5308 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5310 assert!(
5311 !json["vars"][0]
5312 .as_object()
5313 .unwrap()
5314 .contains_key("optional")
5315 );
5316
5317 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5318 match deserialized {
5319 AuthMethod::EnvVar(AuthMethodEnvVar {
5320 id,
5321 name: method_name,
5322 vars,
5323 link,
5324 ..
5325 }) => {
5326 assert_eq!(id.0.as_ref(), "api-key");
5327 assert_eq!(method_name, "API Key");
5328 assert_eq!(vars.len(), 1);
5329 assert_eq!(vars[0].name, "API_KEY");
5330 assert!(vars[0].secret);
5331 assert!(!vars[0].optional);
5332 assert!(link.is_none());
5333 }
5334 _ => panic!("Expected EnvVar variant"),
5335 }
5336 }
5337
5338 #[cfg(feature = "unstable_auth_methods")]
5339 #[test]
5340 fn test_auth_method_env_var_with_link_serialization() {
5341 let method = AuthMethod::EnvVar(
5342 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5343 .link("https://example.com/keys"),
5344 );
5345
5346 let json = serde_json::to_value(&method).unwrap();
5347 assert_eq!(
5348 json,
5349 json!({
5350 "id": "api-key",
5351 "name": "API Key",
5352 "type": "env_var",
5353 "vars": [{"name": "API_KEY"}],
5354 "link": "https://example.com/keys"
5355 })
5356 );
5357
5358 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5359 match deserialized {
5360 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5361 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5362 }
5363 _ => panic!("Expected EnvVar variant"),
5364 }
5365 }
5366
5367 #[cfg(feature = "unstable_auth_methods")]
5368 #[test]
5369 fn test_auth_method_env_var_multiple_vars() {
5370 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5371 "azure-openai",
5372 "Azure OpenAI",
5373 vec![
5374 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5375 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5376 .label("Endpoint URL")
5377 .secret(false),
5378 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5379 .label("API Version")
5380 .secret(false)
5381 .optional(true),
5382 ],
5383 ));
5384
5385 let json = serde_json::to_value(&method).unwrap();
5386 assert_eq!(
5387 json,
5388 json!({
5389 "id": "azure-openai",
5390 "name": "Azure OpenAI",
5391 "type": "env_var",
5392 "vars": [
5393 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5394 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5395 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5396 ]
5397 })
5398 );
5399
5400 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5401 match deserialized {
5402 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5403 assert_eq!(vars.len(), 3);
5404 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5406 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5407 assert!(vars[0].secret);
5408 assert!(!vars[0].optional);
5409 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5411 assert!(!vars[1].secret);
5412 assert!(!vars[1].optional);
5413 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5415 assert!(!vars[2].secret);
5416 assert!(vars[2].optional);
5417 }
5418 _ => panic!("Expected EnvVar variant"),
5419 }
5420 }
5421
5422 #[cfg(feature = "unstable_auth_methods")]
5423 #[test]
5424 fn test_auth_method_terminal_serialization() {
5425 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5426
5427 let json = serde_json::to_value(&method).unwrap();
5428 assert_eq!(
5429 json,
5430 json!({
5431 "id": "tui-auth",
5432 "name": "Terminal Auth",
5433 "type": "terminal"
5434 })
5435 );
5436 assert!(!json.as_object().unwrap().contains_key("args"));
5438 assert!(!json.as_object().unwrap().contains_key("env"));
5439
5440 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5441 match deserialized {
5442 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5443 assert!(args.is_empty());
5444 assert!(env.is_empty());
5445 }
5446 _ => panic!("Expected Terminal variant"),
5447 }
5448 }
5449
5450 #[cfg(feature = "unstable_auth_methods")]
5451 #[test]
5452 fn test_auth_method_terminal_with_args_and_env_serialization() {
5453 use std::collections::HashMap;
5454
5455 let mut env = HashMap::new();
5456 env.insert("TERM".to_string(), "xterm-256color".to_string());
5457
5458 let method = AuthMethod::Terminal(
5459 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5460 .args(vec!["--interactive".to_string(), "--color".to_string()])
5461 .env(env),
5462 );
5463
5464 let json = serde_json::to_value(&method).unwrap();
5465 assert_eq!(
5466 json,
5467 json!({
5468 "id": "tui-auth",
5469 "name": "Terminal Auth",
5470 "type": "terminal",
5471 "args": ["--interactive", "--color"],
5472 "env": {
5473 "TERM": "xterm-256color"
5474 }
5475 })
5476 );
5477
5478 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5479 match deserialized {
5480 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5481 assert_eq!(args, vec!["--interactive", "--color"]);
5482 assert_eq!(env.len(), 1);
5483 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5484 }
5485 _ => panic!("Expected Terminal variant"),
5486 }
5487 }
5488
5489 #[cfg(feature = "unstable_boolean_config")]
5490 #[test]
5491 fn test_session_config_option_value_id_serialize() {
5492 let val = SessionConfigOptionValue::value_id("model-1");
5493 let json = serde_json::to_value(&val).unwrap();
5494 assert_eq!(json, json!({ "value": "model-1" }));
5496 assert!(!json.as_object().unwrap().contains_key("type"));
5497 }
5498
5499 #[cfg(feature = "unstable_boolean_config")]
5500 #[test]
5501 fn test_session_config_option_value_boolean_serialize() {
5502 let val = SessionConfigOptionValue::boolean(true);
5503 let json = serde_json::to_value(&val).unwrap();
5504 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5505 }
5506
5507 #[cfg(feature = "unstable_boolean_config")]
5508 #[test]
5509 fn test_session_config_option_value_deserialize_no_type() {
5510 let json = json!({ "value": "model-1" });
5512 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5513 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5514 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5515 }
5516
5517 #[cfg(feature = "unstable_boolean_config")]
5518 #[test]
5519 fn test_session_config_option_value_deserialize_boolean() {
5520 let json = json!({ "type": "boolean", "value": true });
5521 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5522 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5523 assert_eq!(val.as_bool(), Some(true));
5524 }
5525
5526 #[cfg(feature = "unstable_boolean_config")]
5527 #[test]
5528 fn test_session_config_option_value_deserialize_boolean_false() {
5529 let json = json!({ "type": "boolean", "value": false });
5530 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5531 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5532 assert_eq!(val.as_bool(), Some(false));
5533 }
5534
5535 #[cfg(feature = "unstable_boolean_config")]
5536 #[test]
5537 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5538 let json = json!({ "type": "text", "value": "freeform input" });
5540 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5541 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5542 }
5543
5544 #[cfg(feature = "unstable_boolean_config")]
5545 #[test]
5546 fn test_session_config_option_value_roundtrip_value_id() {
5547 let original = SessionConfigOptionValue::value_id("option-a");
5548 let json = serde_json::to_value(&original).unwrap();
5549 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5550 assert_eq!(original, roundtripped);
5551 }
5552
5553 #[cfg(feature = "unstable_boolean_config")]
5554 #[test]
5555 fn test_session_config_option_value_roundtrip_boolean() {
5556 let original = SessionConfigOptionValue::boolean(false);
5557 let json = serde_json::to_value(&original).unwrap();
5558 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5559 assert_eq!(original, roundtripped);
5560 }
5561
5562 #[cfg(feature = "unstable_boolean_config")]
5563 #[test]
5564 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5565 let json = json!({ "type": "boolean", "value": "not a bool" });
5567 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5568 assert!(result.is_ok());
5570 assert_eq!(
5571 result.unwrap().as_value_id().unwrap().to_string(),
5572 "not a bool"
5573 );
5574 }
5575
5576 #[cfg(feature = "unstable_boolean_config")]
5577 #[test]
5578 fn test_session_config_option_value_from_impls() {
5579 let from_str: SessionConfigOptionValue = "model-1".into();
5580 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5581
5582 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5583 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5584
5585 let from_bool: SessionConfigOptionValue = true.into();
5586 assert_eq!(from_bool.as_bool(), Some(true));
5587 }
5588
5589 #[cfg(feature = "unstable_boolean_config")]
5590 #[test]
5591 fn test_set_session_config_option_request_value_id() {
5592 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5593 let json = serde_json::to_value(&req).unwrap();
5594 assert_eq!(
5595 json,
5596 json!({
5597 "sessionId": "sess_1",
5598 "configId": "model",
5599 "value": "model-1"
5600 })
5601 );
5602 assert!(!json.as_object().unwrap().contains_key("type"));
5604 }
5605
5606 #[cfg(feature = "unstable_boolean_config")]
5607 #[test]
5608 fn test_set_session_config_option_request_boolean() {
5609 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5610 let json = serde_json::to_value(&req).unwrap();
5611 assert_eq!(
5612 json,
5613 json!({
5614 "sessionId": "sess_1",
5615 "configId": "brave_mode",
5616 "type": "boolean",
5617 "value": true
5618 })
5619 );
5620 }
5621
5622 #[cfg(feature = "unstable_boolean_config")]
5623 #[test]
5624 fn test_set_session_config_option_request_deserialize_no_type() {
5625 let json = json!({
5627 "sessionId": "sess_1",
5628 "configId": "model",
5629 "value": "model-1"
5630 });
5631 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5632 assert_eq!(req.session_id.to_string(), "sess_1");
5633 assert_eq!(req.config_id.to_string(), "model");
5634 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5635 }
5636
5637 #[cfg(feature = "unstable_boolean_config")]
5638 #[test]
5639 fn test_set_session_config_option_request_deserialize_boolean() {
5640 let json = json!({
5641 "sessionId": "sess_1",
5642 "configId": "brave_mode",
5643 "type": "boolean",
5644 "value": true
5645 });
5646 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5647 assert_eq!(req.value.as_bool(), Some(true));
5648 }
5649
5650 #[cfg(feature = "unstable_boolean_config")]
5651 #[test]
5652 fn test_set_session_config_option_request_roundtrip_value_id() {
5653 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5654 let json = serde_json::to_value(&original).unwrap();
5655 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5656 assert_eq!(original, roundtripped);
5657 }
5658
5659 #[cfg(feature = "unstable_boolean_config")]
5660 #[test]
5661 fn test_set_session_config_option_request_roundtrip_boolean() {
5662 let original = SetSessionConfigOptionRequest::new("s", "c", false);
5663 let json = serde_json::to_value(&original).unwrap();
5664 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5665 assert_eq!(original, roundtripped);
5666 }
5667
5668 #[cfg(feature = "unstable_boolean_config")]
5669 #[test]
5670 fn test_session_config_boolean_serialization() {
5671 let cfg = SessionConfigBoolean::new(true);
5672 let json = serde_json::to_value(&cfg).unwrap();
5673 assert_eq!(json, json!({ "currentValue": true }));
5674
5675 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
5676 assert!(deserialized.current_value);
5677 }
5678
5679 #[cfg(feature = "unstable_boolean_config")]
5680 #[test]
5681 fn test_session_config_option_boolean_variant() {
5682 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
5683 .description("Skip confirmation prompts");
5684 let json = serde_json::to_value(&opt).unwrap();
5685 assert_eq!(
5686 json,
5687 json!({
5688 "id": "brave_mode",
5689 "name": "Brave Mode",
5690 "description": "Skip confirmation prompts",
5691 "type": "boolean",
5692 "currentValue": false
5693 })
5694 );
5695
5696 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5697 assert_eq!(deserialized.id.to_string(), "brave_mode");
5698 assert_eq!(deserialized.name, "Brave Mode");
5699 match deserialized.kind {
5700 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
5701 _ => panic!("Expected Boolean kind"),
5702 }
5703 }
5704
5705 #[cfg(feature = "unstable_boolean_config")]
5706 #[test]
5707 fn test_session_config_option_select_still_works() {
5708 let opt = SessionConfigOption::select(
5710 "model",
5711 "Model",
5712 "model-1",
5713 vec![
5714 SessionConfigSelectOption::new("model-1", "Model 1"),
5715 SessionConfigSelectOption::new("model-2", "Model 2"),
5716 ],
5717 );
5718 let json = serde_json::to_value(&opt).unwrap();
5719 assert_eq!(json["type"], "select");
5720 assert_eq!(json["currentValue"], "model-1");
5721 assert_eq!(json["options"].as_array().unwrap().len(), 2);
5722
5723 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5724 match deserialized.kind {
5725 SessionConfigKind::Select(ref s) => {
5726 assert_eq!(s.current_value.to_string(), "model-1");
5727 }
5728 _ => panic!("Expected Select kind"),
5729 }
5730 }
5731
5732 #[cfg(feature = "unstable_llm_providers")]
5733 #[test]
5734 fn test_llm_protocol_known_variants() {
5735 assert_eq!(
5736 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
5737 json!("anthropic")
5738 );
5739 assert_eq!(
5740 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
5741 json!("openai")
5742 );
5743 assert_eq!(
5744 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
5745 json!("azure")
5746 );
5747 assert_eq!(
5748 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
5749 json!("vertex")
5750 );
5751 assert_eq!(
5752 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
5753 json!("bedrock")
5754 );
5755
5756 assert_eq!(
5757 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
5758 LlmProtocol::Anthropic
5759 );
5760 assert_eq!(
5761 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
5762 LlmProtocol::OpenAi
5763 );
5764 assert_eq!(
5765 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
5766 LlmProtocol::Azure
5767 );
5768 assert_eq!(
5769 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
5770 LlmProtocol::Vertex
5771 );
5772 assert_eq!(
5773 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
5774 LlmProtocol::Bedrock
5775 );
5776 }
5777
5778 #[cfg(feature = "unstable_llm_providers")]
5779 #[test]
5780 fn test_llm_protocol_unknown_variant() {
5781 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
5782 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
5783
5784 let json = serde_json::to_value(&unknown).unwrap();
5785 assert_eq!(json, json!("cohere"));
5786 }
5787
5788 #[cfg(feature = "unstable_llm_providers")]
5789 #[test]
5790 fn test_provider_current_config_serialization() {
5791 let config =
5792 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
5793
5794 let json = serde_json::to_value(&config).unwrap();
5795 assert_eq!(
5796 json,
5797 json!({
5798 "apiType": "anthropic",
5799 "baseUrl": "https://api.anthropic.com"
5800 })
5801 );
5802
5803 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
5804 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
5805 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
5806 }
5807
5808 #[cfg(feature = "unstable_llm_providers")]
5809 #[test]
5810 fn test_provider_info_with_current_config() {
5811 let info = ProviderInfo::new(
5812 "main",
5813 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
5814 true,
5815 Some(ProviderCurrentConfig::new(
5816 LlmProtocol::Anthropic,
5817 "https://api.anthropic.com",
5818 )),
5819 );
5820
5821 let json = serde_json::to_value(&info).unwrap();
5822 assert_eq!(
5823 json,
5824 json!({
5825 "id": "main",
5826 "supported": ["anthropic", "openai"],
5827 "required": true,
5828 "current": {
5829 "apiType": "anthropic",
5830 "baseUrl": "https://api.anthropic.com"
5831 }
5832 })
5833 );
5834
5835 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5836 assert_eq!(deserialized.id, "main");
5837 assert_eq!(deserialized.supported.len(), 2);
5838 assert!(deserialized.required);
5839 assert!(deserialized.current.is_some());
5840 assert_eq!(
5841 deserialized.current.as_ref().unwrap().api_type,
5842 LlmProtocol::Anthropic
5843 );
5844 }
5845
5846 #[cfg(feature = "unstable_llm_providers")]
5847 #[test]
5848 fn test_provider_info_disabled() {
5849 let info = ProviderInfo::new(
5850 "secondary",
5851 vec![LlmProtocol::OpenAi],
5852 false,
5853 None::<ProviderCurrentConfig>,
5854 );
5855
5856 let json = serde_json::to_value(&info).unwrap();
5857 assert_eq!(
5858 json,
5859 json!({
5860 "id": "secondary",
5861 "supported": ["openai"],
5862 "required": false
5863 })
5864 );
5865
5866 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5867 assert_eq!(deserialized.id, "secondary");
5868 assert!(!deserialized.required);
5869 assert!(deserialized.current.is_none());
5870 }
5871
5872 #[cfg(feature = "unstable_llm_providers")]
5873 #[test]
5874 fn test_provider_info_missing_current_defaults_to_none() {
5875 let json = json!({
5877 "id": "main",
5878 "supported": ["anthropic"],
5879 "required": true
5880 });
5881 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5882 assert!(deserialized.current.is_none());
5883 }
5884
5885 #[cfg(feature = "unstable_llm_providers")]
5886 #[test]
5887 fn test_provider_info_explicit_null_current_decodes_to_none() {
5888 let json = json!({
5892 "id": "main",
5893 "supported": ["anthropic"],
5894 "required": true,
5895 "current": null
5896 });
5897 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
5898 assert!(deserialized.current.is_none());
5899 }
5900
5901 #[cfg(feature = "unstable_llm_providers")]
5902 #[test]
5903 fn test_list_providers_response_serialization() {
5904 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
5905 "main",
5906 vec![LlmProtocol::Anthropic],
5907 true,
5908 Some(ProviderCurrentConfig::new(
5909 LlmProtocol::Anthropic,
5910 "https://api.anthropic.com",
5911 )),
5912 )]);
5913
5914 let json = serde_json::to_value(&response).unwrap();
5915 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
5916 assert_eq!(json["providers"][0]["id"], "main");
5917
5918 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
5919 assert_eq!(deserialized.providers.len(), 1);
5920 }
5921
5922 #[cfg(feature = "unstable_llm_providers")]
5923 #[test]
5924 fn test_set_provider_request_serialization() {
5925 use std::collections::HashMap;
5926
5927 let mut headers = HashMap::new();
5928 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
5929
5930 let request =
5931 SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
5932 .headers(headers);
5933
5934 let json = serde_json::to_value(&request).unwrap();
5935 assert_eq!(
5936 json,
5937 json!({
5938 "id": "main",
5939 "apiType": "openai",
5940 "baseUrl": "https://api.openai.com/v1",
5941 "headers": {
5942 "Authorization": "Bearer sk-test"
5943 }
5944 })
5945 );
5946
5947 let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
5948 assert_eq!(deserialized.id, "main");
5949 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
5950 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
5951 assert_eq!(deserialized.headers.len(), 1);
5952 assert_eq!(
5953 deserialized.headers.get("Authorization").unwrap(),
5954 "Bearer sk-test"
5955 );
5956 }
5957
5958 #[cfg(feature = "unstable_llm_providers")]
5959 #[test]
5960 fn test_set_provider_request_omits_empty_headers() {
5961 let request =
5962 SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
5963
5964 let json = serde_json::to_value(&request).unwrap();
5965 assert!(!json.as_object().unwrap().contains_key("headers"));
5967 }
5968
5969 #[cfg(feature = "unstable_llm_providers")]
5970 #[test]
5971 fn test_disable_provider_request_serialization() {
5972 let request = DisableProviderRequest::new("secondary");
5973
5974 let json = serde_json::to_value(&request).unwrap();
5975 assert_eq!(json, json!({ "id": "secondary" }));
5976
5977 let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
5978 assert_eq!(deserialized.id, "secondary");
5979 }
5980
5981 #[cfg(feature = "unstable_llm_providers")]
5982 #[test]
5983 fn test_providers_capabilities_serialization() {
5984 let caps = ProvidersCapabilities::new();
5985
5986 let json = serde_json::to_value(&caps).unwrap();
5987 assert_eq!(json, json!({}));
5988
5989 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
5990 assert!(deserialized.meta.is_none());
5991 }
5992
5993 #[cfg(feature = "unstable_llm_providers")]
5994 #[test]
5995 fn test_agent_capabilities_with_providers() {
5996 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
5997
5998 let json = serde_json::to_value(&caps).unwrap();
5999 assert_eq!(json["providers"], json!({}));
6000
6001 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6002 assert!(deserialized.providers.is_some());
6003 }
6004}