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#[serde_as]
31#[skip_serializing_none]
32#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
34#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME)))]
35#[serde(rename_all = "camelCase")]
36#[non_exhaustive]
37pub struct InitializeRequest {
38 pub protocol_version: ProtocolVersion,
40 #[serde_as(deserialize_as = "DefaultOnError")]
42 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
43 #[serde(default)]
44 pub client_capabilities: ClientCapabilities,
45 #[serde_as(deserialize_as = "DefaultOnError")]
49 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
50 #[serde(default)]
51 pub client_info: Option<Implementation>,
52 #[serde_as(deserialize_as = "DefaultOnError")]
58 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
59 #[serde(default)]
60 #[serde(rename = "_meta")]
61 pub meta: Option<Meta>,
62}
63
64impl InitializeRequest {
65 #[must_use]
67 pub fn new(protocol_version: ProtocolVersion) -> Self {
68 Self {
69 protocol_version,
70 client_capabilities: ClientCapabilities::default(),
71 client_info: None,
72 meta: None,
73 }
74 }
75
76 #[must_use]
78 pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
79 self.client_capabilities = client_capabilities;
80 self
81 }
82
83 #[must_use]
85 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
86 self.client_info = client_info.into_option();
87 self
88 }
89
90 #[must_use]
96 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
97 self.meta = meta.into_option();
98 self
99 }
100}
101
102#[serde_as]
108#[skip_serializing_none]
109#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
110#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
111#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME)))]
112#[serde(rename_all = "camelCase")]
113#[non_exhaustive]
114pub struct InitializeResponse {
115 pub protocol_version: ProtocolVersion,
120 #[serde_as(deserialize_as = "DefaultOnError")]
122 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
123 #[serde(default)]
124 pub agent_capabilities: AgentCapabilities,
125 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
127 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
128 #[serde(default)]
129 pub auth_methods: Vec<AuthMethod>,
130 #[serde_as(deserialize_as = "DefaultOnError")]
134 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
135 #[serde(default)]
136 pub agent_info: Option<Implementation>,
137 #[serde_as(deserialize_as = "DefaultOnError")]
143 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
144 #[serde(default)]
145 #[serde(rename = "_meta")]
146 pub meta: Option<Meta>,
147}
148
149impl InitializeResponse {
150 #[must_use]
152 pub fn new(protocol_version: ProtocolVersion) -> Self {
153 Self {
154 protocol_version,
155 agent_capabilities: AgentCapabilities::default(),
156 auth_methods: vec![],
157 agent_info: None,
158 meta: None,
159 }
160 }
161
162 #[must_use]
164 pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
165 self.agent_capabilities = agent_capabilities;
166 self
167 }
168
169 #[must_use]
171 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
172 self.auth_methods = auth_methods;
173 self
174 }
175
176 #[must_use]
178 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
179 self.agent_info = agent_info.into_option();
180 self
181 }
182
183 #[must_use]
189 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
190 self.meta = meta.into_option();
191 self
192 }
193}
194
195#[serde_as]
199#[skip_serializing_none]
200#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
201#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
202#[serde(rename_all = "camelCase")]
203#[non_exhaustive]
204pub struct Implementation {
205 pub name: String,
208 #[serde_as(deserialize_as = "DefaultOnError")]
213 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
214 #[serde(default)]
215 pub title: Option<String>,
216 pub version: String,
219 #[serde_as(deserialize_as = "DefaultOnError")]
225 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
226 #[serde(default)]
227 #[serde(rename = "_meta")]
228 pub meta: Option<Meta>,
229}
230
231impl Implementation {
232 #[must_use]
234 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
235 Self {
236 name: name.into(),
237 title: None,
238 version: version.into(),
239 meta: None,
240 }
241 }
242
243 #[must_use]
248 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
249 self.title = title.into_option();
250 self
251 }
252
253 #[must_use]
259 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
260 self.meta = meta.into_option();
261 self
262 }
263}
264
265#[serde_as]
271#[skip_serializing_none]
272#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
273#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
274#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME)))]
275#[serde(rename_all = "camelCase")]
276#[non_exhaustive]
277pub struct AuthenticateRequest {
278 pub method_id: AuthMethodId,
281 #[serde_as(deserialize_as = "DefaultOnError")]
287 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
288 #[serde(default)]
289 #[serde(rename = "_meta")]
290 pub meta: Option<Meta>,
291}
292
293impl AuthenticateRequest {
294 #[must_use]
296 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
297 Self {
298 method_id: method_id.into(),
299 meta: None,
300 }
301 }
302
303 #[must_use]
309 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
310 self.meta = meta.into_option();
311 self
312 }
313}
314
315crate::serde_util::default_on_null! {
316 #[serde_as]
318 #[skip_serializing_none]
319 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
320 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
321 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME)))]
322 #[serde(rename_all = "camelCase")]
323 #[non_exhaustive]
324 pub struct AuthenticateResponse {
325 #[serde_as(deserialize_as = "DefaultOnError")]
331 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
332 #[serde(default)]
333 #[serde(rename = "_meta")]
334 pub meta: Option<Meta>,
335 }
336}
337
338impl AuthenticateResponse {
339 #[must_use]
341 pub fn new() -> Self {
342 Self::default()
343 }
344
345 #[must_use]
351 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
352 self.meta = meta.into_option();
353 self
354 }
355}
356
357crate::serde_util::default_on_null! {
360 #[serde_as]
364 #[skip_serializing_none]
365 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
366 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
367 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME)))]
368 #[serde(rename_all = "camelCase")]
369 #[non_exhaustive]
370 pub struct LogoutRequest {
371 #[serde_as(deserialize_as = "DefaultOnError")]
377 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
378 #[serde(default)]
379 #[serde(rename = "_meta")]
380 pub meta: Option<Meta>,
381 }
382}
383
384impl LogoutRequest {
385 #[must_use]
387 pub fn new() -> Self {
388 Self::default()
389 }
390
391 #[must_use]
397 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
398 self.meta = meta.into_option();
399 self
400 }
401}
402
403crate::serde_util::default_on_null! {
404 #[serde_as]
406 #[skip_serializing_none]
407 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
408 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
409 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME)))]
410 #[serde(rename_all = "camelCase")]
411 #[non_exhaustive]
412 pub struct LogoutResponse {
413 #[serde_as(deserialize_as = "DefaultOnError")]
419 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
420 #[serde(default)]
421 #[serde(rename = "_meta")]
422 pub meta: Option<Meta>,
423 }
424}
425
426impl LogoutResponse {
427 #[must_use]
429 pub fn new() -> Self {
430 Self::default()
431 }
432
433 #[must_use]
439 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
440 self.meta = meta.into_option();
441 self
442 }
443}
444
445#[serde_as]
447#[skip_serializing_none]
448#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
449#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
450#[serde(rename_all = "camelCase")]
451#[non_exhaustive]
452pub struct AgentAuthCapabilities {
453 #[serde_as(deserialize_as = "DefaultOnError")]
458 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
459 #[serde(default)]
460 pub logout: Option<LogoutCapabilities>,
461 #[serde_as(deserialize_as = "DefaultOnError")]
467 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
468 #[serde(default)]
469 #[serde(rename = "_meta")]
470 pub meta: Option<Meta>,
471}
472
473impl AgentAuthCapabilities {
474 #[must_use]
476 pub fn new() -> Self {
477 Self::default()
478 }
479
480 #[must_use]
482 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
483 self.logout = logout.into_option();
484 self
485 }
486
487 #[must_use]
493 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
494 self.meta = meta.into_option();
495 self
496 }
497}
498
499#[serde_as]
503#[skip_serializing_none]
504#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
505#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
506#[non_exhaustive]
507pub struct LogoutCapabilities {
508 #[serde_as(deserialize_as = "DefaultOnError")]
514 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
515 #[serde(default)]
516 #[serde(rename = "_meta")]
517 pub meta: Option<Meta>,
518}
519
520impl LogoutCapabilities {
521 #[must_use]
523 pub fn new() -> Self {
524 Self::default()
525 }
526
527 #[must_use]
533 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
534 self.meta = meta.into_option();
535 self
536 }
537}
538
539#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
541#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
542#[serde(transparent)]
543#[from(Arc<str>, String, &'static str)]
544#[non_exhaustive]
545pub struct AuthMethodId(pub Arc<str>);
546
547impl AuthMethodId {
548 #[must_use]
550 pub fn new(id: impl Into<Arc<str>>) -> Self {
551 Self(id.into())
552 }
553}
554
555#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
560#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
561#[serde(tag = "type", rename_all = "snake_case")]
562#[non_exhaustive]
563pub enum AuthMethod {
564 Terminal(AuthMethodTerminal),
567 #[serde(untagged, deserialize_with = "deserialize_agent_auth_method_fallback")]
571 Agent(AuthMethodAgent),
572}
573
574fn deserialize_agent_auth_method_fallback<'de, D>(
579 deserializer: D,
580) -> Result<AuthMethodAgent, D::Error>
581where
582 D: serde::Deserializer<'de>,
583{
584 let value = serde_json::Value::deserialize(deserializer)?;
585 if value.get("type").and_then(serde_json::Value::as_str) == Some("terminal") {
586 return Err(serde::de::Error::custom(
587 "known authentication method `terminal` did not match its schema",
588 ));
589 }
590 AuthMethodAgent::deserialize(value).map_err(serde::de::Error::custom)
591}
592
593impl AuthMethod {
594 #[must_use]
596 pub fn id(&self) -> &AuthMethodId {
597 match self {
598 Self::Agent(a) => &a.id,
599 Self::Terminal(t) => &t.id,
600 }
601 }
602
603 #[must_use]
605 pub fn name(&self) -> &str {
606 match self {
607 Self::Agent(a) => &a.name,
608 Self::Terminal(t) => &t.name,
609 }
610 }
611
612 #[must_use]
614 pub fn description(&self) -> Option<&str> {
615 match self {
616 Self::Agent(a) => a.description.as_deref(),
617 Self::Terminal(t) => t.description.as_deref(),
618 }
619 }
620
621 #[must_use]
627 pub fn meta(&self) -> Option<&Meta> {
628 match self {
629 Self::Agent(a) => a.meta.as_ref(),
630 Self::Terminal(t) => t.meta.as_ref(),
631 }
632 }
633}
634
635#[serde_as]
639#[skip_serializing_none]
640#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
641#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
642#[serde(rename_all = "camelCase")]
643#[non_exhaustive]
644pub struct AuthMethodAgent {
645 pub id: AuthMethodId,
647 pub name: String,
649 #[serde_as(deserialize_as = "DefaultOnError")]
651 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
652 #[serde(default)]
653 pub description: Option<String>,
654 #[serde_as(deserialize_as = "DefaultOnError")]
660 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
661 #[serde(default)]
662 #[serde(rename = "_meta")]
663 pub meta: Option<Meta>,
664}
665
666impl AuthMethodAgent {
667 #[must_use]
669 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
670 Self {
671 id: id.into(),
672 name: name.into(),
673 description: None,
674 meta: None,
675 }
676 }
677
678 #[must_use]
680 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
681 self.description = description.into_option();
682 self
683 }
684
685 #[must_use]
691 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
692 self.meta = meta.into_option();
693 self
694 }
695}
696
697#[serde_as]
705#[skip_serializing_none]
706#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
707#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
708#[serde(rename_all = "camelCase")]
709#[non_exhaustive]
710pub struct AuthMethodTerminal {
711 pub id: AuthMethodId,
713 pub name: String,
715 #[serde_as(deserialize_as = "DefaultOnError")]
717 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
718 #[serde(default)]
719 pub description: Option<String>,
720 #[serde_as(deserialize_as = "DefaultOnNull")]
722 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
723 #[serde(default, skip_serializing_if = "Vec::is_empty")]
724 pub args: Vec<String>,
725 #[serde_as(deserialize_as = "DefaultOnNull")]
728 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
729 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
730 pub env: HashMap<String, String>,
731 #[serde_as(deserialize_as = "DefaultOnError")]
737 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
738 #[serde(default)]
739 #[serde(rename = "_meta")]
740 pub meta: Option<Meta>,
741}
742
743impl AuthMethodTerminal {
744 #[must_use]
746 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
747 Self {
748 id: id.into(),
749 name: name.into(),
750 description: None,
751 args: Vec::new(),
752 env: HashMap::new(),
753 meta: None,
754 }
755 }
756
757 #[must_use]
759 pub fn args(mut self, args: Vec<String>) -> Self {
760 self.args = args;
761 self
762 }
763
764 #[must_use]
767 pub fn env(mut self, env: HashMap<String, String>) -> Self {
768 self.env = env;
769 self
770 }
771
772 #[must_use]
774 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
775 self.description = description.into_option();
776 self
777 }
778
779 #[must_use]
785 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
786 self.meta = meta.into_option();
787 self
788 }
789}
790
791#[serde_as]
797#[skip_serializing_none]
798#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
799#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
800#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME)))]
801#[serde(rename_all = "camelCase")]
802#[non_exhaustive]
803pub struct NewSessionRequest {
804 pub cwd: PathBuf,
806 #[serde_as(deserialize_as = "DefaultOnNull")]
812 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
813 #[serde(default, skip_serializing_if = "Vec::is_empty")]
814 pub additional_directories: Vec<PathBuf>,
815 #[serde_as(deserialize_as = "DefaultOnNull")]
817 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
818 pub mcp_servers: Vec<McpServer>,
819 #[cfg(feature = "unstable_session_system_prompt")]
829 #[serde(default)]
830 pub system_prompt: Option<SystemPrompt>,
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 #[cfg(feature = "unstable_session_system_prompt")]
852 system_prompt: None,
853 meta: None,
854 }
855 }
856
857 #[must_use]
859 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
860 self.additional_directories = additional_directories;
861 self
862 }
863
864 #[must_use]
866 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
867 self.mcp_servers = mcp_servers;
868 self
869 }
870
871 #[cfg(feature = "unstable_session_system_prompt")]
877 #[must_use]
878 pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
879 self.system_prompt = system_prompt.into_option();
880 self
881 }
882
883 #[must_use]
889 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
890 self.meta = meta.into_option();
891 self
892 }
893}
894
895#[serde_as]
899#[skip_serializing_none]
900#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
901#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
902#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME)))]
903#[serde(rename_all = "camelCase")]
904#[non_exhaustive]
905pub struct NewSessionResponse {
906 pub session_id: SessionId,
910 #[serde_as(deserialize_as = "DefaultOnError")]
914 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
915 #[serde(default)]
916 pub modes: Option<SessionModeState>,
917 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
919 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
920 #[serde(default)]
921 pub config_options: Option<Vec<SessionConfigOption>>,
922 #[serde_as(deserialize_as = "DefaultOnError")]
928 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
929 #[serde(default)]
930 #[serde(rename = "_meta")]
931 pub meta: Option<Meta>,
932}
933
934impl NewSessionResponse {
935 #[must_use]
937 pub fn new(session_id: impl Into<SessionId>) -> Self {
938 Self {
939 session_id: session_id.into(),
940 modes: None,
941 config_options: None,
942 meta: None,
943 }
944 }
945
946 #[must_use]
950 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
951 self.modes = modes.into_option();
952 self
953 }
954
955 #[must_use]
957 pub fn config_options(
958 mut self,
959 config_options: impl IntoOption<Vec<SessionConfigOption>>,
960 ) -> Self {
961 self.config_options = config_options.into_option();
962 self
963 }
964
965 #[must_use]
971 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
972 self.meta = meta.into_option();
973 self
974 }
975}
976
977#[serde_as]
985#[skip_serializing_none]
986#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
987#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
988#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME)))]
989#[serde(rename_all = "camelCase")]
990#[non_exhaustive]
991pub struct LoadSessionRequest {
992 #[serde_as(deserialize_as = "DefaultOnNull")]
994 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
995 pub mcp_servers: Vec<McpServer>,
996 pub cwd: PathBuf,
998 #[serde_as(deserialize_as = "DefaultOnNull")]
1005 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1006 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1007 pub additional_directories: Vec<PathBuf>,
1008 pub session_id: SessionId,
1010 #[cfg(feature = "unstable_session_system_prompt")]
1022 #[serde(default)]
1023 pub system_prompt: Option<SystemPrompt>,
1024 #[serde_as(deserialize_as = "DefaultOnError")]
1030 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1031 #[serde(default)]
1032 #[serde(rename = "_meta")]
1033 pub meta: Option<Meta>,
1034}
1035
1036impl LoadSessionRequest {
1037 #[must_use]
1039 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1040 Self {
1041 mcp_servers: vec![],
1042 cwd: cwd.into(),
1043 additional_directories: vec![],
1044 session_id: session_id.into(),
1045 #[cfg(feature = "unstable_session_system_prompt")]
1046 system_prompt: None,
1047 meta: None,
1048 }
1049 }
1050
1051 #[must_use]
1053 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1054 self.additional_directories = additional_directories;
1055 self
1056 }
1057
1058 #[must_use]
1060 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1061 self.mcp_servers = mcp_servers;
1062 self
1063 }
1064
1065 #[cfg(feature = "unstable_session_system_prompt")]
1071 #[must_use]
1072 pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1073 self.system_prompt = system_prompt.into_option();
1074 self
1075 }
1076
1077 #[must_use]
1083 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1084 self.meta = meta.into_option();
1085 self
1086 }
1087}
1088
1089crate::serde_util::default_on_null! {
1090 #[serde_as]
1092 #[skip_serializing_none]
1093 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1094 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1095 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME)))]
1096 #[serde(rename_all = "camelCase")]
1097 #[non_exhaustive]
1098 pub struct LoadSessionResponse {
1099 #[serde_as(deserialize_as = "DefaultOnError")]
1103 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1104 #[serde(default)]
1105 pub modes: Option<SessionModeState>,
1106 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1108 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1109 #[serde(default)]
1110 pub config_options: Option<Vec<SessionConfigOption>>,
1111 #[serde_as(deserialize_as = "DefaultOnError")]
1117 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1118 #[serde(default)]
1119 #[serde(rename = "_meta")]
1120 pub meta: Option<Meta>,
1121 }
1122}
1123
1124impl LoadSessionResponse {
1125 #[must_use]
1127 pub fn new() -> Self {
1128 Self::default()
1129 }
1130
1131 #[must_use]
1135 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1136 self.modes = modes.into_option();
1137 self
1138 }
1139
1140 #[must_use]
1142 pub fn config_options(
1143 mut self,
1144 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1145 ) -> Self {
1146 self.config_options = config_options.into_option();
1147 self
1148 }
1149
1150 #[must_use]
1156 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1157 self.meta = meta.into_option();
1158 self
1159 }
1160}
1161
1162#[cfg(feature = "unstable_session_fork")]
1175#[serde_as]
1176#[skip_serializing_none]
1177#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1178#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1179#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME)))]
1180#[serde(rename_all = "camelCase")]
1181#[non_exhaustive]
1182pub struct ForkSessionRequest {
1183 pub session_id: SessionId,
1185 pub cwd: PathBuf,
1187 #[serde_as(deserialize_as = "DefaultOnNull")]
1193 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1194 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1195 pub additional_directories: Vec<PathBuf>,
1196 #[serde_as(deserialize_as = "DefaultOnNull")]
1198 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1199 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1200 pub mcp_servers: Vec<McpServer>,
1201 #[cfg(feature = "unstable_session_system_prompt")]
1213 #[serde(default)]
1214 pub system_prompt: Option<SystemPrompt>,
1215 #[serde_as(deserialize_as = "DefaultOnError")]
1221 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1222 #[serde(default)]
1223 #[serde(rename = "_meta")]
1224 pub meta: Option<Meta>,
1225}
1226
1227#[cfg(feature = "unstable_session_fork")]
1228impl ForkSessionRequest {
1229 #[must_use]
1231 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1232 Self {
1233 session_id: session_id.into(),
1234 cwd: cwd.into(),
1235 additional_directories: vec![],
1236 mcp_servers: vec![],
1237 #[cfg(feature = "unstable_session_system_prompt")]
1238 system_prompt: None,
1239 meta: None,
1240 }
1241 }
1242
1243 #[must_use]
1245 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1246 self.additional_directories = additional_directories;
1247 self
1248 }
1249
1250 #[must_use]
1252 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1253 self.mcp_servers = mcp_servers;
1254 self
1255 }
1256
1257 #[cfg(feature = "unstable_session_system_prompt")]
1263 #[must_use]
1264 pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1265 self.system_prompt = system_prompt.into_option();
1266 self
1267 }
1268
1269 #[must_use]
1275 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1276 self.meta = meta.into_option();
1277 self
1278 }
1279}
1280
1281#[cfg(feature = "unstable_session_fork")]
1287#[serde_as]
1288#[skip_serializing_none]
1289#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1290#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1291#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME)))]
1292#[serde(rename_all = "camelCase")]
1293#[non_exhaustive]
1294pub struct ForkSessionResponse {
1295 pub session_id: SessionId,
1297 #[serde_as(deserialize_as = "DefaultOnError")]
1301 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1302 #[serde(default)]
1303 pub modes: Option<SessionModeState>,
1304 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1306 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1307 #[serde(default)]
1308 pub config_options: Option<Vec<SessionConfigOption>>,
1309 #[serde_as(deserialize_as = "DefaultOnError")]
1315 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1316 #[serde(default)]
1317 #[serde(rename = "_meta")]
1318 pub meta: Option<Meta>,
1319}
1320
1321#[cfg(feature = "unstable_session_fork")]
1322impl ForkSessionResponse {
1323 #[must_use]
1325 pub fn new(session_id: impl Into<SessionId>) -> Self {
1326 Self {
1327 session_id: session_id.into(),
1328 modes: None,
1329 config_options: None,
1330 meta: None,
1331 }
1332 }
1333
1334 #[must_use]
1338 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1339 self.modes = modes.into_option();
1340 self
1341 }
1342
1343 #[must_use]
1345 pub fn config_options(
1346 mut self,
1347 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1348 ) -> Self {
1349 self.config_options = config_options.into_option();
1350 self
1351 }
1352
1353 #[must_use]
1359 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1360 self.meta = meta.into_option();
1361 self
1362 }
1363}
1364
1365#[serde_as]
1374#[skip_serializing_none]
1375#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1376#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1377#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME)))]
1378#[serde(rename_all = "camelCase")]
1379#[non_exhaustive]
1380pub struct ResumeSessionRequest {
1381 pub session_id: SessionId,
1383 pub cwd: PathBuf,
1385 #[serde_as(deserialize_as = "DefaultOnNull")]
1392 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1393 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1394 pub additional_directories: Vec<PathBuf>,
1395 #[serde_as(deserialize_as = "DefaultOnNull")]
1397 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1398 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1399 pub mcp_servers: Vec<McpServer>,
1400 #[cfg(feature = "unstable_session_system_prompt")]
1412 #[serde(default)]
1413 pub system_prompt: Option<SystemPrompt>,
1414 #[serde_as(deserialize_as = "DefaultOnError")]
1420 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1421 #[serde(default)]
1422 #[serde(rename = "_meta")]
1423 pub meta: Option<Meta>,
1424}
1425
1426impl ResumeSessionRequest {
1427 #[must_use]
1429 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1430 Self {
1431 session_id: session_id.into(),
1432 cwd: cwd.into(),
1433 additional_directories: vec![],
1434 mcp_servers: vec![],
1435 #[cfg(feature = "unstable_session_system_prompt")]
1436 system_prompt: None,
1437 meta: None,
1438 }
1439 }
1440
1441 #[must_use]
1443 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1444 self.additional_directories = additional_directories;
1445 self
1446 }
1447
1448 #[must_use]
1450 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1451 self.mcp_servers = mcp_servers;
1452 self
1453 }
1454
1455 #[cfg(feature = "unstable_session_system_prompt")]
1461 #[must_use]
1462 pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1463 self.system_prompt = system_prompt.into_option();
1464 self
1465 }
1466
1467 #[must_use]
1473 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1474 self.meta = meta.into_option();
1475 self
1476 }
1477}
1478
1479crate::serde_util::default_on_null! {
1480 #[serde_as]
1482 #[skip_serializing_none]
1483 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1484 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1485 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME)))]
1486 #[serde(rename_all = "camelCase")]
1487 #[non_exhaustive]
1488 pub struct ResumeSessionResponse {
1489 #[serde_as(deserialize_as = "DefaultOnError")]
1493 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1494 #[serde(default)]
1495 pub modes: Option<SessionModeState>,
1496 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1498 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1499 #[serde(default)]
1500 pub config_options: Option<Vec<SessionConfigOption>>,
1501 #[serde_as(deserialize_as = "DefaultOnError")]
1507 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1508 #[serde(default)]
1509 #[serde(rename = "_meta")]
1510 pub meta: Option<Meta>,
1511 }
1512}
1513
1514impl ResumeSessionResponse {
1515 #[must_use]
1517 pub fn new() -> Self {
1518 Self::default()
1519 }
1520
1521 #[must_use]
1525 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1526 self.modes = modes.into_option();
1527 self
1528 }
1529
1530 #[must_use]
1532 pub fn config_options(
1533 mut self,
1534 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1535 ) -> Self {
1536 self.config_options = config_options.into_option();
1537 self
1538 }
1539
1540 #[must_use]
1546 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1547 self.meta = meta.into_option();
1548 self
1549 }
1550}
1551
1552#[serde_as]
1562#[skip_serializing_none]
1563#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1564#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1565#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME)))]
1566#[serde(rename_all = "camelCase")]
1567#[non_exhaustive]
1568pub struct CloseSessionRequest {
1569 pub session_id: SessionId,
1571 #[serde_as(deserialize_as = "DefaultOnError")]
1577 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1578 #[serde(default)]
1579 #[serde(rename = "_meta")]
1580 pub meta: Option<Meta>,
1581}
1582
1583impl CloseSessionRequest {
1584 #[must_use]
1586 pub fn new(session_id: impl Into<SessionId>) -> Self {
1587 Self {
1588 session_id: session_id.into(),
1589 meta: None,
1590 }
1591 }
1592
1593 #[must_use]
1599 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1600 self.meta = meta.into_option();
1601 self
1602 }
1603}
1604
1605crate::serde_util::default_on_null! {
1606 #[serde_as]
1608 #[skip_serializing_none]
1609 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1610 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1611 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME)))]
1612 #[serde(rename_all = "camelCase")]
1613 #[non_exhaustive]
1614 pub struct CloseSessionResponse {
1615 #[serde_as(deserialize_as = "DefaultOnError")]
1621 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1622 #[serde(default)]
1623 #[serde(rename = "_meta")]
1624 pub meta: Option<Meta>,
1625 }
1626}
1627
1628impl CloseSessionResponse {
1629 #[must_use]
1631 pub fn new() -> Self {
1632 Self::default()
1633 }
1634
1635 #[must_use]
1641 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1642 self.meta = meta.into_option();
1643 self
1644 }
1645}
1646
1647crate::serde_util::default_on_null! {
1650 #[serde_as]
1654 #[skip_serializing_none]
1655 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1656 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1657 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME)))]
1658 #[serde(rename_all = "camelCase")]
1659 #[non_exhaustive]
1660 pub struct ListSessionsRequest {
1661 #[serde(default)]
1663 pub cwd: Option<PathBuf>,
1664 #[serde(default)]
1666 pub cursor: Option<String>,
1667 #[serde_as(deserialize_as = "DefaultOnError")]
1673 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1674 #[serde(default)]
1675 #[serde(rename = "_meta")]
1676 pub meta: Option<Meta>,
1677 }
1678}
1679
1680impl ListSessionsRequest {
1681 #[must_use]
1683 pub fn new() -> Self {
1684 Self::default()
1685 }
1686
1687 #[must_use]
1689 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1690 self.cwd = cwd.into_option();
1691 self
1692 }
1693
1694 #[must_use]
1696 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1697 self.cursor = cursor.into_option();
1698 self
1699 }
1700
1701 #[must_use]
1707 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1708 self.meta = meta.into_option();
1709 self
1710 }
1711}
1712
1713#[serde_as]
1715#[skip_serializing_none]
1716#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1717#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1718#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME)))]
1719#[serde(rename_all = "camelCase")]
1720#[non_exhaustive]
1721pub struct ListSessionsResponse {
1722 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1724 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1725 pub sessions: Vec<SessionInfo>,
1726 #[serde_as(deserialize_as = "DefaultOnError")]
1729 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1730 #[serde(default)]
1731 pub next_cursor: Option<String>,
1732 #[serde_as(deserialize_as = "DefaultOnError")]
1738 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1739 #[serde(default)]
1740 #[serde(rename = "_meta")]
1741 pub meta: Option<Meta>,
1742}
1743
1744impl ListSessionsResponse {
1745 #[must_use]
1747 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1748 Self {
1749 sessions,
1750 next_cursor: None,
1751 meta: None,
1752 }
1753 }
1754
1755 #[must_use]
1757 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1758 self.next_cursor = next_cursor.into_option();
1759 self
1760 }
1761
1762 #[must_use]
1768 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1769 self.meta = meta.into_option();
1770 self
1771 }
1772}
1773
1774#[serde_as]
1780#[skip_serializing_none]
1781#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1782#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1783#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME)))]
1784#[serde(rename_all = "camelCase")]
1785#[non_exhaustive]
1786pub struct DeleteSessionRequest {
1787 pub session_id: SessionId,
1789 #[serde_as(deserialize_as = "DefaultOnError")]
1795 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1796 #[serde(default)]
1797 #[serde(rename = "_meta")]
1798 pub meta: Option<Meta>,
1799}
1800
1801impl DeleteSessionRequest {
1802 #[must_use]
1804 pub fn new(session_id: impl Into<SessionId>) -> Self {
1805 Self {
1806 session_id: session_id.into(),
1807 meta: None,
1808 }
1809 }
1810
1811 #[must_use]
1817 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1818 self.meta = meta.into_option();
1819 self
1820 }
1821}
1822
1823crate::serde_util::default_on_null! {
1824 #[serde_as]
1826 #[skip_serializing_none]
1827 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1828 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1829 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME)))]
1830 #[serde(rename_all = "camelCase")]
1831 #[non_exhaustive]
1832 pub struct DeleteSessionResponse {
1833 #[serde_as(deserialize_as = "DefaultOnError")]
1839 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1840 #[serde(default)]
1841 #[serde(rename = "_meta")]
1842 pub meta: Option<Meta>,
1843 }
1844}
1845
1846impl DeleteSessionResponse {
1847 #[must_use]
1849 pub fn new() -> Self {
1850 Self::default()
1851 }
1852
1853 #[must_use]
1859 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1860 self.meta = meta.into_option();
1861 self
1862 }
1863}
1864
1865#[serde_as]
1867#[skip_serializing_none]
1868#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1869#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1870#[serde(rename_all = "camelCase")]
1871#[non_exhaustive]
1872pub struct SessionInfo {
1873 pub session_id: SessionId,
1875 pub cwd: PathBuf,
1877 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1883 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1884 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1885 pub additional_directories: Vec<PathBuf>,
1886
1887 #[serde_as(deserialize_as = "DefaultOnError")]
1889 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1890 #[serde(default)]
1891 pub title: Option<String>,
1892 #[serde_as(deserialize_as = "DefaultOnError")]
1894 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1895 #[serde(default)]
1896 pub updated_at: Option<String>,
1897 #[serde_as(deserialize_as = "DefaultOnError")]
1903 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1904 #[serde(default)]
1905 #[serde(rename = "_meta")]
1906 pub meta: Option<Meta>,
1907}
1908
1909impl SessionInfo {
1910 #[must_use]
1912 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1913 Self {
1914 session_id: session_id.into(),
1915 cwd: cwd.into(),
1916 additional_directories: vec![],
1917 title: None,
1918 updated_at: None,
1919 meta: None,
1920 }
1921 }
1922
1923 #[must_use]
1925 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1926 self.additional_directories = additional_directories;
1927 self
1928 }
1929
1930 #[must_use]
1932 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1933 self.title = title.into_option();
1934 self
1935 }
1936
1937 #[must_use]
1939 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1940 self.updated_at = updated_at.into_option();
1941 self
1942 }
1943
1944 #[must_use]
1950 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1951 self.meta = meta.into_option();
1952 self
1953 }
1954}
1955
1956#[serde_as]
1960#[skip_serializing_none]
1961#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1962#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1963#[serde(rename_all = "camelCase")]
1964#[non_exhaustive]
1965pub struct SessionModeState {
1966 pub current_mode_id: SessionModeId,
1968 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1970 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1971 pub available_modes: Vec<SessionMode>,
1972 #[serde_as(deserialize_as = "DefaultOnError")]
1978 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1979 #[serde(default)]
1980 #[serde(rename = "_meta")]
1981 pub meta: Option<Meta>,
1982}
1983
1984impl SessionModeState {
1985 #[must_use]
1987 pub fn new(
1988 current_mode_id: impl Into<SessionModeId>,
1989 available_modes: Vec<SessionMode>,
1990 ) -> Self {
1991 Self {
1992 current_mode_id: current_mode_id.into(),
1993 available_modes,
1994 meta: None,
1995 }
1996 }
1997
1998 #[must_use]
2004 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2005 self.meta = meta.into_option();
2006 self
2007 }
2008}
2009
2010#[serde_as]
2014#[skip_serializing_none]
2015#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2016#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2017#[serde(rename_all = "camelCase")]
2018#[non_exhaustive]
2019pub struct SessionMode {
2020 pub id: SessionModeId,
2022 pub name: String,
2024 #[serde_as(deserialize_as = "DefaultOnError")]
2026 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2027 #[serde(default)]
2028 pub description: Option<String>,
2029 #[serde_as(deserialize_as = "DefaultOnError")]
2035 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2036 #[serde(default)]
2037 #[serde(rename = "_meta")]
2038 pub meta: Option<Meta>,
2039}
2040
2041impl SessionMode {
2042 #[must_use]
2044 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
2045 Self {
2046 id: id.into(),
2047 name: name.into(),
2048 description: None,
2049 meta: None,
2050 }
2051 }
2052
2053 #[must_use]
2055 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2056 self.description = description.into_option();
2057 self
2058 }
2059
2060 #[must_use]
2066 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2067 self.meta = meta.into_option();
2068 self
2069 }
2070}
2071
2072#[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 SessionModeId(pub Arc<str>);
2079
2080impl SessionModeId {
2081 #[must_use]
2083 pub fn new(id: impl Into<Arc<str>>) -> Self {
2084 Self(id.into())
2085 }
2086}
2087
2088#[serde_as]
2090#[skip_serializing_none]
2091#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2092#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2093#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME)))]
2094#[serde(rename_all = "camelCase")]
2095#[non_exhaustive]
2096pub struct SetSessionModeRequest {
2097 pub session_id: SessionId,
2099 pub mode_id: SessionModeId,
2101 #[serde_as(deserialize_as = "DefaultOnError")]
2107 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2108 #[serde(default)]
2109 #[serde(rename = "_meta")]
2110 pub meta: Option<Meta>,
2111}
2112
2113impl SetSessionModeRequest {
2114 #[must_use]
2116 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
2117 Self {
2118 session_id: session_id.into(),
2119 mode_id: mode_id.into(),
2120 meta: None,
2121 }
2122 }
2123
2124 #[must_use]
2126 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2127 self.meta = meta.into_option();
2128 self
2129 }
2130}
2131
2132crate::serde_util::default_on_null! {
2133 #[serde_as]
2135 #[skip_serializing_none]
2136 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2137 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
2138 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME)))]
2139 #[serde(rename_all = "camelCase")]
2140 #[non_exhaustive]
2141 pub struct SetSessionModeResponse {
2142 #[serde_as(deserialize_as = "DefaultOnError")]
2148 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2149 #[serde(default)]
2150 #[serde(rename = "_meta")]
2151 pub meta: Option<Meta>,
2152 }
2153}
2154
2155impl SetSessionModeResponse {
2156 #[must_use]
2158 pub fn new() -> Self {
2159 Self::default()
2160 }
2161
2162 #[must_use]
2168 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2169 self.meta = meta.into_option();
2170 self
2171 }
2172}
2173
2174#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2178#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2179#[serde(transparent)]
2180#[from(Arc<str>, String, &'static str)]
2181#[non_exhaustive]
2182pub struct SessionConfigId(pub Arc<str>);
2183
2184impl SessionConfigId {
2185 #[must_use]
2187 pub fn new(id: impl Into<Arc<str>>) -> Self {
2188 Self(id.into())
2189 }
2190}
2191
2192#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2194#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2195#[serde(transparent)]
2196#[from(Arc<str>, String, &'static str)]
2197#[non_exhaustive]
2198pub struct SessionConfigValueId(pub Arc<str>);
2199
2200impl SessionConfigValueId {
2201 #[must_use]
2203 pub fn new(id: impl Into<Arc<str>>) -> Self {
2204 Self(id.into())
2205 }
2206}
2207
2208#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2210#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2211#[serde(transparent)]
2212#[from(Arc<str>, String, &'static str)]
2213#[non_exhaustive]
2214pub struct SessionConfigGroupId(pub Arc<str>);
2215
2216impl SessionConfigGroupId {
2217 #[must_use]
2219 pub fn new(id: impl Into<Arc<str>>) -> Self {
2220 Self(id.into())
2221 }
2222}
2223
2224#[serde_as]
2226#[skip_serializing_none]
2227#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2228#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2229#[serde(rename_all = "camelCase")]
2230#[non_exhaustive]
2231pub struct SessionConfigSelectOption {
2232 pub value: SessionConfigValueId,
2234 pub name: String,
2236 #[serde_as(deserialize_as = "DefaultOnError")]
2238 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2239 #[serde(default)]
2240 pub description: Option<String>,
2241 #[serde_as(deserialize_as = "DefaultOnError")]
2247 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2248 #[serde(default)]
2249 #[serde(rename = "_meta")]
2250 pub meta: Option<Meta>,
2251}
2252
2253impl SessionConfigSelectOption {
2254 #[must_use]
2256 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2257 Self {
2258 value: value.into(),
2259 name: name.into(),
2260 description: None,
2261 meta: None,
2262 }
2263 }
2264
2265 #[must_use]
2267 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2268 self.description = description.into_option();
2269 self
2270 }
2271
2272 #[must_use]
2278 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2279 self.meta = meta.into_option();
2280 self
2281 }
2282}
2283
2284#[serde_as]
2286#[skip_serializing_none]
2287#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2288#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2289#[serde(rename_all = "camelCase")]
2290#[non_exhaustive]
2291pub struct SessionConfigSelectGroup {
2292 pub group: SessionConfigGroupId,
2294 pub name: String,
2296 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2298 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2299 pub options: Vec<SessionConfigSelectOption>,
2300 #[serde_as(deserialize_as = "DefaultOnError")]
2306 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2307 #[serde(default)]
2308 #[serde(rename = "_meta")]
2309 pub meta: Option<Meta>,
2310}
2311
2312impl SessionConfigSelectGroup {
2313 #[must_use]
2315 pub fn new(
2316 group: impl Into<SessionConfigGroupId>,
2317 name: impl Into<String>,
2318 options: Vec<SessionConfigSelectOption>,
2319 ) -> Self {
2320 Self {
2321 group: group.into(),
2322 name: name.into(),
2323 options,
2324 meta: None,
2325 }
2326 }
2327
2328 #[must_use]
2334 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2335 self.meta = meta.into_option();
2336 self
2337 }
2338}
2339
2340#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2342#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2343#[serde(untagged)]
2344#[non_exhaustive]
2345pub enum SessionConfigSelectOptions {
2346 Ungrouped(Vec<SessionConfigSelectOption>),
2348 Grouped(Vec<SessionConfigSelectGroup>),
2350}
2351
2352impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2353 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2354 SessionConfigSelectOptions::Ungrouped(options)
2355 }
2356}
2357
2358impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2359 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2360 SessionConfigSelectOptions::Grouped(groups)
2361 }
2362}
2363
2364#[skip_serializing_none]
2366#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2367#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2368#[serde(rename_all = "camelCase")]
2369#[non_exhaustive]
2370pub struct SessionConfigSelect {
2371 pub current_value: SessionConfigValueId,
2373 pub options: SessionConfigSelectOptions,
2375}
2376
2377impl SessionConfigSelect {
2378 #[must_use]
2380 pub fn new(
2381 current_value: impl Into<SessionConfigValueId>,
2382 options: impl Into<SessionConfigSelectOptions>,
2383 ) -> Self {
2384 Self {
2385 current_value: current_value.into(),
2386 options: options.into(),
2387 }
2388 }
2389}
2390
2391#[skip_serializing_none]
2393#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2394#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2395#[serde(rename_all = "camelCase")]
2396#[non_exhaustive]
2397pub struct SessionConfigBoolean {
2398 pub current_value: bool,
2400}
2401
2402impl SessionConfigBoolean {
2403 #[must_use]
2405 pub fn new(current_value: bool) -> Self {
2406 Self { current_value }
2407 }
2408}
2409
2410#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2420#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2421#[serde(rename_all = "snake_case")]
2422#[non_exhaustive]
2423pub enum SessionConfigOptionCategory {
2424 Mode,
2426 Model,
2428 ModelConfig,
2430 ThoughtLevel,
2432 #[serde(untagged)]
2434 Other(String),
2435}
2436
2437#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2439#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2440#[serde(tag = "type", rename_all = "snake_case")]
2441#[cfg_attr(feature = "schemars", schemars(extend("discriminator" = {"propertyName": "type"})))]
2442#[non_exhaustive]
2443pub enum SessionConfigKind {
2444 Select(SessionConfigSelect),
2446 Boolean(SessionConfigBoolean),
2448}
2449
2450#[serde_as]
2452#[skip_serializing_none]
2453#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2454#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2455#[serde(rename_all = "camelCase")]
2456#[non_exhaustive]
2457pub struct SessionConfigOption {
2458 pub id: SessionConfigId,
2460 pub name: String,
2462 #[serde_as(deserialize_as = "DefaultOnError")]
2464 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2465 #[serde(default)]
2466 pub description: Option<String>,
2467 #[serde_as(deserialize_as = "DefaultOnError")]
2469 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2470 #[serde(default)]
2471 pub category: Option<SessionConfigOptionCategory>,
2472 #[serde(flatten)]
2474 pub kind: SessionConfigKind,
2475 #[serde_as(deserialize_as = "DefaultOnError")]
2481 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2482 #[serde(default)]
2483 #[serde(rename = "_meta")]
2484 pub meta: Option<Meta>,
2485}
2486
2487impl SessionConfigOption {
2488 #[must_use]
2490 pub fn new(
2491 id: impl Into<SessionConfigId>,
2492 name: impl Into<String>,
2493 kind: SessionConfigKind,
2494 ) -> Self {
2495 Self {
2496 id: id.into(),
2497 name: name.into(),
2498 description: None,
2499 category: None,
2500 kind,
2501 meta: None,
2502 }
2503 }
2504
2505 #[must_use]
2507 pub fn select(
2508 id: impl Into<SessionConfigId>,
2509 name: impl Into<String>,
2510 current_value: impl Into<SessionConfigValueId>,
2511 options: impl Into<SessionConfigSelectOptions>,
2512 ) -> Self {
2513 Self::new(
2514 id,
2515 name,
2516 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2517 )
2518 }
2519
2520 #[must_use]
2522 pub fn boolean(
2523 id: impl Into<SessionConfigId>,
2524 name: impl Into<String>,
2525 current_value: bool,
2526 ) -> Self {
2527 Self::new(
2528 id,
2529 name,
2530 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2531 )
2532 }
2533
2534 #[must_use]
2536 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2537 self.description = description.into_option();
2538 self
2539 }
2540
2541 #[must_use]
2543 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2544 self.category = category.into_option();
2545 self
2546 }
2547
2548 #[must_use]
2554 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2555 self.meta = meta.into_option();
2556 self
2557 }
2558}
2559
2560#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2571#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2572#[serde(tag = "type", rename_all = "snake_case")]
2573#[non_exhaustive]
2574pub enum SessionConfigOptionValue {
2575 Boolean {
2577 value: bool,
2579 },
2580 #[serde(untagged)]
2586 ValueId {
2587 value: SessionConfigValueId,
2589 },
2590}
2591
2592impl SessionConfigOptionValue {
2593 #[must_use]
2595 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2596 Self::ValueId { value: id.into() }
2597 }
2598
2599 #[must_use]
2601 pub fn boolean(val: bool) -> Self {
2602 Self::Boolean { value: val }
2603 }
2604
2605 #[must_use]
2608 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2609 match self {
2610 Self::ValueId { value } => Some(value),
2611 _ => None,
2612 }
2613 }
2614
2615 #[must_use]
2617 pub fn as_bool(&self) -> Option<bool> {
2618 match self {
2619 Self::Boolean { value } => Some(*value),
2620 _ => None,
2621 }
2622 }
2623}
2624
2625impl From<SessionConfigValueId> for SessionConfigOptionValue {
2626 fn from(value: SessionConfigValueId) -> Self {
2627 Self::ValueId { value }
2628 }
2629}
2630
2631impl From<bool> for SessionConfigOptionValue {
2632 fn from(value: bool) -> Self {
2633 Self::Boolean { value }
2634 }
2635}
2636
2637impl From<&str> for SessionConfigOptionValue {
2638 fn from(value: &str) -> Self {
2639 Self::ValueId {
2640 value: SessionConfigValueId::new(value),
2641 }
2642 }
2643}
2644
2645#[serde_as]
2647#[skip_serializing_none]
2648#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2649#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2650#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME)))]
2651#[serde(rename_all = "camelCase")]
2652#[non_exhaustive]
2653pub struct SetSessionConfigOptionRequest {
2654 pub session_id: SessionId,
2656 pub config_id: SessionConfigId,
2658 #[serde(flatten)]
2663 pub value: SessionConfigOptionValue,
2664 #[serde_as(deserialize_as = "DefaultOnError")]
2670 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2671 #[serde(default)]
2672 #[serde(rename = "_meta")]
2673 pub meta: Option<Meta>,
2674}
2675
2676impl SetSessionConfigOptionRequest {
2677 #[must_use]
2679 pub fn new(
2680 session_id: impl Into<SessionId>,
2681 config_id: impl Into<SessionConfigId>,
2682 value: impl Into<SessionConfigOptionValue>,
2683 ) -> Self {
2684 Self {
2685 session_id: session_id.into(),
2686 config_id: config_id.into(),
2687 value: value.into(),
2688 meta: None,
2689 }
2690 }
2691
2692 #[must_use]
2698 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2699 self.meta = meta.into_option();
2700 self
2701 }
2702}
2703
2704#[serde_as]
2706#[skip_serializing_none]
2707#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2708#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2709#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME)))]
2710#[serde(rename_all = "camelCase")]
2711#[non_exhaustive]
2712pub struct SetSessionConfigOptionResponse {
2713 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2715 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2716 pub config_options: Vec<SessionConfigOption>,
2717 #[serde_as(deserialize_as = "DefaultOnError")]
2723 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2724 #[serde(default)]
2725 #[serde(rename = "_meta")]
2726 pub meta: Option<Meta>,
2727}
2728
2729impl SetSessionConfigOptionResponse {
2730 #[must_use]
2732 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2733 Self {
2734 config_options,
2735 meta: None,
2736 }
2737 }
2738
2739 #[must_use]
2745 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2746 self.meta = meta.into_option();
2747 self
2748 }
2749}
2750
2751#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2760#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2761#[serde(tag = "type", rename_all = "snake_case")]
2762#[non_exhaustive]
2763pub enum McpServer {
2764 Http(McpServerHttp),
2768 Sse(McpServerSse),
2772 #[cfg(feature = "unstable_mcp_over_acp")]
2781 Acp(McpServerAcp),
2782 #[serde(untagged)]
2786 Stdio(McpServerStdio),
2787}
2788
2789#[serde_as]
2791#[skip_serializing_none]
2792#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2793#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2794#[serde(rename_all = "camelCase")]
2795#[non_exhaustive]
2796pub struct McpServerHttp {
2797 pub name: String,
2799 pub url: String,
2801 #[serde_as(deserialize_as = "DefaultOnNull")]
2803 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
2804 pub headers: Vec<HttpHeader>,
2805 #[serde_as(deserialize_as = "DefaultOnError")]
2811 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2812 #[serde(default)]
2813 #[serde(rename = "_meta")]
2814 pub meta: Option<Meta>,
2815}
2816
2817impl McpServerHttp {
2818 #[must_use]
2820 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2821 Self {
2822 name: name.into(),
2823 url: url.into(),
2824 headers: Vec::new(),
2825 meta: None,
2826 }
2827 }
2828
2829 #[must_use]
2831 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2832 self.headers = headers;
2833 self
2834 }
2835
2836 #[must_use]
2842 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2843 self.meta = meta.into_option();
2844 self
2845 }
2846}
2847
2848#[serde_as]
2850#[skip_serializing_none]
2851#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2852#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2853#[serde(rename_all = "camelCase")]
2854#[non_exhaustive]
2855pub struct McpServerSse {
2856 pub name: String,
2858 pub url: String,
2860 #[serde_as(deserialize_as = "DefaultOnNull")]
2862 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
2863 pub headers: Vec<HttpHeader>,
2864 #[serde_as(deserialize_as = "DefaultOnError")]
2870 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2871 #[serde(default)]
2872 #[serde(rename = "_meta")]
2873 pub meta: Option<Meta>,
2874}
2875
2876impl McpServerSse {
2877 #[must_use]
2879 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2880 Self {
2881 name: name.into(),
2882 url: url.into(),
2883 headers: Vec::new(),
2884 meta: None,
2885 }
2886 }
2887
2888 #[must_use]
2890 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2891 self.headers = headers;
2892 self
2893 }
2894
2895 #[must_use]
2901 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2902 self.meta = meta.into_option();
2903 self
2904 }
2905}
2906
2907#[cfg(feature = "unstable_mcp_over_acp")]
2916#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2917#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
2918#[serde(transparent)]
2919#[from(Arc<str>, String, &'static str)]
2920#[non_exhaustive]
2921pub struct McpServerAcpId(pub Arc<str>);
2922
2923#[cfg(feature = "unstable_mcp_over_acp")]
2924impl McpServerAcpId {
2925 #[must_use]
2927 pub fn new(id: impl Into<Arc<str>>) -> Self {
2928 Self(id.into())
2929 }
2930}
2931
2932#[serde_as]
2941#[skip_serializing_none]
2942#[cfg(feature = "unstable_mcp_over_acp")]
2943#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2944#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2945#[serde(rename_all = "camelCase")]
2946#[non_exhaustive]
2947pub struct McpServerAcp {
2948 pub name: String,
2950 pub server_id: McpServerAcpId,
2955 #[serde_as(deserialize_as = "DefaultOnError")]
2961 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2962 #[serde(default)]
2963 #[serde(rename = "_meta")]
2964 pub meta: Option<Meta>,
2965}
2966
2967#[cfg(feature = "unstable_mcp_over_acp")]
2968impl McpServerAcp {
2969 #[must_use]
2971 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2972 Self {
2973 name: name.into(),
2974 server_id: id.into(),
2975 meta: None,
2976 }
2977 }
2978
2979 #[must_use]
2985 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2986 self.meta = meta.into_option();
2987 self
2988 }
2989}
2990
2991#[serde_as]
2993#[skip_serializing_none]
2994#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2995#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2996#[serde(rename_all = "camelCase")]
2997#[non_exhaustive]
2998pub struct McpServerStdio {
2999 pub name: String,
3001 pub command: PathBuf,
3003 #[serde_as(deserialize_as = "DefaultOnNull")]
3005 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
3006 pub args: Vec<String>,
3007 #[serde_as(deserialize_as = "DefaultOnNull")]
3009 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
3010 pub env: Vec<EnvVariable>,
3011 #[serde_as(deserialize_as = "DefaultOnError")]
3017 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3018 #[serde(default)]
3019 #[serde(rename = "_meta")]
3020 pub meta: Option<Meta>,
3021}
3022
3023impl McpServerStdio {
3024 #[must_use]
3026 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
3027 Self {
3028 name: name.into(),
3029 command: command.into(),
3030 args: Vec::new(),
3031 env: Vec::new(),
3032 meta: None,
3033 }
3034 }
3035
3036 #[must_use]
3038 pub fn args(mut self, args: Vec<String>) -> Self {
3039 self.args = args;
3040 self
3041 }
3042
3043 #[must_use]
3045 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
3046 self.env = env;
3047 self
3048 }
3049
3050 #[must_use]
3056 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3057 self.meta = meta.into_option();
3058 self
3059 }
3060}
3061
3062#[serde_as]
3064#[skip_serializing_none]
3065#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3066#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3067#[serde(rename_all = "camelCase")]
3068#[non_exhaustive]
3069pub struct EnvVariable {
3070 pub name: String,
3072 pub value: String,
3074 #[serde_as(deserialize_as = "DefaultOnError")]
3080 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3081 #[serde(default)]
3082 #[serde(rename = "_meta")]
3083 pub meta: Option<Meta>,
3084}
3085
3086impl EnvVariable {
3087 #[must_use]
3089 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3090 Self {
3091 name: name.into(),
3092 value: value.into(),
3093 meta: None,
3094 }
3095 }
3096
3097 #[must_use]
3103 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3104 self.meta = meta.into_option();
3105 self
3106 }
3107}
3108
3109#[serde_as]
3111#[skip_serializing_none]
3112#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3113#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3114#[serde(rename_all = "camelCase")]
3115#[non_exhaustive]
3116pub struct HttpHeader {
3117 pub name: String,
3119 pub value: String,
3121 #[serde_as(deserialize_as = "DefaultOnError")]
3127 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3128 #[serde(default)]
3129 #[serde(rename = "_meta")]
3130 pub meta: Option<Meta>,
3131}
3132
3133impl HttpHeader {
3134 #[must_use]
3136 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3137 Self {
3138 name: name.into(),
3139 value: value.into(),
3140 meta: None,
3141 }
3142 }
3143
3144 #[must_use]
3150 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3151 self.meta = meta.into_option();
3152 self
3153 }
3154}
3155
3156#[cfg(feature = "unstable_session_system_prompt")]
3170#[serde_as]
3171#[skip_serializing_none]
3172#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3173#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3174#[serde(rename_all = "camelCase")]
3175#[non_exhaustive]
3176pub struct SystemPrompt {
3177 pub mode: SystemPromptMode,
3184 pub content: Vec<ContentBlock>,
3191 #[serde_as(deserialize_as = "DefaultOnError")]
3197 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3198 #[serde(default)]
3199 #[serde(rename = "_meta")]
3200 pub meta: Option<Meta>,
3201}
3202
3203#[cfg(feature = "unstable_session_system_prompt")]
3204impl SystemPrompt {
3205 #[must_use]
3210 pub fn new(content: Vec<ContentBlock>) -> Self {
3211 Self {
3212 mode: SystemPromptMode::default(),
3213 content,
3214 meta: None,
3215 }
3216 }
3217
3218 #[must_use]
3220 pub fn mode(mut self, mode: SystemPromptMode) -> Self {
3221 self.mode = mode;
3222 self
3223 }
3224
3225 #[must_use]
3231 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3232 self.meta = meta.into_option();
3233 self
3234 }
3235}
3236
3237#[cfg(feature = "unstable_session_system_prompt")]
3247#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3248#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
3249#[serde(rename_all = "snake_case")]
3250#[non_exhaustive]
3251pub enum SystemPromptMode {
3252 #[default]
3259 Append,
3260 Override,
3269 #[serde(untagged)]
3275 Other(String),
3276}
3277
3278#[serde_as]
3286#[skip_serializing_none]
3287#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3288#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3289#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME)))]
3290#[serde(rename_all = "camelCase")]
3291#[non_exhaustive]
3292pub struct PromptRequest {
3293 pub session_id: SessionId,
3295 pub prompt: Vec<ContentBlock>,
3309 #[serde_as(deserialize_as = "DefaultOnError")]
3315 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3316 #[serde(default)]
3317 #[serde(rename = "_meta")]
3318 pub meta: Option<Meta>,
3319}
3320
3321impl PromptRequest {
3322 #[must_use]
3324 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3325 Self {
3326 session_id: session_id.into(),
3327 prompt,
3328 meta: None,
3329 }
3330 }
3331
3332 #[must_use]
3338 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3339 self.meta = meta.into_option();
3340 self
3341 }
3342}
3343
3344#[serde_as]
3348#[skip_serializing_none]
3349#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3350#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3351#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME)))]
3352#[serde(rename_all = "camelCase")]
3353#[non_exhaustive]
3354pub struct PromptResponse {
3355 pub stop_reason: StopReason,
3357 #[cfg(feature = "unstable_end_turn_token_usage")]
3363 #[serde_as(deserialize_as = "DefaultOnError")]
3364 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3365 #[serde(default)]
3366 pub usage: Option<Usage>,
3367 #[serde_as(deserialize_as = "DefaultOnError")]
3373 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3374 #[serde(default)]
3375 #[serde(rename = "_meta")]
3376 pub meta: Option<Meta>,
3377}
3378
3379impl PromptResponse {
3380 #[must_use]
3382 pub fn new(stop_reason: StopReason) -> Self {
3383 Self {
3384 stop_reason,
3385 #[cfg(feature = "unstable_end_turn_token_usage")]
3386 usage: None,
3387 meta: None,
3388 }
3389 }
3390
3391 #[cfg(feature = "unstable_end_turn_token_usage")]
3397 #[must_use]
3398 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3399 self.usage = usage.into_option();
3400 self
3401 }
3402
3403 #[must_use]
3409 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3410 self.meta = meta.into_option();
3411 self
3412 }
3413}
3414
3415#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3419#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
3420#[serde(rename_all = "snake_case")]
3421#[non_exhaustive]
3422pub enum StopReason {
3423 EndTurn,
3425 MaxTokens,
3427 MaxTurnRequests,
3430 Refusal,
3434 Cancelled,
3441}
3442
3443#[cfg(feature = "unstable_end_turn_token_usage")]
3449#[serde_as]
3450#[skip_serializing_none]
3451#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3452#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3453#[serde(rename_all = "camelCase")]
3454#[non_exhaustive]
3455pub struct Usage {
3456 pub total_tokens: u64,
3458 pub input_tokens: u64,
3460 pub output_tokens: u64,
3462 #[serde_as(deserialize_as = "DefaultOnError")]
3464 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3465 #[serde(default)]
3466 pub thought_tokens: Option<u64>,
3467 #[serde_as(deserialize_as = "DefaultOnError")]
3469 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3470 #[serde(default)]
3471 pub cached_read_tokens: Option<u64>,
3472 #[serde_as(deserialize_as = "DefaultOnError")]
3474 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3475 #[serde(default)]
3476 pub cached_write_tokens: Option<u64>,
3477 #[serde_as(deserialize_as = "DefaultOnError")]
3483 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3484 #[serde(default)]
3485 #[serde(rename = "_meta")]
3486 pub meta: Option<Meta>,
3487}
3488
3489#[cfg(feature = "unstable_end_turn_token_usage")]
3490impl Usage {
3491 #[must_use]
3493 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3494 Self {
3495 total_tokens,
3496 input_tokens,
3497 output_tokens,
3498 thought_tokens: None,
3499 cached_read_tokens: None,
3500 cached_write_tokens: None,
3501 meta: None,
3502 }
3503 }
3504
3505 #[must_use]
3507 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3508 self.thought_tokens = thought_tokens.into_option();
3509 self
3510 }
3511
3512 #[must_use]
3514 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3515 self.cached_read_tokens = cached_read_tokens.into_option();
3516 self
3517 }
3518
3519 #[must_use]
3521 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3522 self.cached_write_tokens = cached_write_tokens.into_option();
3523 self
3524 }
3525
3526 #[must_use]
3532 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3533 self.meta = meta.into_option();
3534 self
3535 }
3536}
3537
3538#[cfg(feature = "unstable_llm_providers")]
3551#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3552#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3553#[serde(rename_all = "snake_case")]
3554#[non_exhaustive]
3555#[expect(clippy::doc_markdown)]
3556pub enum LlmProtocol {
3557 Anthropic,
3559 #[serde(rename = "openai")]
3561 OpenAi,
3562 Azure,
3564 Vertex,
3566 Bedrock,
3568 #[serde(untagged)]
3570 Other(String),
3571}
3572
3573#[cfg(feature = "unstable_llm_providers")]
3579#[serde_as]
3580#[skip_serializing_none]
3581#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3582#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3583#[serde(rename_all = "camelCase")]
3584#[non_exhaustive]
3585pub struct ProviderCurrentConfig {
3586 pub api_type: LlmProtocol,
3588 pub base_url: String,
3590 #[serde_as(deserialize_as = "DefaultOnError")]
3596 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3597 #[serde(default)]
3598 #[serde(rename = "_meta")]
3599 pub meta: Option<Meta>,
3600}
3601
3602#[cfg(feature = "unstable_llm_providers")]
3603impl ProviderCurrentConfig {
3604 #[must_use]
3606 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3607 Self {
3608 api_type,
3609 base_url: base_url.into(),
3610 meta: None,
3611 }
3612 }
3613
3614 #[must_use]
3620 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3621 self.meta = meta.into_option();
3622 self
3623 }
3624}
3625
3626#[cfg(feature = "unstable_llm_providers")]
3632#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3633#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
3634#[serde(transparent)]
3635#[from(Arc<str>, String, &'static str)]
3636#[non_exhaustive]
3637pub struct ProviderId(pub Arc<str>);
3638
3639#[cfg(feature = "unstable_llm_providers")]
3640impl ProviderId {
3641 #[must_use]
3643 pub fn new(id: impl Into<Arc<str>>) -> Self {
3644 Self(id.into())
3645 }
3646}
3647
3648#[cfg(feature = "unstable_llm_providers")]
3654#[serde_as]
3655#[skip_serializing_none]
3656#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3657#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3658#[serde(rename_all = "camelCase")]
3659#[non_exhaustive]
3660pub struct ProviderInfo {
3661 pub provider_id: ProviderId,
3663 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
3665 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
3666 pub supported: Vec<LlmProtocol>,
3667 pub required: bool,
3670 #[serde(default)]
3673 pub current: Option<ProviderCurrentConfig>,
3674 #[serde_as(deserialize_as = "DefaultOnError")]
3680 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3681 #[serde(default)]
3682 #[serde(rename = "_meta")]
3683 pub meta: Option<Meta>,
3684}
3685
3686#[cfg(feature = "unstable_llm_providers")]
3687impl ProviderInfo {
3688 #[must_use]
3690 pub fn new(
3691 provider_id: impl Into<ProviderId>,
3692 supported: Vec<LlmProtocol>,
3693 required: bool,
3694 current: impl IntoOption<ProviderCurrentConfig>,
3695 ) -> Self {
3696 Self {
3697 provider_id: provider_id.into(),
3698 supported,
3699 required,
3700 current: current.into_option(),
3701 meta: None,
3702 }
3703 }
3704
3705 #[must_use]
3711 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3712 self.meta = meta.into_option();
3713 self
3714 }
3715}
3716
3717#[cfg(feature = "unstable_llm_providers")]
3718crate::serde_util::default_on_null! {
3719 #[serde_as]
3725 #[skip_serializing_none]
3726 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3727 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3728 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))]
3729 #[serde(rename_all = "camelCase")]
3730 #[non_exhaustive]
3731 pub struct ListProvidersRequest {
3732 #[serde_as(deserialize_as = "DefaultOnError")]
3738 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3739 #[serde(default)]
3740 #[serde(rename = "_meta")]
3741 pub meta: Option<Meta>,
3742 }
3743}
3744
3745#[cfg(feature = "unstable_llm_providers")]
3746impl ListProvidersRequest {
3747 #[must_use]
3749 pub fn new() -> Self {
3750 Self::default()
3751 }
3752
3753 #[must_use]
3759 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3760 self.meta = meta.into_option();
3761 self
3762 }
3763}
3764
3765#[cfg(feature = "unstable_llm_providers")]
3771#[serde_as]
3772#[skip_serializing_none]
3773#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3774#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3775#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))]
3776#[serde(rename_all = "camelCase")]
3777#[non_exhaustive]
3778pub struct ListProvidersResponse {
3779 pub providers: Vec<ProviderInfo>,
3781 #[serde_as(deserialize_as = "DefaultOnError")]
3787 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3788 #[serde(default)]
3789 #[serde(rename = "_meta")]
3790 pub meta: Option<Meta>,
3791}
3792
3793#[cfg(feature = "unstable_llm_providers")]
3794impl ListProvidersResponse {
3795 #[must_use]
3797 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3798 Self {
3799 providers,
3800 meta: None,
3801 }
3802 }
3803
3804 #[must_use]
3810 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3811 self.meta = meta.into_option();
3812 self
3813 }
3814}
3815
3816#[cfg(feature = "unstable_llm_providers")]
3824#[serde_as]
3825#[skip_serializing_none]
3826#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3827#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
3828#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))]
3829#[serde(rename_all = "camelCase")]
3830#[non_exhaustive]
3831pub struct SetProviderRequest {
3832 pub provider_id: ProviderId,
3834 pub api_type: LlmProtocol,
3836 pub base_url: String,
3838 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3841 pub headers: HashMap<String, String>,
3842 #[serde_as(deserialize_as = "DefaultOnError")]
3848 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3849 #[serde(default)]
3850 #[serde(rename = "_meta")]
3851 pub meta: Option<Meta>,
3852}
3853
3854#[cfg(feature = "unstable_llm_providers")]
3855impl SetProviderRequest {
3856 #[must_use]
3858 pub fn new(
3859 provider_id: impl Into<ProviderId>,
3860 api_type: LlmProtocol,
3861 base_url: impl Into<String>,
3862 ) -> Self {
3863 Self {
3864 provider_id: provider_id.into(),
3865 api_type,
3866 base_url: base_url.into(),
3867 headers: HashMap::new(),
3868 meta: None,
3869 }
3870 }
3871
3872 #[must_use]
3875 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3876 self.headers = headers;
3877 self
3878 }
3879
3880 #[must_use]
3886 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3887 self.meta = meta.into_option();
3888 self
3889 }
3890}
3891
3892#[cfg(feature = "unstable_llm_providers")]
3893crate::serde_util::default_on_null! {
3894 #[serde_as]
3900 #[skip_serializing_none]
3901 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3902 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3903 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))]
3904 #[serde(rename_all = "camelCase")]
3905 #[non_exhaustive]
3906 pub struct SetProviderResponse {
3907 #[serde_as(deserialize_as = "DefaultOnError")]
3913 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3914 #[serde(default)]
3915 #[serde(rename = "_meta")]
3916 pub meta: Option<Meta>,
3917 }
3918}
3919
3920#[cfg(feature = "unstable_llm_providers")]
3921impl SetProviderResponse {
3922 #[must_use]
3924 pub fn new() -> Self {
3925 Self::default()
3926 }
3927
3928 #[must_use]
3934 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3935 self.meta = meta.into_option();
3936 self
3937 }
3938}
3939
3940#[cfg(feature = "unstable_llm_providers")]
3946#[serde_as]
3947#[skip_serializing_none]
3948#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3949#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3950#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))]
3951#[serde(rename_all = "camelCase")]
3952#[non_exhaustive]
3953pub struct DisableProviderRequest {
3954 pub provider_id: ProviderId,
3956 #[serde_as(deserialize_as = "DefaultOnError")]
3962 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3963 #[serde(default)]
3964 #[serde(rename = "_meta")]
3965 pub meta: Option<Meta>,
3966}
3967
3968#[cfg(feature = "unstable_llm_providers")]
3969impl DisableProviderRequest {
3970 #[must_use]
3972 pub fn new(provider_id: impl Into<ProviderId>) -> Self {
3973 Self {
3974 provider_id: provider_id.into(),
3975 meta: None,
3976 }
3977 }
3978
3979 #[must_use]
3985 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3986 self.meta = meta.into_option();
3987 self
3988 }
3989}
3990
3991#[cfg(feature = "unstable_llm_providers")]
3992crate::serde_util::default_on_null! {
3993 #[serde_as]
3999 #[skip_serializing_none]
4000 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4001 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
4002 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))]
4003 #[serde(rename_all = "camelCase")]
4004 #[non_exhaustive]
4005 pub struct DisableProviderResponse {
4006 #[serde_as(deserialize_as = "DefaultOnError")]
4012 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4013 #[serde(default)]
4014 #[serde(rename = "_meta")]
4015 pub meta: Option<Meta>,
4016 }
4017}
4018
4019#[cfg(feature = "unstable_llm_providers")]
4020impl DisableProviderResponse {
4021 #[must_use]
4023 pub fn new() -> Self {
4024 Self::default()
4025 }
4026
4027 #[must_use]
4033 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4034 self.meta = meta.into_option();
4035 self
4036 }
4037}
4038
4039#[serde_as]
4048#[skip_serializing_none]
4049#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4050#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4051#[serde(rename_all = "camelCase")]
4052#[non_exhaustive]
4053pub struct AgentCapabilities {
4054 #[serde_as(deserialize_as = "DefaultOnError")]
4056 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4057 #[serde(default)]
4058 pub load_session: bool,
4059 #[serde_as(deserialize_as = "DefaultOnError")]
4061 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4062 #[serde(default)]
4063 pub prompt_capabilities: PromptCapabilities,
4064 #[serde_as(deserialize_as = "DefaultOnError")]
4066 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4067 #[serde(default)]
4068 pub mcp_capabilities: McpCapabilities,
4069 #[serde_as(deserialize_as = "DefaultOnError")]
4071 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4072 #[serde(default)]
4073 pub session_capabilities: SessionCapabilities,
4074 #[serde_as(deserialize_as = "DefaultOnError")]
4076 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4077 #[serde(default)]
4078 pub auth: AgentAuthCapabilities,
4079 #[cfg(feature = "unstable_llm_providers")]
4088 #[serde_as(deserialize_as = "DefaultOnError")]
4089 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4090 #[serde(default)]
4091 pub providers: Option<ProvidersCapabilities>,
4092 #[serde_as(deserialize_as = "DefaultOnError")]
4098 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4099 #[serde(default)]
4100 #[serde(rename = "_meta")]
4101 pub meta: Option<Meta>,
4102}
4103
4104impl AgentCapabilities {
4105 #[must_use]
4107 pub fn new() -> Self {
4108 Self::default()
4109 }
4110
4111 #[must_use]
4113 pub fn load_session(mut self, load_session: bool) -> Self {
4114 self.load_session = load_session;
4115 self
4116 }
4117
4118 #[must_use]
4120 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
4121 self.prompt_capabilities = prompt_capabilities;
4122 self
4123 }
4124
4125 #[must_use]
4127 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
4128 self.mcp_capabilities = mcp_capabilities;
4129 self
4130 }
4131
4132 #[must_use]
4134 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
4135 self.session_capabilities = session_capabilities;
4136 self
4137 }
4138
4139 #[must_use]
4141 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
4142 self.auth = auth;
4143 self
4144 }
4145
4146 #[cfg(feature = "unstable_llm_providers")]
4152 #[must_use]
4153 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
4154 self.providers = providers.into_option();
4155 self
4156 }
4157
4158 #[must_use]
4164 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4165 self.meta = meta.into_option();
4166 self
4167 }
4168}
4169
4170#[cfg(feature = "unstable_llm_providers")]
4178#[serde_as]
4179#[skip_serializing_none]
4180#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4181#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4182#[non_exhaustive]
4183pub struct ProvidersCapabilities {
4184 #[serde_as(deserialize_as = "DefaultOnError")]
4190 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4191 #[serde(default)]
4192 #[serde(rename = "_meta")]
4193 pub meta: Option<Meta>,
4194}
4195
4196#[cfg(feature = "unstable_llm_providers")]
4197impl ProvidersCapabilities {
4198 #[must_use]
4200 pub fn new() -> Self {
4201 Self::default()
4202 }
4203
4204 #[must_use]
4210 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4211 self.meta = meta.into_option();
4212 self
4213 }
4214}
4215
4216#[serde_as]
4226#[skip_serializing_none]
4227#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4228#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4229#[serde(rename_all = "camelCase")]
4230#[non_exhaustive]
4231pub struct SessionCapabilities {
4232 #[serde_as(deserialize_as = "DefaultOnError")]
4237 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4238 #[serde(default)]
4239 pub list: Option<SessionListCapabilities>,
4240 #[serde_as(deserialize_as = "DefaultOnError")]
4245 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4246 #[serde(default)]
4247 pub delete: Option<SessionDeleteCapabilities>,
4248 #[serde_as(deserialize_as = "DefaultOnError")]
4258 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4259 #[serde(default)]
4260 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
4261 #[cfg(feature = "unstable_session_system_prompt")]
4270 #[serde_as(deserialize_as = "DefaultOnError")]
4271 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4272 #[serde(default)]
4273 pub system_prompt: Option<SessionSystemPromptCapabilities>,
4274 #[cfg(feature = "unstable_session_fork")]
4283 #[serde_as(deserialize_as = "DefaultOnError")]
4284 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4285 #[serde(default)]
4286 pub fork: Option<SessionForkCapabilities>,
4287 #[serde_as(deserialize_as = "DefaultOnError")]
4292 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4293 #[serde(default)]
4294 pub resume: Option<SessionResumeCapabilities>,
4295 #[serde_as(deserialize_as = "DefaultOnError")]
4300 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4301 #[serde(default)]
4302 pub close: Option<SessionCloseCapabilities>,
4303 #[serde_as(deserialize_as = "DefaultOnError")]
4309 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4310 #[serde(default)]
4311 #[serde(rename = "_meta")]
4312 pub meta: Option<Meta>,
4313}
4314
4315impl SessionCapabilities {
4316 #[must_use]
4318 pub fn new() -> Self {
4319 Self::default()
4320 }
4321
4322 #[must_use]
4327 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
4328 self.list = list.into_option();
4329 self
4330 }
4331
4332 #[must_use]
4337 pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
4338 self.delete = delete.into_option();
4339 self
4340 }
4341
4342 #[must_use]
4352 pub fn additional_directories(
4353 mut self,
4354 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4355 ) -> Self {
4356 self.additional_directories = additional_directories.into_option();
4357 self
4358 }
4359
4360 #[cfg(feature = "unstable_session_system_prompt")]
4369 #[must_use]
4370 pub fn system_prompt(
4371 mut self,
4372 system_prompt: impl IntoOption<SessionSystemPromptCapabilities>,
4373 ) -> Self {
4374 self.system_prompt = system_prompt.into_option();
4375 self
4376 }
4377
4378 #[cfg(feature = "unstable_session_fork")]
4379 #[must_use]
4384 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4385 self.fork = fork.into_option();
4386 self
4387 }
4388
4389 #[must_use]
4394 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4395 self.resume = resume.into_option();
4396 self
4397 }
4398
4399 #[must_use]
4404 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4405 self.close = close.into_option();
4406 self
4407 }
4408
4409 #[must_use]
4415 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4416 self.meta = meta.into_option();
4417 self
4418 }
4419}
4420
4421#[serde_as]
4425#[skip_serializing_none]
4426#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4427#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4428#[non_exhaustive]
4429pub struct SessionListCapabilities {
4430 #[serde_as(deserialize_as = "DefaultOnError")]
4436 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4437 #[serde(default)]
4438 #[serde(rename = "_meta")]
4439 pub meta: Option<Meta>,
4440}
4441
4442impl SessionListCapabilities {
4443 #[must_use]
4445 pub fn new() -> Self {
4446 Self::default()
4447 }
4448
4449 #[must_use]
4455 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4456 self.meta = meta.into_option();
4457 self
4458 }
4459}
4460
4461#[serde_as]
4465#[skip_serializing_none]
4466#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4467#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4468#[non_exhaustive]
4469pub struct SessionDeleteCapabilities {
4470 #[serde_as(deserialize_as = "DefaultOnError")]
4476 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4477 #[serde(default)]
4478 #[serde(rename = "_meta")]
4479 pub meta: Option<Meta>,
4480}
4481
4482impl SessionDeleteCapabilities {
4483 #[must_use]
4485 pub fn new() -> Self {
4486 Self::default()
4487 }
4488
4489 #[must_use]
4495 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4496 self.meta = meta.into_option();
4497 self
4498 }
4499}
4500
4501#[serde_as]
4508#[skip_serializing_none]
4509#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4510#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4511#[non_exhaustive]
4512pub struct SessionAdditionalDirectoriesCapabilities {
4513 #[serde_as(deserialize_as = "DefaultOnError")]
4519 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4520 #[serde(default)]
4521 #[serde(rename = "_meta")]
4522 pub meta: Option<Meta>,
4523}
4524
4525impl SessionAdditionalDirectoriesCapabilities {
4526 #[must_use]
4528 pub fn new() -> Self {
4529 Self::default()
4530 }
4531
4532 #[must_use]
4538 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4539 self.meta = meta.into_option();
4540 self
4541 }
4542}
4543
4544#[cfg(feature = "unstable_session_system_prompt")]
4553#[serde_as]
4554#[skip_serializing_none]
4555#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4556#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4557#[serde(rename_all = "camelCase")]
4558#[non_exhaustive]
4559pub struct SessionSystemPromptCapabilities {
4560 #[serde_as(deserialize_as = "DefaultOnError")]
4564 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4565 #[serde(default)]
4566 pub mode: Option<SessionSystemPromptModeCapabilities>,
4567 #[serde_as(deserialize_as = "DefaultOnError")]
4573 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4574 #[serde(default)]
4575 #[serde(rename = "_meta")]
4576 pub meta: Option<Meta>,
4577}
4578
4579#[cfg(feature = "unstable_session_system_prompt")]
4580impl SessionSystemPromptCapabilities {
4581 #[must_use]
4583 pub fn new() -> Self {
4584 Self::default()
4585 }
4586
4587 #[must_use]
4591 pub fn mode(mut self, mode: impl IntoOption<SessionSystemPromptModeCapabilities>) -> Self {
4592 self.mode = mode.into_option();
4593 self
4594 }
4595
4596 #[must_use]
4602 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4603 self.meta = meta.into_option();
4604 self
4605 }
4606}
4607
4608#[cfg(feature = "unstable_session_system_prompt")]
4617#[serde_as]
4618#[skip_serializing_none]
4619#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4620#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4621#[serde(rename_all = "camelCase")]
4622#[non_exhaustive]
4623pub struct SessionSystemPromptModeCapabilities {
4624 #[serde_as(deserialize_as = "DefaultOnError")]
4630 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4631 #[serde(default, rename = "override")]
4632 pub override_: Option<SessionSystemPromptOverrideCapabilities>,
4633 #[serde_as(deserialize_as = "DefaultOnError")]
4639 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4640 #[serde(default)]
4641 #[serde(rename = "_meta")]
4642 pub meta: Option<Meta>,
4643}
4644
4645#[cfg(feature = "unstable_session_system_prompt")]
4646impl SessionSystemPromptModeCapabilities {
4647 #[must_use]
4649 pub fn new() -> Self {
4650 Self::default()
4651 }
4652
4653 #[must_use]
4659 pub fn override_(
4660 mut self,
4661 override_: impl IntoOption<SessionSystemPromptOverrideCapabilities>,
4662 ) -> Self {
4663 self.override_ = override_.into_option();
4664 self
4665 }
4666
4667 #[must_use]
4673 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4674 self.meta = meta.into_option();
4675 self
4676 }
4677}
4678
4679#[cfg(feature = "unstable_session_system_prompt")]
4688#[serde_as]
4689#[skip_serializing_none]
4690#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4691#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4692#[non_exhaustive]
4693pub struct SessionSystemPromptOverrideCapabilities {
4694 #[serde_as(deserialize_as = "DefaultOnError")]
4700 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4701 #[serde(default)]
4702 #[serde(rename = "_meta")]
4703 pub meta: Option<Meta>,
4704}
4705
4706#[cfg(feature = "unstable_session_system_prompt")]
4707impl SessionSystemPromptOverrideCapabilities {
4708 #[must_use]
4710 pub fn new() -> Self {
4711 Self::default()
4712 }
4713
4714 #[must_use]
4720 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4721 self.meta = meta.into_option();
4722 self
4723 }
4724}
4725
4726#[cfg(feature = "unstable_session_fork")]
4734#[serde_as]
4735#[skip_serializing_none]
4736#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4737#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4738#[non_exhaustive]
4739pub struct SessionForkCapabilities {
4740 #[serde_as(deserialize_as = "DefaultOnError")]
4746 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4747 #[serde(default)]
4748 #[serde(rename = "_meta")]
4749 pub meta: Option<Meta>,
4750}
4751
4752#[cfg(feature = "unstable_session_fork")]
4753impl SessionForkCapabilities {
4754 #[must_use]
4756 pub fn new() -> Self {
4757 Self::default()
4758 }
4759
4760 #[must_use]
4766 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4767 self.meta = meta.into_option();
4768 self
4769 }
4770}
4771
4772#[serde_as]
4776#[skip_serializing_none]
4777#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4778#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4779#[non_exhaustive]
4780pub struct SessionResumeCapabilities {
4781 #[serde_as(deserialize_as = "DefaultOnError")]
4787 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4788 #[serde(default)]
4789 #[serde(rename = "_meta")]
4790 pub meta: Option<Meta>,
4791}
4792
4793impl SessionResumeCapabilities {
4794 #[must_use]
4796 pub fn new() -> Self {
4797 Self::default()
4798 }
4799
4800 #[must_use]
4806 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4807 self.meta = meta.into_option();
4808 self
4809 }
4810}
4811
4812#[serde_as]
4816#[skip_serializing_none]
4817#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4818#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4819#[non_exhaustive]
4820pub struct SessionCloseCapabilities {
4821 #[serde_as(deserialize_as = "DefaultOnError")]
4827 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4828 #[serde(default)]
4829 #[serde(rename = "_meta")]
4830 pub meta: Option<Meta>,
4831}
4832
4833impl SessionCloseCapabilities {
4834 #[must_use]
4836 pub fn new() -> Self {
4837 Self::default()
4838 }
4839
4840 #[must_use]
4846 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4847 self.meta = meta.into_option();
4848 self
4849 }
4850}
4851
4852#[serde_as]
4865#[skip_serializing_none]
4866#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4867#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4868#[serde(rename_all = "camelCase")]
4869#[non_exhaustive]
4870pub struct PromptCapabilities {
4871 #[serde_as(deserialize_as = "DefaultOnError")]
4873 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4874 #[serde(default)]
4875 pub image: bool,
4876 #[serde_as(deserialize_as = "DefaultOnError")]
4878 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4879 #[serde(default)]
4880 pub audio: bool,
4881 #[serde_as(deserialize_as = "DefaultOnError")]
4886 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4887 #[serde(default)]
4888 pub embedded_context: bool,
4889 #[serde_as(deserialize_as = "DefaultOnError")]
4895 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4896 #[serde(default)]
4897 #[serde(rename = "_meta")]
4898 pub meta: Option<Meta>,
4899}
4900
4901impl PromptCapabilities {
4902 #[must_use]
4904 pub fn new() -> Self {
4905 Self::default()
4906 }
4907
4908 #[must_use]
4910 pub fn image(mut self, image: bool) -> Self {
4911 self.image = image;
4912 self
4913 }
4914
4915 #[must_use]
4917 pub fn audio(mut self, audio: bool) -> Self {
4918 self.audio = audio;
4919 self
4920 }
4921
4922 #[must_use]
4927 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4928 self.embedded_context = embedded_context;
4929 self
4930 }
4931
4932 #[must_use]
4938 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4939 self.meta = meta.into_option();
4940 self
4941 }
4942}
4943
4944#[serde_as]
4946#[skip_serializing_none]
4947#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4948#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4949#[serde(rename_all = "camelCase")]
4950#[non_exhaustive]
4951pub struct McpCapabilities {
4952 #[serde_as(deserialize_as = "DefaultOnError")]
4954 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4955 #[serde(default)]
4956 pub http: bool,
4957 #[serde_as(deserialize_as = "DefaultOnError")]
4959 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4960 #[serde(default)]
4961 pub sse: bool,
4962 #[cfg(feature = "unstable_mcp_over_acp")]
4968 #[serde_as(deserialize_as = "DefaultOnError")]
4969 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4970 #[serde(default)]
4971 pub acp: bool,
4972 #[serde_as(deserialize_as = "DefaultOnError")]
4978 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4979 #[serde(default)]
4980 #[serde(rename = "_meta")]
4981 pub meta: Option<Meta>,
4982}
4983
4984impl McpCapabilities {
4985 #[must_use]
4987 pub fn new() -> Self {
4988 Self::default()
4989 }
4990
4991 #[must_use]
4993 pub fn http(mut self, http: bool) -> Self {
4994 self.http = http;
4995 self
4996 }
4997
4998 #[must_use]
5000 pub fn sse(mut self, sse: bool) -> Self {
5001 self.sse = sse;
5002 self
5003 }
5004
5005 #[cfg(feature = "unstable_mcp_over_acp")]
5011 #[must_use]
5012 pub fn acp(mut self, acp: bool) -> Self {
5013 self.acp = acp;
5014 self
5015 }
5016
5017 #[must_use]
5023 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5024 self.meta = meta.into_option();
5025 self
5026 }
5027}
5028
5029#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5035#[non_exhaustive]
5036pub struct AgentMethodNames {
5037 pub initialize: &'static str,
5039 pub authenticate: &'static str,
5041 #[cfg(feature = "unstable_llm_providers")]
5043 pub providers_list: &'static str,
5044 #[cfg(feature = "unstable_llm_providers")]
5046 pub providers_set: &'static str,
5047 #[cfg(feature = "unstable_llm_providers")]
5049 pub providers_disable: &'static str,
5050 pub session_new: &'static str,
5052 pub session_load: &'static str,
5054 pub session_set_mode: &'static str,
5056 pub session_set_config_option: &'static str,
5058 pub session_prompt: &'static str,
5060 pub session_cancel: &'static str,
5062 #[cfg(feature = "unstable_mcp_over_acp")]
5064 pub mcp_message: &'static str,
5065 pub session_list: &'static str,
5067 pub session_delete: &'static str,
5069 #[cfg(feature = "unstable_session_fork")]
5071 pub session_fork: &'static str,
5072 pub session_resume: &'static str,
5074 pub session_close: &'static str,
5076 pub logout: &'static str,
5078}
5079
5080pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
5082 initialize: INITIALIZE_METHOD_NAME,
5083 authenticate: AUTHENTICATE_METHOD_NAME,
5084 #[cfg(feature = "unstable_llm_providers")]
5085 providers_list: PROVIDERS_LIST_METHOD_NAME,
5086 #[cfg(feature = "unstable_llm_providers")]
5087 providers_set: PROVIDERS_SET_METHOD_NAME,
5088 #[cfg(feature = "unstable_llm_providers")]
5089 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
5090 session_new: SESSION_NEW_METHOD_NAME,
5091 session_load: SESSION_LOAD_METHOD_NAME,
5092 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
5093 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
5094 session_prompt: SESSION_PROMPT_METHOD_NAME,
5095 session_cancel: SESSION_CANCEL_METHOD_NAME,
5096 #[cfg(feature = "unstable_mcp_over_acp")]
5097 mcp_message: MCP_MESSAGE_METHOD_NAME,
5098 session_list: SESSION_LIST_METHOD_NAME,
5099 session_delete: SESSION_DELETE_METHOD_NAME,
5100 #[cfg(feature = "unstable_session_fork")]
5101 session_fork: SESSION_FORK_METHOD_NAME,
5102 session_resume: SESSION_RESUME_METHOD_NAME,
5103 session_close: SESSION_CLOSE_METHOD_NAME,
5104 logout: LOGOUT_METHOD_NAME,
5105};
5106
5107pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
5109pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
5111#[cfg(feature = "unstable_llm_providers")]
5113pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
5114#[cfg(feature = "unstable_llm_providers")]
5116pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
5117#[cfg(feature = "unstable_llm_providers")]
5119pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
5120pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
5122pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
5124pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
5126pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
5128pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
5130pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
5132pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
5134pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
5136#[cfg(feature = "unstable_session_fork")]
5138pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
5139pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
5141pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
5143pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
5145
5146#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5153#[derive(Clone, Debug, Serialize, Deserialize)]
5154#[serde(untagged)]
5155#[cfg_attr(feature = "schemars", schemars(inline))]
5156#[non_exhaustive]
5157#[allow(clippy::large_enum_variant)]
5158pub enum ClientRequest {
5159 InitializeRequest(InitializeRequest),
5170 AuthenticateRequest(AuthenticateRequest),
5181 #[cfg(feature = "unstable_llm_providers")]
5187 ListProvidersRequest(ListProvidersRequest),
5188 #[cfg(feature = "unstable_llm_providers")]
5194 SetProviderRequest(SetProviderRequest),
5195 #[cfg(feature = "unstable_llm_providers")]
5201 DisableProviderRequest(DisableProviderRequest),
5202 LogoutRequest(LogoutRequest),
5207 NewSessionRequest(NewSessionRequest),
5220 LoadSessionRequest(LoadSessionRequest),
5231 ListSessionsRequest(ListSessionsRequest),
5237 DeleteSessionRequest(DeleteSessionRequest),
5241 #[cfg(feature = "unstable_session_fork")]
5242 ForkSessionRequest(ForkSessionRequest),
5258 ResumeSessionRequest(ResumeSessionRequest),
5265 CloseSessionRequest(CloseSessionRequest),
5272 SetSessionModeRequest(SetSessionModeRequest),
5286 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
5288 PromptRequest(PromptRequest),
5300 ExtMethodRequest(ExtRequest),
5307}
5308
5309impl ClientRequest {
5310 #[must_use]
5312 pub fn method(&self) -> &str {
5313 match self {
5314 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
5315 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
5316 #[cfg(feature = "unstable_llm_providers")]
5317 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
5318 #[cfg(feature = "unstable_llm_providers")]
5319 Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
5320 #[cfg(feature = "unstable_llm_providers")]
5321 Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
5322 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
5323 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
5324 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
5325 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
5326 Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
5327 #[cfg(feature = "unstable_session_fork")]
5328 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
5329 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
5330 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
5331 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
5332 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
5333 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
5334 Self::ExtMethodRequest(ext_request) => &ext_request.method,
5335 }
5336 }
5337}
5338
5339#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5346#[derive(Clone, Debug, Serialize, Deserialize)]
5347#[serde(untagged)]
5348#[cfg_attr(feature = "schemars", schemars(inline))]
5349#[non_exhaustive]
5350#[allow(clippy::large_enum_variant)]
5351pub enum AgentResponse {
5352 InitializeResponse(InitializeResponse),
5354 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
5356 #[cfg(feature = "unstable_llm_providers")]
5358 ListProvidersResponse(ListProvidersResponse),
5359 #[cfg(feature = "unstable_llm_providers")]
5361 SetProviderResponse(#[serde(default)] SetProviderResponse),
5362 #[cfg(feature = "unstable_llm_providers")]
5364 DisableProviderResponse(#[serde(default)] DisableProviderResponse),
5365 LogoutResponse(#[serde(default)] LogoutResponse),
5367 NewSessionResponse(NewSessionResponse),
5369 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5371 ListSessionsResponse(ListSessionsResponse),
5373 DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
5375 #[cfg(feature = "unstable_session_fork")]
5377 ForkSessionResponse(ForkSessionResponse),
5378 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5380 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5382 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
5384 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5386 PromptResponse(PromptResponse),
5388 ExtMethodResponse(ExtResponse),
5390}
5391
5392#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5399#[derive(Clone, Debug, Serialize, Deserialize)]
5400#[serde(untagged)]
5401#[cfg_attr(feature = "schemars", schemars(inline))]
5402#[non_exhaustive]
5403#[allow(clippy::large_enum_variant)]
5404pub enum ClientNotification {
5405 CancelNotification(CancelNotification),
5417 #[cfg(feature = "unstable_mcp_over_acp")]
5423 MessageMcpNotification(MessageMcpNotification),
5424 ExtNotification(ExtNotification),
5431}
5432
5433impl ClientNotification {
5434 #[must_use]
5436 pub fn method(&self) -> &str {
5437 match self {
5438 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5439 #[cfg(feature = "unstable_mcp_over_acp")]
5440 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5441 Self::ExtNotification(ext_notification) => &ext_notification.method,
5442 }
5443 }
5444}
5445
5446#[serde_as]
5450#[skip_serializing_none]
5451#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5452#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5453#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME)))]
5454#[serde(rename_all = "camelCase")]
5455#[non_exhaustive]
5456pub struct CancelNotification {
5457 pub session_id: SessionId,
5459 #[serde_as(deserialize_as = "DefaultOnError")]
5465 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5466 #[serde(default)]
5467 #[serde(rename = "_meta")]
5468 pub meta: Option<Meta>,
5469}
5470
5471impl CancelNotification {
5472 #[must_use]
5474 pub fn new(session_id: impl Into<SessionId>) -> Self {
5475 Self {
5476 session_id: session_id.into(),
5477 meta: None,
5478 }
5479 }
5480
5481 #[must_use]
5487 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5488 self.meta = meta.into_option();
5489 self
5490 }
5491}
5492
5493#[cfg(test)]
5494mod test_serialization {
5495 use super::*;
5496 use serde_json::json;
5497
5498 fn test_meta() -> Meta {
5499 json!({ "source": "test" }).as_object().unwrap().clone()
5500 }
5501
5502 fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
5503 serde_json::to_string(value)
5504 .unwrap()
5505 .matches("\"_meta\"")
5506 .count()
5507 }
5508
5509 #[test]
5512 fn prompt_response_has_no_error_stop_reason() {
5513 assert_eq!(
5514 serde_json::from_value::<PromptResponse>(json!({ "stopReason": "end_turn" }))
5515 .unwrap()
5516 .stop_reason,
5517 StopReason::EndTurn
5518 );
5519 assert!(
5520 serde_json::from_value::<PromptResponse>(json!({ "stopReason": "error" })).is_err()
5521 );
5522 }
5523
5524 #[test]
5525 fn test_initialize_capabilities_default_on_malformed_values() {
5526 let request: InitializeRequest = serde_json::from_value(json!({
5527 "protocolVersion": 1,
5528 "clientCapabilities": false
5529 }))
5530 .unwrap();
5531 assert_eq!(request.client_capabilities, ClientCapabilities::default());
5532
5533 let response: InitializeResponse = serde_json::from_value(json!({
5534 "protocolVersion": 1,
5535 "agentCapabilities": false
5536 }))
5537 .unwrap();
5538 assert_eq!(response.agent_capabilities, AgentCapabilities::default());
5539 }
5540
5541 #[test]
5542 fn test_agent_capabilities_default_on_malformed_values() {
5543 let capabilities: AgentCapabilities = serde_json::from_value(json!({
5544 "loadSession": "yes",
5545 "promptCapabilities": {
5546 "image": "yes",
5547 "audio": true,
5548 "embeddedContext": {}
5549 },
5550 "mcpCapabilities": {
5551 "http": "yes",
5552 "sse": true
5553 },
5554 "sessionCapabilities": false,
5555 "auth": false
5556 }))
5557 .unwrap();
5558
5559 assert!(!capabilities.load_session);
5560 assert!(!capabilities.prompt_capabilities.image);
5561 assert!(capabilities.prompt_capabilities.audio);
5562 assert!(!capabilities.prompt_capabilities.embedded_context);
5563 assert!(!capabilities.mcp_capabilities.http);
5564 assert!(capabilities.mcp_capabilities.sse);
5565 assert_eq!(
5566 capabilities.session_capabilities,
5567 SessionCapabilities::default()
5568 );
5569 assert_eq!(capabilities.auth, AgentAuthCapabilities::default());
5570 }
5571
5572 #[test]
5573 fn test_mcp_server_stdio_serialization() {
5574 let server = McpServer::Stdio(
5575 McpServerStdio::new("test-server", "/usr/bin/server")
5576 .args(vec!["--port".to_string(), "3000".to_string()])
5577 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5578 );
5579
5580 let json = serde_json::to_value(&server).unwrap();
5581 assert_eq!(
5582 json,
5583 json!({
5584 "name": "test-server",
5585 "command": "/usr/bin/server",
5586 "args": ["--port", "3000"],
5587 "env": [
5588 {
5589 "name": "API_KEY",
5590 "value": "secret123"
5591 }
5592 ]
5593 })
5594 );
5595
5596 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5597 match deserialized {
5598 McpServer::Stdio(McpServerStdio {
5599 name,
5600 command,
5601 args,
5602 env,
5603 meta: _,
5604 }) => {
5605 assert_eq!(name, "test-server");
5606 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5607 assert_eq!(args, vec!["--port", "3000"]);
5608 assert_eq!(env.len(), 1);
5609 assert_eq!(env[0].name, "API_KEY");
5610 assert_eq!(env[0].value, "secret123");
5611 }
5612 _ => panic!("Expected Stdio variant"),
5613 }
5614 }
5615
5616 #[test]
5617 fn test_mcp_server_http_serialization() {
5618 let server = McpServer::Http(
5619 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5620 HttpHeader::new("Authorization", "Bearer token123"),
5621 HttpHeader::new("Content-Type", "application/json"),
5622 ]),
5623 );
5624
5625 let json = serde_json::to_value(&server).unwrap();
5626 assert_eq!(
5627 json,
5628 json!({
5629 "type": "http",
5630 "name": "http-server",
5631 "url": "https://api.example.com",
5632 "headers": [
5633 {
5634 "name": "Authorization",
5635 "value": "Bearer token123"
5636 },
5637 {
5638 "name": "Content-Type",
5639 "value": "application/json"
5640 }
5641 ]
5642 })
5643 );
5644
5645 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5646 match deserialized {
5647 McpServer::Http(McpServerHttp {
5648 name,
5649 url,
5650 headers,
5651 meta: _,
5652 }) => {
5653 assert_eq!(name, "http-server");
5654 assert_eq!(url, "https://api.example.com");
5655 assert_eq!(headers.len(), 2);
5656 assert_eq!(headers[0].name, "Authorization");
5657 assert_eq!(headers[0].value, "Bearer token123");
5658 assert_eq!(headers[1].name, "Content-Type");
5659 assert_eq!(headers[1].value, "application/json");
5660 }
5661 _ => panic!("Expected Http variant"),
5662 }
5663 }
5664
5665 #[cfg(feature = "unstable_mcp_over_acp")]
5666 #[test]
5667 fn test_mcp_server_acp_serialization() {
5668 let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id"));
5669
5670 let json = serde_json::to_value(&server).unwrap();
5671 assert_eq!(
5672 json,
5673 json!({
5674 "type": "acp",
5675 "name": "project-tools",
5676 "serverId": "project-tools-id"
5677 })
5678 );
5679
5680 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5681 match deserialized {
5682 McpServer::Acp(McpServerAcp {
5683 name,
5684 server_id: id,
5685 meta: _,
5686 }) => {
5687 assert_eq!(name, "project-tools");
5688 assert_eq!(id, McpServerAcpId::new("project-tools-id"));
5689 }
5690 _ => panic!("Expected Acp variant"),
5691 }
5692 }
5693
5694 #[cfg(feature = "unstable_mcp_over_acp")]
5695 #[test]
5696 fn test_client_mcp_message_method_names() {
5697 use serde_json::json;
5698
5699 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5700
5701 let notification =
5702 MessageMcpNotification::new("server-1", "req-1", "notifications/progress");
5703 assert_eq!(
5704 ClientNotification::MessageMcpNotification(notification.clone()).method(),
5705 "mcp/message"
5706 );
5707 assert_eq!(
5708 serde_json::to_value(notification).unwrap(),
5709 json!({
5710 "serverId": "server-1",
5711 "requestId": "req-1",
5712 "method": "notifications/progress"
5713 })
5714 );
5715 let notification: MessageMcpNotification = serde_json::from_value(json!({
5716 "serverId": "server-1", "requestId": "req-1", "method": "notifications/progress",
5717 "params": null, "_meta": null
5718 }))
5719 .unwrap();
5720 assert_eq!(notification.params, None);
5721 assert_eq!(notification.meta, None);
5722 for key in ["serverId", "requestId", "method"] {
5723 let mut value = json!({"serverId":"server-1", "requestId":"req-1", "method":"notifications/progress"});
5724 value.as_object_mut().unwrap().remove(key);
5725 assert!(serde_json::from_value::<MessageMcpNotification>(value).is_err());
5726 }
5727 }
5728
5729 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5730 #[test]
5731 fn test_mcp_server_acp_schema() {
5732 let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap();
5733 assert!(json_contains_entry(
5734 &mcp_server_schema,
5735 "const",
5736 &json!("acp")
5737 ));
5738 assert!(json_contains_entry(
5739 &mcp_server_schema,
5740 "$ref",
5741 &json!("#/$defs/McpServerAcp")
5742 ));
5743
5744 let capabilities_schema =
5745 serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap();
5746 assert!(json_contains_key(&capabilities_schema, "acp"));
5747 }
5748
5749 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5750 fn json_contains_entry(
5751 value: &serde_json::Value,
5752 key: &str,
5753 expected: &serde_json::Value,
5754 ) -> bool {
5755 match value {
5756 serde_json::Value::Object(map) => {
5757 map.get(key) == Some(expected)
5758 || map
5759 .values()
5760 .any(|value| json_contains_entry(value, key, expected))
5761 }
5762 serde_json::Value::Array(values) => values
5763 .iter()
5764 .any(|value| json_contains_entry(value, key, expected)),
5765 _ => false,
5766 }
5767 }
5768
5769 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5770 fn json_contains_key(value: &serde_json::Value, key: &str) -> bool {
5771 match value {
5772 serde_json::Value::Object(map) => {
5773 map.contains_key(key) || map.values().any(|value| json_contains_key(value, key))
5774 }
5775 serde_json::Value::Array(values) => {
5776 values.iter().any(|value| json_contains_key(value, key))
5777 }
5778 _ => false,
5779 }
5780 }
5781
5782 #[test]
5783 fn test_mcp_server_sse_serialization() {
5784 let server = McpServer::Sse(
5785 McpServerSse::new("sse-server", "https://sse.example.com/events")
5786 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5787 );
5788
5789 let json = serde_json::to_value(&server).unwrap();
5790 assert_eq!(
5791 json,
5792 json!({
5793 "type": "sse",
5794 "name": "sse-server",
5795 "url": "https://sse.example.com/events",
5796 "headers": [
5797 {
5798 "name": "X-API-Key",
5799 "value": "apikey456"
5800 }
5801 ]
5802 })
5803 );
5804
5805 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5806 match deserialized {
5807 McpServer::Sse(McpServerSse {
5808 name,
5809 url,
5810 headers,
5811 meta: _,
5812 }) => {
5813 assert_eq!(name, "sse-server");
5814 assert_eq!(url, "https://sse.example.com/events");
5815 assert_eq!(headers.len(), 1);
5816 assert_eq!(headers[0].name, "X-API-Key");
5817 assert_eq!(headers[0].value, "apikey456");
5818 }
5819 _ => panic!("Expected Sse variant"),
5820 }
5821 }
5822
5823 #[test]
5824 fn test_session_config_option_category_known_variants() {
5825 assert_eq!(
5827 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5828 json!("mode")
5829 );
5830 assert_eq!(
5831 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5832 json!("model")
5833 );
5834 assert_eq!(
5835 serde_json::to_value(&SessionConfigOptionCategory::ModelConfig).unwrap(),
5836 json!("model_config")
5837 );
5838 assert_eq!(
5839 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5840 json!("thought_level")
5841 );
5842
5843 assert_eq!(
5845 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5846 SessionConfigOptionCategory::Mode
5847 );
5848 assert_eq!(
5849 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5850 SessionConfigOptionCategory::Model
5851 );
5852 assert_eq!(
5853 serde_json::from_str::<SessionConfigOptionCategory>("\"model_config\"").unwrap(),
5854 SessionConfigOptionCategory::ModelConfig
5855 );
5856 assert_eq!(
5857 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5858 SessionConfigOptionCategory::ThoughtLevel
5859 );
5860 }
5861
5862 #[test]
5863 fn test_session_config_option_category_unknown_variants() {
5864 let unknown: SessionConfigOptionCategory =
5866 serde_json::from_str("\"some_future_category\"").unwrap();
5867 assert_eq!(
5868 unknown,
5869 SessionConfigOptionCategory::Other("some_future_category".to_string())
5870 );
5871
5872 let json = serde_json::to_value(&unknown).unwrap();
5874 assert_eq!(json, json!("some_future_category"));
5875 }
5876
5877 #[test]
5878 fn test_session_config_option_category_custom_categories() {
5879 let custom: SessionConfigOptionCategory =
5881 serde_json::from_str("\"_my_custom_category\"").unwrap();
5882 assert_eq!(
5883 custom,
5884 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5885 );
5886
5887 let json = serde_json::to_value(&custom).unwrap();
5889 assert_eq!(json, json!("_my_custom_category"));
5890
5891 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5893 assert_eq!(
5894 deserialized,
5895 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5896 );
5897 }
5898
5899 #[test]
5900 fn test_auth_method_agent_serialization() {
5901 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5902
5903 let json = serde_json::to_value(&method).unwrap();
5904 assert_eq!(
5905 json,
5906 json!({
5907 "id": "default-auth",
5908 "name": "Default Auth"
5909 })
5910 );
5911 assert!(!json.as_object().unwrap().contains_key("description"));
5913 assert!(!json.as_object().unwrap().contains_key("type"));
5915
5916 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5917 match deserialized {
5918 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5919 assert_eq!(id.0.as_ref(), "default-auth");
5920 assert_eq!(name, "Default Auth");
5921 }
5922 _ => panic!("Expected Agent variant"),
5923 }
5924 }
5925
5926 #[test]
5927 fn test_auth_method_explicit_agent_deserialization() {
5928 let json = json!({
5930 "id": "agent-auth",
5931 "name": "Agent Auth",
5932 "type": "agent"
5933 });
5934
5935 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5936 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5937 }
5938
5939 #[test]
5940 fn test_session_delete_serialization() {
5941 assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5942 assert_eq!(
5943 ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5944 "session/delete"
5945 );
5946 assert_eq!(
5947 serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5948 json!({
5949 "sessionId": "sess_abc123"
5950 })
5951 );
5952 assert_eq!(
5953 serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5954 json!({})
5955 );
5956 assert_eq!(
5957 serde_json::to_value(
5958 SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5959 )
5960 .unwrap(),
5961 json!({
5962 "delete": {}
5963 })
5964 );
5965 }
5966 #[test]
5967 fn test_session_additional_directories_serialization() {
5968 assert_eq!(
5969 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5970 json!({
5971 "cwd": "/home/user/project",
5972 "mcpServers": []
5973 })
5974 );
5975 assert_eq!(
5976 serde_json::to_value(
5977 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5978 PathBuf::from("/home/user/shared-lib"),
5979 PathBuf::from("/home/user/product-docs"),
5980 ])
5981 )
5982 .unwrap(),
5983 json!({
5984 "cwd": "/home/user/project",
5985 "additionalDirectories": [
5986 "/home/user/shared-lib",
5987 "/home/user/product-docs"
5988 ],
5989 "mcpServers": []
5990 })
5991 );
5992 assert_eq!(
5993 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5994 json!({
5995 "sessionId": "sess_abc123",
5996 "cwd": "/home/user/project"
5997 })
5998 );
5999 assert_eq!(
6000 serde_json::to_value(
6001 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
6002 PathBuf::from("/home/user/shared-lib"),
6003 PathBuf::from("/home/user/product-docs"),
6004 ])
6005 )
6006 .unwrap(),
6007 json!({
6008 "sessionId": "sess_abc123",
6009 "cwd": "/home/user/project",
6010 "additionalDirectories": [
6011 "/home/user/shared-lib",
6012 "/home/user/product-docs"
6013 ]
6014 })
6015 );
6016 assert_eq!(
6017 serde_json::from_value::<SessionInfo>(json!({
6018 "sessionId": "sess_abc123",
6019 "cwd": "/home/user/project"
6020 }))
6021 .unwrap()
6022 .additional_directories,
6023 Vec::<PathBuf>::new()
6024 );
6025 }
6026 #[test]
6027 fn test_session_additional_directories_capabilities_serialization() {
6028 assert_eq!(
6029 serde_json::to_value(
6030 SessionCapabilities::new()
6031 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
6032 )
6033 .unwrap(),
6034 json!({
6035 "additionalDirectories": {}
6036 })
6037 );
6038 }
6039
6040 #[cfg(feature = "unstable_session_system_prompt")]
6041 #[test]
6042 fn test_session_system_prompt_capabilities_serialization() {
6043 assert_eq!(
6044 serde_json::to_value(
6045 SessionCapabilities::new().system_prompt(SessionSystemPromptCapabilities::new())
6046 )
6047 .unwrap(),
6048 json!({ "systemPrompt": {} })
6049 );
6050 assert_eq!(
6051 serde_json::to_value(
6052 SessionCapabilities::new().system_prompt(
6053 SessionSystemPromptCapabilities::new().mode(
6054 SessionSystemPromptModeCapabilities::new()
6055 .override_(SessionSystemPromptOverrideCapabilities::new())
6056 )
6057 )
6058 )
6059 .unwrap(),
6060 json!({ "systemPrompt": { "mode": { "override": {} } } })
6061 );
6062 assert_eq!(
6063 serde_json::from_value::<SessionCapabilities>(
6064 json!({ "systemPrompt": { "mode": { "override": {} } } })
6065 )
6066 .unwrap()
6067 .system_prompt
6068 .and_then(|capabilities| capabilities.mode)
6069 .and_then(|mode| mode.override_),
6070 Some(SessionSystemPromptOverrideCapabilities::new())
6071 );
6072
6073 assert_eq!(
6075 serde_json::from_value::<SessionCapabilities>(json!({ "systemPrompt": "yes" }))
6076 .unwrap()
6077 .system_prompt,
6078 None
6079 );
6080 assert_eq!(
6081 serde_json::from_value::<SessionCapabilities>(
6082 json!({ "systemPrompt": { "mode": { "override": true } } })
6083 )
6084 .unwrap()
6085 .system_prompt,
6086 Some(
6087 SessionSystemPromptCapabilities::new()
6088 .mode(SessionSystemPromptModeCapabilities::new())
6089 )
6090 );
6091 assert_eq!(
6092 serde_json::from_value::<SessionCapabilities>(
6093 json!({ "systemPrompt": { "mode": "override" } })
6094 )
6095 .unwrap()
6096 .system_prompt,
6097 Some(SessionSystemPromptCapabilities::new())
6098 );
6099 }
6100
6101 #[cfg(feature = "unstable_session_system_prompt")]
6102 #[test]
6103 fn test_system_prompt_lifecycle_request_serialization() {
6104 let system_prompt = SystemPrompt::new(vec![ContentBlock::from(
6105 "You are a code review specialist.",
6106 )]);
6107 let system_prompt_json = json!({
6108 "mode": "append",
6109 "content": [{ "type": "text", "text": "You are a code review specialist." }]
6110 });
6111
6112 let request =
6113 NewSessionRequest::new("/home/user/project").system_prompt(system_prompt.clone());
6114 let request_json = json!({
6115 "cwd": "/home/user/project",
6116 "mcpServers": [],
6117 "systemPrompt": system_prompt_json
6118 });
6119 assert_eq!(serde_json::to_value(&request).unwrap(), request_json);
6120 assert_eq!(
6121 serde_json::from_value::<NewSessionRequest>(request_json).unwrap(),
6122 request
6123 );
6124
6125 assert_eq!(
6126 serde_json::to_value(
6127 LoadSessionRequest::new("sess_abc123", "/home/user/project")
6128 .system_prompt(system_prompt.clone())
6129 )
6130 .unwrap()["systemPrompt"],
6131 system_prompt_json
6132 );
6133 assert_eq!(
6134 serde_json::to_value(
6135 ResumeSessionRequest::new("sess_abc123", "/home/user/project")
6136 .system_prompt(system_prompt.clone())
6137 )
6138 .unwrap()["systemPrompt"],
6139 system_prompt_json
6140 );
6141 #[cfg(feature = "unstable_session_fork")]
6142 assert_eq!(
6143 serde_json::to_value(
6144 ForkSessionRequest::new("sess_abc123", "/home/user/project")
6145 .system_prompt(system_prompt.clone())
6146 )
6147 .unwrap()["systemPrompt"],
6148 system_prompt_json
6149 );
6150
6151 let override_prompt =
6152 SystemPrompt::new(vec![ContentBlock::from("...")]).mode(SystemPromptMode::Override);
6153 let override_json = json!({
6154 "mode": "override",
6155 "content": [{ "type": "text", "text": "..." }]
6156 });
6157 assert_eq!(
6158 serde_json::to_value(&override_prompt).unwrap(),
6159 override_json
6160 );
6161 assert_eq!(
6162 serde_json::from_value::<SystemPrompt>(override_json).unwrap(),
6163 override_prompt
6164 );
6165 }
6166
6167 #[cfg(feature = "unstable_session_system_prompt")]
6170 #[test]
6171 fn test_system_prompt_new_defaults_to_append() {
6172 let system_prompt = SystemPrompt::new(vec![ContentBlock::from("...")]);
6173 assert_eq!(system_prompt.mode, SystemPromptMode::Append);
6174 assert_eq!(
6175 serde_json::to_value(&system_prompt).unwrap(),
6176 json!({ "mode": "append", "content": [{ "type": "text", "text": "..." }] })
6177 );
6178 }
6179
6180 #[cfg(feature = "unstable_session_system_prompt")]
6184 #[test]
6185 fn test_system_prompt_preserves_unknown_modes() {
6186 for mode in ["_vendor_mode", "prepend"] {
6187 let system_prompt_json =
6188 json!({ "mode": mode, "content": [{ "type": "text", "text": "..." }] });
6189 let system_prompt: SystemPrompt =
6190 serde_json::from_value(system_prompt_json.clone()).unwrap();
6191 assert_eq!(
6192 system_prompt.mode,
6193 SystemPromptMode::Other(mode.to_string())
6194 );
6195 assert_eq!(
6196 serde_json::to_value(&system_prompt).unwrap(),
6197 system_prompt_json
6198 );
6199 }
6200 }
6201
6202 #[cfg(feature = "unstable_session_system_prompt")]
6206 fn assert_system_prompt_is_strict<T>(base: &serde_json::Value)
6207 where
6208 T: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
6209 {
6210 let name = std::any::type_name::<T>();
6211 let with = |system_prompt: serde_json::Value| {
6212 let mut request = base.clone();
6213 request["systemPrompt"] = system_prompt;
6214 serde_json::from_value::<T>(request)
6215 };
6216
6217 for system_prompt in [
6218 json!("You are a code review specialist."),
6219 json!({ "content": [{ "type": "text", "text": "..." }] }),
6220 json!({ "mode": null, "content": [{ "type": "text", "text": "..." }] }),
6221 json!({ "mode": 1, "content": [{ "type": "text", "text": "..." }] }),
6222 json!({ "mode": "append" }),
6223 json!({ "mode": "append", "content": "..." }),
6224 json!({ "mode": "append", "content": [{ "type": "text" }] }),
6225 json!({ "mode": "append", "content": [{ "type": "video", "uri": "..." }] }),
6226 ] {
6227 assert!(
6228 with(system_prompt.clone()).is_err(),
6229 "{name}.systemPrompt: {system_prompt}"
6230 );
6231 }
6232
6233 assert_eq!(
6234 with(serde_json::Value::Null).unwrap(),
6235 serde_json::from_value::<T>(base.clone()).unwrap(),
6236 "{name}.systemPrompt"
6237 );
6238 }
6239
6240 #[cfg(feature = "unstable_session_system_prompt")]
6241 #[test]
6242 fn test_session_setup_requests_reject_malformed_system_prompts() {
6243 assert!(
6244 serde_json::to_value(NewSessionRequest::new("/repo"))
6245 .unwrap()
6246 .get("systemPrompt")
6247 .is_none()
6248 );
6249 assert_system_prompt_is_strict::<NewSessionRequest>(&json!({
6250 "cwd": "/repo",
6251 "mcpServers": []
6252 }));
6253 assert_system_prompt_is_strict::<LoadSessionRequest>(&json!({
6254 "sessionId": "sess-1",
6255 "cwd": "/repo",
6256 "mcpServers": []
6257 }));
6258 assert_system_prompt_is_strict::<ResumeSessionRequest>(&json!({
6259 "sessionId": "sess-1",
6260 "cwd": "/repo"
6261 }));
6262 #[cfg(feature = "unstable_session_fork")]
6263 assert_system_prompt_is_strict::<ForkSessionRequest>(&json!({
6264 "sessionId": "sess-1",
6265 "cwd": "/repo"
6266 }));
6267 }
6268
6269 #[test]
6270 fn test_auth_method_terminal_serialization() {
6271 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
6272
6273 let json = serde_json::to_value(&method).unwrap();
6274 assert_eq!(
6275 json,
6276 json!({
6277 "id": "tui-auth",
6278 "name": "Terminal Auth",
6279 "type": "terminal"
6280 })
6281 );
6282 assert!(!json.as_object().unwrap().contains_key("args"));
6284 assert!(!json.as_object().unwrap().contains_key("env"));
6285
6286 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6287 match deserialized {
6288 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
6289 assert_eq!(args, Vec::<String>::new());
6290 assert!(env.is_empty());
6291 }
6292 _ => panic!("Expected Terminal variant"),
6293 }
6294 }
6295
6296 #[test]
6297 fn test_auth_method_terminal_with_args_and_env_serialization() {
6298 use std::collections::HashMap;
6299
6300 let mut env = HashMap::new();
6301 env.insert("TERM".to_string(), "xterm-256color".to_string());
6302
6303 let method = AuthMethod::Terminal(
6304 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
6305 .args(vec!["--interactive".to_string(), "--color".to_string()])
6306 .env(env),
6307 );
6308
6309 let json = serde_json::to_value(&method).unwrap();
6310 assert_eq!(
6311 json,
6312 json!({
6313 "id": "tui-auth",
6314 "name": "Terminal Auth",
6315 "type": "terminal",
6316 "args": ["--interactive", "--color"],
6317 "env": {
6318 "TERM": "xterm-256color"
6319 }
6320 })
6321 );
6322
6323 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6324 match deserialized {
6325 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
6326 assert_eq!(args, vec!["--interactive", "--color"]);
6327 assert_eq!(env.len(), 1);
6328 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
6329 }
6330 _ => panic!("Expected Terminal variant"),
6331 }
6332 }
6333
6334 #[test]
6335 fn test_session_config_option_value_id_serialize() {
6336 let val = SessionConfigOptionValue::value_id("model-1");
6337 let json = serde_json::to_value(&val).unwrap();
6338 assert_eq!(json, json!({ "value": "model-1" }));
6340 assert!(!json.as_object().unwrap().contains_key("type"));
6341 }
6342
6343 #[test]
6344 fn test_session_config_option_value_boolean_serialize() {
6345 let val = SessionConfigOptionValue::boolean(true);
6346 let json = serde_json::to_value(&val).unwrap();
6347 assert_eq!(json, json!({ "type": "boolean", "value": true }));
6348 }
6349
6350 #[test]
6351 fn test_session_config_option_value_deserialize_no_type() {
6352 let json = json!({ "value": "model-1" });
6354 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6355 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
6356 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
6357 }
6358
6359 #[test]
6360 fn test_session_config_option_value_deserialize_boolean() {
6361 let json = json!({ "type": "boolean", "value": true });
6362 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6363 assert_eq!(val, SessionConfigOptionValue::boolean(true));
6364 assert_eq!(val.as_bool(), Some(true));
6365 }
6366
6367 #[test]
6368 fn test_session_config_option_value_deserialize_boolean_false() {
6369 let json = json!({ "type": "boolean", "value": false });
6370 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6371 assert_eq!(val, SessionConfigOptionValue::boolean(false));
6372 assert_eq!(val.as_bool(), Some(false));
6373 }
6374
6375 #[test]
6376 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
6377 let json = json!({ "type": "text", "value": "freeform input" });
6379 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6380 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
6381 }
6382
6383 #[test]
6384 fn test_session_config_option_value_roundtrip_value_id() {
6385 let original = SessionConfigOptionValue::value_id("option-a");
6386 let json = serde_json::to_value(&original).unwrap();
6387 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6388 assert_eq!(original, roundtripped);
6389 }
6390
6391 #[test]
6392 fn test_session_config_option_value_roundtrip_boolean() {
6393 let original = SessionConfigOptionValue::boolean(false);
6394 let json = serde_json::to_value(&original).unwrap();
6395 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6396 assert_eq!(original, roundtripped);
6397 }
6398
6399 #[test]
6400 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
6401 let json = json!({ "type": "boolean", "value": "not a bool" });
6403 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
6404 assert!(result.is_ok());
6406 assert_eq!(
6407 result.unwrap().as_value_id().unwrap().to_string(),
6408 "not a bool"
6409 );
6410 }
6411
6412 #[test]
6413 fn test_session_config_option_value_from_impls() {
6414 let from_str: SessionConfigOptionValue = "model-1".into();
6415 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
6416
6417 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
6418 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
6419
6420 let from_bool: SessionConfigOptionValue = true.into();
6421 assert_eq!(from_bool.as_bool(), Some(true));
6422 }
6423
6424 #[test]
6425 fn test_set_session_config_option_request_value_id() {
6426 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
6427 let json = serde_json::to_value(&req).unwrap();
6428 assert_eq!(
6429 json,
6430 json!({
6431 "sessionId": "sess_1",
6432 "configId": "model",
6433 "value": "model-1"
6434 })
6435 );
6436 assert!(!json.as_object().unwrap().contains_key("type"));
6438 }
6439
6440 #[test]
6441 fn test_set_session_config_option_request_boolean() {
6442 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
6443 let json = serde_json::to_value(&req).unwrap();
6444 assert_eq!(
6445 json,
6446 json!({
6447 "sessionId": "sess_1",
6448 "configId": "brave_mode",
6449 "type": "boolean",
6450 "value": true
6451 })
6452 );
6453 }
6454
6455 #[test]
6456 fn test_set_session_config_option_request_deserialize_no_type() {
6457 let json = json!({
6459 "sessionId": "sess_1",
6460 "configId": "model",
6461 "value": "model-1"
6462 });
6463 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6464 assert_eq!(req.session_id.to_string(), "sess_1");
6465 assert_eq!(req.config_id.to_string(), "model");
6466 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
6467 }
6468
6469 #[test]
6470 fn test_set_session_config_option_request_deserialize_boolean() {
6471 let json = json!({
6472 "sessionId": "sess_1",
6473 "configId": "brave_mode",
6474 "type": "boolean",
6475 "value": true
6476 });
6477 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6478 assert_eq!(req.value.as_bool(), Some(true));
6479 }
6480
6481 #[test]
6482 fn test_set_session_config_option_request_roundtrip_value_id() {
6483 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
6484 let json = serde_json::to_value(&original).unwrap();
6485 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6486 assert_eq!(original, roundtripped);
6487 }
6488
6489 #[test]
6490 fn test_set_session_config_option_request_roundtrip_boolean() {
6491 let original = SetSessionConfigOptionRequest::new("s", "c", false);
6492 let json = serde_json::to_value(&original).unwrap();
6493 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6494 assert_eq!(original, roundtripped);
6495 }
6496
6497 #[test]
6498 fn test_session_config_boolean_serialization() {
6499 let cfg = SessionConfigBoolean::new(true);
6500 let json = serde_json::to_value(&cfg).unwrap();
6501 assert_eq!(json, json!({ "currentValue": true }));
6502
6503 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6504 assert!(deserialized.current_value);
6505 }
6506
6507 #[test]
6508 fn test_session_config_option_boolean_variant() {
6509 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6510 .description("Skip confirmation prompts")
6511 .meta(test_meta());
6512 assert_eq!(serialized_meta_key_count(&opt), 1);
6513
6514 let json = serde_json::to_value(&opt).unwrap();
6515 assert_eq!(
6516 json,
6517 json!({
6518 "id": "brave_mode",
6519 "name": "Brave Mode",
6520 "description": "Skip confirmation prompts",
6521 "type": "boolean",
6522 "currentValue": false,
6523 "_meta": {
6524 "source": "test"
6525 }
6526 })
6527 );
6528
6529 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6530 assert_eq!(deserialized.id.to_string(), "brave_mode");
6531 assert_eq!(deserialized.name, "Brave Mode");
6532 match deserialized.kind {
6533 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6534 _ => panic!("Expected Boolean kind"),
6535 }
6536 }
6537
6538 #[test]
6539 fn test_session_config_option_select_still_works() {
6540 let opt = SessionConfigOption::select(
6542 "model",
6543 "Model",
6544 "model-1",
6545 vec![
6546 SessionConfigSelectOption::new("model-1", "Model 1"),
6547 SessionConfigSelectOption::new("model-2", "Model 2"),
6548 ],
6549 )
6550 .meta(test_meta());
6551 assert_eq!(serialized_meta_key_count(&opt), 1);
6552
6553 let json = serde_json::to_value(&opt).unwrap();
6554 assert_eq!(json["type"], "select");
6555 assert_eq!(json["currentValue"], "model-1");
6556 assert_eq!(json["options"].as_array().unwrap().len(), 2);
6557 assert_eq!(json["_meta"]["source"], "test");
6558
6559 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6560 match deserialized.kind {
6561 SessionConfigKind::Select(ref s) => {
6562 assert_eq!(s.current_value.to_string(), "model-1");
6563 }
6564 _ => panic!("Expected Select kind"),
6565 }
6566 }
6567
6568 #[cfg(feature = "unstable_llm_providers")]
6569 #[test]
6570 fn test_llm_protocol_known_variants() {
6571 assert_eq!(
6572 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6573 json!("anthropic")
6574 );
6575 assert_eq!(
6576 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6577 json!("openai")
6578 );
6579 assert_eq!(
6580 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6581 json!("azure")
6582 );
6583 assert_eq!(
6584 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6585 json!("vertex")
6586 );
6587 assert_eq!(
6588 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6589 json!("bedrock")
6590 );
6591
6592 assert_eq!(
6593 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6594 LlmProtocol::Anthropic
6595 );
6596 assert_eq!(
6597 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6598 LlmProtocol::OpenAi
6599 );
6600 assert_eq!(
6601 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6602 LlmProtocol::Azure
6603 );
6604 assert_eq!(
6605 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6606 LlmProtocol::Vertex
6607 );
6608 assert_eq!(
6609 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6610 LlmProtocol::Bedrock
6611 );
6612 }
6613
6614 #[cfg(feature = "unstable_llm_providers")]
6615 #[test]
6616 fn test_llm_protocol_unknown_variant() {
6617 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6618 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6619
6620 let json = serde_json::to_value(&unknown).unwrap();
6621 assert_eq!(json, json!("cohere"));
6622 }
6623
6624 #[cfg(feature = "unstable_llm_providers")]
6625 #[test]
6626 fn test_provider_current_config_serialization() {
6627 let config =
6628 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6629
6630 let json = serde_json::to_value(&config).unwrap();
6631 assert_eq!(
6632 json,
6633 json!({
6634 "apiType": "anthropic",
6635 "baseUrl": "https://api.anthropic.com"
6636 })
6637 );
6638
6639 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6640 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6641 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6642 }
6643
6644 #[cfg(feature = "unstable_llm_providers")]
6645 #[test]
6646 fn test_provider_info_with_current_config() {
6647 let info = ProviderInfo::new(
6648 "main",
6649 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6650 true,
6651 Some(ProviderCurrentConfig::new(
6652 LlmProtocol::Anthropic,
6653 "https://api.anthropic.com",
6654 )),
6655 );
6656
6657 let json = serde_json::to_value(&info).unwrap();
6658 assert_eq!(
6659 json,
6660 json!({
6661 "providerId": "main",
6662 "supported": ["anthropic", "openai"],
6663 "required": true,
6664 "current": {
6665 "apiType": "anthropic",
6666 "baseUrl": "https://api.anthropic.com"
6667 }
6668 })
6669 );
6670
6671 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6672 assert_eq!(deserialized.provider_id.to_string(), "main");
6673 assert_eq!(deserialized.supported.len(), 2);
6674 assert!(deserialized.required);
6675 assert!(deserialized.current.is_some());
6676 assert_eq!(
6677 deserialized.current.as_ref().unwrap().api_type,
6678 LlmProtocol::Anthropic
6679 );
6680 }
6681
6682 #[cfg(feature = "unstable_llm_providers")]
6683 #[test]
6684 fn test_provider_info_disabled() {
6685 let info = ProviderInfo::new(
6686 "secondary",
6687 vec![LlmProtocol::OpenAi],
6688 false,
6689 None::<ProviderCurrentConfig>,
6690 );
6691
6692 let json = serde_json::to_value(&info).unwrap();
6693 assert_eq!(
6694 json,
6695 json!({
6696 "providerId": "secondary",
6697 "supported": ["openai"],
6698 "required": false
6699 })
6700 );
6701
6702 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6703 assert_eq!(deserialized.provider_id.to_string(), "secondary");
6704 assert!(!deserialized.required);
6705 assert!(deserialized.current.is_none());
6706 }
6707
6708 #[cfg(feature = "unstable_llm_providers")]
6709 #[test]
6710 fn test_provider_info_missing_current_defaults_to_none() {
6711 let json = json!({
6713 "providerId": "main",
6714 "supported": ["anthropic"],
6715 "required": true
6716 });
6717 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6718 assert!(deserialized.current.is_none());
6719 }
6720
6721 #[cfg(feature = "unstable_llm_providers")]
6722 #[test]
6723 fn test_provider_info_explicit_null_current_decodes_to_none() {
6724 let json = json!({
6728 "providerId": "main",
6729 "supported": ["anthropic"],
6730 "required": true,
6731 "current": null
6732 });
6733 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6734 assert!(deserialized.current.is_none());
6735 }
6736
6737 #[cfg(feature = "unstable_llm_providers")]
6738 #[test]
6739 fn test_list_providers_response_serialization() {
6740 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6741 "main",
6742 vec![LlmProtocol::Anthropic],
6743 true,
6744 Some(ProviderCurrentConfig::new(
6745 LlmProtocol::Anthropic,
6746 "https://api.anthropic.com",
6747 )),
6748 )]);
6749
6750 let json = serde_json::to_value(&response).unwrap();
6751 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6752 assert_eq!(json["providers"][0]["providerId"], "main");
6753
6754 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6755 assert_eq!(deserialized.providers.len(), 1);
6756 }
6757
6758 #[cfg(feature = "unstable_llm_providers")]
6759 #[test]
6760 fn test_set_provider_request_serialization() {
6761 use std::collections::HashMap;
6762
6763 let mut headers = HashMap::new();
6764 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6765
6766 let request =
6767 SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6768 .headers(headers);
6769
6770 let json = serde_json::to_value(&request).unwrap();
6771 assert_eq!(
6772 json,
6773 json!({
6774 "providerId": "main",
6775 "apiType": "openai",
6776 "baseUrl": "https://api.openai.com/v1",
6777 "headers": {
6778 "Authorization": "Bearer sk-test"
6779 }
6780 })
6781 );
6782
6783 let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6784 assert_eq!(deserialized.provider_id.to_string(), "main");
6785 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6786 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6787 assert_eq!(deserialized.headers.len(), 1);
6788 assert_eq!(
6789 deserialized.headers.get("Authorization").unwrap(),
6790 "Bearer sk-test"
6791 );
6792 }
6793
6794 #[cfg(feature = "unstable_llm_providers")]
6795 #[test]
6796 fn test_set_provider_request_omits_empty_headers() {
6797 let request =
6798 SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6799
6800 let json = serde_json::to_value(&request).unwrap();
6801 assert!(!json.as_object().unwrap().contains_key("headers"));
6803 }
6804
6805 #[cfg(feature = "unstable_llm_providers")]
6806 #[test]
6807 fn test_disable_provider_request_serialization() {
6808 let request = DisableProviderRequest::new("secondary");
6809
6810 let json = serde_json::to_value(&request).unwrap();
6811 assert_eq!(json, json!({ "providerId": "secondary" }));
6812
6813 let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6814 assert_eq!(deserialized.provider_id.to_string(), "secondary");
6815 }
6816
6817 #[cfg(feature = "unstable_llm_providers")]
6818 #[test]
6819 fn test_providers_capabilities_serialization() {
6820 let caps = ProvidersCapabilities::new();
6821
6822 let json = serde_json::to_value(&caps).unwrap();
6823 assert_eq!(json, json!({}));
6824
6825 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6826 assert!(deserialized.meta.is_none());
6827 }
6828
6829 #[cfg(feature = "unstable_llm_providers")]
6830 #[test]
6831 fn test_agent_capabilities_with_providers() {
6832 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6833
6834 let json = serde_json::to_value(&caps).unwrap();
6835 assert_eq!(json["providers"], json!({}));
6836
6837 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6838 assert!(deserialized.providers.is_some());
6839 }
6840
6841 #[test]
6842 fn prompt_request_rejects_malformed_content_block() {
6843 use serde_json::json;
6844
6845 assert!(
6846 serde_json::from_value::<PromptRequest>(json!({
6847 "sessionId": "sess-1",
6848 "prompt": [{"type": "text"}]
6849 }))
6850 .is_err()
6851 );
6852 }
6853
6854 #[test]
6855 fn prompt_request_rejects_non_array_prompt() {
6856 use serde_json::json;
6857
6858 assert!(
6859 serde_json::from_value::<PromptRequest>(json!({
6860 "sessionId": "sess-1",
6861 "prompt": "hello"
6862 }))
6863 .is_err()
6864 );
6865 }
6866
6867 fn assert_session_setup_lists_are_strict<T>(base: &serde_json::Value)
6868 where
6869 T: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
6870 {
6871 let name = std::any::type_name::<T>();
6872 let with = |field: &str, value: serde_json::Value| {
6873 let mut request = base.clone();
6874 request[field] = value;
6875 serde_json::from_value::<T>(request)
6876 };
6877
6878 for (field, value) in [
6879 (
6881 "mcpServers",
6882 json!([
6883 {"name": "github", "command": "/usr/bin/gh-mcp", "args": [], "env": [{"name": "GITHUB_TOKEN", "value": null}]},
6884 {"name": "fs", "command": "/usr/bin/fs-mcp", "args": [], "env": []}
6885 ]),
6886 ),
6887 ("mcpServers", json!({"name": "fs"})),
6888 ("additionalDirectories", json!(["/repo/lib", 42])),
6889 ("additionalDirectories", json!("/repo/lib")),
6890 ] {
6891 assert!(
6892 with(field, value.clone()).is_err(),
6893 "{name}.{field}: {value}"
6894 );
6895 }
6896
6897 let empty = serde_json::from_value::<T>(base.clone()).unwrap();
6898 for field in ["mcpServers", "additionalDirectories"] {
6899 assert_eq!(
6900 with(field, serde_json::Value::Null).unwrap(),
6901 empty,
6902 "{name}.{field}"
6903 );
6904 }
6905 }
6906
6907 #[test]
6908 fn session_setup_requests_reject_malformed_mcp_servers_and_directories() {
6909 assert_session_setup_lists_are_strict::<NewSessionRequest>(&json!({
6910 "cwd": "/repo",
6911 "mcpServers": []
6912 }));
6913 assert_session_setup_lists_are_strict::<LoadSessionRequest>(&json!({
6914 "sessionId": "sess-1",
6915 "cwd": "/repo",
6916 "mcpServers": []
6917 }));
6918 assert_session_setup_lists_are_strict::<ResumeSessionRequest>(&json!({
6919 "sessionId": "sess-1",
6920 "cwd": "/repo"
6921 }));
6922 #[cfg(feature = "unstable_session_fork")]
6923 assert_session_setup_lists_are_strict::<ForkSessionRequest>(&json!({
6924 "sessionId": "sess-1",
6925 "cwd": "/repo"
6926 }));
6927 }
6928
6929 #[test]
6930 fn mcp_server_lists_treat_null_as_empty() {
6931 let servers: Vec<McpServer> = serde_json::from_value(json!([
6932 {"name": "fs", "command": "/usr/bin/fs-mcp", "args": null, "env": null},
6933 {"type": "http", "name": "api", "url": "https://example.com/mcp", "headers": null},
6934 {"type": "sse", "name": "events", "url": "https://example.com/sse", "headers": null}
6935 ]))
6936 .unwrap();
6937
6938 assert_eq!(
6939 servers,
6940 vec![
6941 McpServer::Stdio(McpServerStdio::new("fs", "/usr/bin/fs-mcp")),
6942 McpServer::Http(McpServerHttp::new("api", "https://example.com/mcp")),
6943 McpServer::Sse(McpServerSse::new("events", "https://example.com/sse")),
6944 ]
6945 );
6946 }
6947
6948 #[test]
6949 fn terminal_auth_methods_reject_malformed_launch_config() {
6950 let response: InitializeResponse = serde_json::from_value(json!({
6954 "protocolVersion": 1,
6955 "authMethods": [
6956 {"type": "terminal", "id": "bad-args", "name": "Log in", "args": ["auth", "--port", 8123]},
6957 {"type": "terminal", "id": "bad-env", "name": "Log in", "env": {"AUTH_MODE": "device", "DEBUG": 1}},
6958 {"type": "terminal", "id": "null-config", "name": "Log in", "args": null, "env": null},
6959 {"id": "agent", "name": "Agent login"}
6960 ]
6961 }))
6962 .unwrap();
6963
6964 assert_eq!(
6965 response.auth_methods,
6966 vec![
6967 AuthMethod::Terminal(AuthMethodTerminal::new("null-config", "Log in")),
6968 AuthMethod::Agent(AuthMethodAgent::new("agent", "Agent login")),
6969 ]
6970 );
6971 assert!(
6972 serde_json::from_value::<AuthMethod>(json!({
6973 "type": "terminal",
6974 "id": "bad-args",
6975 "name": "Log in",
6976 "args": ["auth", 8123]
6977 }))
6978 .is_err()
6979 );
6980 }
6981}