1use std::{path::PathBuf, sync::Arc};
7
8use std::collections::HashMap;
9
10use derive_more::{Display, From};
11use serde::{Deserialize, Serialize};
12use serde_with::{DefaultOnError, DefaultOnNull, VecSkipError, serde_as, skip_serializing_none};
13
14use crate::{IntoOption, ProtocolVersion};
15
16use super::{
17 ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, Meta, SessionId,
18};
19
20#[cfg(feature = "unstable_mcp_over_acp")]
21use super::mcp::{MCP_MESSAGE_METHOD_NAME, MessageMcpNotification};
22
23#[cfg(feature = "unstable_nes")]
24use super::{
25 AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
26 DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
27 DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
28 StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
29};
30
31#[cfg(feature = "unstable_nes")]
32use super::{
33 DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
34 DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
35 NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
36 NES_SUGGEST_METHOD_NAME,
37};
38
39#[serde_as]
47#[skip_serializing_none]
48#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
50#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME)))]
51#[serde(rename_all = "camelCase")]
52#[non_exhaustive]
53pub struct InitializeRequest {
54 pub protocol_version: ProtocolVersion,
56 #[serde_as(deserialize_as = "DefaultOnError")]
58 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
59 #[serde(default)]
60 pub client_capabilities: ClientCapabilities,
61 #[serde_as(deserialize_as = "DefaultOnError")]
65 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
66 #[serde(default)]
67 pub client_info: Option<Implementation>,
68 #[serde_as(deserialize_as = "DefaultOnError")]
74 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
75 #[serde(default)]
76 #[serde(rename = "_meta")]
77 pub meta: Option<Meta>,
78}
79
80impl InitializeRequest {
81 #[must_use]
83 pub fn new(protocol_version: ProtocolVersion) -> Self {
84 Self {
85 protocol_version,
86 client_capabilities: ClientCapabilities::default(),
87 client_info: None,
88 meta: None,
89 }
90 }
91
92 #[must_use]
94 pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
95 self.client_capabilities = client_capabilities;
96 self
97 }
98
99 #[must_use]
101 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
102 self.client_info = client_info.into_option();
103 self
104 }
105
106 #[must_use]
112 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
113 self.meta = meta.into_option();
114 self
115 }
116}
117
118#[serde_as]
124#[skip_serializing_none]
125#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
126#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
127#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME)))]
128#[serde(rename_all = "camelCase")]
129#[non_exhaustive]
130pub struct InitializeResponse {
131 pub protocol_version: ProtocolVersion,
136 #[serde_as(deserialize_as = "DefaultOnError")]
138 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
139 #[serde(default)]
140 pub agent_capabilities: AgentCapabilities,
141 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
143 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
144 #[serde(default)]
145 pub auth_methods: Vec<AuthMethod>,
146 #[serde_as(deserialize_as = "DefaultOnError")]
150 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
151 #[serde(default)]
152 pub agent_info: Option<Implementation>,
153 #[serde_as(deserialize_as = "DefaultOnError")]
159 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
160 #[serde(default)]
161 #[serde(rename = "_meta")]
162 pub meta: Option<Meta>,
163}
164
165impl InitializeResponse {
166 #[must_use]
168 pub fn new(protocol_version: ProtocolVersion) -> Self {
169 Self {
170 protocol_version,
171 agent_capabilities: AgentCapabilities::default(),
172 auth_methods: vec![],
173 agent_info: None,
174 meta: None,
175 }
176 }
177
178 #[must_use]
180 pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
181 self.agent_capabilities = agent_capabilities;
182 self
183 }
184
185 #[must_use]
187 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
188 self.auth_methods = auth_methods;
189 self
190 }
191
192 #[must_use]
194 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
195 self.agent_info = agent_info.into_option();
196 self
197 }
198
199 #[must_use]
205 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
206 self.meta = meta.into_option();
207 self
208 }
209}
210
211#[serde_as]
215#[skip_serializing_none]
216#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
217#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
218#[serde(rename_all = "camelCase")]
219#[non_exhaustive]
220pub struct Implementation {
221 pub name: String,
224 #[serde_as(deserialize_as = "DefaultOnError")]
229 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
230 #[serde(default)]
231 pub title: Option<String>,
232 pub version: String,
235 #[serde_as(deserialize_as = "DefaultOnError")]
241 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
242 #[serde(default)]
243 #[serde(rename = "_meta")]
244 pub meta: Option<Meta>,
245}
246
247impl Implementation {
248 #[must_use]
250 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
251 Self {
252 name: name.into(),
253 title: None,
254 version: version.into(),
255 meta: None,
256 }
257 }
258
259 #[must_use]
264 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
265 self.title = title.into_option();
266 self
267 }
268
269 #[must_use]
275 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
276 self.meta = meta.into_option();
277 self
278 }
279}
280
281#[serde_as]
287#[skip_serializing_none]
288#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
289#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
290#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME)))]
291#[serde(rename_all = "camelCase")]
292#[non_exhaustive]
293pub struct AuthenticateRequest {
294 pub method_id: AuthMethodId,
297 #[serde_as(deserialize_as = "DefaultOnError")]
303 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
304 #[serde(default)]
305 #[serde(rename = "_meta")]
306 pub meta: Option<Meta>,
307}
308
309impl AuthenticateRequest {
310 #[must_use]
312 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
313 Self {
314 method_id: method_id.into(),
315 meta: None,
316 }
317 }
318
319 #[must_use]
325 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
326 self.meta = meta.into_option();
327 self
328 }
329}
330
331crate::serde_util::default_on_null! {
332 #[serde_as]
334 #[skip_serializing_none]
335 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
336 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
337 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME)))]
338 #[serde(rename_all = "camelCase")]
339 #[non_exhaustive]
340 pub struct AuthenticateResponse {
341 #[serde_as(deserialize_as = "DefaultOnError")]
347 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
348 #[serde(default)]
349 #[serde(rename = "_meta")]
350 pub meta: Option<Meta>,
351 }
352}
353
354impl AuthenticateResponse {
355 #[must_use]
357 pub fn new() -> Self {
358 Self::default()
359 }
360
361 #[must_use]
367 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
368 self.meta = meta.into_option();
369 self
370 }
371}
372
373crate::serde_util::default_on_null! {
376 #[serde_as]
380 #[skip_serializing_none]
381 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
382 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
383 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME)))]
384 #[serde(rename_all = "camelCase")]
385 #[non_exhaustive]
386 pub struct LogoutRequest {
387 #[serde_as(deserialize_as = "DefaultOnError")]
393 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
394 #[serde(default)]
395 #[serde(rename = "_meta")]
396 pub meta: Option<Meta>,
397 }
398}
399
400impl LogoutRequest {
401 #[must_use]
403 pub fn new() -> Self {
404 Self::default()
405 }
406
407 #[must_use]
413 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
414 self.meta = meta.into_option();
415 self
416 }
417}
418
419crate::serde_util::default_on_null! {
420 #[serde_as]
422 #[skip_serializing_none]
423 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
424 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
425 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME)))]
426 #[serde(rename_all = "camelCase")]
427 #[non_exhaustive]
428 pub struct LogoutResponse {
429 #[serde_as(deserialize_as = "DefaultOnError")]
435 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
436 #[serde(default)]
437 #[serde(rename = "_meta")]
438 pub meta: Option<Meta>,
439 }
440}
441
442impl LogoutResponse {
443 #[must_use]
445 pub fn new() -> Self {
446 Self::default()
447 }
448
449 #[must_use]
455 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
456 self.meta = meta.into_option();
457 self
458 }
459}
460
461#[serde_as]
463#[skip_serializing_none]
464#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
465#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
466#[serde(rename_all = "camelCase")]
467#[non_exhaustive]
468pub struct AgentAuthCapabilities {
469 #[serde_as(deserialize_as = "DefaultOnError")]
474 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
475 #[serde(default)]
476 pub logout: Option<LogoutCapabilities>,
477 #[serde_as(deserialize_as = "DefaultOnError")]
483 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
484 #[serde(default)]
485 #[serde(rename = "_meta")]
486 pub meta: Option<Meta>,
487}
488
489impl AgentAuthCapabilities {
490 #[must_use]
492 pub fn new() -> Self {
493 Self::default()
494 }
495
496 #[must_use]
498 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
499 self.logout = logout.into_option();
500 self
501 }
502
503 #[must_use]
509 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
510 self.meta = meta.into_option();
511 self
512 }
513}
514
515#[serde_as]
519#[skip_serializing_none]
520#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
521#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
522#[non_exhaustive]
523pub struct LogoutCapabilities {
524 #[serde_as(deserialize_as = "DefaultOnError")]
530 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
531 #[serde(default)]
532 #[serde(rename = "_meta")]
533 pub meta: Option<Meta>,
534}
535
536impl LogoutCapabilities {
537 #[must_use]
539 pub fn new() -> Self {
540 Self::default()
541 }
542
543 #[must_use]
549 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
550 self.meta = meta.into_option();
551 self
552 }
553}
554
555#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
557#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
558#[serde(transparent)]
559#[from(Arc<str>, String, &'static str)]
560#[non_exhaustive]
561pub struct AuthMethodId(pub Arc<str>);
562
563impl AuthMethodId {
564 #[must_use]
566 pub fn new(id: impl Into<Arc<str>>) -> Self {
567 Self(id.into())
568 }
569}
570
571#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
576#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
577#[serde(tag = "type", rename_all = "snake_case")]
578#[non_exhaustive]
579pub enum AuthMethod {
580 Terminal(AuthMethodTerminal),
583 #[serde(untagged, deserialize_with = "deserialize_agent_auth_method_fallback")]
587 Agent(AuthMethodAgent),
588}
589
590fn deserialize_agent_auth_method_fallback<'de, D>(
595 deserializer: D,
596) -> Result<AuthMethodAgent, D::Error>
597where
598 D: serde::Deserializer<'de>,
599{
600 let value = serde_json::Value::deserialize(deserializer)?;
601 if value.get("type").and_then(serde_json::Value::as_str) == Some("terminal") {
602 return Err(serde::de::Error::custom(
603 "known authentication method `terminal` did not match its schema",
604 ));
605 }
606 AuthMethodAgent::deserialize(value).map_err(serde::de::Error::custom)
607}
608
609impl AuthMethod {
610 #[must_use]
612 pub fn id(&self) -> &AuthMethodId {
613 match self {
614 Self::Agent(a) => &a.id,
615 Self::Terminal(t) => &t.id,
616 }
617 }
618
619 #[must_use]
621 pub fn name(&self) -> &str {
622 match self {
623 Self::Agent(a) => &a.name,
624 Self::Terminal(t) => &t.name,
625 }
626 }
627
628 #[must_use]
630 pub fn description(&self) -> Option<&str> {
631 match self {
632 Self::Agent(a) => a.description.as_deref(),
633 Self::Terminal(t) => t.description.as_deref(),
634 }
635 }
636
637 #[must_use]
643 pub fn meta(&self) -> Option<&Meta> {
644 match self {
645 Self::Agent(a) => a.meta.as_ref(),
646 Self::Terminal(t) => t.meta.as_ref(),
647 }
648 }
649}
650
651#[serde_as]
655#[skip_serializing_none]
656#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
657#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
658#[serde(rename_all = "camelCase")]
659#[non_exhaustive]
660pub struct AuthMethodAgent {
661 pub id: AuthMethodId,
663 pub name: String,
665 #[serde_as(deserialize_as = "DefaultOnError")]
667 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
668 #[serde(default)]
669 pub description: Option<String>,
670 #[serde_as(deserialize_as = "DefaultOnError")]
676 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
677 #[serde(default)]
678 #[serde(rename = "_meta")]
679 pub meta: Option<Meta>,
680}
681
682impl AuthMethodAgent {
683 #[must_use]
685 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
686 Self {
687 id: id.into(),
688 name: name.into(),
689 description: None,
690 meta: None,
691 }
692 }
693
694 #[must_use]
696 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
697 self.description = description.into_option();
698 self
699 }
700
701 #[must_use]
707 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
708 self.meta = meta.into_option();
709 self
710 }
711}
712
713#[serde_as]
721#[skip_serializing_none]
722#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
723#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
724#[serde(rename_all = "camelCase")]
725#[non_exhaustive]
726pub struct AuthMethodTerminal {
727 pub id: AuthMethodId,
729 pub name: String,
731 #[serde_as(deserialize_as = "DefaultOnError")]
733 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
734 #[serde(default)]
735 pub description: Option<String>,
736 #[serde_as(deserialize_as = "DefaultOnNull")]
738 #[serde(default, skip_serializing_if = "Vec::is_empty")]
739 pub args: Vec<String>,
740 #[serde_as(deserialize_as = "DefaultOnNull")]
743 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
744 pub env: HashMap<String, String>,
745 #[serde_as(deserialize_as = "DefaultOnError")]
751 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
752 #[serde(default)]
753 #[serde(rename = "_meta")]
754 pub meta: Option<Meta>,
755}
756
757impl AuthMethodTerminal {
758 #[must_use]
760 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
761 Self {
762 id: id.into(),
763 name: name.into(),
764 description: None,
765 args: Vec::new(),
766 env: HashMap::new(),
767 meta: None,
768 }
769 }
770
771 #[must_use]
773 pub fn args(mut self, args: Vec<String>) -> Self {
774 self.args = args;
775 self
776 }
777
778 #[must_use]
781 pub fn env(mut self, env: HashMap<String, String>) -> Self {
782 self.env = env;
783 self
784 }
785
786 #[must_use]
788 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
789 self.description = description.into_option();
790 self
791 }
792
793 #[must_use]
799 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
800 self.meta = meta.into_option();
801 self
802 }
803}
804
805#[serde_as]
811#[skip_serializing_none]
812#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
813#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
814#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME)))]
815#[serde(rename_all = "camelCase")]
816#[non_exhaustive]
817pub struct NewSessionRequest {
818 pub cwd: PathBuf,
820 #[serde_as(deserialize_as = "DefaultOnNull")]
826 #[serde(default, skip_serializing_if = "Vec::is_empty")]
827 pub additional_directories: Vec<PathBuf>,
828 #[serde_as(deserialize_as = "DefaultOnNull")]
830 pub mcp_servers: Vec<McpServer>,
831 #[serde_as(deserialize_as = "DefaultOnError")]
837 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
838 #[serde(default)]
839 #[serde(rename = "_meta")]
840 pub meta: Option<Meta>,
841}
842
843impl NewSessionRequest {
844 #[must_use]
846 pub fn new(cwd: impl Into<PathBuf>) -> Self {
847 Self {
848 cwd: cwd.into(),
849 additional_directories: vec![],
850 mcp_servers: vec![],
851 meta: None,
852 }
853 }
854
855 #[must_use]
857 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
858 self.additional_directories = additional_directories;
859 self
860 }
861
862 #[must_use]
864 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
865 self.mcp_servers = mcp_servers;
866 self
867 }
868
869 #[must_use]
875 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
876 self.meta = meta.into_option();
877 self
878 }
879}
880
881#[serde_as]
885#[skip_serializing_none]
886#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
887#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
888#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME)))]
889#[serde(rename_all = "camelCase")]
890#[non_exhaustive]
891pub struct NewSessionResponse {
892 pub session_id: SessionId,
896 #[serde_as(deserialize_as = "DefaultOnError")]
900 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
901 #[serde(default)]
902 pub modes: Option<SessionModeState>,
903 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
905 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
906 #[serde(default)]
907 pub config_options: Option<Vec<SessionConfigOption>>,
908 #[serde_as(deserialize_as = "DefaultOnError")]
914 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
915 #[serde(default)]
916 #[serde(rename = "_meta")]
917 pub meta: Option<Meta>,
918}
919
920impl NewSessionResponse {
921 #[must_use]
923 pub fn new(session_id: impl Into<SessionId>) -> Self {
924 Self {
925 session_id: session_id.into(),
926 modes: None,
927 config_options: None,
928 meta: None,
929 }
930 }
931
932 #[must_use]
936 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
937 self.modes = modes.into_option();
938 self
939 }
940
941 #[must_use]
943 pub fn config_options(
944 mut self,
945 config_options: impl IntoOption<Vec<SessionConfigOption>>,
946 ) -> Self {
947 self.config_options = config_options.into_option();
948 self
949 }
950
951 #[must_use]
957 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
958 self.meta = meta.into_option();
959 self
960 }
961}
962
963#[serde_as]
971#[skip_serializing_none]
972#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
973#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
974#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME)))]
975#[serde(rename_all = "camelCase")]
976#[non_exhaustive]
977pub struct LoadSessionRequest {
978 #[serde_as(deserialize_as = "DefaultOnNull")]
980 pub mcp_servers: Vec<McpServer>,
981 pub cwd: PathBuf,
983 #[serde_as(deserialize_as = "DefaultOnNull")]
990 #[serde(default, skip_serializing_if = "Vec::is_empty")]
991 pub additional_directories: Vec<PathBuf>,
992 pub session_id: SessionId,
994 #[serde_as(deserialize_as = "DefaultOnError")]
1000 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1001 #[serde(default)]
1002 #[serde(rename = "_meta")]
1003 pub meta: Option<Meta>,
1004}
1005
1006impl LoadSessionRequest {
1007 #[must_use]
1009 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1010 Self {
1011 mcp_servers: vec![],
1012 cwd: cwd.into(),
1013 additional_directories: vec![],
1014 session_id: session_id.into(),
1015 meta: None,
1016 }
1017 }
1018
1019 #[must_use]
1021 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1022 self.additional_directories = additional_directories;
1023 self
1024 }
1025
1026 #[must_use]
1028 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1029 self.mcp_servers = mcp_servers;
1030 self
1031 }
1032
1033 #[must_use]
1039 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1040 self.meta = meta.into_option();
1041 self
1042 }
1043}
1044
1045crate::serde_util::default_on_null! {
1046 #[serde_as]
1048 #[skip_serializing_none]
1049 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1050 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1051 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME)))]
1052 #[serde(rename_all = "camelCase")]
1053 #[non_exhaustive]
1054 pub struct LoadSessionResponse {
1055 #[serde_as(deserialize_as = "DefaultOnError")]
1059 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1060 #[serde(default)]
1061 pub modes: Option<SessionModeState>,
1062 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1064 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1065 #[serde(default)]
1066 pub config_options: Option<Vec<SessionConfigOption>>,
1067 #[serde_as(deserialize_as = "DefaultOnError")]
1073 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1074 #[serde(default)]
1075 #[serde(rename = "_meta")]
1076 pub meta: Option<Meta>,
1077 }
1078}
1079
1080impl LoadSessionResponse {
1081 #[must_use]
1083 pub fn new() -> Self {
1084 Self::default()
1085 }
1086
1087 #[must_use]
1091 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1092 self.modes = modes.into_option();
1093 self
1094 }
1095
1096 #[must_use]
1098 pub fn config_options(
1099 mut self,
1100 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1101 ) -> Self {
1102 self.config_options = config_options.into_option();
1103 self
1104 }
1105
1106 #[must_use]
1112 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1113 self.meta = meta.into_option();
1114 self
1115 }
1116}
1117
1118#[cfg(feature = "unstable_session_fork")]
1131#[serde_as]
1132#[skip_serializing_none]
1133#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1134#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1135#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME)))]
1136#[serde(rename_all = "camelCase")]
1137#[non_exhaustive]
1138pub struct ForkSessionRequest {
1139 pub session_id: SessionId,
1141 pub cwd: PathBuf,
1143 #[serde_as(deserialize_as = "DefaultOnNull")]
1149 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1150 pub additional_directories: Vec<PathBuf>,
1151 #[serde_as(deserialize_as = "DefaultOnNull")]
1153 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1154 pub mcp_servers: Vec<McpServer>,
1155 #[serde_as(deserialize_as = "DefaultOnError")]
1161 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1162 #[serde(default)]
1163 #[serde(rename = "_meta")]
1164 pub meta: Option<Meta>,
1165}
1166
1167#[cfg(feature = "unstable_session_fork")]
1168impl ForkSessionRequest {
1169 #[must_use]
1171 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1172 Self {
1173 session_id: session_id.into(),
1174 cwd: cwd.into(),
1175 additional_directories: vec![],
1176 mcp_servers: vec![],
1177 meta: None,
1178 }
1179 }
1180
1181 #[must_use]
1183 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1184 self.additional_directories = additional_directories;
1185 self
1186 }
1187
1188 #[must_use]
1190 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1191 self.mcp_servers = mcp_servers;
1192 self
1193 }
1194
1195 #[must_use]
1201 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1202 self.meta = meta.into_option();
1203 self
1204 }
1205}
1206
1207#[cfg(feature = "unstable_session_fork")]
1213#[serde_as]
1214#[skip_serializing_none]
1215#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1216#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1217#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME)))]
1218#[serde(rename_all = "camelCase")]
1219#[non_exhaustive]
1220pub struct ForkSessionResponse {
1221 pub session_id: SessionId,
1223 #[serde_as(deserialize_as = "DefaultOnError")]
1227 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1228 #[serde(default)]
1229 pub modes: Option<SessionModeState>,
1230 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1232 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1233 #[serde(default)]
1234 pub config_options: Option<Vec<SessionConfigOption>>,
1235 #[serde_as(deserialize_as = "DefaultOnError")]
1241 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1242 #[serde(default)]
1243 #[serde(rename = "_meta")]
1244 pub meta: Option<Meta>,
1245}
1246
1247#[cfg(feature = "unstable_session_fork")]
1248impl ForkSessionResponse {
1249 #[must_use]
1251 pub fn new(session_id: impl Into<SessionId>) -> Self {
1252 Self {
1253 session_id: session_id.into(),
1254 modes: None,
1255 config_options: None,
1256 meta: None,
1257 }
1258 }
1259
1260 #[must_use]
1264 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1265 self.modes = modes.into_option();
1266 self
1267 }
1268
1269 #[must_use]
1271 pub fn config_options(
1272 mut self,
1273 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1274 ) -> Self {
1275 self.config_options = config_options.into_option();
1276 self
1277 }
1278
1279 #[must_use]
1285 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1286 self.meta = meta.into_option();
1287 self
1288 }
1289}
1290
1291#[serde_as]
1300#[skip_serializing_none]
1301#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1302#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1303#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME)))]
1304#[serde(rename_all = "camelCase")]
1305#[non_exhaustive]
1306pub struct ResumeSessionRequest {
1307 pub session_id: SessionId,
1309 pub cwd: PathBuf,
1311 #[serde_as(deserialize_as = "DefaultOnNull")]
1318 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1319 pub additional_directories: Vec<PathBuf>,
1320 #[serde_as(deserialize_as = "DefaultOnNull")]
1322 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1323 pub mcp_servers: Vec<McpServer>,
1324 #[serde_as(deserialize_as = "DefaultOnError")]
1330 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1331 #[serde(default)]
1332 #[serde(rename = "_meta")]
1333 pub meta: Option<Meta>,
1334}
1335
1336impl ResumeSessionRequest {
1337 #[must_use]
1339 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1340 Self {
1341 session_id: session_id.into(),
1342 cwd: cwd.into(),
1343 additional_directories: vec![],
1344 mcp_servers: vec![],
1345 meta: None,
1346 }
1347 }
1348
1349 #[must_use]
1351 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1352 self.additional_directories = additional_directories;
1353 self
1354 }
1355
1356 #[must_use]
1358 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1359 self.mcp_servers = mcp_servers;
1360 self
1361 }
1362
1363 #[must_use]
1369 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1370 self.meta = meta.into_option();
1371 self
1372 }
1373}
1374
1375crate::serde_util::default_on_null! {
1376 #[serde_as]
1378 #[skip_serializing_none]
1379 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1380 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1381 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME)))]
1382 #[serde(rename_all = "camelCase")]
1383 #[non_exhaustive]
1384 pub struct ResumeSessionResponse {
1385 #[serde_as(deserialize_as = "DefaultOnError")]
1389 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1390 #[serde(default)]
1391 pub modes: Option<SessionModeState>,
1392 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1394 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1395 #[serde(default)]
1396 pub config_options: Option<Vec<SessionConfigOption>>,
1397 #[serde_as(deserialize_as = "DefaultOnError")]
1403 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1404 #[serde(default)]
1405 #[serde(rename = "_meta")]
1406 pub meta: Option<Meta>,
1407 }
1408}
1409
1410impl ResumeSessionResponse {
1411 #[must_use]
1413 pub fn new() -> Self {
1414 Self::default()
1415 }
1416
1417 #[must_use]
1421 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1422 self.modes = modes.into_option();
1423 self
1424 }
1425
1426 #[must_use]
1428 pub fn config_options(
1429 mut self,
1430 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1431 ) -> Self {
1432 self.config_options = config_options.into_option();
1433 self
1434 }
1435
1436 #[must_use]
1442 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1443 self.meta = meta.into_option();
1444 self
1445 }
1446}
1447
1448#[serde_as]
1458#[skip_serializing_none]
1459#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1460#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1461#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME)))]
1462#[serde(rename_all = "camelCase")]
1463#[non_exhaustive]
1464pub struct CloseSessionRequest {
1465 pub session_id: SessionId,
1467 #[serde_as(deserialize_as = "DefaultOnError")]
1473 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1474 #[serde(default)]
1475 #[serde(rename = "_meta")]
1476 pub meta: Option<Meta>,
1477}
1478
1479impl CloseSessionRequest {
1480 #[must_use]
1482 pub fn new(session_id: impl Into<SessionId>) -> Self {
1483 Self {
1484 session_id: session_id.into(),
1485 meta: None,
1486 }
1487 }
1488
1489 #[must_use]
1495 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1496 self.meta = meta.into_option();
1497 self
1498 }
1499}
1500
1501crate::serde_util::default_on_null! {
1502 #[serde_as]
1504 #[skip_serializing_none]
1505 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1506 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1507 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME)))]
1508 #[serde(rename_all = "camelCase")]
1509 #[non_exhaustive]
1510 pub struct CloseSessionResponse {
1511 #[serde_as(deserialize_as = "DefaultOnError")]
1517 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1518 #[serde(default)]
1519 #[serde(rename = "_meta")]
1520 pub meta: Option<Meta>,
1521 }
1522}
1523
1524impl CloseSessionResponse {
1525 #[must_use]
1527 pub fn new() -> Self {
1528 Self::default()
1529 }
1530
1531 #[must_use]
1537 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1538 self.meta = meta.into_option();
1539 self
1540 }
1541}
1542
1543crate::serde_util::default_on_null! {
1546 #[serde_as]
1550 #[skip_serializing_none]
1551 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1552 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1553 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME)))]
1554 #[serde(rename_all = "camelCase")]
1555 #[non_exhaustive]
1556 pub struct ListSessionsRequest {
1557 #[serde(default)]
1559 pub cwd: Option<PathBuf>,
1560 #[serde(default)]
1562 pub cursor: Option<String>,
1563 #[serde_as(deserialize_as = "DefaultOnError")]
1569 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1570 #[serde(default)]
1571 #[serde(rename = "_meta")]
1572 pub meta: Option<Meta>,
1573 }
1574}
1575
1576impl ListSessionsRequest {
1577 #[must_use]
1579 pub fn new() -> Self {
1580 Self::default()
1581 }
1582
1583 #[must_use]
1585 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1586 self.cwd = cwd.into_option();
1587 self
1588 }
1589
1590 #[must_use]
1592 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1593 self.cursor = cursor.into_option();
1594 self
1595 }
1596
1597 #[must_use]
1603 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1604 self.meta = meta.into_option();
1605 self
1606 }
1607}
1608
1609#[serde_as]
1611#[skip_serializing_none]
1612#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1613#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1614#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME)))]
1615#[serde(rename_all = "camelCase")]
1616#[non_exhaustive]
1617pub struct ListSessionsResponse {
1618 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1620 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1621 pub sessions: Vec<SessionInfo>,
1622 #[serde_as(deserialize_as = "DefaultOnError")]
1625 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1626 #[serde(default)]
1627 pub next_cursor: Option<String>,
1628 #[serde_as(deserialize_as = "DefaultOnError")]
1634 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1635 #[serde(default)]
1636 #[serde(rename = "_meta")]
1637 pub meta: Option<Meta>,
1638}
1639
1640impl ListSessionsResponse {
1641 #[must_use]
1643 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1644 Self {
1645 sessions,
1646 next_cursor: None,
1647 meta: None,
1648 }
1649 }
1650
1651 #[must_use]
1653 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1654 self.next_cursor = next_cursor.into_option();
1655 self
1656 }
1657
1658 #[must_use]
1664 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1665 self.meta = meta.into_option();
1666 self
1667 }
1668}
1669
1670#[serde_as]
1676#[skip_serializing_none]
1677#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1678#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1679#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME)))]
1680#[serde(rename_all = "camelCase")]
1681#[non_exhaustive]
1682pub struct DeleteSessionRequest {
1683 pub session_id: SessionId,
1685 #[serde_as(deserialize_as = "DefaultOnError")]
1691 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1692 #[serde(default)]
1693 #[serde(rename = "_meta")]
1694 pub meta: Option<Meta>,
1695}
1696
1697impl DeleteSessionRequest {
1698 #[must_use]
1700 pub fn new(session_id: impl Into<SessionId>) -> Self {
1701 Self {
1702 session_id: session_id.into(),
1703 meta: None,
1704 }
1705 }
1706
1707 #[must_use]
1713 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1714 self.meta = meta.into_option();
1715 self
1716 }
1717}
1718
1719crate::serde_util::default_on_null! {
1720 #[serde_as]
1722 #[skip_serializing_none]
1723 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1724 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1725 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME)))]
1726 #[serde(rename_all = "camelCase")]
1727 #[non_exhaustive]
1728 pub struct DeleteSessionResponse {
1729 #[serde_as(deserialize_as = "DefaultOnError")]
1735 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1736 #[serde(default)]
1737 #[serde(rename = "_meta")]
1738 pub meta: Option<Meta>,
1739 }
1740}
1741
1742impl DeleteSessionResponse {
1743 #[must_use]
1745 pub fn new() -> Self {
1746 Self::default()
1747 }
1748
1749 #[must_use]
1755 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1756 self.meta = meta.into_option();
1757 self
1758 }
1759}
1760
1761#[serde_as]
1763#[skip_serializing_none]
1764#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1765#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1766#[serde(rename_all = "camelCase")]
1767#[non_exhaustive]
1768pub struct SessionInfo {
1769 pub session_id: SessionId,
1771 pub cwd: PathBuf,
1773 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1779 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1780 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1781 pub additional_directories: Vec<PathBuf>,
1782
1783 #[serde_as(deserialize_as = "DefaultOnError")]
1785 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1786 #[serde(default)]
1787 pub title: Option<String>,
1788 #[serde_as(deserialize_as = "DefaultOnError")]
1790 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1791 #[serde(default)]
1792 pub updated_at: Option<String>,
1793 #[serde_as(deserialize_as = "DefaultOnError")]
1799 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1800 #[serde(default)]
1801 #[serde(rename = "_meta")]
1802 pub meta: Option<Meta>,
1803}
1804
1805impl SessionInfo {
1806 #[must_use]
1808 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1809 Self {
1810 session_id: session_id.into(),
1811 cwd: cwd.into(),
1812 additional_directories: vec![],
1813 title: None,
1814 updated_at: None,
1815 meta: None,
1816 }
1817 }
1818
1819 #[must_use]
1821 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1822 self.additional_directories = additional_directories;
1823 self
1824 }
1825
1826 #[must_use]
1828 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1829 self.title = title.into_option();
1830 self
1831 }
1832
1833 #[must_use]
1835 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1836 self.updated_at = updated_at.into_option();
1837 self
1838 }
1839
1840 #[must_use]
1846 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1847 self.meta = meta.into_option();
1848 self
1849 }
1850}
1851
1852#[serde_as]
1856#[skip_serializing_none]
1857#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1858#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1859#[serde(rename_all = "camelCase")]
1860#[non_exhaustive]
1861pub struct SessionModeState {
1862 pub current_mode_id: SessionModeId,
1864 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1866 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1867 pub available_modes: Vec<SessionMode>,
1868 #[serde_as(deserialize_as = "DefaultOnError")]
1874 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1875 #[serde(default)]
1876 #[serde(rename = "_meta")]
1877 pub meta: Option<Meta>,
1878}
1879
1880impl SessionModeState {
1881 #[must_use]
1883 pub fn new(
1884 current_mode_id: impl Into<SessionModeId>,
1885 available_modes: Vec<SessionMode>,
1886 ) -> Self {
1887 Self {
1888 current_mode_id: current_mode_id.into(),
1889 available_modes,
1890 meta: None,
1891 }
1892 }
1893
1894 #[must_use]
1900 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1901 self.meta = meta.into_option();
1902 self
1903 }
1904}
1905
1906#[serde_as]
1910#[skip_serializing_none]
1911#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1912#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1913#[serde(rename_all = "camelCase")]
1914#[non_exhaustive]
1915pub struct SessionMode {
1916 pub id: SessionModeId,
1918 pub name: String,
1920 #[serde_as(deserialize_as = "DefaultOnError")]
1922 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1923 #[serde(default)]
1924 pub description: Option<String>,
1925 #[serde_as(deserialize_as = "DefaultOnError")]
1931 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1932 #[serde(default)]
1933 #[serde(rename = "_meta")]
1934 pub meta: Option<Meta>,
1935}
1936
1937impl SessionMode {
1938 #[must_use]
1940 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
1941 Self {
1942 id: id.into(),
1943 name: name.into(),
1944 description: None,
1945 meta: None,
1946 }
1947 }
1948
1949 #[must_use]
1951 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1952 self.description = description.into_option();
1953 self
1954 }
1955
1956 #[must_use]
1962 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1963 self.meta = meta.into_option();
1964 self
1965 }
1966}
1967
1968#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1970#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
1971#[serde(transparent)]
1972#[from(Arc<str>, String, &'static str)]
1973#[non_exhaustive]
1974pub struct SessionModeId(pub Arc<str>);
1975
1976impl SessionModeId {
1977 #[must_use]
1979 pub fn new(id: impl Into<Arc<str>>) -> Self {
1980 Self(id.into())
1981 }
1982}
1983
1984#[serde_as]
1986#[skip_serializing_none]
1987#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1988#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1989#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME)))]
1990#[serde(rename_all = "camelCase")]
1991#[non_exhaustive]
1992pub struct SetSessionModeRequest {
1993 pub session_id: SessionId,
1995 pub mode_id: SessionModeId,
1997 #[serde_as(deserialize_as = "DefaultOnError")]
2003 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2004 #[serde(default)]
2005 #[serde(rename = "_meta")]
2006 pub meta: Option<Meta>,
2007}
2008
2009impl SetSessionModeRequest {
2010 #[must_use]
2012 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
2013 Self {
2014 session_id: session_id.into(),
2015 mode_id: mode_id.into(),
2016 meta: None,
2017 }
2018 }
2019
2020 #[must_use]
2022 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2023 self.meta = meta.into_option();
2024 self
2025 }
2026}
2027
2028crate::serde_util::default_on_null! {
2029 #[serde_as]
2031 #[skip_serializing_none]
2032 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2033 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
2034 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME)))]
2035 #[serde(rename_all = "camelCase")]
2036 #[non_exhaustive]
2037 pub struct SetSessionModeResponse {
2038 #[serde_as(deserialize_as = "DefaultOnError")]
2044 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2045 #[serde(default)]
2046 #[serde(rename = "_meta")]
2047 pub meta: Option<Meta>,
2048 }
2049}
2050
2051impl SetSessionModeResponse {
2052 #[must_use]
2054 pub fn new() -> Self {
2055 Self::default()
2056 }
2057
2058 #[must_use]
2064 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2065 self.meta = meta.into_option();
2066 self
2067 }
2068}
2069
2070#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2074#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2075#[serde(transparent)]
2076#[from(Arc<str>, String, &'static str)]
2077#[non_exhaustive]
2078pub struct SessionConfigId(pub Arc<str>);
2079
2080impl SessionConfigId {
2081 #[must_use]
2083 pub fn new(id: impl Into<Arc<str>>) -> Self {
2084 Self(id.into())
2085 }
2086}
2087
2088#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2090#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2091#[serde(transparent)]
2092#[from(Arc<str>, String, &'static str)]
2093#[non_exhaustive]
2094pub struct SessionConfigValueId(pub Arc<str>);
2095
2096impl SessionConfigValueId {
2097 #[must_use]
2099 pub fn new(id: impl Into<Arc<str>>) -> Self {
2100 Self(id.into())
2101 }
2102}
2103
2104#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2106#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2107#[serde(transparent)]
2108#[from(Arc<str>, String, &'static str)]
2109#[non_exhaustive]
2110pub struct SessionConfigGroupId(pub Arc<str>);
2111
2112impl SessionConfigGroupId {
2113 #[must_use]
2115 pub fn new(id: impl Into<Arc<str>>) -> Self {
2116 Self(id.into())
2117 }
2118}
2119
2120#[serde_as]
2122#[skip_serializing_none]
2123#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2124#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2125#[serde(rename_all = "camelCase")]
2126#[non_exhaustive]
2127pub struct SessionConfigSelectOption {
2128 pub value: SessionConfigValueId,
2130 pub name: String,
2132 #[serde_as(deserialize_as = "DefaultOnError")]
2134 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2135 #[serde(default)]
2136 pub description: Option<String>,
2137 #[serde_as(deserialize_as = "DefaultOnError")]
2143 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2144 #[serde(default)]
2145 #[serde(rename = "_meta")]
2146 pub meta: Option<Meta>,
2147}
2148
2149impl SessionConfigSelectOption {
2150 #[must_use]
2152 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2153 Self {
2154 value: value.into(),
2155 name: name.into(),
2156 description: None,
2157 meta: None,
2158 }
2159 }
2160
2161 #[must_use]
2163 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2164 self.description = description.into_option();
2165 self
2166 }
2167
2168 #[must_use]
2174 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2175 self.meta = meta.into_option();
2176 self
2177 }
2178}
2179
2180#[serde_as]
2182#[skip_serializing_none]
2183#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2184#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2185#[serde(rename_all = "camelCase")]
2186#[non_exhaustive]
2187pub struct SessionConfigSelectGroup {
2188 pub group: SessionConfigGroupId,
2190 pub name: String,
2192 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2194 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2195 pub options: Vec<SessionConfigSelectOption>,
2196 #[serde_as(deserialize_as = "DefaultOnError")]
2202 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2203 #[serde(default)]
2204 #[serde(rename = "_meta")]
2205 pub meta: Option<Meta>,
2206}
2207
2208impl SessionConfigSelectGroup {
2209 #[must_use]
2211 pub fn new(
2212 group: impl Into<SessionConfigGroupId>,
2213 name: impl Into<String>,
2214 options: Vec<SessionConfigSelectOption>,
2215 ) -> Self {
2216 Self {
2217 group: group.into(),
2218 name: name.into(),
2219 options,
2220 meta: None,
2221 }
2222 }
2223
2224 #[must_use]
2230 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2231 self.meta = meta.into_option();
2232 self
2233 }
2234}
2235
2236#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2238#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2239#[serde(untagged)]
2240#[non_exhaustive]
2241pub enum SessionConfigSelectOptions {
2242 Ungrouped(Vec<SessionConfigSelectOption>),
2244 Grouped(Vec<SessionConfigSelectGroup>),
2246}
2247
2248impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2249 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2250 SessionConfigSelectOptions::Ungrouped(options)
2251 }
2252}
2253
2254impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2255 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2256 SessionConfigSelectOptions::Grouped(groups)
2257 }
2258}
2259
2260#[skip_serializing_none]
2262#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2263#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2264#[serde(rename_all = "camelCase")]
2265#[non_exhaustive]
2266pub struct SessionConfigSelect {
2267 pub current_value: SessionConfigValueId,
2269 pub options: SessionConfigSelectOptions,
2271}
2272
2273impl SessionConfigSelect {
2274 #[must_use]
2276 pub fn new(
2277 current_value: impl Into<SessionConfigValueId>,
2278 options: impl Into<SessionConfigSelectOptions>,
2279 ) -> Self {
2280 Self {
2281 current_value: current_value.into(),
2282 options: options.into(),
2283 }
2284 }
2285}
2286
2287#[skip_serializing_none]
2289#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2290#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2291#[serde(rename_all = "camelCase")]
2292#[non_exhaustive]
2293pub struct SessionConfigBoolean {
2294 pub current_value: bool,
2296}
2297
2298impl SessionConfigBoolean {
2299 #[must_use]
2301 pub fn new(current_value: bool) -> Self {
2302 Self { current_value }
2303 }
2304}
2305
2306#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2316#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2317#[serde(rename_all = "snake_case")]
2318#[non_exhaustive]
2319pub enum SessionConfigOptionCategory {
2320 Mode,
2322 Model,
2324 ModelConfig,
2326 ThoughtLevel,
2328 #[serde(untagged)]
2330 Other(String),
2331}
2332
2333#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2335#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2336#[serde(tag = "type", rename_all = "snake_case")]
2337#[cfg_attr(feature = "schemars", schemars(extend("discriminator" = {"propertyName": "type"})))]
2338#[non_exhaustive]
2339pub enum SessionConfigKind {
2340 Select(SessionConfigSelect),
2342 Boolean(SessionConfigBoolean),
2344}
2345
2346#[serde_as]
2348#[skip_serializing_none]
2349#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2350#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2351#[serde(rename_all = "camelCase")]
2352#[non_exhaustive]
2353pub struct SessionConfigOption {
2354 pub id: SessionConfigId,
2356 pub name: String,
2358 #[serde_as(deserialize_as = "DefaultOnError")]
2360 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2361 #[serde(default)]
2362 pub description: Option<String>,
2363 #[serde_as(deserialize_as = "DefaultOnError")]
2365 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2366 #[serde(default)]
2367 pub category: Option<SessionConfigOptionCategory>,
2368 #[serde(flatten)]
2370 pub kind: SessionConfigKind,
2371 #[serde_as(deserialize_as = "DefaultOnError")]
2377 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2378 #[serde(default)]
2379 #[serde(rename = "_meta")]
2380 pub meta: Option<Meta>,
2381}
2382
2383impl SessionConfigOption {
2384 #[must_use]
2386 pub fn new(
2387 id: impl Into<SessionConfigId>,
2388 name: impl Into<String>,
2389 kind: SessionConfigKind,
2390 ) -> Self {
2391 Self {
2392 id: id.into(),
2393 name: name.into(),
2394 description: None,
2395 category: None,
2396 kind,
2397 meta: None,
2398 }
2399 }
2400
2401 #[must_use]
2403 pub fn select(
2404 id: impl Into<SessionConfigId>,
2405 name: impl Into<String>,
2406 current_value: impl Into<SessionConfigValueId>,
2407 options: impl Into<SessionConfigSelectOptions>,
2408 ) -> Self {
2409 Self::new(
2410 id,
2411 name,
2412 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2413 )
2414 }
2415
2416 #[must_use]
2418 pub fn boolean(
2419 id: impl Into<SessionConfigId>,
2420 name: impl Into<String>,
2421 current_value: bool,
2422 ) -> Self {
2423 Self::new(
2424 id,
2425 name,
2426 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2427 )
2428 }
2429
2430 #[must_use]
2432 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2433 self.description = description.into_option();
2434 self
2435 }
2436
2437 #[must_use]
2439 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2440 self.category = category.into_option();
2441 self
2442 }
2443
2444 #[must_use]
2450 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2451 self.meta = meta.into_option();
2452 self
2453 }
2454}
2455
2456#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2467#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2468#[serde(tag = "type", rename_all = "snake_case")]
2469#[non_exhaustive]
2470pub enum SessionConfigOptionValue {
2471 Boolean {
2473 value: bool,
2475 },
2476 #[serde(untagged)]
2482 ValueId {
2483 value: SessionConfigValueId,
2485 },
2486}
2487
2488impl SessionConfigOptionValue {
2489 #[must_use]
2491 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2492 Self::ValueId { value: id.into() }
2493 }
2494
2495 #[must_use]
2497 pub fn boolean(val: bool) -> Self {
2498 Self::Boolean { value: val }
2499 }
2500
2501 #[must_use]
2504 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2505 match self {
2506 Self::ValueId { value } => Some(value),
2507 _ => None,
2508 }
2509 }
2510
2511 #[must_use]
2513 pub fn as_bool(&self) -> Option<bool> {
2514 match self {
2515 Self::Boolean { value } => Some(*value),
2516 _ => None,
2517 }
2518 }
2519}
2520
2521impl From<SessionConfigValueId> for SessionConfigOptionValue {
2522 fn from(value: SessionConfigValueId) -> Self {
2523 Self::ValueId { value }
2524 }
2525}
2526
2527impl From<bool> for SessionConfigOptionValue {
2528 fn from(value: bool) -> Self {
2529 Self::Boolean { value }
2530 }
2531}
2532
2533impl From<&str> for SessionConfigOptionValue {
2534 fn from(value: &str) -> Self {
2535 Self::ValueId {
2536 value: SessionConfigValueId::new(value),
2537 }
2538 }
2539}
2540
2541#[serde_as]
2543#[skip_serializing_none]
2544#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2545#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2546#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME)))]
2547#[serde(rename_all = "camelCase")]
2548#[non_exhaustive]
2549pub struct SetSessionConfigOptionRequest {
2550 pub session_id: SessionId,
2552 pub config_id: SessionConfigId,
2554 #[serde(flatten)]
2559 pub value: SessionConfigOptionValue,
2560 #[serde_as(deserialize_as = "DefaultOnError")]
2566 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2567 #[serde(default)]
2568 #[serde(rename = "_meta")]
2569 pub meta: Option<Meta>,
2570}
2571
2572impl SetSessionConfigOptionRequest {
2573 #[must_use]
2575 pub fn new(
2576 session_id: impl Into<SessionId>,
2577 config_id: impl Into<SessionConfigId>,
2578 value: impl Into<SessionConfigOptionValue>,
2579 ) -> Self {
2580 Self {
2581 session_id: session_id.into(),
2582 config_id: config_id.into(),
2583 value: value.into(),
2584 meta: None,
2585 }
2586 }
2587
2588 #[must_use]
2594 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2595 self.meta = meta.into_option();
2596 self
2597 }
2598}
2599
2600#[serde_as]
2602#[skip_serializing_none]
2603#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2604#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2605#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME)))]
2606#[serde(rename_all = "camelCase")]
2607#[non_exhaustive]
2608pub struct SetSessionConfigOptionResponse {
2609 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2611 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2612 pub config_options: Vec<SessionConfigOption>,
2613 #[serde_as(deserialize_as = "DefaultOnError")]
2619 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2620 #[serde(default)]
2621 #[serde(rename = "_meta")]
2622 pub meta: Option<Meta>,
2623}
2624
2625impl SetSessionConfigOptionResponse {
2626 #[must_use]
2628 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2629 Self {
2630 config_options,
2631 meta: None,
2632 }
2633 }
2634
2635 #[must_use]
2641 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2642 self.meta = meta.into_option();
2643 self
2644 }
2645}
2646
2647#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2656#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2657#[serde(tag = "type", rename_all = "snake_case")]
2658#[non_exhaustive]
2659pub enum McpServer {
2660 Http(McpServerHttp),
2664 Sse(McpServerSse),
2668 #[cfg(feature = "unstable_mcp_over_acp")]
2677 Acp(McpServerAcp),
2678 #[serde(untagged)]
2682 Stdio(McpServerStdio),
2683}
2684
2685#[serde_as]
2687#[skip_serializing_none]
2688#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2689#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2690#[serde(rename_all = "camelCase")]
2691#[non_exhaustive]
2692pub struct McpServerHttp {
2693 pub name: String,
2695 pub url: String,
2697 #[serde_as(deserialize_as = "DefaultOnNull")]
2699 pub headers: Vec<HttpHeader>,
2700 #[serde_as(deserialize_as = "DefaultOnError")]
2706 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2707 #[serde(default)]
2708 #[serde(rename = "_meta")]
2709 pub meta: Option<Meta>,
2710}
2711
2712impl McpServerHttp {
2713 #[must_use]
2715 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2716 Self {
2717 name: name.into(),
2718 url: url.into(),
2719 headers: Vec::new(),
2720 meta: None,
2721 }
2722 }
2723
2724 #[must_use]
2726 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2727 self.headers = headers;
2728 self
2729 }
2730
2731 #[must_use]
2737 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2738 self.meta = meta.into_option();
2739 self
2740 }
2741}
2742
2743#[serde_as]
2745#[skip_serializing_none]
2746#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2747#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2748#[serde(rename_all = "camelCase")]
2749#[non_exhaustive]
2750pub struct McpServerSse {
2751 pub name: String,
2753 pub url: String,
2755 #[serde_as(deserialize_as = "DefaultOnNull")]
2757 pub headers: Vec<HttpHeader>,
2758 #[serde_as(deserialize_as = "DefaultOnError")]
2764 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2765 #[serde(default)]
2766 #[serde(rename = "_meta")]
2767 pub meta: Option<Meta>,
2768}
2769
2770impl McpServerSse {
2771 #[must_use]
2773 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2774 Self {
2775 name: name.into(),
2776 url: url.into(),
2777 headers: Vec::new(),
2778 meta: None,
2779 }
2780 }
2781
2782 #[must_use]
2784 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2785 self.headers = headers;
2786 self
2787 }
2788
2789 #[must_use]
2795 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2796 self.meta = meta.into_option();
2797 self
2798 }
2799}
2800
2801#[cfg(feature = "unstable_mcp_over_acp")]
2810#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2811#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
2812#[serde(transparent)]
2813#[from(Arc<str>, String, &'static str)]
2814#[non_exhaustive]
2815pub struct McpServerAcpId(pub Arc<str>);
2816
2817#[cfg(feature = "unstable_mcp_over_acp")]
2818impl McpServerAcpId {
2819 #[must_use]
2821 pub fn new(id: impl Into<Arc<str>>) -> Self {
2822 Self(id.into())
2823 }
2824}
2825
2826#[serde_as]
2835#[skip_serializing_none]
2836#[cfg(feature = "unstable_mcp_over_acp")]
2837#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2838#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2839#[serde(rename_all = "camelCase")]
2840#[non_exhaustive]
2841pub struct McpServerAcp {
2842 pub name: String,
2844 pub server_id: McpServerAcpId,
2849 #[serde_as(deserialize_as = "DefaultOnError")]
2855 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2856 #[serde(default)]
2857 #[serde(rename = "_meta")]
2858 pub meta: Option<Meta>,
2859}
2860
2861#[cfg(feature = "unstable_mcp_over_acp")]
2862impl McpServerAcp {
2863 #[must_use]
2865 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2866 Self {
2867 name: name.into(),
2868 server_id: id.into(),
2869 meta: None,
2870 }
2871 }
2872
2873 #[must_use]
2879 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2880 self.meta = meta.into_option();
2881 self
2882 }
2883}
2884
2885#[serde_as]
2887#[skip_serializing_none]
2888#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2889#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2890#[serde(rename_all = "camelCase")]
2891#[non_exhaustive]
2892pub struct McpServerStdio {
2893 pub name: String,
2895 pub command: PathBuf,
2897 #[serde_as(deserialize_as = "DefaultOnNull")]
2899 pub args: Vec<String>,
2900 #[serde_as(deserialize_as = "DefaultOnNull")]
2902 pub env: Vec<EnvVariable>,
2903 #[serde_as(deserialize_as = "DefaultOnError")]
2909 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2910 #[serde(default)]
2911 #[serde(rename = "_meta")]
2912 pub meta: Option<Meta>,
2913}
2914
2915impl McpServerStdio {
2916 #[must_use]
2918 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2919 Self {
2920 name: name.into(),
2921 command: command.into(),
2922 args: Vec::new(),
2923 env: Vec::new(),
2924 meta: None,
2925 }
2926 }
2927
2928 #[must_use]
2930 pub fn args(mut self, args: Vec<String>) -> Self {
2931 self.args = args;
2932 self
2933 }
2934
2935 #[must_use]
2937 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2938 self.env = env;
2939 self
2940 }
2941
2942 #[must_use]
2948 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2949 self.meta = meta.into_option();
2950 self
2951 }
2952}
2953
2954#[serde_as]
2956#[skip_serializing_none]
2957#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2958#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2959#[serde(rename_all = "camelCase")]
2960#[non_exhaustive]
2961pub struct EnvVariable {
2962 pub name: String,
2964 pub value: String,
2966 #[serde_as(deserialize_as = "DefaultOnError")]
2972 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2973 #[serde(default)]
2974 #[serde(rename = "_meta")]
2975 pub meta: Option<Meta>,
2976}
2977
2978impl EnvVariable {
2979 #[must_use]
2981 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2982 Self {
2983 name: name.into(),
2984 value: value.into(),
2985 meta: None,
2986 }
2987 }
2988
2989 #[must_use]
2995 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2996 self.meta = meta.into_option();
2997 self
2998 }
2999}
3000
3001#[serde_as]
3003#[skip_serializing_none]
3004#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3005#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3006#[serde(rename_all = "camelCase")]
3007#[non_exhaustive]
3008pub struct HttpHeader {
3009 pub name: String,
3011 pub value: String,
3013 #[serde_as(deserialize_as = "DefaultOnError")]
3019 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3020 #[serde(default)]
3021 #[serde(rename = "_meta")]
3022 pub meta: Option<Meta>,
3023}
3024
3025impl HttpHeader {
3026 #[must_use]
3028 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3029 Self {
3030 name: name.into(),
3031 value: value.into(),
3032 meta: None,
3033 }
3034 }
3035
3036 #[must_use]
3042 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3043 self.meta = meta.into_option();
3044 self
3045 }
3046}
3047
3048#[serde_as]
3056#[skip_serializing_none]
3057#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3058#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
3059#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME)))]
3060#[serde(rename_all = "camelCase")]
3061#[non_exhaustive]
3062pub struct PromptRequest {
3063 pub session_id: SessionId,
3065 pub prompt: Vec<ContentBlock>,
3079 #[serde_as(deserialize_as = "DefaultOnError")]
3085 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3086 #[serde(default)]
3087 #[serde(rename = "_meta")]
3088 pub meta: Option<Meta>,
3089}
3090
3091impl PromptRequest {
3092 #[must_use]
3094 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3095 Self {
3096 session_id: session_id.into(),
3097 prompt,
3098 meta: None,
3099 }
3100 }
3101
3102 #[must_use]
3108 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3109 self.meta = meta.into_option();
3110 self
3111 }
3112}
3113
3114#[serde_as]
3118#[skip_serializing_none]
3119#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3120#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3121#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME)))]
3122#[serde(rename_all = "camelCase")]
3123#[non_exhaustive]
3124pub struct PromptResponse {
3125 pub stop_reason: StopReason,
3127 #[cfg(feature = "unstable_end_turn_token_usage")]
3133 #[serde_as(deserialize_as = "DefaultOnError")]
3134 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3135 #[serde(default)]
3136 pub usage: Option<Usage>,
3137 #[serde_as(deserialize_as = "DefaultOnError")]
3143 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3144 #[serde(default)]
3145 #[serde(rename = "_meta")]
3146 pub meta: Option<Meta>,
3147}
3148
3149impl PromptResponse {
3150 #[must_use]
3152 pub fn new(stop_reason: StopReason) -> Self {
3153 Self {
3154 stop_reason,
3155 #[cfg(feature = "unstable_end_turn_token_usage")]
3156 usage: None,
3157 meta: None,
3158 }
3159 }
3160
3161 #[cfg(feature = "unstable_end_turn_token_usage")]
3167 #[must_use]
3168 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3169 self.usage = usage.into_option();
3170 self
3171 }
3172
3173 #[must_use]
3179 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3180 self.meta = meta.into_option();
3181 self
3182 }
3183}
3184
3185#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3189#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
3190#[serde(rename_all = "snake_case")]
3191#[non_exhaustive]
3192pub enum StopReason {
3193 EndTurn,
3195 MaxTokens,
3197 MaxTurnRequests,
3200 Refusal,
3204 Cancelled,
3211}
3212
3213#[cfg(feature = "unstable_end_turn_token_usage")]
3219#[serde_as]
3220#[skip_serializing_none]
3221#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3222#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3223#[serde(rename_all = "camelCase")]
3224#[non_exhaustive]
3225pub struct Usage {
3226 pub total_tokens: u64,
3228 pub input_tokens: u64,
3230 pub output_tokens: u64,
3232 #[serde_as(deserialize_as = "DefaultOnError")]
3234 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3235 #[serde(default)]
3236 pub thought_tokens: Option<u64>,
3237 #[serde_as(deserialize_as = "DefaultOnError")]
3239 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3240 #[serde(default)]
3241 pub cached_read_tokens: Option<u64>,
3242 #[serde_as(deserialize_as = "DefaultOnError")]
3244 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3245 #[serde(default)]
3246 pub cached_write_tokens: Option<u64>,
3247 #[serde_as(deserialize_as = "DefaultOnError")]
3253 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3254 #[serde(default)]
3255 #[serde(rename = "_meta")]
3256 pub meta: Option<Meta>,
3257}
3258
3259#[cfg(feature = "unstable_end_turn_token_usage")]
3260impl Usage {
3261 #[must_use]
3263 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3264 Self {
3265 total_tokens,
3266 input_tokens,
3267 output_tokens,
3268 thought_tokens: None,
3269 cached_read_tokens: None,
3270 cached_write_tokens: None,
3271 meta: None,
3272 }
3273 }
3274
3275 #[must_use]
3277 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3278 self.thought_tokens = thought_tokens.into_option();
3279 self
3280 }
3281
3282 #[must_use]
3284 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3285 self.cached_read_tokens = cached_read_tokens.into_option();
3286 self
3287 }
3288
3289 #[must_use]
3291 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3292 self.cached_write_tokens = cached_write_tokens.into_option();
3293 self
3294 }
3295
3296 #[must_use]
3302 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3303 self.meta = meta.into_option();
3304 self
3305 }
3306}
3307
3308#[cfg(feature = "unstable_llm_providers")]
3321#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3322#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3323#[serde(rename_all = "snake_case")]
3324#[non_exhaustive]
3325#[expect(clippy::doc_markdown)]
3326pub enum LlmProtocol {
3327 Anthropic,
3329 #[serde(rename = "openai")]
3331 OpenAi,
3332 Azure,
3334 Vertex,
3336 Bedrock,
3338 #[serde(untagged)]
3340 Other(String),
3341}
3342
3343#[cfg(feature = "unstable_llm_providers")]
3349#[serde_as]
3350#[skip_serializing_none]
3351#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3352#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3353#[serde(rename_all = "camelCase")]
3354#[non_exhaustive]
3355pub struct ProviderCurrentConfig {
3356 pub api_type: LlmProtocol,
3358 pub base_url: String,
3360 #[serde_as(deserialize_as = "DefaultOnError")]
3366 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3367 #[serde(default)]
3368 #[serde(rename = "_meta")]
3369 pub meta: Option<Meta>,
3370}
3371
3372#[cfg(feature = "unstable_llm_providers")]
3373impl ProviderCurrentConfig {
3374 #[must_use]
3376 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3377 Self {
3378 api_type,
3379 base_url: base_url.into(),
3380 meta: None,
3381 }
3382 }
3383
3384 #[must_use]
3390 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3391 self.meta = meta.into_option();
3392 self
3393 }
3394}
3395
3396#[cfg(feature = "unstable_llm_providers")]
3402#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3403#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
3404#[serde(transparent)]
3405#[from(Arc<str>, String, &'static str)]
3406#[non_exhaustive]
3407pub struct ProviderId(pub Arc<str>);
3408
3409#[cfg(feature = "unstable_llm_providers")]
3410impl ProviderId {
3411 #[must_use]
3413 pub fn new(id: impl Into<Arc<str>>) -> Self {
3414 Self(id.into())
3415 }
3416}
3417
3418#[cfg(feature = "unstable_llm_providers")]
3424#[serde_as]
3425#[skip_serializing_none]
3426#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3427#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3428#[serde(rename_all = "camelCase")]
3429#[non_exhaustive]
3430pub struct ProviderInfo {
3431 pub provider_id: ProviderId,
3433 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
3435 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
3436 pub supported: Vec<LlmProtocol>,
3437 pub required: bool,
3440 #[serde(default)]
3443 pub current: Option<ProviderCurrentConfig>,
3444 #[serde_as(deserialize_as = "DefaultOnError")]
3450 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3451 #[serde(default)]
3452 #[serde(rename = "_meta")]
3453 pub meta: Option<Meta>,
3454}
3455
3456#[cfg(feature = "unstable_llm_providers")]
3457impl ProviderInfo {
3458 #[must_use]
3460 pub fn new(
3461 provider_id: impl Into<ProviderId>,
3462 supported: Vec<LlmProtocol>,
3463 required: bool,
3464 current: impl IntoOption<ProviderCurrentConfig>,
3465 ) -> Self {
3466 Self {
3467 provider_id: provider_id.into(),
3468 supported,
3469 required,
3470 current: current.into_option(),
3471 meta: None,
3472 }
3473 }
3474
3475 #[must_use]
3481 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3482 self.meta = meta.into_option();
3483 self
3484 }
3485}
3486
3487#[cfg(feature = "unstable_llm_providers")]
3488crate::serde_util::default_on_null! {
3489 #[serde_as]
3495 #[skip_serializing_none]
3496 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3497 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3498 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))]
3499 #[serde(rename_all = "camelCase")]
3500 #[non_exhaustive]
3501 pub struct ListProvidersRequest {
3502 #[serde_as(deserialize_as = "DefaultOnError")]
3508 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3509 #[serde(default)]
3510 #[serde(rename = "_meta")]
3511 pub meta: Option<Meta>,
3512 }
3513}
3514
3515#[cfg(feature = "unstable_llm_providers")]
3516impl ListProvidersRequest {
3517 #[must_use]
3519 pub fn new() -> Self {
3520 Self::default()
3521 }
3522
3523 #[must_use]
3529 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3530 self.meta = meta.into_option();
3531 self
3532 }
3533}
3534
3535#[cfg(feature = "unstable_llm_providers")]
3541#[serde_as]
3542#[skip_serializing_none]
3543#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3544#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3545#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))]
3546#[serde(rename_all = "camelCase")]
3547#[non_exhaustive]
3548pub struct ListProvidersResponse {
3549 pub providers: Vec<ProviderInfo>,
3551 #[serde_as(deserialize_as = "DefaultOnError")]
3557 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3558 #[serde(default)]
3559 #[serde(rename = "_meta")]
3560 pub meta: Option<Meta>,
3561}
3562
3563#[cfg(feature = "unstable_llm_providers")]
3564impl ListProvidersResponse {
3565 #[must_use]
3567 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3568 Self {
3569 providers,
3570 meta: None,
3571 }
3572 }
3573
3574 #[must_use]
3580 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3581 self.meta = meta.into_option();
3582 self
3583 }
3584}
3585
3586#[cfg(feature = "unstable_llm_providers")]
3594#[serde_as]
3595#[skip_serializing_none]
3596#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3597#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
3598#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))]
3599#[serde(rename_all = "camelCase")]
3600#[non_exhaustive]
3601pub struct SetProviderRequest {
3602 pub provider_id: ProviderId,
3604 pub api_type: LlmProtocol,
3606 pub base_url: String,
3608 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3611 pub headers: HashMap<String, String>,
3612 #[serde_as(deserialize_as = "DefaultOnError")]
3618 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3619 #[serde(default)]
3620 #[serde(rename = "_meta")]
3621 pub meta: Option<Meta>,
3622}
3623
3624#[cfg(feature = "unstable_llm_providers")]
3625impl SetProviderRequest {
3626 #[must_use]
3628 pub fn new(
3629 provider_id: impl Into<ProviderId>,
3630 api_type: LlmProtocol,
3631 base_url: impl Into<String>,
3632 ) -> Self {
3633 Self {
3634 provider_id: provider_id.into(),
3635 api_type,
3636 base_url: base_url.into(),
3637 headers: HashMap::new(),
3638 meta: None,
3639 }
3640 }
3641
3642 #[must_use]
3645 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3646 self.headers = headers;
3647 self
3648 }
3649
3650 #[must_use]
3656 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3657 self.meta = meta.into_option();
3658 self
3659 }
3660}
3661
3662#[cfg(feature = "unstable_llm_providers")]
3663crate::serde_util::default_on_null! {
3664 #[serde_as]
3670 #[skip_serializing_none]
3671 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3672 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3673 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))]
3674 #[serde(rename_all = "camelCase")]
3675 #[non_exhaustive]
3676 pub struct SetProviderResponse {
3677 #[serde_as(deserialize_as = "DefaultOnError")]
3683 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3684 #[serde(default)]
3685 #[serde(rename = "_meta")]
3686 pub meta: Option<Meta>,
3687 }
3688}
3689
3690#[cfg(feature = "unstable_llm_providers")]
3691impl SetProviderResponse {
3692 #[must_use]
3694 pub fn new() -> Self {
3695 Self::default()
3696 }
3697
3698 #[must_use]
3704 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3705 self.meta = meta.into_option();
3706 self
3707 }
3708}
3709
3710#[cfg(feature = "unstable_llm_providers")]
3716#[serde_as]
3717#[skip_serializing_none]
3718#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3719#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3720#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))]
3721#[serde(rename_all = "camelCase")]
3722#[non_exhaustive]
3723pub struct DisableProviderRequest {
3724 pub provider_id: ProviderId,
3726 #[serde_as(deserialize_as = "DefaultOnError")]
3732 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3733 #[serde(default)]
3734 #[serde(rename = "_meta")]
3735 pub meta: Option<Meta>,
3736}
3737
3738#[cfg(feature = "unstable_llm_providers")]
3739impl DisableProviderRequest {
3740 #[must_use]
3742 pub fn new(provider_id: impl Into<ProviderId>) -> Self {
3743 Self {
3744 provider_id: provider_id.into(),
3745 meta: None,
3746 }
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#[cfg(feature = "unstable_llm_providers")]
3762crate::serde_util::default_on_null! {
3763 #[serde_as]
3769 #[skip_serializing_none]
3770 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3771 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3772 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))]
3773 #[serde(rename_all = "camelCase")]
3774 #[non_exhaustive]
3775 pub struct DisableProviderResponse {
3776 #[serde_as(deserialize_as = "DefaultOnError")]
3782 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3783 #[serde(default)]
3784 #[serde(rename = "_meta")]
3785 pub meta: Option<Meta>,
3786 }
3787}
3788
3789#[cfg(feature = "unstable_llm_providers")]
3790impl DisableProviderResponse {
3791 #[must_use]
3793 pub fn new() -> Self {
3794 Self::default()
3795 }
3796
3797 #[must_use]
3803 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3804 self.meta = meta.into_option();
3805 self
3806 }
3807}
3808
3809#[serde_as]
3818#[skip_serializing_none]
3819#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3820#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3821#[serde(rename_all = "camelCase")]
3822#[non_exhaustive]
3823pub struct AgentCapabilities {
3824 #[serde_as(deserialize_as = "DefaultOnError")]
3826 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3827 #[serde(default)]
3828 pub load_session: bool,
3829 #[serde_as(deserialize_as = "DefaultOnError")]
3831 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3832 #[serde(default)]
3833 pub prompt_capabilities: PromptCapabilities,
3834 #[serde_as(deserialize_as = "DefaultOnError")]
3836 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3837 #[serde(default)]
3838 pub mcp_capabilities: McpCapabilities,
3839 #[serde_as(deserialize_as = "DefaultOnError")]
3841 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3842 #[serde(default)]
3843 pub session_capabilities: SessionCapabilities,
3844 #[serde_as(deserialize_as = "DefaultOnError")]
3846 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3847 #[serde(default)]
3848 pub auth: AgentAuthCapabilities,
3849 #[cfg(feature = "unstable_llm_providers")]
3858 #[serde_as(deserialize_as = "DefaultOnError")]
3859 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3860 #[serde(default)]
3861 pub providers: Option<ProvidersCapabilities>,
3862 #[cfg(feature = "unstable_nes")]
3871 #[serde_as(deserialize_as = "DefaultOnError")]
3872 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3873 #[serde(default)]
3874 pub nes: Option<NesCapabilities>,
3875 #[cfg(feature = "unstable_nes")]
3881 #[serde_as(deserialize_as = "DefaultOnError")]
3882 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3883 #[serde(default)]
3884 pub position_encoding: Option<PositionEncodingKind>,
3885 #[serde_as(deserialize_as = "DefaultOnError")]
3891 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3892 #[serde(default)]
3893 #[serde(rename = "_meta")]
3894 pub meta: Option<Meta>,
3895}
3896
3897impl AgentCapabilities {
3898 #[must_use]
3900 pub fn new() -> Self {
3901 Self::default()
3902 }
3903
3904 #[must_use]
3906 pub fn load_session(mut self, load_session: bool) -> Self {
3907 self.load_session = load_session;
3908 self
3909 }
3910
3911 #[must_use]
3913 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3914 self.prompt_capabilities = prompt_capabilities;
3915 self
3916 }
3917
3918 #[must_use]
3920 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3921 self.mcp_capabilities = mcp_capabilities;
3922 self
3923 }
3924
3925 #[must_use]
3927 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3928 self.session_capabilities = session_capabilities;
3929 self
3930 }
3931
3932 #[must_use]
3934 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3935 self.auth = auth;
3936 self
3937 }
3938
3939 #[cfg(feature = "unstable_llm_providers")]
3945 #[must_use]
3946 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3947 self.providers = providers.into_option();
3948 self
3949 }
3950
3951 #[cfg(feature = "unstable_nes")]
3957 #[must_use]
3958 pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3959 self.nes = nes.into_option();
3960 self
3961 }
3962
3963 #[cfg(feature = "unstable_nes")]
3967 #[must_use]
3968 pub fn position_encoding(
3969 mut self,
3970 position_encoding: impl IntoOption<PositionEncodingKind>,
3971 ) -> Self {
3972 self.position_encoding = position_encoding.into_option();
3973 self
3974 }
3975
3976 #[must_use]
3982 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3983 self.meta = meta.into_option();
3984 self
3985 }
3986}
3987
3988#[cfg(feature = "unstable_llm_providers")]
3996#[serde_as]
3997#[skip_serializing_none]
3998#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3999#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4000#[non_exhaustive]
4001pub struct ProvidersCapabilities {
4002 #[serde_as(deserialize_as = "DefaultOnError")]
4008 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4009 #[serde(default)]
4010 #[serde(rename = "_meta")]
4011 pub meta: Option<Meta>,
4012}
4013
4014#[cfg(feature = "unstable_llm_providers")]
4015impl ProvidersCapabilities {
4016 #[must_use]
4018 pub fn new() -> Self {
4019 Self::default()
4020 }
4021
4022 #[must_use]
4028 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4029 self.meta = meta.into_option();
4030 self
4031 }
4032}
4033
4034#[serde_as]
4044#[skip_serializing_none]
4045#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4046#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4047#[serde(rename_all = "camelCase")]
4048#[non_exhaustive]
4049pub struct SessionCapabilities {
4050 #[serde_as(deserialize_as = "DefaultOnError")]
4055 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4056 #[serde(default)]
4057 pub list: Option<SessionListCapabilities>,
4058 #[serde_as(deserialize_as = "DefaultOnError")]
4063 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4064 #[serde(default)]
4065 pub delete: Option<SessionDeleteCapabilities>,
4066 #[serde_as(deserialize_as = "DefaultOnError")]
4076 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4077 #[serde(default)]
4078 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
4079 #[cfg(feature = "unstable_session_fork")]
4088 #[serde_as(deserialize_as = "DefaultOnError")]
4089 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4090 #[serde(default)]
4091 pub fork: Option<SessionForkCapabilities>,
4092 #[serde_as(deserialize_as = "DefaultOnError")]
4097 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4098 #[serde(default)]
4099 pub resume: Option<SessionResumeCapabilities>,
4100 #[serde_as(deserialize_as = "DefaultOnError")]
4105 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4106 #[serde(default)]
4107 pub close: Option<SessionCloseCapabilities>,
4108 #[serde_as(deserialize_as = "DefaultOnError")]
4114 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4115 #[serde(default)]
4116 #[serde(rename = "_meta")]
4117 pub meta: Option<Meta>,
4118}
4119
4120impl SessionCapabilities {
4121 #[must_use]
4123 pub fn new() -> Self {
4124 Self::default()
4125 }
4126
4127 #[must_use]
4132 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
4133 self.list = list.into_option();
4134 self
4135 }
4136
4137 #[must_use]
4142 pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
4143 self.delete = delete.into_option();
4144 self
4145 }
4146
4147 #[must_use]
4157 pub fn additional_directories(
4158 mut self,
4159 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4160 ) -> Self {
4161 self.additional_directories = additional_directories.into_option();
4162 self
4163 }
4164
4165 #[cfg(feature = "unstable_session_fork")]
4166 #[must_use]
4171 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4172 self.fork = fork.into_option();
4173 self
4174 }
4175
4176 #[must_use]
4181 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4182 self.resume = resume.into_option();
4183 self
4184 }
4185
4186 #[must_use]
4191 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4192 self.close = close.into_option();
4193 self
4194 }
4195
4196 #[must_use]
4202 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4203 self.meta = meta.into_option();
4204 self
4205 }
4206}
4207
4208#[serde_as]
4212#[skip_serializing_none]
4213#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4214#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4215#[non_exhaustive]
4216pub struct SessionListCapabilities {
4217 #[serde_as(deserialize_as = "DefaultOnError")]
4223 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4224 #[serde(default)]
4225 #[serde(rename = "_meta")]
4226 pub meta: Option<Meta>,
4227}
4228
4229impl SessionListCapabilities {
4230 #[must_use]
4232 pub fn new() -> Self {
4233 Self::default()
4234 }
4235
4236 #[must_use]
4242 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4243 self.meta = meta.into_option();
4244 self
4245 }
4246}
4247
4248#[serde_as]
4252#[skip_serializing_none]
4253#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4254#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4255#[non_exhaustive]
4256pub struct SessionDeleteCapabilities {
4257 #[serde_as(deserialize_as = "DefaultOnError")]
4263 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4264 #[serde(default)]
4265 #[serde(rename = "_meta")]
4266 pub meta: Option<Meta>,
4267}
4268
4269impl SessionDeleteCapabilities {
4270 #[must_use]
4272 pub fn new() -> Self {
4273 Self::default()
4274 }
4275
4276 #[must_use]
4282 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4283 self.meta = meta.into_option();
4284 self
4285 }
4286}
4287
4288#[serde_as]
4295#[skip_serializing_none]
4296#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4297#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4298#[non_exhaustive]
4299pub struct SessionAdditionalDirectoriesCapabilities {
4300 #[serde_as(deserialize_as = "DefaultOnError")]
4306 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4307 #[serde(default)]
4308 #[serde(rename = "_meta")]
4309 pub meta: Option<Meta>,
4310}
4311
4312impl SessionAdditionalDirectoriesCapabilities {
4313 #[must_use]
4315 pub fn new() -> Self {
4316 Self::default()
4317 }
4318
4319 #[must_use]
4325 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4326 self.meta = meta.into_option();
4327 self
4328 }
4329}
4330
4331#[cfg(feature = "unstable_session_fork")]
4339#[serde_as]
4340#[skip_serializing_none]
4341#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4342#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4343#[non_exhaustive]
4344pub struct SessionForkCapabilities {
4345 #[serde_as(deserialize_as = "DefaultOnError")]
4351 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4352 #[serde(default)]
4353 #[serde(rename = "_meta")]
4354 pub meta: Option<Meta>,
4355}
4356
4357#[cfg(feature = "unstable_session_fork")]
4358impl SessionForkCapabilities {
4359 #[must_use]
4361 pub fn new() -> Self {
4362 Self::default()
4363 }
4364
4365 #[must_use]
4371 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4372 self.meta = meta.into_option();
4373 self
4374 }
4375}
4376
4377#[serde_as]
4381#[skip_serializing_none]
4382#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4383#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4384#[non_exhaustive]
4385pub struct SessionResumeCapabilities {
4386 #[serde_as(deserialize_as = "DefaultOnError")]
4392 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4393 #[serde(default)]
4394 #[serde(rename = "_meta")]
4395 pub meta: Option<Meta>,
4396}
4397
4398impl SessionResumeCapabilities {
4399 #[must_use]
4401 pub fn new() -> Self {
4402 Self::default()
4403 }
4404
4405 #[must_use]
4411 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4412 self.meta = meta.into_option();
4413 self
4414 }
4415}
4416
4417#[serde_as]
4421#[skip_serializing_none]
4422#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4423#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4424#[non_exhaustive]
4425pub struct SessionCloseCapabilities {
4426 #[serde_as(deserialize_as = "DefaultOnError")]
4432 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4433 #[serde(default)]
4434 #[serde(rename = "_meta")]
4435 pub meta: Option<Meta>,
4436}
4437
4438impl SessionCloseCapabilities {
4439 #[must_use]
4441 pub fn new() -> Self {
4442 Self::default()
4443 }
4444
4445 #[must_use]
4451 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4452 self.meta = meta.into_option();
4453 self
4454 }
4455}
4456
4457#[serde_as]
4470#[skip_serializing_none]
4471#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4472#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4473#[serde(rename_all = "camelCase")]
4474#[non_exhaustive]
4475pub struct PromptCapabilities {
4476 #[serde_as(deserialize_as = "DefaultOnError")]
4478 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4479 #[serde(default)]
4480 pub image: bool,
4481 #[serde_as(deserialize_as = "DefaultOnError")]
4483 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4484 #[serde(default)]
4485 pub audio: bool,
4486 #[serde_as(deserialize_as = "DefaultOnError")]
4491 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4492 #[serde(default)]
4493 pub embedded_context: bool,
4494 #[serde_as(deserialize_as = "DefaultOnError")]
4500 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4501 #[serde(default)]
4502 #[serde(rename = "_meta")]
4503 pub meta: Option<Meta>,
4504}
4505
4506impl PromptCapabilities {
4507 #[must_use]
4509 pub fn new() -> Self {
4510 Self::default()
4511 }
4512
4513 #[must_use]
4515 pub fn image(mut self, image: bool) -> Self {
4516 self.image = image;
4517 self
4518 }
4519
4520 #[must_use]
4522 pub fn audio(mut self, audio: bool) -> Self {
4523 self.audio = audio;
4524 self
4525 }
4526
4527 #[must_use]
4532 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4533 self.embedded_context = embedded_context;
4534 self
4535 }
4536
4537 #[must_use]
4543 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4544 self.meta = meta.into_option();
4545 self
4546 }
4547}
4548
4549#[serde_as]
4551#[skip_serializing_none]
4552#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4553#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4554#[serde(rename_all = "camelCase")]
4555#[non_exhaustive]
4556pub struct McpCapabilities {
4557 #[serde_as(deserialize_as = "DefaultOnError")]
4559 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4560 #[serde(default)]
4561 pub http: bool,
4562 #[serde_as(deserialize_as = "DefaultOnError")]
4564 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4565 #[serde(default)]
4566 pub sse: bool,
4567 #[cfg(feature = "unstable_mcp_over_acp")]
4573 #[serde_as(deserialize_as = "DefaultOnError")]
4574 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4575 #[serde(default)]
4576 pub acp: bool,
4577 #[serde_as(deserialize_as = "DefaultOnError")]
4583 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4584 #[serde(default)]
4585 #[serde(rename = "_meta")]
4586 pub meta: Option<Meta>,
4587}
4588
4589impl McpCapabilities {
4590 #[must_use]
4592 pub fn new() -> Self {
4593 Self::default()
4594 }
4595
4596 #[must_use]
4598 pub fn http(mut self, http: bool) -> Self {
4599 self.http = http;
4600 self
4601 }
4602
4603 #[must_use]
4605 pub fn sse(mut self, sse: bool) -> Self {
4606 self.sse = sse;
4607 self
4608 }
4609
4610 #[cfg(feature = "unstable_mcp_over_acp")]
4616 #[must_use]
4617 pub fn acp(mut self, acp: bool) -> Self {
4618 self.acp = acp;
4619 self
4620 }
4621
4622 #[must_use]
4628 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4629 self.meta = meta.into_option();
4630 self
4631 }
4632}
4633
4634#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4640#[non_exhaustive]
4641pub struct AgentMethodNames {
4642 pub initialize: &'static str,
4644 pub authenticate: &'static str,
4646 #[cfg(feature = "unstable_llm_providers")]
4648 pub providers_list: &'static str,
4649 #[cfg(feature = "unstable_llm_providers")]
4651 pub providers_set: &'static str,
4652 #[cfg(feature = "unstable_llm_providers")]
4654 pub providers_disable: &'static str,
4655 pub session_new: &'static str,
4657 pub session_load: &'static str,
4659 pub session_set_mode: &'static str,
4661 pub session_set_config_option: &'static str,
4663 pub session_prompt: &'static str,
4665 pub session_cancel: &'static str,
4667 #[cfg(feature = "unstable_mcp_over_acp")]
4669 pub mcp_message: &'static str,
4670 pub session_list: &'static str,
4672 pub session_delete: &'static str,
4674 #[cfg(feature = "unstable_session_fork")]
4676 pub session_fork: &'static str,
4677 pub session_resume: &'static str,
4679 pub session_close: &'static str,
4681 pub logout: &'static str,
4683 #[cfg(feature = "unstable_nes")]
4685 pub nes_start: &'static str,
4686 #[cfg(feature = "unstable_nes")]
4688 pub nes_suggest: &'static str,
4689 #[cfg(feature = "unstable_nes")]
4691 pub nes_accept: &'static str,
4692 #[cfg(feature = "unstable_nes")]
4694 pub nes_reject: &'static str,
4695 #[cfg(feature = "unstable_nes")]
4697 pub nes_close: &'static str,
4698 #[cfg(feature = "unstable_nes")]
4700 pub document_did_open: &'static str,
4701 #[cfg(feature = "unstable_nes")]
4703 pub document_did_change: &'static str,
4704 #[cfg(feature = "unstable_nes")]
4706 pub document_did_close: &'static str,
4707 #[cfg(feature = "unstable_nes")]
4709 pub document_did_save: &'static str,
4710 #[cfg(feature = "unstable_nes")]
4712 pub document_did_focus: &'static str,
4713}
4714
4715pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4717 initialize: INITIALIZE_METHOD_NAME,
4718 authenticate: AUTHENTICATE_METHOD_NAME,
4719 #[cfg(feature = "unstable_llm_providers")]
4720 providers_list: PROVIDERS_LIST_METHOD_NAME,
4721 #[cfg(feature = "unstable_llm_providers")]
4722 providers_set: PROVIDERS_SET_METHOD_NAME,
4723 #[cfg(feature = "unstable_llm_providers")]
4724 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4725 session_new: SESSION_NEW_METHOD_NAME,
4726 session_load: SESSION_LOAD_METHOD_NAME,
4727 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4728 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4729 session_prompt: SESSION_PROMPT_METHOD_NAME,
4730 session_cancel: SESSION_CANCEL_METHOD_NAME,
4731 #[cfg(feature = "unstable_mcp_over_acp")]
4732 mcp_message: MCP_MESSAGE_METHOD_NAME,
4733 session_list: SESSION_LIST_METHOD_NAME,
4734 session_delete: SESSION_DELETE_METHOD_NAME,
4735 #[cfg(feature = "unstable_session_fork")]
4736 session_fork: SESSION_FORK_METHOD_NAME,
4737 session_resume: SESSION_RESUME_METHOD_NAME,
4738 session_close: SESSION_CLOSE_METHOD_NAME,
4739 logout: LOGOUT_METHOD_NAME,
4740 #[cfg(feature = "unstable_nes")]
4741 nes_start: NES_START_METHOD_NAME,
4742 #[cfg(feature = "unstable_nes")]
4743 nes_suggest: NES_SUGGEST_METHOD_NAME,
4744 #[cfg(feature = "unstable_nes")]
4745 nes_accept: NES_ACCEPT_METHOD_NAME,
4746 #[cfg(feature = "unstable_nes")]
4747 nes_reject: NES_REJECT_METHOD_NAME,
4748 #[cfg(feature = "unstable_nes")]
4749 nes_close: NES_CLOSE_METHOD_NAME,
4750 #[cfg(feature = "unstable_nes")]
4751 document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4752 #[cfg(feature = "unstable_nes")]
4753 document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4754 #[cfg(feature = "unstable_nes")]
4755 document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4756 #[cfg(feature = "unstable_nes")]
4757 document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4758 #[cfg(feature = "unstable_nes")]
4759 document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4760};
4761
4762pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4764pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4766#[cfg(feature = "unstable_llm_providers")]
4768pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4769#[cfg(feature = "unstable_llm_providers")]
4771pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4772#[cfg(feature = "unstable_llm_providers")]
4774pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4775pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4777pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4779pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4781pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4783pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4785pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4787pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4789pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
4791#[cfg(feature = "unstable_session_fork")]
4793pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4794pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4796pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4798pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4800
4801#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4808#[derive(Clone, Debug, Serialize, Deserialize)]
4809#[serde(untagged)]
4810#[cfg_attr(feature = "schemars", schemars(inline))]
4811#[non_exhaustive]
4812#[allow(clippy::large_enum_variant)]
4813pub enum ClientRequest {
4814 InitializeRequest(InitializeRequest),
4825 AuthenticateRequest(AuthenticateRequest),
4836 #[cfg(feature = "unstable_llm_providers")]
4842 ListProvidersRequest(ListProvidersRequest),
4843 #[cfg(feature = "unstable_llm_providers")]
4849 SetProviderRequest(SetProviderRequest),
4850 #[cfg(feature = "unstable_llm_providers")]
4856 DisableProviderRequest(DisableProviderRequest),
4857 LogoutRequest(LogoutRequest),
4862 NewSessionRequest(NewSessionRequest),
4875 LoadSessionRequest(LoadSessionRequest),
4886 ListSessionsRequest(ListSessionsRequest),
4892 DeleteSessionRequest(DeleteSessionRequest),
4896 #[cfg(feature = "unstable_session_fork")]
4897 ForkSessionRequest(ForkSessionRequest),
4909 ResumeSessionRequest(ResumeSessionRequest),
4916 CloseSessionRequest(CloseSessionRequest),
4923 SetSessionModeRequest(SetSessionModeRequest),
4937 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4939 PromptRequest(PromptRequest),
4951 #[cfg(feature = "unstable_nes")]
4952 StartNesRequest(StartNesRequest),
4958 #[cfg(feature = "unstable_nes")]
4959 SuggestNesRequest(SuggestNesRequest),
4965 #[cfg(feature = "unstable_nes")]
4966 CloseNesRequest(CloseNesRequest),
4975 ExtMethodRequest(ExtRequest),
4982}
4983
4984impl ClientRequest {
4985 #[must_use]
4987 pub fn method(&self) -> &str {
4988 match self {
4989 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4990 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4991 #[cfg(feature = "unstable_llm_providers")]
4992 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4993 #[cfg(feature = "unstable_llm_providers")]
4994 Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
4995 #[cfg(feature = "unstable_llm_providers")]
4996 Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4997 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4998 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4999 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
5000 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
5001 Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
5002 #[cfg(feature = "unstable_session_fork")]
5003 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
5004 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
5005 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
5006 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
5007 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
5008 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
5009 #[cfg(feature = "unstable_nes")]
5010 Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
5011 #[cfg(feature = "unstable_nes")]
5012 Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
5013 #[cfg(feature = "unstable_nes")]
5014 Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
5015 Self::ExtMethodRequest(ext_request) => &ext_request.method,
5016 }
5017 }
5018}
5019
5020#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5027#[derive(Clone, Debug, Serialize, Deserialize)]
5028#[serde(untagged)]
5029#[cfg_attr(feature = "schemars", schemars(inline))]
5030#[non_exhaustive]
5031#[allow(clippy::large_enum_variant)]
5032pub enum AgentResponse {
5033 InitializeResponse(InitializeResponse),
5035 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
5037 #[cfg(feature = "unstable_llm_providers")]
5039 ListProvidersResponse(ListProvidersResponse),
5040 #[cfg(feature = "unstable_llm_providers")]
5042 SetProviderResponse(#[serde(default)] SetProviderResponse),
5043 #[cfg(feature = "unstable_llm_providers")]
5045 DisableProviderResponse(#[serde(default)] DisableProviderResponse),
5046 LogoutResponse(#[serde(default)] LogoutResponse),
5048 NewSessionResponse(NewSessionResponse),
5050 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5052 ListSessionsResponse(ListSessionsResponse),
5054 DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
5056 #[cfg(feature = "unstable_session_fork")]
5058 ForkSessionResponse(ForkSessionResponse),
5059 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5061 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5063 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
5065 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5067 PromptResponse(PromptResponse),
5069 #[cfg(feature = "unstable_nes")]
5071 StartNesResponse(StartNesResponse),
5072 #[cfg(feature = "unstable_nes")]
5074 SuggestNesResponse(SuggestNesResponse),
5075 #[cfg(feature = "unstable_nes")]
5077 CloseNesResponse(#[serde(default)] CloseNesResponse),
5078 ExtMethodResponse(ExtResponse),
5080}
5081
5082#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5089#[derive(Clone, Debug, Serialize, Deserialize)]
5090#[serde(untagged)]
5091#[cfg_attr(feature = "schemars", schemars(inline))]
5092#[non_exhaustive]
5093#[allow(clippy::large_enum_variant)]
5094pub enum ClientNotification {
5095 CancelNotification(CancelNotification),
5107 #[cfg(feature = "unstable_nes")]
5108 DidOpenDocumentNotification(DidOpenDocumentNotification),
5112 #[cfg(feature = "unstable_nes")]
5113 DidChangeDocumentNotification(DidChangeDocumentNotification),
5117 #[cfg(feature = "unstable_nes")]
5118 DidCloseDocumentNotification(DidCloseDocumentNotification),
5122 #[cfg(feature = "unstable_nes")]
5123 DidSaveDocumentNotification(DidSaveDocumentNotification),
5127 #[cfg(feature = "unstable_nes")]
5128 DidFocusDocumentNotification(DidFocusDocumentNotification),
5132 #[cfg(feature = "unstable_nes")]
5133 AcceptNesNotification(AcceptNesNotification),
5137 #[cfg(feature = "unstable_nes")]
5138 RejectNesNotification(RejectNesNotification),
5142 #[cfg(feature = "unstable_mcp_over_acp")]
5148 MessageMcpNotification(MessageMcpNotification),
5149 ExtNotification(ExtNotification),
5156}
5157
5158impl ClientNotification {
5159 #[must_use]
5161 pub fn method(&self) -> &str {
5162 match self {
5163 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5164 #[cfg(feature = "unstable_nes")]
5165 Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5166 #[cfg(feature = "unstable_nes")]
5167 Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5168 #[cfg(feature = "unstable_nes")]
5169 Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5170 #[cfg(feature = "unstable_nes")]
5171 Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5172 #[cfg(feature = "unstable_nes")]
5173 Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5174 #[cfg(feature = "unstable_nes")]
5175 Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5176 #[cfg(feature = "unstable_nes")]
5177 Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5178 #[cfg(feature = "unstable_mcp_over_acp")]
5179 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5180 Self::ExtNotification(ext_notification) => &ext_notification.method,
5181 }
5182 }
5183}
5184
5185#[serde_as]
5189#[skip_serializing_none]
5190#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5191#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5192#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME)))]
5193#[serde(rename_all = "camelCase")]
5194#[non_exhaustive]
5195pub struct CancelNotification {
5196 pub session_id: SessionId,
5198 #[serde_as(deserialize_as = "DefaultOnError")]
5204 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5205 #[serde(default)]
5206 #[serde(rename = "_meta")]
5207 pub meta: Option<Meta>,
5208}
5209
5210impl CancelNotification {
5211 #[must_use]
5213 pub fn new(session_id: impl Into<SessionId>) -> Self {
5214 Self {
5215 session_id: session_id.into(),
5216 meta: None,
5217 }
5218 }
5219
5220 #[must_use]
5226 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5227 self.meta = meta.into_option();
5228 self
5229 }
5230}
5231
5232#[cfg(test)]
5233mod test_serialization {
5234 use super::*;
5235 use serde_json::json;
5236
5237 fn test_meta() -> Meta {
5238 json!({ "source": "test" }).as_object().unwrap().clone()
5239 }
5240
5241 fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
5242 serde_json::to_string(value)
5243 .unwrap()
5244 .matches("\"_meta\"")
5245 .count()
5246 }
5247
5248 #[test]
5251 fn prompt_response_has_no_error_stop_reason() {
5252 assert_eq!(
5253 serde_json::from_value::<PromptResponse>(json!({ "stopReason": "end_turn" }))
5254 .unwrap()
5255 .stop_reason,
5256 StopReason::EndTurn
5257 );
5258 assert!(
5259 serde_json::from_value::<PromptResponse>(json!({ "stopReason": "error" })).is_err()
5260 );
5261 }
5262
5263 #[test]
5264 fn test_initialize_capabilities_default_on_malformed_values() {
5265 let request: InitializeRequest = serde_json::from_value(json!({
5266 "protocolVersion": 1,
5267 "clientCapabilities": false
5268 }))
5269 .unwrap();
5270 assert_eq!(request.client_capabilities, ClientCapabilities::default());
5271
5272 let response: InitializeResponse = serde_json::from_value(json!({
5273 "protocolVersion": 1,
5274 "agentCapabilities": false
5275 }))
5276 .unwrap();
5277 assert_eq!(response.agent_capabilities, AgentCapabilities::default());
5278 }
5279
5280 #[test]
5281 fn test_agent_capabilities_default_on_malformed_values() {
5282 let capabilities: AgentCapabilities = serde_json::from_value(json!({
5283 "loadSession": "yes",
5284 "promptCapabilities": {
5285 "image": "yes",
5286 "audio": true,
5287 "embeddedContext": {}
5288 },
5289 "mcpCapabilities": {
5290 "http": "yes",
5291 "sse": true
5292 },
5293 "sessionCapabilities": false,
5294 "auth": false
5295 }))
5296 .unwrap();
5297
5298 assert!(!capabilities.load_session);
5299 assert!(!capabilities.prompt_capabilities.image);
5300 assert!(capabilities.prompt_capabilities.audio);
5301 assert!(!capabilities.prompt_capabilities.embedded_context);
5302 assert!(!capabilities.mcp_capabilities.http);
5303 assert!(capabilities.mcp_capabilities.sse);
5304 assert_eq!(
5305 capabilities.session_capabilities,
5306 SessionCapabilities::default()
5307 );
5308 assert_eq!(capabilities.auth, AgentAuthCapabilities::default());
5309 }
5310
5311 #[test]
5312 fn test_mcp_server_stdio_serialization() {
5313 let server = McpServer::Stdio(
5314 McpServerStdio::new("test-server", "/usr/bin/server")
5315 .args(vec!["--port".to_string(), "3000".to_string()])
5316 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5317 );
5318
5319 let json = serde_json::to_value(&server).unwrap();
5320 assert_eq!(
5321 json,
5322 json!({
5323 "name": "test-server",
5324 "command": "/usr/bin/server",
5325 "args": ["--port", "3000"],
5326 "env": [
5327 {
5328 "name": "API_KEY",
5329 "value": "secret123"
5330 }
5331 ]
5332 })
5333 );
5334
5335 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5336 match deserialized {
5337 McpServer::Stdio(McpServerStdio {
5338 name,
5339 command,
5340 args,
5341 env,
5342 meta: _,
5343 }) => {
5344 assert_eq!(name, "test-server");
5345 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5346 assert_eq!(args, vec!["--port", "3000"]);
5347 assert_eq!(env.len(), 1);
5348 assert_eq!(env[0].name, "API_KEY");
5349 assert_eq!(env[0].value, "secret123");
5350 }
5351 _ => panic!("Expected Stdio variant"),
5352 }
5353 }
5354
5355 #[test]
5356 fn test_mcp_server_http_serialization() {
5357 let server = McpServer::Http(
5358 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5359 HttpHeader::new("Authorization", "Bearer token123"),
5360 HttpHeader::new("Content-Type", "application/json"),
5361 ]),
5362 );
5363
5364 let json = serde_json::to_value(&server).unwrap();
5365 assert_eq!(
5366 json,
5367 json!({
5368 "type": "http",
5369 "name": "http-server",
5370 "url": "https://api.example.com",
5371 "headers": [
5372 {
5373 "name": "Authorization",
5374 "value": "Bearer token123"
5375 },
5376 {
5377 "name": "Content-Type",
5378 "value": "application/json"
5379 }
5380 ]
5381 })
5382 );
5383
5384 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5385 match deserialized {
5386 McpServer::Http(McpServerHttp {
5387 name,
5388 url,
5389 headers,
5390 meta: _,
5391 }) => {
5392 assert_eq!(name, "http-server");
5393 assert_eq!(url, "https://api.example.com");
5394 assert_eq!(headers.len(), 2);
5395 assert_eq!(headers[0].name, "Authorization");
5396 assert_eq!(headers[0].value, "Bearer token123");
5397 assert_eq!(headers[1].name, "Content-Type");
5398 assert_eq!(headers[1].value, "application/json");
5399 }
5400 _ => panic!("Expected Http variant"),
5401 }
5402 }
5403
5404 #[cfg(feature = "unstable_mcp_over_acp")]
5405 #[test]
5406 fn test_mcp_server_acp_serialization() {
5407 let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id"));
5408
5409 let json = serde_json::to_value(&server).unwrap();
5410 assert_eq!(
5411 json,
5412 json!({
5413 "type": "acp",
5414 "name": "project-tools",
5415 "serverId": "project-tools-id"
5416 })
5417 );
5418
5419 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5420 match deserialized {
5421 McpServer::Acp(McpServerAcp {
5422 name,
5423 server_id: id,
5424 meta: _,
5425 }) => {
5426 assert_eq!(name, "project-tools");
5427 assert_eq!(id, McpServerAcpId::new("project-tools-id"));
5428 }
5429 _ => panic!("Expected Acp variant"),
5430 }
5431 }
5432
5433 #[cfg(feature = "unstable_mcp_over_acp")]
5434 #[test]
5435 fn test_client_mcp_message_method_names() {
5436 use serde_json::json;
5437
5438 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5439
5440 let notification =
5441 MessageMcpNotification::new("server-1", "req-1", "notifications/progress");
5442 assert_eq!(
5443 ClientNotification::MessageMcpNotification(notification.clone()).method(),
5444 "mcp/message"
5445 );
5446 assert_eq!(
5447 serde_json::to_value(notification).unwrap(),
5448 json!({
5449 "serverId": "server-1",
5450 "requestId": "req-1",
5451 "method": "notifications/progress"
5452 })
5453 );
5454 let notification: MessageMcpNotification = serde_json::from_value(json!({
5455 "serverId": "server-1", "requestId": "req-1", "method": "notifications/progress",
5456 "params": null, "_meta": null
5457 }))
5458 .unwrap();
5459 assert_eq!(notification.params, None);
5460 assert_eq!(notification.meta, None);
5461 for key in ["serverId", "requestId", "method"] {
5462 let mut value = json!({"serverId":"server-1", "requestId":"req-1", "method":"notifications/progress"});
5463 value.as_object_mut().unwrap().remove(key);
5464 assert!(serde_json::from_value::<MessageMcpNotification>(value).is_err());
5465 }
5466 }
5467
5468 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5469 #[test]
5470 fn test_mcp_server_acp_schema() {
5471 let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap();
5472 assert!(json_contains_entry(
5473 &mcp_server_schema,
5474 "const",
5475 &json!("acp")
5476 ));
5477 assert!(json_contains_entry(
5478 &mcp_server_schema,
5479 "$ref",
5480 &json!("#/$defs/McpServerAcp")
5481 ));
5482
5483 let capabilities_schema =
5484 serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap();
5485 assert!(json_contains_key(&capabilities_schema, "acp"));
5486 }
5487
5488 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5489 fn json_contains_entry(
5490 value: &serde_json::Value,
5491 key: &str,
5492 expected: &serde_json::Value,
5493 ) -> bool {
5494 match value {
5495 serde_json::Value::Object(map) => {
5496 map.get(key) == Some(expected)
5497 || map
5498 .values()
5499 .any(|value| json_contains_entry(value, key, expected))
5500 }
5501 serde_json::Value::Array(values) => values
5502 .iter()
5503 .any(|value| json_contains_entry(value, key, expected)),
5504 _ => false,
5505 }
5506 }
5507
5508 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5509 fn json_contains_key(value: &serde_json::Value, key: &str) -> bool {
5510 match value {
5511 serde_json::Value::Object(map) => {
5512 map.contains_key(key) || map.values().any(|value| json_contains_key(value, key))
5513 }
5514 serde_json::Value::Array(values) => {
5515 values.iter().any(|value| json_contains_key(value, key))
5516 }
5517 _ => false,
5518 }
5519 }
5520
5521 #[test]
5522 fn test_mcp_server_sse_serialization() {
5523 let server = McpServer::Sse(
5524 McpServerSse::new("sse-server", "https://sse.example.com/events")
5525 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5526 );
5527
5528 let json = serde_json::to_value(&server).unwrap();
5529 assert_eq!(
5530 json,
5531 json!({
5532 "type": "sse",
5533 "name": "sse-server",
5534 "url": "https://sse.example.com/events",
5535 "headers": [
5536 {
5537 "name": "X-API-Key",
5538 "value": "apikey456"
5539 }
5540 ]
5541 })
5542 );
5543
5544 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5545 match deserialized {
5546 McpServer::Sse(McpServerSse {
5547 name,
5548 url,
5549 headers,
5550 meta: _,
5551 }) => {
5552 assert_eq!(name, "sse-server");
5553 assert_eq!(url, "https://sse.example.com/events");
5554 assert_eq!(headers.len(), 1);
5555 assert_eq!(headers[0].name, "X-API-Key");
5556 assert_eq!(headers[0].value, "apikey456");
5557 }
5558 _ => panic!("Expected Sse variant"),
5559 }
5560 }
5561
5562 #[test]
5563 fn test_session_config_option_category_known_variants() {
5564 assert_eq!(
5566 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5567 json!("mode")
5568 );
5569 assert_eq!(
5570 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5571 json!("model")
5572 );
5573 assert_eq!(
5574 serde_json::to_value(&SessionConfigOptionCategory::ModelConfig).unwrap(),
5575 json!("model_config")
5576 );
5577 assert_eq!(
5578 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5579 json!("thought_level")
5580 );
5581
5582 assert_eq!(
5584 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5585 SessionConfigOptionCategory::Mode
5586 );
5587 assert_eq!(
5588 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5589 SessionConfigOptionCategory::Model
5590 );
5591 assert_eq!(
5592 serde_json::from_str::<SessionConfigOptionCategory>("\"model_config\"").unwrap(),
5593 SessionConfigOptionCategory::ModelConfig
5594 );
5595 assert_eq!(
5596 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5597 SessionConfigOptionCategory::ThoughtLevel
5598 );
5599 }
5600
5601 #[test]
5602 fn test_session_config_option_category_unknown_variants() {
5603 let unknown: SessionConfigOptionCategory =
5605 serde_json::from_str("\"some_future_category\"").unwrap();
5606 assert_eq!(
5607 unknown,
5608 SessionConfigOptionCategory::Other("some_future_category".to_string())
5609 );
5610
5611 let json = serde_json::to_value(&unknown).unwrap();
5613 assert_eq!(json, json!("some_future_category"));
5614 }
5615
5616 #[test]
5617 fn test_session_config_option_category_custom_categories() {
5618 let custom: SessionConfigOptionCategory =
5620 serde_json::from_str("\"_my_custom_category\"").unwrap();
5621 assert_eq!(
5622 custom,
5623 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5624 );
5625
5626 let json = serde_json::to_value(&custom).unwrap();
5628 assert_eq!(json, json!("_my_custom_category"));
5629
5630 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5632 assert_eq!(
5633 deserialized,
5634 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5635 );
5636 }
5637
5638 #[test]
5639 fn test_auth_method_agent_serialization() {
5640 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5641
5642 let json = serde_json::to_value(&method).unwrap();
5643 assert_eq!(
5644 json,
5645 json!({
5646 "id": "default-auth",
5647 "name": "Default Auth"
5648 })
5649 );
5650 assert!(!json.as_object().unwrap().contains_key("description"));
5652 assert!(!json.as_object().unwrap().contains_key("type"));
5654
5655 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5656 match deserialized {
5657 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5658 assert_eq!(id.0.as_ref(), "default-auth");
5659 assert_eq!(name, "Default Auth");
5660 }
5661 _ => panic!("Expected Agent variant"),
5662 }
5663 }
5664
5665 #[test]
5666 fn test_auth_method_explicit_agent_deserialization() {
5667 let json = json!({
5669 "id": "agent-auth",
5670 "name": "Agent Auth",
5671 "type": "agent"
5672 });
5673
5674 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5675 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5676 }
5677
5678 #[test]
5679 fn test_session_delete_serialization() {
5680 assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5681 assert_eq!(
5682 ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5683 "session/delete"
5684 );
5685 assert_eq!(
5686 serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5687 json!({
5688 "sessionId": "sess_abc123"
5689 })
5690 );
5691 assert_eq!(
5692 serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5693 json!({})
5694 );
5695 assert_eq!(
5696 serde_json::to_value(
5697 SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5698 )
5699 .unwrap(),
5700 json!({
5701 "delete": {}
5702 })
5703 );
5704 }
5705 #[test]
5706 fn test_session_additional_directories_serialization() {
5707 assert_eq!(
5708 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5709 json!({
5710 "cwd": "/home/user/project",
5711 "mcpServers": []
5712 })
5713 );
5714 assert_eq!(
5715 serde_json::to_value(
5716 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5717 PathBuf::from("/home/user/shared-lib"),
5718 PathBuf::from("/home/user/product-docs"),
5719 ])
5720 )
5721 .unwrap(),
5722 json!({
5723 "cwd": "/home/user/project",
5724 "additionalDirectories": [
5725 "/home/user/shared-lib",
5726 "/home/user/product-docs"
5727 ],
5728 "mcpServers": []
5729 })
5730 );
5731 assert_eq!(
5732 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5733 json!({
5734 "sessionId": "sess_abc123",
5735 "cwd": "/home/user/project"
5736 })
5737 );
5738 assert_eq!(
5739 serde_json::to_value(
5740 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5741 PathBuf::from("/home/user/shared-lib"),
5742 PathBuf::from("/home/user/product-docs"),
5743 ])
5744 )
5745 .unwrap(),
5746 json!({
5747 "sessionId": "sess_abc123",
5748 "cwd": "/home/user/project",
5749 "additionalDirectories": [
5750 "/home/user/shared-lib",
5751 "/home/user/product-docs"
5752 ]
5753 })
5754 );
5755 assert_eq!(
5756 serde_json::from_value::<SessionInfo>(json!({
5757 "sessionId": "sess_abc123",
5758 "cwd": "/home/user/project"
5759 }))
5760 .unwrap()
5761 .additional_directories,
5762 Vec::<PathBuf>::new()
5763 );
5764 }
5765 #[test]
5766 fn test_session_additional_directories_capabilities_serialization() {
5767 assert_eq!(
5768 serde_json::to_value(
5769 SessionCapabilities::new()
5770 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5771 )
5772 .unwrap(),
5773 json!({
5774 "additionalDirectories": {}
5775 })
5776 );
5777 }
5778
5779 #[test]
5780 fn test_auth_method_terminal_serialization() {
5781 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5782
5783 let json = serde_json::to_value(&method).unwrap();
5784 assert_eq!(
5785 json,
5786 json!({
5787 "id": "tui-auth",
5788 "name": "Terminal Auth",
5789 "type": "terminal"
5790 })
5791 );
5792 assert!(!json.as_object().unwrap().contains_key("args"));
5794 assert!(!json.as_object().unwrap().contains_key("env"));
5795
5796 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5797 match deserialized {
5798 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5799 assert_eq!(args, Vec::<String>::new());
5800 assert!(env.is_empty());
5801 }
5802 _ => panic!("Expected Terminal variant"),
5803 }
5804 }
5805
5806 #[test]
5807 fn test_auth_method_terminal_with_args_and_env_serialization() {
5808 use std::collections::HashMap;
5809
5810 let mut env = HashMap::new();
5811 env.insert("TERM".to_string(), "xterm-256color".to_string());
5812
5813 let method = AuthMethod::Terminal(
5814 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5815 .args(vec!["--interactive".to_string(), "--color".to_string()])
5816 .env(env),
5817 );
5818
5819 let json = serde_json::to_value(&method).unwrap();
5820 assert_eq!(
5821 json,
5822 json!({
5823 "id": "tui-auth",
5824 "name": "Terminal Auth",
5825 "type": "terminal",
5826 "args": ["--interactive", "--color"],
5827 "env": {
5828 "TERM": "xterm-256color"
5829 }
5830 })
5831 );
5832
5833 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5834 match deserialized {
5835 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5836 assert_eq!(args, vec!["--interactive", "--color"]);
5837 assert_eq!(env.len(), 1);
5838 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5839 }
5840 _ => panic!("Expected Terminal variant"),
5841 }
5842 }
5843
5844 #[test]
5845 fn test_session_config_option_value_id_serialize() {
5846 let val = SessionConfigOptionValue::value_id("model-1");
5847 let json = serde_json::to_value(&val).unwrap();
5848 assert_eq!(json, json!({ "value": "model-1" }));
5850 assert!(!json.as_object().unwrap().contains_key("type"));
5851 }
5852
5853 #[test]
5854 fn test_session_config_option_value_boolean_serialize() {
5855 let val = SessionConfigOptionValue::boolean(true);
5856 let json = serde_json::to_value(&val).unwrap();
5857 assert_eq!(json, json!({ "type": "boolean", "value": true }));
5858 }
5859
5860 #[test]
5861 fn test_session_config_option_value_deserialize_no_type() {
5862 let json = json!({ "value": "model-1" });
5864 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5865 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5866 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5867 }
5868
5869 #[test]
5870 fn test_session_config_option_value_deserialize_boolean() {
5871 let json = json!({ "type": "boolean", "value": true });
5872 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5873 assert_eq!(val, SessionConfigOptionValue::boolean(true));
5874 assert_eq!(val.as_bool(), Some(true));
5875 }
5876
5877 #[test]
5878 fn test_session_config_option_value_deserialize_boolean_false() {
5879 let json = json!({ "type": "boolean", "value": false });
5880 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5881 assert_eq!(val, SessionConfigOptionValue::boolean(false));
5882 assert_eq!(val.as_bool(), Some(false));
5883 }
5884
5885 #[test]
5886 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5887 let json = json!({ "type": "text", "value": "freeform input" });
5889 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5890 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5891 }
5892
5893 #[test]
5894 fn test_session_config_option_value_roundtrip_value_id() {
5895 let original = SessionConfigOptionValue::value_id("option-a");
5896 let json = serde_json::to_value(&original).unwrap();
5897 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5898 assert_eq!(original, roundtripped);
5899 }
5900
5901 #[test]
5902 fn test_session_config_option_value_roundtrip_boolean() {
5903 let original = SessionConfigOptionValue::boolean(false);
5904 let json = serde_json::to_value(&original).unwrap();
5905 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5906 assert_eq!(original, roundtripped);
5907 }
5908
5909 #[test]
5910 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5911 let json = json!({ "type": "boolean", "value": "not a bool" });
5913 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5914 assert!(result.is_ok());
5916 assert_eq!(
5917 result.unwrap().as_value_id().unwrap().to_string(),
5918 "not a bool"
5919 );
5920 }
5921
5922 #[test]
5923 fn test_session_config_option_value_from_impls() {
5924 let from_str: SessionConfigOptionValue = "model-1".into();
5925 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5926
5927 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5928 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5929
5930 let from_bool: SessionConfigOptionValue = true.into();
5931 assert_eq!(from_bool.as_bool(), Some(true));
5932 }
5933
5934 #[test]
5935 fn test_set_session_config_option_request_value_id() {
5936 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5937 let json = serde_json::to_value(&req).unwrap();
5938 assert_eq!(
5939 json,
5940 json!({
5941 "sessionId": "sess_1",
5942 "configId": "model",
5943 "value": "model-1"
5944 })
5945 );
5946 assert!(!json.as_object().unwrap().contains_key("type"));
5948 }
5949
5950 #[test]
5951 fn test_set_session_config_option_request_boolean() {
5952 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5953 let json = serde_json::to_value(&req).unwrap();
5954 assert_eq!(
5955 json,
5956 json!({
5957 "sessionId": "sess_1",
5958 "configId": "brave_mode",
5959 "type": "boolean",
5960 "value": true
5961 })
5962 );
5963 }
5964
5965 #[test]
5966 fn test_set_session_config_option_request_deserialize_no_type() {
5967 let json = json!({
5969 "sessionId": "sess_1",
5970 "configId": "model",
5971 "value": "model-1"
5972 });
5973 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5974 assert_eq!(req.session_id.to_string(), "sess_1");
5975 assert_eq!(req.config_id.to_string(), "model");
5976 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5977 }
5978
5979 #[test]
5980 fn test_set_session_config_option_request_deserialize_boolean() {
5981 let json = json!({
5982 "sessionId": "sess_1",
5983 "configId": "brave_mode",
5984 "type": "boolean",
5985 "value": true
5986 });
5987 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5988 assert_eq!(req.value.as_bool(), Some(true));
5989 }
5990
5991 #[test]
5992 fn test_set_session_config_option_request_roundtrip_value_id() {
5993 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5994 let json = serde_json::to_value(&original).unwrap();
5995 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5996 assert_eq!(original, roundtripped);
5997 }
5998
5999 #[test]
6000 fn test_set_session_config_option_request_roundtrip_boolean() {
6001 let original = SetSessionConfigOptionRequest::new("s", "c", false);
6002 let json = serde_json::to_value(&original).unwrap();
6003 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6004 assert_eq!(original, roundtripped);
6005 }
6006
6007 #[test]
6008 fn test_session_config_boolean_serialization() {
6009 let cfg = SessionConfigBoolean::new(true);
6010 let json = serde_json::to_value(&cfg).unwrap();
6011 assert_eq!(json, json!({ "currentValue": true }));
6012
6013 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6014 assert!(deserialized.current_value);
6015 }
6016
6017 #[test]
6018 fn test_session_config_option_boolean_variant() {
6019 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6020 .description("Skip confirmation prompts")
6021 .meta(test_meta());
6022 assert_eq!(serialized_meta_key_count(&opt), 1);
6023
6024 let json = serde_json::to_value(&opt).unwrap();
6025 assert_eq!(
6026 json,
6027 json!({
6028 "id": "brave_mode",
6029 "name": "Brave Mode",
6030 "description": "Skip confirmation prompts",
6031 "type": "boolean",
6032 "currentValue": false,
6033 "_meta": {
6034 "source": "test"
6035 }
6036 })
6037 );
6038
6039 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6040 assert_eq!(deserialized.id.to_string(), "brave_mode");
6041 assert_eq!(deserialized.name, "Brave Mode");
6042 match deserialized.kind {
6043 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6044 _ => panic!("Expected Boolean kind"),
6045 }
6046 }
6047
6048 #[test]
6049 fn test_session_config_option_select_still_works() {
6050 let opt = SessionConfigOption::select(
6052 "model",
6053 "Model",
6054 "model-1",
6055 vec![
6056 SessionConfigSelectOption::new("model-1", "Model 1"),
6057 SessionConfigSelectOption::new("model-2", "Model 2"),
6058 ],
6059 )
6060 .meta(test_meta());
6061 assert_eq!(serialized_meta_key_count(&opt), 1);
6062
6063 let json = serde_json::to_value(&opt).unwrap();
6064 assert_eq!(json["type"], "select");
6065 assert_eq!(json["currentValue"], "model-1");
6066 assert_eq!(json["options"].as_array().unwrap().len(), 2);
6067 assert_eq!(json["_meta"]["source"], "test");
6068
6069 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6070 match deserialized.kind {
6071 SessionConfigKind::Select(ref s) => {
6072 assert_eq!(s.current_value.to_string(), "model-1");
6073 }
6074 _ => panic!("Expected Select kind"),
6075 }
6076 }
6077
6078 #[cfg(feature = "unstable_llm_providers")]
6079 #[test]
6080 fn test_llm_protocol_known_variants() {
6081 assert_eq!(
6082 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6083 json!("anthropic")
6084 );
6085 assert_eq!(
6086 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6087 json!("openai")
6088 );
6089 assert_eq!(
6090 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6091 json!("azure")
6092 );
6093 assert_eq!(
6094 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6095 json!("vertex")
6096 );
6097 assert_eq!(
6098 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6099 json!("bedrock")
6100 );
6101
6102 assert_eq!(
6103 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6104 LlmProtocol::Anthropic
6105 );
6106 assert_eq!(
6107 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6108 LlmProtocol::OpenAi
6109 );
6110 assert_eq!(
6111 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6112 LlmProtocol::Azure
6113 );
6114 assert_eq!(
6115 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6116 LlmProtocol::Vertex
6117 );
6118 assert_eq!(
6119 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6120 LlmProtocol::Bedrock
6121 );
6122 }
6123
6124 #[cfg(feature = "unstable_llm_providers")]
6125 #[test]
6126 fn test_llm_protocol_unknown_variant() {
6127 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6128 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6129
6130 let json = serde_json::to_value(&unknown).unwrap();
6131 assert_eq!(json, json!("cohere"));
6132 }
6133
6134 #[cfg(feature = "unstable_llm_providers")]
6135 #[test]
6136 fn test_provider_current_config_serialization() {
6137 let config =
6138 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6139
6140 let json = serde_json::to_value(&config).unwrap();
6141 assert_eq!(
6142 json,
6143 json!({
6144 "apiType": "anthropic",
6145 "baseUrl": "https://api.anthropic.com"
6146 })
6147 );
6148
6149 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6150 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6151 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6152 }
6153
6154 #[cfg(feature = "unstable_llm_providers")]
6155 #[test]
6156 fn test_provider_info_with_current_config() {
6157 let info = ProviderInfo::new(
6158 "main",
6159 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6160 true,
6161 Some(ProviderCurrentConfig::new(
6162 LlmProtocol::Anthropic,
6163 "https://api.anthropic.com",
6164 )),
6165 );
6166
6167 let json = serde_json::to_value(&info).unwrap();
6168 assert_eq!(
6169 json,
6170 json!({
6171 "providerId": "main",
6172 "supported": ["anthropic", "openai"],
6173 "required": true,
6174 "current": {
6175 "apiType": "anthropic",
6176 "baseUrl": "https://api.anthropic.com"
6177 }
6178 })
6179 );
6180
6181 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6182 assert_eq!(deserialized.provider_id.to_string(), "main");
6183 assert_eq!(deserialized.supported.len(), 2);
6184 assert!(deserialized.required);
6185 assert!(deserialized.current.is_some());
6186 assert_eq!(
6187 deserialized.current.as_ref().unwrap().api_type,
6188 LlmProtocol::Anthropic
6189 );
6190 }
6191
6192 #[cfg(feature = "unstable_llm_providers")]
6193 #[test]
6194 fn test_provider_info_disabled() {
6195 let info = ProviderInfo::new(
6196 "secondary",
6197 vec![LlmProtocol::OpenAi],
6198 false,
6199 None::<ProviderCurrentConfig>,
6200 );
6201
6202 let json = serde_json::to_value(&info).unwrap();
6203 assert_eq!(
6204 json,
6205 json!({
6206 "providerId": "secondary",
6207 "supported": ["openai"],
6208 "required": false
6209 })
6210 );
6211
6212 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6213 assert_eq!(deserialized.provider_id.to_string(), "secondary");
6214 assert!(!deserialized.required);
6215 assert!(deserialized.current.is_none());
6216 }
6217
6218 #[cfg(feature = "unstable_llm_providers")]
6219 #[test]
6220 fn test_provider_info_missing_current_defaults_to_none() {
6221 let json = json!({
6223 "providerId": "main",
6224 "supported": ["anthropic"],
6225 "required": true
6226 });
6227 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6228 assert!(deserialized.current.is_none());
6229 }
6230
6231 #[cfg(feature = "unstable_llm_providers")]
6232 #[test]
6233 fn test_provider_info_explicit_null_current_decodes_to_none() {
6234 let json = json!({
6238 "providerId": "main",
6239 "supported": ["anthropic"],
6240 "required": true,
6241 "current": null
6242 });
6243 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6244 assert!(deserialized.current.is_none());
6245 }
6246
6247 #[cfg(feature = "unstable_llm_providers")]
6248 #[test]
6249 fn test_list_providers_response_serialization() {
6250 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6251 "main",
6252 vec![LlmProtocol::Anthropic],
6253 true,
6254 Some(ProviderCurrentConfig::new(
6255 LlmProtocol::Anthropic,
6256 "https://api.anthropic.com",
6257 )),
6258 )]);
6259
6260 let json = serde_json::to_value(&response).unwrap();
6261 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6262 assert_eq!(json["providers"][0]["providerId"], "main");
6263
6264 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6265 assert_eq!(deserialized.providers.len(), 1);
6266 }
6267
6268 #[cfg(feature = "unstable_llm_providers")]
6269 #[test]
6270 fn test_set_provider_request_serialization() {
6271 use std::collections::HashMap;
6272
6273 let mut headers = HashMap::new();
6274 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6275
6276 let request =
6277 SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6278 .headers(headers);
6279
6280 let json = serde_json::to_value(&request).unwrap();
6281 assert_eq!(
6282 json,
6283 json!({
6284 "providerId": "main",
6285 "apiType": "openai",
6286 "baseUrl": "https://api.openai.com/v1",
6287 "headers": {
6288 "Authorization": "Bearer sk-test"
6289 }
6290 })
6291 );
6292
6293 let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6294 assert_eq!(deserialized.provider_id.to_string(), "main");
6295 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6296 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6297 assert_eq!(deserialized.headers.len(), 1);
6298 assert_eq!(
6299 deserialized.headers.get("Authorization").unwrap(),
6300 "Bearer sk-test"
6301 );
6302 }
6303
6304 #[cfg(feature = "unstable_llm_providers")]
6305 #[test]
6306 fn test_set_provider_request_omits_empty_headers() {
6307 let request =
6308 SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6309
6310 let json = serde_json::to_value(&request).unwrap();
6311 assert!(!json.as_object().unwrap().contains_key("headers"));
6313 }
6314
6315 #[cfg(feature = "unstable_llm_providers")]
6316 #[test]
6317 fn test_disable_provider_request_serialization() {
6318 let request = DisableProviderRequest::new("secondary");
6319
6320 let json = serde_json::to_value(&request).unwrap();
6321 assert_eq!(json, json!({ "providerId": "secondary" }));
6322
6323 let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6324 assert_eq!(deserialized.provider_id.to_string(), "secondary");
6325 }
6326
6327 #[cfg(feature = "unstable_llm_providers")]
6328 #[test]
6329 fn test_providers_capabilities_serialization() {
6330 let caps = ProvidersCapabilities::new();
6331
6332 let json = serde_json::to_value(&caps).unwrap();
6333 assert_eq!(json, json!({}));
6334
6335 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6336 assert!(deserialized.meta.is_none());
6337 }
6338
6339 #[cfg(feature = "unstable_llm_providers")]
6340 #[test]
6341 fn test_agent_capabilities_with_providers() {
6342 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6343
6344 let json = serde_json::to_value(&caps).unwrap();
6345 assert_eq!(json["providers"], json!({}));
6346
6347 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6348 assert!(deserialized.providers.is_some());
6349 }
6350
6351 #[test]
6352 fn prompt_request_rejects_malformed_content_block() {
6353 use serde_json::json;
6354
6355 assert!(
6356 serde_json::from_value::<PromptRequest>(json!({
6357 "sessionId": "sess-1",
6358 "prompt": [{"type": "text"}]
6359 }))
6360 .is_err()
6361 );
6362 }
6363
6364 #[test]
6365 fn prompt_request_rejects_non_array_prompt() {
6366 use serde_json::json;
6367
6368 assert!(
6369 serde_json::from_value::<PromptRequest>(json!({
6370 "sessionId": "sess-1",
6371 "prompt": "hello"
6372 }))
6373 .is_err()
6374 );
6375 }
6376
6377 fn assert_session_setup_lists_are_strict<T>(base: &serde_json::Value)
6378 where
6379 T: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
6380 {
6381 let name = std::any::type_name::<T>();
6382 let with = |field: &str, value: serde_json::Value| {
6383 let mut request = base.clone();
6384 request[field] = value;
6385 serde_json::from_value::<T>(request)
6386 };
6387
6388 for (field, value) in [
6389 (
6391 "mcpServers",
6392 json!([
6393 {"name": "github", "command": "/usr/bin/gh-mcp", "args": [], "env": [{"name": "GITHUB_TOKEN", "value": null}]},
6394 {"name": "fs", "command": "/usr/bin/fs-mcp", "args": [], "env": []}
6395 ]),
6396 ),
6397 ("mcpServers", json!({"name": "fs"})),
6398 ("additionalDirectories", json!(["/repo/lib", 42])),
6399 ("additionalDirectories", json!("/repo/lib")),
6400 ] {
6401 assert!(
6402 with(field, value.clone()).is_err(),
6403 "{name}.{field}: {value}"
6404 );
6405 }
6406
6407 let empty = serde_json::from_value::<T>(base.clone()).unwrap();
6408 for field in ["mcpServers", "additionalDirectories"] {
6409 assert_eq!(
6410 with(field, serde_json::Value::Null).unwrap(),
6411 empty,
6412 "{name}.{field}"
6413 );
6414 }
6415 }
6416
6417 #[test]
6418 fn session_setup_requests_reject_malformed_mcp_servers_and_directories() {
6419 assert_session_setup_lists_are_strict::<NewSessionRequest>(&json!({
6420 "cwd": "/repo",
6421 "mcpServers": []
6422 }));
6423 assert_session_setup_lists_are_strict::<LoadSessionRequest>(&json!({
6424 "sessionId": "sess-1",
6425 "cwd": "/repo",
6426 "mcpServers": []
6427 }));
6428 assert_session_setup_lists_are_strict::<ResumeSessionRequest>(&json!({
6429 "sessionId": "sess-1",
6430 "cwd": "/repo"
6431 }));
6432 #[cfg(feature = "unstable_session_fork")]
6433 assert_session_setup_lists_are_strict::<ForkSessionRequest>(&json!({
6434 "sessionId": "sess-1",
6435 "cwd": "/repo"
6436 }));
6437 }
6438
6439 #[test]
6440 fn mcp_server_lists_treat_null_as_empty() {
6441 let servers: Vec<McpServer> = serde_json::from_value(json!([
6442 {"name": "fs", "command": "/usr/bin/fs-mcp", "args": null, "env": null},
6443 {"type": "http", "name": "api", "url": "https://example.com/mcp", "headers": null},
6444 {"type": "sse", "name": "events", "url": "https://example.com/sse", "headers": null}
6445 ]))
6446 .unwrap();
6447
6448 assert_eq!(
6449 servers,
6450 vec![
6451 McpServer::Stdio(McpServerStdio::new("fs", "/usr/bin/fs-mcp")),
6452 McpServer::Http(McpServerHttp::new("api", "https://example.com/mcp")),
6453 McpServer::Sse(McpServerSse::new("events", "https://example.com/sse")),
6454 ]
6455 );
6456 }
6457
6458 #[test]
6459 fn terminal_auth_methods_reject_malformed_launch_config() {
6460 let response: InitializeResponse = serde_json::from_value(json!({
6464 "protocolVersion": 1,
6465 "authMethods": [
6466 {"type": "terminal", "id": "bad-args", "name": "Log in", "args": ["auth", "--port", 8123]},
6467 {"type": "terminal", "id": "bad-env", "name": "Log in", "env": {"AUTH_MODE": "device", "DEBUG": 1}},
6468 {"type": "terminal", "id": "null-config", "name": "Log in", "args": null, "env": null},
6469 {"id": "agent", "name": "Agent login"}
6470 ]
6471 }))
6472 .unwrap();
6473
6474 assert_eq!(
6475 response.auth_methods,
6476 vec![
6477 AuthMethod::Terminal(AuthMethodTerminal::new("null-config", "Log in")),
6478 AuthMethod::Agent(AuthMethodAgent::new("agent", "Agent login")),
6479 ]
6480 );
6481 assert!(
6482 serde_json::from_value::<AuthMethod>(json!({
6483 "type": "terminal",
6484 "id": "bad-args",
6485 "name": "Log in",
6486 "args": ["auth", 8123]
6487 }))
6488 .is_err()
6489 );
6490 }
6491}