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 #[serde(default, skip_serializing_if = "Vec::is_empty")]
723 pub args: Vec<String>,
724 #[serde_as(deserialize_as = "DefaultOnNull")]
727 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
728 pub env: HashMap<String, String>,
729 #[serde_as(deserialize_as = "DefaultOnError")]
735 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
736 #[serde(default)]
737 #[serde(rename = "_meta")]
738 pub meta: Option<Meta>,
739}
740
741impl AuthMethodTerminal {
742 #[must_use]
744 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
745 Self {
746 id: id.into(),
747 name: name.into(),
748 description: None,
749 args: Vec::new(),
750 env: HashMap::new(),
751 meta: None,
752 }
753 }
754
755 #[must_use]
757 pub fn args(mut self, args: Vec<String>) -> Self {
758 self.args = args;
759 self
760 }
761
762 #[must_use]
765 pub fn env(mut self, env: HashMap<String, String>) -> Self {
766 self.env = env;
767 self
768 }
769
770 #[must_use]
772 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
773 self.description = description.into_option();
774 self
775 }
776
777 #[must_use]
783 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
784 self.meta = meta.into_option();
785 self
786 }
787}
788
789#[serde_as]
795#[skip_serializing_none]
796#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
797#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
798#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME)))]
799#[serde(rename_all = "camelCase")]
800#[non_exhaustive]
801pub struct NewSessionRequest {
802 pub cwd: PathBuf,
804 #[serde_as(deserialize_as = "DefaultOnNull")]
810 #[serde(default, skip_serializing_if = "Vec::is_empty")]
811 pub additional_directories: Vec<PathBuf>,
812 #[serde_as(deserialize_as = "DefaultOnNull")]
814 pub mcp_servers: Vec<McpServer>,
815 #[cfg(feature = "unstable_session_system_prompt")]
825 #[serde(default)]
826 pub system_prompt: Option<SystemPrompt>,
827 #[serde_as(deserialize_as = "DefaultOnError")]
833 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
834 #[serde(default)]
835 #[serde(rename = "_meta")]
836 pub meta: Option<Meta>,
837}
838
839impl NewSessionRequest {
840 #[must_use]
842 pub fn new(cwd: impl Into<PathBuf>) -> Self {
843 Self {
844 cwd: cwd.into(),
845 additional_directories: vec![],
846 mcp_servers: vec![],
847 #[cfg(feature = "unstable_session_system_prompt")]
848 system_prompt: None,
849 meta: None,
850 }
851 }
852
853 #[must_use]
855 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
856 self.additional_directories = additional_directories;
857 self
858 }
859
860 #[must_use]
862 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
863 self.mcp_servers = mcp_servers;
864 self
865 }
866
867 #[cfg(feature = "unstable_session_system_prompt")]
873 #[must_use]
874 pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
875 self.system_prompt = system_prompt.into_option();
876 self
877 }
878
879 #[must_use]
885 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
886 self.meta = meta.into_option();
887 self
888 }
889}
890
891#[serde_as]
895#[skip_serializing_none]
896#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
897#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
898#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME)))]
899#[serde(rename_all = "camelCase")]
900#[non_exhaustive]
901pub struct NewSessionResponse {
902 pub session_id: SessionId,
906 #[serde_as(deserialize_as = "DefaultOnError")]
910 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
911 #[serde(default)]
912 pub modes: Option<SessionModeState>,
913 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
915 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
916 #[serde(default)]
917 pub config_options: Option<Vec<SessionConfigOption>>,
918 #[serde_as(deserialize_as = "DefaultOnError")]
924 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
925 #[serde(default)]
926 #[serde(rename = "_meta")]
927 pub meta: Option<Meta>,
928}
929
930impl NewSessionResponse {
931 #[must_use]
933 pub fn new(session_id: impl Into<SessionId>) -> Self {
934 Self {
935 session_id: session_id.into(),
936 modes: None,
937 config_options: None,
938 meta: None,
939 }
940 }
941
942 #[must_use]
946 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
947 self.modes = modes.into_option();
948 self
949 }
950
951 #[must_use]
953 pub fn config_options(
954 mut self,
955 config_options: impl IntoOption<Vec<SessionConfigOption>>,
956 ) -> Self {
957 self.config_options = config_options.into_option();
958 self
959 }
960
961 #[must_use]
967 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
968 self.meta = meta.into_option();
969 self
970 }
971}
972
973#[serde_as]
981#[skip_serializing_none]
982#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
983#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
984#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME)))]
985#[serde(rename_all = "camelCase")]
986#[non_exhaustive]
987pub struct LoadSessionRequest {
988 #[serde_as(deserialize_as = "DefaultOnNull")]
990 pub mcp_servers: Vec<McpServer>,
991 pub cwd: PathBuf,
993 #[serde_as(deserialize_as = "DefaultOnNull")]
1000 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1001 pub additional_directories: Vec<PathBuf>,
1002 pub session_id: SessionId,
1004 #[cfg(feature = "unstable_session_system_prompt")]
1016 #[serde(default)]
1017 pub system_prompt: Option<SystemPrompt>,
1018 #[serde_as(deserialize_as = "DefaultOnError")]
1024 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1025 #[serde(default)]
1026 #[serde(rename = "_meta")]
1027 pub meta: Option<Meta>,
1028}
1029
1030impl LoadSessionRequest {
1031 #[must_use]
1033 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1034 Self {
1035 mcp_servers: vec![],
1036 cwd: cwd.into(),
1037 additional_directories: vec![],
1038 session_id: session_id.into(),
1039 #[cfg(feature = "unstable_session_system_prompt")]
1040 system_prompt: None,
1041 meta: None,
1042 }
1043 }
1044
1045 #[must_use]
1047 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1048 self.additional_directories = additional_directories;
1049 self
1050 }
1051
1052 #[must_use]
1054 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1055 self.mcp_servers = mcp_servers;
1056 self
1057 }
1058
1059 #[cfg(feature = "unstable_session_system_prompt")]
1065 #[must_use]
1066 pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1067 self.system_prompt = system_prompt.into_option();
1068 self
1069 }
1070
1071 #[must_use]
1077 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1078 self.meta = meta.into_option();
1079 self
1080 }
1081}
1082
1083crate::serde_util::default_on_null! {
1084 #[serde_as]
1086 #[skip_serializing_none]
1087 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1088 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1089 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME)))]
1090 #[serde(rename_all = "camelCase")]
1091 #[non_exhaustive]
1092 pub struct LoadSessionResponse {
1093 #[serde_as(deserialize_as = "DefaultOnError")]
1097 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1098 #[serde(default)]
1099 pub modes: Option<SessionModeState>,
1100 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1102 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1103 #[serde(default)]
1104 pub config_options: Option<Vec<SessionConfigOption>>,
1105 #[serde_as(deserialize_as = "DefaultOnError")]
1111 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1112 #[serde(default)]
1113 #[serde(rename = "_meta")]
1114 pub meta: Option<Meta>,
1115 }
1116}
1117
1118impl LoadSessionResponse {
1119 #[must_use]
1121 pub fn new() -> Self {
1122 Self::default()
1123 }
1124
1125 #[must_use]
1129 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1130 self.modes = modes.into_option();
1131 self
1132 }
1133
1134 #[must_use]
1136 pub fn config_options(
1137 mut self,
1138 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1139 ) -> Self {
1140 self.config_options = config_options.into_option();
1141 self
1142 }
1143
1144 #[must_use]
1150 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1151 self.meta = meta.into_option();
1152 self
1153 }
1154}
1155
1156#[cfg(feature = "unstable_session_fork")]
1169#[serde_as]
1170#[skip_serializing_none]
1171#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1172#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1173#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME)))]
1174#[serde(rename_all = "camelCase")]
1175#[non_exhaustive]
1176pub struct ForkSessionRequest {
1177 pub session_id: SessionId,
1179 pub cwd: PathBuf,
1181 #[serde_as(deserialize_as = "DefaultOnNull")]
1187 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1188 pub additional_directories: Vec<PathBuf>,
1189 #[serde_as(deserialize_as = "DefaultOnNull")]
1191 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1192 pub mcp_servers: Vec<McpServer>,
1193 #[cfg(feature = "unstable_session_system_prompt")]
1205 #[serde(default)]
1206 pub system_prompt: Option<SystemPrompt>,
1207 #[serde_as(deserialize_as = "DefaultOnError")]
1213 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1214 #[serde(default)]
1215 #[serde(rename = "_meta")]
1216 pub meta: Option<Meta>,
1217}
1218
1219#[cfg(feature = "unstable_session_fork")]
1220impl ForkSessionRequest {
1221 #[must_use]
1223 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1224 Self {
1225 session_id: session_id.into(),
1226 cwd: cwd.into(),
1227 additional_directories: vec![],
1228 mcp_servers: vec![],
1229 #[cfg(feature = "unstable_session_system_prompt")]
1230 system_prompt: None,
1231 meta: None,
1232 }
1233 }
1234
1235 #[must_use]
1237 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1238 self.additional_directories = additional_directories;
1239 self
1240 }
1241
1242 #[must_use]
1244 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1245 self.mcp_servers = mcp_servers;
1246 self
1247 }
1248
1249 #[cfg(feature = "unstable_session_system_prompt")]
1255 #[must_use]
1256 pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1257 self.system_prompt = system_prompt.into_option();
1258 self
1259 }
1260
1261 #[must_use]
1267 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1268 self.meta = meta.into_option();
1269 self
1270 }
1271}
1272
1273#[cfg(feature = "unstable_session_fork")]
1279#[serde_as]
1280#[skip_serializing_none]
1281#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1282#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1283#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME)))]
1284#[serde(rename_all = "camelCase")]
1285#[non_exhaustive]
1286pub struct ForkSessionResponse {
1287 pub session_id: SessionId,
1289 #[serde_as(deserialize_as = "DefaultOnError")]
1293 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1294 #[serde(default)]
1295 pub modes: Option<SessionModeState>,
1296 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1298 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1299 #[serde(default)]
1300 pub config_options: Option<Vec<SessionConfigOption>>,
1301 #[serde_as(deserialize_as = "DefaultOnError")]
1307 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1308 #[serde(default)]
1309 #[serde(rename = "_meta")]
1310 pub meta: Option<Meta>,
1311}
1312
1313#[cfg(feature = "unstable_session_fork")]
1314impl ForkSessionResponse {
1315 #[must_use]
1317 pub fn new(session_id: impl Into<SessionId>) -> Self {
1318 Self {
1319 session_id: session_id.into(),
1320 modes: None,
1321 config_options: None,
1322 meta: None,
1323 }
1324 }
1325
1326 #[must_use]
1330 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1331 self.modes = modes.into_option();
1332 self
1333 }
1334
1335 #[must_use]
1337 pub fn config_options(
1338 mut self,
1339 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1340 ) -> Self {
1341 self.config_options = config_options.into_option();
1342 self
1343 }
1344
1345 #[must_use]
1351 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1352 self.meta = meta.into_option();
1353 self
1354 }
1355}
1356
1357#[serde_as]
1366#[skip_serializing_none]
1367#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1368#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1369#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME)))]
1370#[serde(rename_all = "camelCase")]
1371#[non_exhaustive]
1372pub struct ResumeSessionRequest {
1373 pub session_id: SessionId,
1375 pub cwd: PathBuf,
1377 #[serde_as(deserialize_as = "DefaultOnNull")]
1384 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1385 pub additional_directories: Vec<PathBuf>,
1386 #[serde_as(deserialize_as = "DefaultOnNull")]
1388 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1389 pub mcp_servers: Vec<McpServer>,
1390 #[cfg(feature = "unstable_session_system_prompt")]
1402 #[serde(default)]
1403 pub system_prompt: Option<SystemPrompt>,
1404 #[serde_as(deserialize_as = "DefaultOnError")]
1410 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1411 #[serde(default)]
1412 #[serde(rename = "_meta")]
1413 pub meta: Option<Meta>,
1414}
1415
1416impl ResumeSessionRequest {
1417 #[must_use]
1419 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1420 Self {
1421 session_id: session_id.into(),
1422 cwd: cwd.into(),
1423 additional_directories: vec![],
1424 mcp_servers: vec![],
1425 #[cfg(feature = "unstable_session_system_prompt")]
1426 system_prompt: None,
1427 meta: None,
1428 }
1429 }
1430
1431 #[must_use]
1433 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1434 self.additional_directories = additional_directories;
1435 self
1436 }
1437
1438 #[must_use]
1440 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1441 self.mcp_servers = mcp_servers;
1442 self
1443 }
1444
1445 #[cfg(feature = "unstable_session_system_prompt")]
1451 #[must_use]
1452 pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1453 self.system_prompt = system_prompt.into_option();
1454 self
1455 }
1456
1457 #[must_use]
1463 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1464 self.meta = meta.into_option();
1465 self
1466 }
1467}
1468
1469crate::serde_util::default_on_null! {
1470 #[serde_as]
1472 #[skip_serializing_none]
1473 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1474 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1475 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME)))]
1476 #[serde(rename_all = "camelCase")]
1477 #[non_exhaustive]
1478 pub struct ResumeSessionResponse {
1479 #[serde_as(deserialize_as = "DefaultOnError")]
1483 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1484 #[serde(default)]
1485 pub modes: Option<SessionModeState>,
1486 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1488 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1489 #[serde(default)]
1490 pub config_options: Option<Vec<SessionConfigOption>>,
1491 #[serde_as(deserialize_as = "DefaultOnError")]
1497 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1498 #[serde(default)]
1499 #[serde(rename = "_meta")]
1500 pub meta: Option<Meta>,
1501 }
1502}
1503
1504impl ResumeSessionResponse {
1505 #[must_use]
1507 pub fn new() -> Self {
1508 Self::default()
1509 }
1510
1511 #[must_use]
1515 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1516 self.modes = modes.into_option();
1517 self
1518 }
1519
1520 #[must_use]
1522 pub fn config_options(
1523 mut self,
1524 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1525 ) -> Self {
1526 self.config_options = config_options.into_option();
1527 self
1528 }
1529
1530 #[must_use]
1536 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1537 self.meta = meta.into_option();
1538 self
1539 }
1540}
1541
1542#[serde_as]
1552#[skip_serializing_none]
1553#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1554#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1555#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME)))]
1556#[serde(rename_all = "camelCase")]
1557#[non_exhaustive]
1558pub struct CloseSessionRequest {
1559 pub session_id: SessionId,
1561 #[serde_as(deserialize_as = "DefaultOnError")]
1567 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1568 #[serde(default)]
1569 #[serde(rename = "_meta")]
1570 pub meta: Option<Meta>,
1571}
1572
1573impl CloseSessionRequest {
1574 #[must_use]
1576 pub fn new(session_id: impl Into<SessionId>) -> Self {
1577 Self {
1578 session_id: session_id.into(),
1579 meta: None,
1580 }
1581 }
1582
1583 #[must_use]
1589 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1590 self.meta = meta.into_option();
1591 self
1592 }
1593}
1594
1595crate::serde_util::default_on_null! {
1596 #[serde_as]
1598 #[skip_serializing_none]
1599 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1600 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1601 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME)))]
1602 #[serde(rename_all = "camelCase")]
1603 #[non_exhaustive]
1604 pub struct CloseSessionResponse {
1605 #[serde_as(deserialize_as = "DefaultOnError")]
1611 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1612 #[serde(default)]
1613 #[serde(rename = "_meta")]
1614 pub meta: Option<Meta>,
1615 }
1616}
1617
1618impl CloseSessionResponse {
1619 #[must_use]
1621 pub fn new() -> Self {
1622 Self::default()
1623 }
1624
1625 #[must_use]
1631 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1632 self.meta = meta.into_option();
1633 self
1634 }
1635}
1636
1637crate::serde_util::default_on_null! {
1640 #[serde_as]
1644 #[skip_serializing_none]
1645 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1646 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1647 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME)))]
1648 #[serde(rename_all = "camelCase")]
1649 #[non_exhaustive]
1650 pub struct ListSessionsRequest {
1651 #[serde(default)]
1653 pub cwd: Option<PathBuf>,
1654 #[serde(default)]
1656 pub cursor: Option<String>,
1657 #[serde_as(deserialize_as = "DefaultOnError")]
1663 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1664 #[serde(default)]
1665 #[serde(rename = "_meta")]
1666 pub meta: Option<Meta>,
1667 }
1668}
1669
1670impl ListSessionsRequest {
1671 #[must_use]
1673 pub fn new() -> Self {
1674 Self::default()
1675 }
1676
1677 #[must_use]
1679 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1680 self.cwd = cwd.into_option();
1681 self
1682 }
1683
1684 #[must_use]
1686 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1687 self.cursor = cursor.into_option();
1688 self
1689 }
1690
1691 #[must_use]
1697 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1698 self.meta = meta.into_option();
1699 self
1700 }
1701}
1702
1703#[serde_as]
1705#[skip_serializing_none]
1706#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1707#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1708#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME)))]
1709#[serde(rename_all = "camelCase")]
1710#[non_exhaustive]
1711pub struct ListSessionsResponse {
1712 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1714 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1715 pub sessions: Vec<SessionInfo>,
1716 #[serde_as(deserialize_as = "DefaultOnError")]
1719 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1720 #[serde(default)]
1721 pub next_cursor: Option<String>,
1722 #[serde_as(deserialize_as = "DefaultOnError")]
1728 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1729 #[serde(default)]
1730 #[serde(rename = "_meta")]
1731 pub meta: Option<Meta>,
1732}
1733
1734impl ListSessionsResponse {
1735 #[must_use]
1737 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1738 Self {
1739 sessions,
1740 next_cursor: None,
1741 meta: None,
1742 }
1743 }
1744
1745 #[must_use]
1747 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1748 self.next_cursor = next_cursor.into_option();
1749 self
1750 }
1751
1752 #[must_use]
1758 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1759 self.meta = meta.into_option();
1760 self
1761 }
1762}
1763
1764#[serde_as]
1770#[skip_serializing_none]
1771#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1772#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1773#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME)))]
1774#[serde(rename_all = "camelCase")]
1775#[non_exhaustive]
1776pub struct DeleteSessionRequest {
1777 pub session_id: SessionId,
1779 #[serde_as(deserialize_as = "DefaultOnError")]
1785 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1786 #[serde(default)]
1787 #[serde(rename = "_meta")]
1788 pub meta: Option<Meta>,
1789}
1790
1791impl DeleteSessionRequest {
1792 #[must_use]
1794 pub fn new(session_id: impl Into<SessionId>) -> Self {
1795 Self {
1796 session_id: session_id.into(),
1797 meta: None,
1798 }
1799 }
1800
1801 #[must_use]
1807 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1808 self.meta = meta.into_option();
1809 self
1810 }
1811}
1812
1813crate::serde_util::default_on_null! {
1814 #[serde_as]
1816 #[skip_serializing_none]
1817 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1818 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1819 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME)))]
1820 #[serde(rename_all = "camelCase")]
1821 #[non_exhaustive]
1822 pub struct DeleteSessionResponse {
1823 #[serde_as(deserialize_as = "DefaultOnError")]
1829 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1830 #[serde(default)]
1831 #[serde(rename = "_meta")]
1832 pub meta: Option<Meta>,
1833 }
1834}
1835
1836impl DeleteSessionResponse {
1837 #[must_use]
1839 pub fn new() -> Self {
1840 Self::default()
1841 }
1842
1843 #[must_use]
1849 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1850 self.meta = meta.into_option();
1851 self
1852 }
1853}
1854
1855#[serde_as]
1857#[skip_serializing_none]
1858#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1859#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1860#[serde(rename_all = "camelCase")]
1861#[non_exhaustive]
1862pub struct SessionInfo {
1863 pub session_id: SessionId,
1865 pub cwd: PathBuf,
1867 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1873 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1874 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1875 pub additional_directories: Vec<PathBuf>,
1876
1877 #[serde_as(deserialize_as = "DefaultOnError")]
1879 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1880 #[serde(default)]
1881 pub title: Option<String>,
1882 #[serde_as(deserialize_as = "DefaultOnError")]
1884 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1885 #[serde(default)]
1886 pub updated_at: Option<String>,
1887 #[serde_as(deserialize_as = "DefaultOnError")]
1893 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1894 #[serde(default)]
1895 #[serde(rename = "_meta")]
1896 pub meta: Option<Meta>,
1897}
1898
1899impl SessionInfo {
1900 #[must_use]
1902 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1903 Self {
1904 session_id: session_id.into(),
1905 cwd: cwd.into(),
1906 additional_directories: vec![],
1907 title: None,
1908 updated_at: None,
1909 meta: None,
1910 }
1911 }
1912
1913 #[must_use]
1915 pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1916 self.additional_directories = additional_directories;
1917 self
1918 }
1919
1920 #[must_use]
1922 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1923 self.title = title.into_option();
1924 self
1925 }
1926
1927 #[must_use]
1929 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1930 self.updated_at = updated_at.into_option();
1931 self
1932 }
1933
1934 #[must_use]
1940 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1941 self.meta = meta.into_option();
1942 self
1943 }
1944}
1945
1946#[serde_as]
1950#[skip_serializing_none]
1951#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1952#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1953#[serde(rename_all = "camelCase")]
1954#[non_exhaustive]
1955pub struct SessionModeState {
1956 pub current_mode_id: SessionModeId,
1958 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
1960 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1961 pub available_modes: Vec<SessionMode>,
1962 #[serde_as(deserialize_as = "DefaultOnError")]
1968 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1969 #[serde(default)]
1970 #[serde(rename = "_meta")]
1971 pub meta: Option<Meta>,
1972}
1973
1974impl SessionModeState {
1975 #[must_use]
1977 pub fn new(
1978 current_mode_id: impl Into<SessionModeId>,
1979 available_modes: Vec<SessionMode>,
1980 ) -> Self {
1981 Self {
1982 current_mode_id: current_mode_id.into(),
1983 available_modes,
1984 meta: None,
1985 }
1986 }
1987
1988 #[must_use]
1994 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1995 self.meta = meta.into_option();
1996 self
1997 }
1998}
1999
2000#[serde_as]
2004#[skip_serializing_none]
2005#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2006#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2007#[serde(rename_all = "camelCase")]
2008#[non_exhaustive]
2009pub struct SessionMode {
2010 pub id: SessionModeId,
2012 pub name: String,
2014 #[serde_as(deserialize_as = "DefaultOnError")]
2016 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2017 #[serde(default)]
2018 pub description: Option<String>,
2019 #[serde_as(deserialize_as = "DefaultOnError")]
2025 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2026 #[serde(default)]
2027 #[serde(rename = "_meta")]
2028 pub meta: Option<Meta>,
2029}
2030
2031impl SessionMode {
2032 #[must_use]
2034 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
2035 Self {
2036 id: id.into(),
2037 name: name.into(),
2038 description: None,
2039 meta: None,
2040 }
2041 }
2042
2043 #[must_use]
2045 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2046 self.description = description.into_option();
2047 self
2048 }
2049
2050 #[must_use]
2056 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2057 self.meta = meta.into_option();
2058 self
2059 }
2060}
2061
2062#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2064#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2065#[serde(transparent)]
2066#[from(Arc<str>, String, &'static str)]
2067#[non_exhaustive]
2068pub struct SessionModeId(pub Arc<str>);
2069
2070impl SessionModeId {
2071 #[must_use]
2073 pub fn new(id: impl Into<Arc<str>>) -> Self {
2074 Self(id.into())
2075 }
2076}
2077
2078#[serde_as]
2080#[skip_serializing_none]
2081#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2082#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2083#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME)))]
2084#[serde(rename_all = "camelCase")]
2085#[non_exhaustive]
2086pub struct SetSessionModeRequest {
2087 pub session_id: SessionId,
2089 pub mode_id: SessionModeId,
2091 #[serde_as(deserialize_as = "DefaultOnError")]
2097 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2098 #[serde(default)]
2099 #[serde(rename = "_meta")]
2100 pub meta: Option<Meta>,
2101}
2102
2103impl SetSessionModeRequest {
2104 #[must_use]
2106 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
2107 Self {
2108 session_id: session_id.into(),
2109 mode_id: mode_id.into(),
2110 meta: None,
2111 }
2112 }
2113
2114 #[must_use]
2116 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2117 self.meta = meta.into_option();
2118 self
2119 }
2120}
2121
2122crate::serde_util::default_on_null! {
2123 #[serde_as]
2125 #[skip_serializing_none]
2126 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2127 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
2128 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME)))]
2129 #[serde(rename_all = "camelCase")]
2130 #[non_exhaustive]
2131 pub struct SetSessionModeResponse {
2132 #[serde_as(deserialize_as = "DefaultOnError")]
2138 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2139 #[serde(default)]
2140 #[serde(rename = "_meta")]
2141 pub meta: Option<Meta>,
2142 }
2143}
2144
2145impl SetSessionModeResponse {
2146 #[must_use]
2148 pub fn new() -> Self {
2149 Self::default()
2150 }
2151
2152 #[must_use]
2158 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2159 self.meta = meta.into_option();
2160 self
2161 }
2162}
2163
2164#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2168#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2169#[serde(transparent)]
2170#[from(Arc<str>, String, &'static str)]
2171#[non_exhaustive]
2172pub struct SessionConfigId(pub Arc<str>);
2173
2174impl SessionConfigId {
2175 #[must_use]
2177 pub fn new(id: impl Into<Arc<str>>) -> Self {
2178 Self(id.into())
2179 }
2180}
2181
2182#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2184#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2185#[serde(transparent)]
2186#[from(Arc<str>, String, &'static str)]
2187#[non_exhaustive]
2188pub struct SessionConfigValueId(pub Arc<str>);
2189
2190impl SessionConfigValueId {
2191 #[must_use]
2193 pub fn new(id: impl Into<Arc<str>>) -> Self {
2194 Self(id.into())
2195 }
2196}
2197
2198#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2200#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
2201#[serde(transparent)]
2202#[from(Arc<str>, String, &'static str)]
2203#[non_exhaustive]
2204pub struct SessionConfigGroupId(pub Arc<str>);
2205
2206impl SessionConfigGroupId {
2207 #[must_use]
2209 pub fn new(id: impl Into<Arc<str>>) -> Self {
2210 Self(id.into())
2211 }
2212}
2213
2214#[serde_as]
2216#[skip_serializing_none]
2217#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2218#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2219#[serde(rename_all = "camelCase")]
2220#[non_exhaustive]
2221pub struct SessionConfigSelectOption {
2222 pub value: SessionConfigValueId,
2224 pub name: String,
2226 #[serde_as(deserialize_as = "DefaultOnError")]
2228 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2229 #[serde(default)]
2230 pub description: Option<String>,
2231 #[serde_as(deserialize_as = "DefaultOnError")]
2237 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2238 #[serde(default)]
2239 #[serde(rename = "_meta")]
2240 pub meta: Option<Meta>,
2241}
2242
2243impl SessionConfigSelectOption {
2244 #[must_use]
2246 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2247 Self {
2248 value: value.into(),
2249 name: name.into(),
2250 description: None,
2251 meta: None,
2252 }
2253 }
2254
2255 #[must_use]
2257 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2258 self.description = description.into_option();
2259 self
2260 }
2261
2262 #[must_use]
2268 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2269 self.meta = meta.into_option();
2270 self
2271 }
2272}
2273
2274#[serde_as]
2276#[skip_serializing_none]
2277#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2278#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2279#[serde(rename_all = "camelCase")]
2280#[non_exhaustive]
2281pub struct SessionConfigSelectGroup {
2282 pub group: SessionConfigGroupId,
2284 pub name: String,
2286 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2288 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2289 pub options: Vec<SessionConfigSelectOption>,
2290 #[serde_as(deserialize_as = "DefaultOnError")]
2296 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2297 #[serde(default)]
2298 #[serde(rename = "_meta")]
2299 pub meta: Option<Meta>,
2300}
2301
2302impl SessionConfigSelectGroup {
2303 #[must_use]
2305 pub fn new(
2306 group: impl Into<SessionConfigGroupId>,
2307 name: impl Into<String>,
2308 options: Vec<SessionConfigSelectOption>,
2309 ) -> Self {
2310 Self {
2311 group: group.into(),
2312 name: name.into(),
2313 options,
2314 meta: None,
2315 }
2316 }
2317
2318 #[must_use]
2324 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2325 self.meta = meta.into_option();
2326 self
2327 }
2328}
2329
2330#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2332#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2333#[serde(untagged)]
2334#[non_exhaustive]
2335pub enum SessionConfigSelectOptions {
2336 Ungrouped(Vec<SessionConfigSelectOption>),
2338 Grouped(Vec<SessionConfigSelectGroup>),
2340}
2341
2342impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2343 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2344 SessionConfigSelectOptions::Ungrouped(options)
2345 }
2346}
2347
2348impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2349 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2350 SessionConfigSelectOptions::Grouped(groups)
2351 }
2352}
2353
2354#[skip_serializing_none]
2356#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2357#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2358#[serde(rename_all = "camelCase")]
2359#[non_exhaustive]
2360pub struct SessionConfigSelect {
2361 pub current_value: SessionConfigValueId,
2363 pub options: SessionConfigSelectOptions,
2365}
2366
2367impl SessionConfigSelect {
2368 #[must_use]
2370 pub fn new(
2371 current_value: impl Into<SessionConfigValueId>,
2372 options: impl Into<SessionConfigSelectOptions>,
2373 ) -> Self {
2374 Self {
2375 current_value: current_value.into(),
2376 options: options.into(),
2377 }
2378 }
2379}
2380
2381#[skip_serializing_none]
2383#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2384#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2385#[serde(rename_all = "camelCase")]
2386#[non_exhaustive]
2387pub struct SessionConfigBoolean {
2388 pub current_value: bool,
2390}
2391
2392impl SessionConfigBoolean {
2393 #[must_use]
2395 pub fn new(current_value: bool) -> Self {
2396 Self { current_value }
2397 }
2398}
2399
2400#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2410#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2411#[serde(rename_all = "snake_case")]
2412#[non_exhaustive]
2413pub enum SessionConfigOptionCategory {
2414 Mode,
2416 Model,
2418 ModelConfig,
2420 ThoughtLevel,
2422 #[serde(untagged)]
2424 Other(String),
2425}
2426
2427#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2429#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2430#[serde(tag = "type", rename_all = "snake_case")]
2431#[cfg_attr(feature = "schemars", schemars(extend("discriminator" = {"propertyName": "type"})))]
2432#[non_exhaustive]
2433pub enum SessionConfigKind {
2434 Select(SessionConfigSelect),
2436 Boolean(SessionConfigBoolean),
2438}
2439
2440#[serde_as]
2442#[skip_serializing_none]
2443#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2444#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2445#[serde(rename_all = "camelCase")]
2446#[non_exhaustive]
2447pub struct SessionConfigOption {
2448 pub id: SessionConfigId,
2450 pub name: String,
2452 #[serde_as(deserialize_as = "DefaultOnError")]
2454 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2455 #[serde(default)]
2456 pub description: Option<String>,
2457 #[serde_as(deserialize_as = "DefaultOnError")]
2459 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2460 #[serde(default)]
2461 pub category: Option<SessionConfigOptionCategory>,
2462 #[serde(flatten)]
2464 pub kind: SessionConfigKind,
2465 #[serde_as(deserialize_as = "DefaultOnError")]
2471 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2472 #[serde(default)]
2473 #[serde(rename = "_meta")]
2474 pub meta: Option<Meta>,
2475}
2476
2477impl SessionConfigOption {
2478 #[must_use]
2480 pub fn new(
2481 id: impl Into<SessionConfigId>,
2482 name: impl Into<String>,
2483 kind: SessionConfigKind,
2484 ) -> Self {
2485 Self {
2486 id: id.into(),
2487 name: name.into(),
2488 description: None,
2489 category: None,
2490 kind,
2491 meta: None,
2492 }
2493 }
2494
2495 #[must_use]
2497 pub fn select(
2498 id: impl Into<SessionConfigId>,
2499 name: impl Into<String>,
2500 current_value: impl Into<SessionConfigValueId>,
2501 options: impl Into<SessionConfigSelectOptions>,
2502 ) -> Self {
2503 Self::new(
2504 id,
2505 name,
2506 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2507 )
2508 }
2509
2510 #[must_use]
2512 pub fn boolean(
2513 id: impl Into<SessionConfigId>,
2514 name: impl Into<String>,
2515 current_value: bool,
2516 ) -> Self {
2517 Self::new(
2518 id,
2519 name,
2520 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2521 )
2522 }
2523
2524 #[must_use]
2526 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2527 self.description = description.into_option();
2528 self
2529 }
2530
2531 #[must_use]
2533 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2534 self.category = category.into_option();
2535 self
2536 }
2537
2538 #[must_use]
2544 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2545 self.meta = meta.into_option();
2546 self
2547 }
2548}
2549
2550#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2561#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2562#[serde(tag = "type", rename_all = "snake_case")]
2563#[non_exhaustive]
2564pub enum SessionConfigOptionValue {
2565 Boolean {
2567 value: bool,
2569 },
2570 #[serde(untagged)]
2576 ValueId {
2577 value: SessionConfigValueId,
2579 },
2580}
2581
2582impl SessionConfigOptionValue {
2583 #[must_use]
2585 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2586 Self::ValueId { value: id.into() }
2587 }
2588
2589 #[must_use]
2591 pub fn boolean(val: bool) -> Self {
2592 Self::Boolean { value: val }
2593 }
2594
2595 #[must_use]
2598 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2599 match self {
2600 Self::ValueId { value } => Some(value),
2601 _ => None,
2602 }
2603 }
2604
2605 #[must_use]
2607 pub fn as_bool(&self) -> Option<bool> {
2608 match self {
2609 Self::Boolean { value } => Some(*value),
2610 _ => None,
2611 }
2612 }
2613}
2614
2615impl From<SessionConfigValueId> for SessionConfigOptionValue {
2616 fn from(value: SessionConfigValueId) -> Self {
2617 Self::ValueId { value }
2618 }
2619}
2620
2621impl From<bool> for SessionConfigOptionValue {
2622 fn from(value: bool) -> Self {
2623 Self::Boolean { value }
2624 }
2625}
2626
2627impl From<&str> for SessionConfigOptionValue {
2628 fn from(value: &str) -> Self {
2629 Self::ValueId {
2630 value: SessionConfigValueId::new(value),
2631 }
2632 }
2633}
2634
2635#[serde_as]
2637#[skip_serializing_none]
2638#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2639#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2640#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME)))]
2641#[serde(rename_all = "camelCase")]
2642#[non_exhaustive]
2643pub struct SetSessionConfigOptionRequest {
2644 pub session_id: SessionId,
2646 pub config_id: SessionConfigId,
2648 #[serde(flatten)]
2653 pub value: SessionConfigOptionValue,
2654 #[serde_as(deserialize_as = "DefaultOnError")]
2660 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2661 #[serde(default)]
2662 #[serde(rename = "_meta")]
2663 pub meta: Option<Meta>,
2664}
2665
2666impl SetSessionConfigOptionRequest {
2667 #[must_use]
2669 pub fn new(
2670 session_id: impl Into<SessionId>,
2671 config_id: impl Into<SessionConfigId>,
2672 value: impl Into<SessionConfigOptionValue>,
2673 ) -> Self {
2674 Self {
2675 session_id: session_id.into(),
2676 config_id: config_id.into(),
2677 value: value.into(),
2678 meta: None,
2679 }
2680 }
2681
2682 #[must_use]
2688 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2689 self.meta = meta.into_option();
2690 self
2691 }
2692}
2693
2694#[serde_as]
2696#[skip_serializing_none]
2697#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2698#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2699#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME)))]
2700#[serde(rename_all = "camelCase")]
2701#[non_exhaustive]
2702pub struct SetSessionConfigOptionResponse {
2703 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2705 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2706 pub config_options: Vec<SessionConfigOption>,
2707 #[serde_as(deserialize_as = "DefaultOnError")]
2713 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2714 #[serde(default)]
2715 #[serde(rename = "_meta")]
2716 pub meta: Option<Meta>,
2717}
2718
2719impl SetSessionConfigOptionResponse {
2720 #[must_use]
2722 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2723 Self {
2724 config_options,
2725 meta: None,
2726 }
2727 }
2728
2729 #[must_use]
2735 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2736 self.meta = meta.into_option();
2737 self
2738 }
2739}
2740
2741#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2750#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2751#[serde(tag = "type", rename_all = "snake_case")]
2752#[non_exhaustive]
2753pub enum McpServer {
2754 Http(McpServerHttp),
2758 Sse(McpServerSse),
2762 #[cfg(feature = "unstable_mcp_over_acp")]
2771 Acp(McpServerAcp),
2772 #[serde(untagged)]
2776 Stdio(McpServerStdio),
2777}
2778
2779#[serde_as]
2781#[skip_serializing_none]
2782#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2783#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2784#[serde(rename_all = "camelCase")]
2785#[non_exhaustive]
2786pub struct McpServerHttp {
2787 pub name: String,
2789 pub url: String,
2791 #[serde_as(deserialize_as = "DefaultOnNull")]
2793 pub headers: Vec<HttpHeader>,
2794 #[serde_as(deserialize_as = "DefaultOnError")]
2800 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2801 #[serde(default)]
2802 #[serde(rename = "_meta")]
2803 pub meta: Option<Meta>,
2804}
2805
2806impl McpServerHttp {
2807 #[must_use]
2809 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2810 Self {
2811 name: name.into(),
2812 url: url.into(),
2813 headers: Vec::new(),
2814 meta: None,
2815 }
2816 }
2817
2818 #[must_use]
2820 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2821 self.headers = headers;
2822 self
2823 }
2824
2825 #[must_use]
2831 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2832 self.meta = meta.into_option();
2833 self
2834 }
2835}
2836
2837#[serde_as]
2839#[skip_serializing_none]
2840#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2841#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2842#[serde(rename_all = "camelCase")]
2843#[non_exhaustive]
2844pub struct McpServerSse {
2845 pub name: String,
2847 pub url: String,
2849 #[serde_as(deserialize_as = "DefaultOnNull")]
2851 pub headers: Vec<HttpHeader>,
2852 #[serde_as(deserialize_as = "DefaultOnError")]
2858 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2859 #[serde(default)]
2860 #[serde(rename = "_meta")]
2861 pub meta: Option<Meta>,
2862}
2863
2864impl McpServerSse {
2865 #[must_use]
2867 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2868 Self {
2869 name: name.into(),
2870 url: url.into(),
2871 headers: Vec::new(),
2872 meta: None,
2873 }
2874 }
2875
2876 #[must_use]
2878 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2879 self.headers = headers;
2880 self
2881 }
2882
2883 #[must_use]
2889 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2890 self.meta = meta.into_option();
2891 self
2892 }
2893}
2894
2895#[cfg(feature = "unstable_mcp_over_acp")]
2904#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2905#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
2906#[serde(transparent)]
2907#[from(Arc<str>, String, &'static str)]
2908#[non_exhaustive]
2909pub struct McpServerAcpId(pub Arc<str>);
2910
2911#[cfg(feature = "unstable_mcp_over_acp")]
2912impl McpServerAcpId {
2913 #[must_use]
2915 pub fn new(id: impl Into<Arc<str>>) -> Self {
2916 Self(id.into())
2917 }
2918}
2919
2920#[serde_as]
2929#[skip_serializing_none]
2930#[cfg(feature = "unstable_mcp_over_acp")]
2931#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2932#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2933#[serde(rename_all = "camelCase")]
2934#[non_exhaustive]
2935pub struct McpServerAcp {
2936 pub name: String,
2938 pub server_id: McpServerAcpId,
2943 #[serde_as(deserialize_as = "DefaultOnError")]
2949 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2950 #[serde(default)]
2951 #[serde(rename = "_meta")]
2952 pub meta: Option<Meta>,
2953}
2954
2955#[cfg(feature = "unstable_mcp_over_acp")]
2956impl McpServerAcp {
2957 #[must_use]
2959 pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2960 Self {
2961 name: name.into(),
2962 server_id: id.into(),
2963 meta: None,
2964 }
2965 }
2966
2967 #[must_use]
2973 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2974 self.meta = meta.into_option();
2975 self
2976 }
2977}
2978
2979#[serde_as]
2981#[skip_serializing_none]
2982#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2983#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2984#[serde(rename_all = "camelCase")]
2985#[non_exhaustive]
2986pub struct McpServerStdio {
2987 pub name: String,
2989 pub command: PathBuf,
2991 #[serde_as(deserialize_as = "DefaultOnNull")]
2993 pub args: Vec<String>,
2994 #[serde_as(deserialize_as = "DefaultOnNull")]
2996 pub env: Vec<EnvVariable>,
2997 #[serde_as(deserialize_as = "DefaultOnError")]
3003 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3004 #[serde(default)]
3005 #[serde(rename = "_meta")]
3006 pub meta: Option<Meta>,
3007}
3008
3009impl McpServerStdio {
3010 #[must_use]
3012 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
3013 Self {
3014 name: name.into(),
3015 command: command.into(),
3016 args: Vec::new(),
3017 env: Vec::new(),
3018 meta: None,
3019 }
3020 }
3021
3022 #[must_use]
3024 pub fn args(mut self, args: Vec<String>) -> Self {
3025 self.args = args;
3026 self
3027 }
3028
3029 #[must_use]
3031 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
3032 self.env = env;
3033 self
3034 }
3035
3036 #[must_use]
3042 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3043 self.meta = meta.into_option();
3044 self
3045 }
3046}
3047
3048#[serde_as]
3050#[skip_serializing_none]
3051#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3052#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3053#[serde(rename_all = "camelCase")]
3054#[non_exhaustive]
3055pub struct EnvVariable {
3056 pub name: String,
3058 pub value: String,
3060 #[serde_as(deserialize_as = "DefaultOnError")]
3066 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3067 #[serde(default)]
3068 #[serde(rename = "_meta")]
3069 pub meta: Option<Meta>,
3070}
3071
3072impl EnvVariable {
3073 #[must_use]
3075 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3076 Self {
3077 name: name.into(),
3078 value: value.into(),
3079 meta: None,
3080 }
3081 }
3082
3083 #[must_use]
3089 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3090 self.meta = meta.into_option();
3091 self
3092 }
3093}
3094
3095#[serde_as]
3097#[skip_serializing_none]
3098#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3099#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3100#[serde(rename_all = "camelCase")]
3101#[non_exhaustive]
3102pub struct HttpHeader {
3103 pub name: String,
3105 pub value: String,
3107 #[serde_as(deserialize_as = "DefaultOnError")]
3113 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3114 #[serde(default)]
3115 #[serde(rename = "_meta")]
3116 pub meta: Option<Meta>,
3117}
3118
3119impl HttpHeader {
3120 #[must_use]
3122 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3123 Self {
3124 name: name.into(),
3125 value: value.into(),
3126 meta: None,
3127 }
3128 }
3129
3130 #[must_use]
3136 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3137 self.meta = meta.into_option();
3138 self
3139 }
3140}
3141
3142#[cfg(feature = "unstable_session_system_prompt")]
3156#[serde_as]
3157#[skip_serializing_none]
3158#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3159#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3160#[serde(rename_all = "camelCase")]
3161#[non_exhaustive]
3162pub struct SystemPrompt {
3163 pub mode: SystemPromptMode,
3170 pub content: Vec<ContentBlock>,
3177 #[serde_as(deserialize_as = "DefaultOnError")]
3183 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3184 #[serde(default)]
3185 #[serde(rename = "_meta")]
3186 pub meta: Option<Meta>,
3187}
3188
3189#[cfg(feature = "unstable_session_system_prompt")]
3190impl SystemPrompt {
3191 #[must_use]
3196 pub fn new(content: Vec<ContentBlock>) -> Self {
3197 Self {
3198 mode: SystemPromptMode::default(),
3199 content,
3200 meta: None,
3201 }
3202 }
3203
3204 #[must_use]
3206 pub fn mode(mut self, mode: SystemPromptMode) -> Self {
3207 self.mode = mode;
3208 self
3209 }
3210
3211 #[must_use]
3217 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3218 self.meta = meta.into_option();
3219 self
3220 }
3221}
3222
3223#[cfg(feature = "unstable_session_system_prompt")]
3233#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3234#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
3235#[serde(rename_all = "snake_case")]
3236#[non_exhaustive]
3237pub enum SystemPromptMode {
3238 #[default]
3245 Append,
3246 Override,
3255 #[serde(untagged)]
3261 Other(String),
3262}
3263
3264#[serde_as]
3272#[skip_serializing_none]
3273#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3274#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3275#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME)))]
3276#[serde(rename_all = "camelCase")]
3277#[non_exhaustive]
3278pub struct PromptRequest {
3279 pub session_id: SessionId,
3281 pub prompt: Vec<ContentBlock>,
3295 #[serde_as(deserialize_as = "DefaultOnError")]
3301 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3302 #[serde(default)]
3303 #[serde(rename = "_meta")]
3304 pub meta: Option<Meta>,
3305}
3306
3307impl PromptRequest {
3308 #[must_use]
3310 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3311 Self {
3312 session_id: session_id.into(),
3313 prompt,
3314 meta: None,
3315 }
3316 }
3317
3318 #[must_use]
3324 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3325 self.meta = meta.into_option();
3326 self
3327 }
3328}
3329
3330#[serde_as]
3334#[skip_serializing_none]
3335#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3336#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3337#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME)))]
3338#[serde(rename_all = "camelCase")]
3339#[non_exhaustive]
3340pub struct PromptResponse {
3341 pub stop_reason: StopReason,
3343 #[cfg(feature = "unstable_end_turn_token_usage")]
3349 #[serde_as(deserialize_as = "DefaultOnError")]
3350 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3351 #[serde(default)]
3352 pub usage: Option<Usage>,
3353 #[serde_as(deserialize_as = "DefaultOnError")]
3359 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3360 #[serde(default)]
3361 #[serde(rename = "_meta")]
3362 pub meta: Option<Meta>,
3363}
3364
3365impl PromptResponse {
3366 #[must_use]
3368 pub fn new(stop_reason: StopReason) -> Self {
3369 Self {
3370 stop_reason,
3371 #[cfg(feature = "unstable_end_turn_token_usage")]
3372 usage: None,
3373 meta: None,
3374 }
3375 }
3376
3377 #[cfg(feature = "unstable_end_turn_token_usage")]
3383 #[must_use]
3384 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3385 self.usage = usage.into_option();
3386 self
3387 }
3388
3389 #[must_use]
3395 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3396 self.meta = meta.into_option();
3397 self
3398 }
3399}
3400
3401#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3405#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
3406#[serde(rename_all = "snake_case")]
3407#[non_exhaustive]
3408pub enum StopReason {
3409 EndTurn,
3411 MaxTokens,
3413 MaxTurnRequests,
3416 Refusal,
3420 Cancelled,
3427}
3428
3429#[cfg(feature = "unstable_end_turn_token_usage")]
3435#[serde_as]
3436#[skip_serializing_none]
3437#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3438#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3439#[serde(rename_all = "camelCase")]
3440#[non_exhaustive]
3441pub struct Usage {
3442 pub total_tokens: u64,
3444 pub input_tokens: u64,
3446 pub output_tokens: u64,
3448 #[serde_as(deserialize_as = "DefaultOnError")]
3450 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3451 #[serde(default)]
3452 pub thought_tokens: Option<u64>,
3453 #[serde_as(deserialize_as = "DefaultOnError")]
3455 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3456 #[serde(default)]
3457 pub cached_read_tokens: Option<u64>,
3458 #[serde_as(deserialize_as = "DefaultOnError")]
3460 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3461 #[serde(default)]
3462 pub cached_write_tokens: Option<u64>,
3463 #[serde_as(deserialize_as = "DefaultOnError")]
3469 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3470 #[serde(default)]
3471 #[serde(rename = "_meta")]
3472 pub meta: Option<Meta>,
3473}
3474
3475#[cfg(feature = "unstable_end_turn_token_usage")]
3476impl Usage {
3477 #[must_use]
3479 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3480 Self {
3481 total_tokens,
3482 input_tokens,
3483 output_tokens,
3484 thought_tokens: None,
3485 cached_read_tokens: None,
3486 cached_write_tokens: None,
3487 meta: None,
3488 }
3489 }
3490
3491 #[must_use]
3493 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3494 self.thought_tokens = thought_tokens.into_option();
3495 self
3496 }
3497
3498 #[must_use]
3500 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3501 self.cached_read_tokens = cached_read_tokens.into_option();
3502 self
3503 }
3504
3505 #[must_use]
3507 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3508 self.cached_write_tokens = cached_write_tokens.into_option();
3509 self
3510 }
3511
3512 #[must_use]
3518 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3519 self.meta = meta.into_option();
3520 self
3521 }
3522}
3523
3524#[cfg(feature = "unstable_llm_providers")]
3537#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3538#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3539#[serde(rename_all = "snake_case")]
3540#[non_exhaustive]
3541#[expect(clippy::doc_markdown)]
3542pub enum LlmProtocol {
3543 Anthropic,
3545 #[serde(rename = "openai")]
3547 OpenAi,
3548 Azure,
3550 Vertex,
3552 Bedrock,
3554 #[serde(untagged)]
3556 Other(String),
3557}
3558
3559#[cfg(feature = "unstable_llm_providers")]
3565#[serde_as]
3566#[skip_serializing_none]
3567#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3568#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3569#[serde(rename_all = "camelCase")]
3570#[non_exhaustive]
3571pub struct ProviderCurrentConfig {
3572 pub api_type: LlmProtocol,
3574 pub base_url: String,
3576 #[serde_as(deserialize_as = "DefaultOnError")]
3582 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3583 #[serde(default)]
3584 #[serde(rename = "_meta")]
3585 pub meta: Option<Meta>,
3586}
3587
3588#[cfg(feature = "unstable_llm_providers")]
3589impl ProviderCurrentConfig {
3590 #[must_use]
3592 pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3593 Self {
3594 api_type,
3595 base_url: base_url.into(),
3596 meta: None,
3597 }
3598 }
3599
3600 #[must_use]
3606 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3607 self.meta = meta.into_option();
3608 self
3609 }
3610}
3611
3612#[cfg(feature = "unstable_llm_providers")]
3618#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3619#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
3620#[serde(transparent)]
3621#[from(Arc<str>, String, &'static str)]
3622#[non_exhaustive]
3623pub struct ProviderId(pub Arc<str>);
3624
3625#[cfg(feature = "unstable_llm_providers")]
3626impl ProviderId {
3627 #[must_use]
3629 pub fn new(id: impl Into<Arc<str>>) -> Self {
3630 Self(id.into())
3631 }
3632}
3633
3634#[cfg(feature = "unstable_llm_providers")]
3640#[serde_as]
3641#[skip_serializing_none]
3642#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3643#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3644#[serde(rename_all = "camelCase")]
3645#[non_exhaustive]
3646pub struct ProviderInfo {
3647 pub provider_id: ProviderId,
3649 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
3651 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
3652 pub supported: Vec<LlmProtocol>,
3653 pub required: bool,
3656 #[serde(default)]
3659 pub current: Option<ProviderCurrentConfig>,
3660 #[serde_as(deserialize_as = "DefaultOnError")]
3666 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3667 #[serde(default)]
3668 #[serde(rename = "_meta")]
3669 pub meta: Option<Meta>,
3670}
3671
3672#[cfg(feature = "unstable_llm_providers")]
3673impl ProviderInfo {
3674 #[must_use]
3676 pub fn new(
3677 provider_id: impl Into<ProviderId>,
3678 supported: Vec<LlmProtocol>,
3679 required: bool,
3680 current: impl IntoOption<ProviderCurrentConfig>,
3681 ) -> Self {
3682 Self {
3683 provider_id: provider_id.into(),
3684 supported,
3685 required,
3686 current: current.into_option(),
3687 meta: None,
3688 }
3689 }
3690
3691 #[must_use]
3697 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3698 self.meta = meta.into_option();
3699 self
3700 }
3701}
3702
3703#[cfg(feature = "unstable_llm_providers")]
3704crate::serde_util::default_on_null! {
3705 #[serde_as]
3711 #[skip_serializing_none]
3712 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3713 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3714 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))]
3715 #[serde(rename_all = "camelCase")]
3716 #[non_exhaustive]
3717 pub struct ListProvidersRequest {
3718 #[serde_as(deserialize_as = "DefaultOnError")]
3724 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3725 #[serde(default)]
3726 #[serde(rename = "_meta")]
3727 pub meta: Option<Meta>,
3728 }
3729}
3730
3731#[cfg(feature = "unstable_llm_providers")]
3732impl ListProvidersRequest {
3733 #[must_use]
3735 pub fn new() -> Self {
3736 Self::default()
3737 }
3738
3739 #[must_use]
3745 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3746 self.meta = meta.into_option();
3747 self
3748 }
3749}
3750
3751#[cfg(feature = "unstable_llm_providers")]
3757#[serde_as]
3758#[skip_serializing_none]
3759#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3760#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3761#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))]
3762#[serde(rename_all = "camelCase")]
3763#[non_exhaustive]
3764pub struct ListProvidersResponse {
3765 pub providers: Vec<ProviderInfo>,
3767 #[serde_as(deserialize_as = "DefaultOnError")]
3773 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3774 #[serde(default)]
3775 #[serde(rename = "_meta")]
3776 pub meta: Option<Meta>,
3777}
3778
3779#[cfg(feature = "unstable_llm_providers")]
3780impl ListProvidersResponse {
3781 #[must_use]
3783 pub fn new(providers: Vec<ProviderInfo>) -> Self {
3784 Self {
3785 providers,
3786 meta: None,
3787 }
3788 }
3789
3790 #[must_use]
3796 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3797 self.meta = meta.into_option();
3798 self
3799 }
3800}
3801
3802#[cfg(feature = "unstable_llm_providers")]
3810#[serde_as]
3811#[skip_serializing_none]
3812#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3813#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
3814#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))]
3815#[serde(rename_all = "camelCase")]
3816#[non_exhaustive]
3817pub struct SetProviderRequest {
3818 pub provider_id: ProviderId,
3820 pub api_type: LlmProtocol,
3822 pub base_url: String,
3824 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3827 pub headers: HashMap<String, String>,
3828 #[serde_as(deserialize_as = "DefaultOnError")]
3834 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3835 #[serde(default)]
3836 #[serde(rename = "_meta")]
3837 pub meta: Option<Meta>,
3838}
3839
3840#[cfg(feature = "unstable_llm_providers")]
3841impl SetProviderRequest {
3842 #[must_use]
3844 pub fn new(
3845 provider_id: impl Into<ProviderId>,
3846 api_type: LlmProtocol,
3847 base_url: impl Into<String>,
3848 ) -> Self {
3849 Self {
3850 provider_id: provider_id.into(),
3851 api_type,
3852 base_url: base_url.into(),
3853 headers: HashMap::new(),
3854 meta: None,
3855 }
3856 }
3857
3858 #[must_use]
3861 pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3862 self.headers = headers;
3863 self
3864 }
3865
3866 #[must_use]
3872 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3873 self.meta = meta.into_option();
3874 self
3875 }
3876}
3877
3878#[cfg(feature = "unstable_llm_providers")]
3879crate::serde_util::default_on_null! {
3880 #[serde_as]
3886 #[skip_serializing_none]
3887 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3888 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3889 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))]
3890 #[serde(rename_all = "camelCase")]
3891 #[non_exhaustive]
3892 pub struct SetProviderResponse {
3893 #[serde_as(deserialize_as = "DefaultOnError")]
3899 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3900 #[serde(default)]
3901 #[serde(rename = "_meta")]
3902 pub meta: Option<Meta>,
3903 }
3904}
3905
3906#[cfg(feature = "unstable_llm_providers")]
3907impl SetProviderResponse {
3908 #[must_use]
3910 pub fn new() -> Self {
3911 Self::default()
3912 }
3913
3914 #[must_use]
3920 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3921 self.meta = meta.into_option();
3922 self
3923 }
3924}
3925
3926#[cfg(feature = "unstable_llm_providers")]
3932#[serde_as]
3933#[skip_serializing_none]
3934#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3935#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3936#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))]
3937#[serde(rename_all = "camelCase")]
3938#[non_exhaustive]
3939pub struct DisableProviderRequest {
3940 pub provider_id: ProviderId,
3942 #[serde_as(deserialize_as = "DefaultOnError")]
3948 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3949 #[serde(default)]
3950 #[serde(rename = "_meta")]
3951 pub meta: Option<Meta>,
3952}
3953
3954#[cfg(feature = "unstable_llm_providers")]
3955impl DisableProviderRequest {
3956 #[must_use]
3958 pub fn new(provider_id: impl Into<ProviderId>) -> Self {
3959 Self {
3960 provider_id: provider_id.into(),
3961 meta: None,
3962 }
3963 }
3964
3965 #[must_use]
3971 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3972 self.meta = meta.into_option();
3973 self
3974 }
3975}
3976
3977#[cfg(feature = "unstable_llm_providers")]
3978crate::serde_util::default_on_null! {
3979 #[serde_as]
3985 #[skip_serializing_none]
3986 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3987 #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3988 #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))]
3989 #[serde(rename_all = "camelCase")]
3990 #[non_exhaustive]
3991 pub struct DisableProviderResponse {
3992 #[serde_as(deserialize_as = "DefaultOnError")]
3998 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3999 #[serde(default)]
4000 #[serde(rename = "_meta")]
4001 pub meta: Option<Meta>,
4002 }
4003}
4004
4005#[cfg(feature = "unstable_llm_providers")]
4006impl DisableProviderResponse {
4007 #[must_use]
4009 pub fn new() -> Self {
4010 Self::default()
4011 }
4012
4013 #[must_use]
4019 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4020 self.meta = meta.into_option();
4021 self
4022 }
4023}
4024
4025#[serde_as]
4034#[skip_serializing_none]
4035#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4036#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4037#[serde(rename_all = "camelCase")]
4038#[non_exhaustive]
4039pub struct AgentCapabilities {
4040 #[serde_as(deserialize_as = "DefaultOnError")]
4042 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4043 #[serde(default)]
4044 pub load_session: bool,
4045 #[serde_as(deserialize_as = "DefaultOnError")]
4047 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4048 #[serde(default)]
4049 pub prompt_capabilities: PromptCapabilities,
4050 #[serde_as(deserialize_as = "DefaultOnError")]
4052 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4053 #[serde(default)]
4054 pub mcp_capabilities: McpCapabilities,
4055 #[serde_as(deserialize_as = "DefaultOnError")]
4057 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4058 #[serde(default)]
4059 pub session_capabilities: SessionCapabilities,
4060 #[serde_as(deserialize_as = "DefaultOnError")]
4062 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4063 #[serde(default)]
4064 pub auth: AgentAuthCapabilities,
4065 #[cfg(feature = "unstable_llm_providers")]
4074 #[serde_as(deserialize_as = "DefaultOnError")]
4075 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4076 #[serde(default)]
4077 pub providers: Option<ProvidersCapabilities>,
4078 #[serde_as(deserialize_as = "DefaultOnError")]
4084 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4085 #[serde(default)]
4086 #[serde(rename = "_meta")]
4087 pub meta: Option<Meta>,
4088}
4089
4090impl AgentCapabilities {
4091 #[must_use]
4093 pub fn new() -> Self {
4094 Self::default()
4095 }
4096
4097 #[must_use]
4099 pub fn load_session(mut self, load_session: bool) -> Self {
4100 self.load_session = load_session;
4101 self
4102 }
4103
4104 #[must_use]
4106 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
4107 self.prompt_capabilities = prompt_capabilities;
4108 self
4109 }
4110
4111 #[must_use]
4113 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
4114 self.mcp_capabilities = mcp_capabilities;
4115 self
4116 }
4117
4118 #[must_use]
4120 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
4121 self.session_capabilities = session_capabilities;
4122 self
4123 }
4124
4125 #[must_use]
4127 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
4128 self.auth = auth;
4129 self
4130 }
4131
4132 #[cfg(feature = "unstable_llm_providers")]
4138 #[must_use]
4139 pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
4140 self.providers = providers.into_option();
4141 self
4142 }
4143
4144 #[must_use]
4150 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4151 self.meta = meta.into_option();
4152 self
4153 }
4154}
4155
4156#[cfg(feature = "unstable_llm_providers")]
4164#[serde_as]
4165#[skip_serializing_none]
4166#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4167#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4168#[non_exhaustive]
4169pub struct ProvidersCapabilities {
4170 #[serde_as(deserialize_as = "DefaultOnError")]
4176 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4177 #[serde(default)]
4178 #[serde(rename = "_meta")]
4179 pub meta: Option<Meta>,
4180}
4181
4182#[cfg(feature = "unstable_llm_providers")]
4183impl ProvidersCapabilities {
4184 #[must_use]
4186 pub fn new() -> Self {
4187 Self::default()
4188 }
4189
4190 #[must_use]
4196 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4197 self.meta = meta.into_option();
4198 self
4199 }
4200}
4201
4202#[serde_as]
4212#[skip_serializing_none]
4213#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4214#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4215#[serde(rename_all = "camelCase")]
4216#[non_exhaustive]
4217pub struct SessionCapabilities {
4218 #[serde_as(deserialize_as = "DefaultOnError")]
4223 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4224 #[serde(default)]
4225 pub list: Option<SessionListCapabilities>,
4226 #[serde_as(deserialize_as = "DefaultOnError")]
4231 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4232 #[serde(default)]
4233 pub delete: Option<SessionDeleteCapabilities>,
4234 #[serde_as(deserialize_as = "DefaultOnError")]
4244 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4245 #[serde(default)]
4246 pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
4247 #[cfg(feature = "unstable_session_system_prompt")]
4256 #[serde_as(deserialize_as = "DefaultOnError")]
4257 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4258 #[serde(default)]
4259 pub system_prompt: Option<SessionSystemPromptCapabilities>,
4260 #[cfg(feature = "unstable_session_fork")]
4269 #[serde_as(deserialize_as = "DefaultOnError")]
4270 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4271 #[serde(default)]
4272 pub fork: Option<SessionForkCapabilities>,
4273 #[serde_as(deserialize_as = "DefaultOnError")]
4278 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4279 #[serde(default)]
4280 pub resume: Option<SessionResumeCapabilities>,
4281 #[serde_as(deserialize_as = "DefaultOnError")]
4286 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4287 #[serde(default)]
4288 pub close: Option<SessionCloseCapabilities>,
4289 #[serde_as(deserialize_as = "DefaultOnError")]
4295 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4296 #[serde(default)]
4297 #[serde(rename = "_meta")]
4298 pub meta: Option<Meta>,
4299}
4300
4301impl SessionCapabilities {
4302 #[must_use]
4304 pub fn new() -> Self {
4305 Self::default()
4306 }
4307
4308 #[must_use]
4313 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
4314 self.list = list.into_option();
4315 self
4316 }
4317
4318 #[must_use]
4323 pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
4324 self.delete = delete.into_option();
4325 self
4326 }
4327
4328 #[must_use]
4338 pub fn additional_directories(
4339 mut self,
4340 additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4341 ) -> Self {
4342 self.additional_directories = additional_directories.into_option();
4343 self
4344 }
4345
4346 #[cfg(feature = "unstable_session_system_prompt")]
4355 #[must_use]
4356 pub fn system_prompt(
4357 mut self,
4358 system_prompt: impl IntoOption<SessionSystemPromptCapabilities>,
4359 ) -> Self {
4360 self.system_prompt = system_prompt.into_option();
4361 self
4362 }
4363
4364 #[cfg(feature = "unstable_session_fork")]
4365 #[must_use]
4370 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4371 self.fork = fork.into_option();
4372 self
4373 }
4374
4375 #[must_use]
4380 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4381 self.resume = resume.into_option();
4382 self
4383 }
4384
4385 #[must_use]
4390 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4391 self.close = close.into_option();
4392 self
4393 }
4394
4395 #[must_use]
4401 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4402 self.meta = meta.into_option();
4403 self
4404 }
4405}
4406
4407#[serde_as]
4411#[skip_serializing_none]
4412#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4413#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4414#[non_exhaustive]
4415pub struct SessionListCapabilities {
4416 #[serde_as(deserialize_as = "DefaultOnError")]
4422 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4423 #[serde(default)]
4424 #[serde(rename = "_meta")]
4425 pub meta: Option<Meta>,
4426}
4427
4428impl SessionListCapabilities {
4429 #[must_use]
4431 pub fn new() -> Self {
4432 Self::default()
4433 }
4434
4435 #[must_use]
4441 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4442 self.meta = meta.into_option();
4443 self
4444 }
4445}
4446
4447#[serde_as]
4451#[skip_serializing_none]
4452#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4453#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4454#[non_exhaustive]
4455pub struct SessionDeleteCapabilities {
4456 #[serde_as(deserialize_as = "DefaultOnError")]
4462 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4463 #[serde(default)]
4464 #[serde(rename = "_meta")]
4465 pub meta: Option<Meta>,
4466}
4467
4468impl SessionDeleteCapabilities {
4469 #[must_use]
4471 pub fn new() -> Self {
4472 Self::default()
4473 }
4474
4475 #[must_use]
4481 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4482 self.meta = meta.into_option();
4483 self
4484 }
4485}
4486
4487#[serde_as]
4494#[skip_serializing_none]
4495#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4496#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4497#[non_exhaustive]
4498pub struct SessionAdditionalDirectoriesCapabilities {
4499 #[serde_as(deserialize_as = "DefaultOnError")]
4505 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4506 #[serde(default)]
4507 #[serde(rename = "_meta")]
4508 pub meta: Option<Meta>,
4509}
4510
4511impl SessionAdditionalDirectoriesCapabilities {
4512 #[must_use]
4514 pub fn new() -> Self {
4515 Self::default()
4516 }
4517
4518 #[must_use]
4524 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4525 self.meta = meta.into_option();
4526 self
4527 }
4528}
4529
4530#[cfg(feature = "unstable_session_system_prompt")]
4539#[serde_as]
4540#[skip_serializing_none]
4541#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4542#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4543#[serde(rename_all = "camelCase")]
4544#[non_exhaustive]
4545pub struct SessionSystemPromptCapabilities {
4546 #[serde_as(deserialize_as = "DefaultOnError")]
4550 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4551 #[serde(default)]
4552 pub mode: Option<SessionSystemPromptModeCapabilities>,
4553 #[serde_as(deserialize_as = "DefaultOnError")]
4559 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4560 #[serde(default)]
4561 #[serde(rename = "_meta")]
4562 pub meta: Option<Meta>,
4563}
4564
4565#[cfg(feature = "unstable_session_system_prompt")]
4566impl SessionSystemPromptCapabilities {
4567 #[must_use]
4569 pub fn new() -> Self {
4570 Self::default()
4571 }
4572
4573 #[must_use]
4577 pub fn mode(mut self, mode: impl IntoOption<SessionSystemPromptModeCapabilities>) -> Self {
4578 self.mode = mode.into_option();
4579 self
4580 }
4581
4582 #[must_use]
4588 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4589 self.meta = meta.into_option();
4590 self
4591 }
4592}
4593
4594#[cfg(feature = "unstable_session_system_prompt")]
4603#[serde_as]
4604#[skip_serializing_none]
4605#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4606#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4607#[serde(rename_all = "camelCase")]
4608#[non_exhaustive]
4609pub struct SessionSystemPromptModeCapabilities {
4610 #[serde_as(deserialize_as = "DefaultOnError")]
4616 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4617 #[serde(default, rename = "override")]
4618 pub override_: Option<SessionSystemPromptOverrideCapabilities>,
4619 #[serde_as(deserialize_as = "DefaultOnError")]
4625 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4626 #[serde(default)]
4627 #[serde(rename = "_meta")]
4628 pub meta: Option<Meta>,
4629}
4630
4631#[cfg(feature = "unstable_session_system_prompt")]
4632impl SessionSystemPromptModeCapabilities {
4633 #[must_use]
4635 pub fn new() -> Self {
4636 Self::default()
4637 }
4638
4639 #[must_use]
4645 pub fn override_(
4646 mut self,
4647 override_: impl IntoOption<SessionSystemPromptOverrideCapabilities>,
4648 ) -> Self {
4649 self.override_ = override_.into_option();
4650 self
4651 }
4652
4653 #[must_use]
4659 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4660 self.meta = meta.into_option();
4661 self
4662 }
4663}
4664
4665#[cfg(feature = "unstable_session_system_prompt")]
4674#[serde_as]
4675#[skip_serializing_none]
4676#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4677#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4678#[non_exhaustive]
4679pub struct SessionSystemPromptOverrideCapabilities {
4680 #[serde_as(deserialize_as = "DefaultOnError")]
4686 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4687 #[serde(default)]
4688 #[serde(rename = "_meta")]
4689 pub meta: Option<Meta>,
4690}
4691
4692#[cfg(feature = "unstable_session_system_prompt")]
4693impl SessionSystemPromptOverrideCapabilities {
4694 #[must_use]
4696 pub fn new() -> Self {
4697 Self::default()
4698 }
4699
4700 #[must_use]
4706 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4707 self.meta = meta.into_option();
4708 self
4709 }
4710}
4711
4712#[cfg(feature = "unstable_session_fork")]
4720#[serde_as]
4721#[skip_serializing_none]
4722#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4723#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4724#[non_exhaustive]
4725pub struct SessionForkCapabilities {
4726 #[serde_as(deserialize_as = "DefaultOnError")]
4732 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4733 #[serde(default)]
4734 #[serde(rename = "_meta")]
4735 pub meta: Option<Meta>,
4736}
4737
4738#[cfg(feature = "unstable_session_fork")]
4739impl SessionForkCapabilities {
4740 #[must_use]
4742 pub fn new() -> Self {
4743 Self::default()
4744 }
4745
4746 #[must_use]
4752 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4753 self.meta = meta.into_option();
4754 self
4755 }
4756}
4757
4758#[serde_as]
4762#[skip_serializing_none]
4763#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4764#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4765#[non_exhaustive]
4766pub struct SessionResumeCapabilities {
4767 #[serde_as(deserialize_as = "DefaultOnError")]
4773 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4774 #[serde(default)]
4775 #[serde(rename = "_meta")]
4776 pub meta: Option<Meta>,
4777}
4778
4779impl SessionResumeCapabilities {
4780 #[must_use]
4782 pub fn new() -> Self {
4783 Self::default()
4784 }
4785
4786 #[must_use]
4792 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4793 self.meta = meta.into_option();
4794 self
4795 }
4796}
4797
4798#[serde_as]
4802#[skip_serializing_none]
4803#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4804#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4805#[non_exhaustive]
4806pub struct SessionCloseCapabilities {
4807 #[serde_as(deserialize_as = "DefaultOnError")]
4813 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4814 #[serde(default)]
4815 #[serde(rename = "_meta")]
4816 pub meta: Option<Meta>,
4817}
4818
4819impl SessionCloseCapabilities {
4820 #[must_use]
4822 pub fn new() -> Self {
4823 Self::default()
4824 }
4825
4826 #[must_use]
4832 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4833 self.meta = meta.into_option();
4834 self
4835 }
4836}
4837
4838#[serde_as]
4851#[skip_serializing_none]
4852#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4853#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4854#[serde(rename_all = "camelCase")]
4855#[non_exhaustive]
4856pub struct PromptCapabilities {
4857 #[serde_as(deserialize_as = "DefaultOnError")]
4859 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4860 #[serde(default)]
4861 pub image: bool,
4862 #[serde_as(deserialize_as = "DefaultOnError")]
4864 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4865 #[serde(default)]
4866 pub audio: bool,
4867 #[serde_as(deserialize_as = "DefaultOnError")]
4872 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4873 #[serde(default)]
4874 pub embedded_context: bool,
4875 #[serde_as(deserialize_as = "DefaultOnError")]
4881 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4882 #[serde(default)]
4883 #[serde(rename = "_meta")]
4884 pub meta: Option<Meta>,
4885}
4886
4887impl PromptCapabilities {
4888 #[must_use]
4890 pub fn new() -> Self {
4891 Self::default()
4892 }
4893
4894 #[must_use]
4896 pub fn image(mut self, image: bool) -> Self {
4897 self.image = image;
4898 self
4899 }
4900
4901 #[must_use]
4903 pub fn audio(mut self, audio: bool) -> Self {
4904 self.audio = audio;
4905 self
4906 }
4907
4908 #[must_use]
4913 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4914 self.embedded_context = embedded_context;
4915 self
4916 }
4917
4918 #[must_use]
4924 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4925 self.meta = meta.into_option();
4926 self
4927 }
4928}
4929
4930#[serde_as]
4932#[skip_serializing_none]
4933#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4934#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4935#[serde(rename_all = "camelCase")]
4936#[non_exhaustive]
4937pub struct McpCapabilities {
4938 #[serde_as(deserialize_as = "DefaultOnError")]
4940 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4941 #[serde(default)]
4942 pub http: bool,
4943 #[serde_as(deserialize_as = "DefaultOnError")]
4945 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4946 #[serde(default)]
4947 pub sse: bool,
4948 #[cfg(feature = "unstable_mcp_over_acp")]
4954 #[serde_as(deserialize_as = "DefaultOnError")]
4955 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4956 #[serde(default)]
4957 pub acp: bool,
4958 #[serde_as(deserialize_as = "DefaultOnError")]
4964 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4965 #[serde(default)]
4966 #[serde(rename = "_meta")]
4967 pub meta: Option<Meta>,
4968}
4969
4970impl McpCapabilities {
4971 #[must_use]
4973 pub fn new() -> Self {
4974 Self::default()
4975 }
4976
4977 #[must_use]
4979 pub fn http(mut self, http: bool) -> Self {
4980 self.http = http;
4981 self
4982 }
4983
4984 #[must_use]
4986 pub fn sse(mut self, sse: bool) -> Self {
4987 self.sse = sse;
4988 self
4989 }
4990
4991 #[cfg(feature = "unstable_mcp_over_acp")]
4997 #[must_use]
4998 pub fn acp(mut self, acp: bool) -> Self {
4999 self.acp = acp;
5000 self
5001 }
5002
5003 #[must_use]
5009 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5010 self.meta = meta.into_option();
5011 self
5012 }
5013}
5014
5015#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5021#[non_exhaustive]
5022pub struct AgentMethodNames {
5023 pub initialize: &'static str,
5025 pub authenticate: &'static str,
5027 #[cfg(feature = "unstable_llm_providers")]
5029 pub providers_list: &'static str,
5030 #[cfg(feature = "unstable_llm_providers")]
5032 pub providers_set: &'static str,
5033 #[cfg(feature = "unstable_llm_providers")]
5035 pub providers_disable: &'static str,
5036 pub session_new: &'static str,
5038 pub session_load: &'static str,
5040 pub session_set_mode: &'static str,
5042 pub session_set_config_option: &'static str,
5044 pub session_prompt: &'static str,
5046 pub session_cancel: &'static str,
5048 #[cfg(feature = "unstable_mcp_over_acp")]
5050 pub mcp_message: &'static str,
5051 pub session_list: &'static str,
5053 pub session_delete: &'static str,
5055 #[cfg(feature = "unstable_session_fork")]
5057 pub session_fork: &'static str,
5058 pub session_resume: &'static str,
5060 pub session_close: &'static str,
5062 pub logout: &'static str,
5064}
5065
5066pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
5068 initialize: INITIALIZE_METHOD_NAME,
5069 authenticate: AUTHENTICATE_METHOD_NAME,
5070 #[cfg(feature = "unstable_llm_providers")]
5071 providers_list: PROVIDERS_LIST_METHOD_NAME,
5072 #[cfg(feature = "unstable_llm_providers")]
5073 providers_set: PROVIDERS_SET_METHOD_NAME,
5074 #[cfg(feature = "unstable_llm_providers")]
5075 providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
5076 session_new: SESSION_NEW_METHOD_NAME,
5077 session_load: SESSION_LOAD_METHOD_NAME,
5078 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
5079 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
5080 session_prompt: SESSION_PROMPT_METHOD_NAME,
5081 session_cancel: SESSION_CANCEL_METHOD_NAME,
5082 #[cfg(feature = "unstable_mcp_over_acp")]
5083 mcp_message: MCP_MESSAGE_METHOD_NAME,
5084 session_list: SESSION_LIST_METHOD_NAME,
5085 session_delete: SESSION_DELETE_METHOD_NAME,
5086 #[cfg(feature = "unstable_session_fork")]
5087 session_fork: SESSION_FORK_METHOD_NAME,
5088 session_resume: SESSION_RESUME_METHOD_NAME,
5089 session_close: SESSION_CLOSE_METHOD_NAME,
5090 logout: LOGOUT_METHOD_NAME,
5091};
5092
5093pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
5095pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
5097#[cfg(feature = "unstable_llm_providers")]
5099pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
5100#[cfg(feature = "unstable_llm_providers")]
5102pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
5103#[cfg(feature = "unstable_llm_providers")]
5105pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
5106pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
5108pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
5110pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
5112pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
5114pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
5116pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
5118pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
5120pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
5122#[cfg(feature = "unstable_session_fork")]
5124pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
5125pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
5127pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
5129pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
5131
5132#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5139#[derive(Clone, Debug, Serialize, Deserialize)]
5140#[serde(untagged)]
5141#[cfg_attr(feature = "schemars", schemars(inline))]
5142#[non_exhaustive]
5143#[allow(clippy::large_enum_variant)]
5144pub enum ClientRequest {
5145 InitializeRequest(InitializeRequest),
5156 AuthenticateRequest(AuthenticateRequest),
5167 #[cfg(feature = "unstable_llm_providers")]
5173 ListProvidersRequest(ListProvidersRequest),
5174 #[cfg(feature = "unstable_llm_providers")]
5180 SetProviderRequest(SetProviderRequest),
5181 #[cfg(feature = "unstable_llm_providers")]
5187 DisableProviderRequest(DisableProviderRequest),
5188 LogoutRequest(LogoutRequest),
5193 NewSessionRequest(NewSessionRequest),
5206 LoadSessionRequest(LoadSessionRequest),
5217 ListSessionsRequest(ListSessionsRequest),
5223 DeleteSessionRequest(DeleteSessionRequest),
5227 #[cfg(feature = "unstable_session_fork")]
5228 ForkSessionRequest(ForkSessionRequest),
5244 ResumeSessionRequest(ResumeSessionRequest),
5251 CloseSessionRequest(CloseSessionRequest),
5258 SetSessionModeRequest(SetSessionModeRequest),
5272 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
5274 PromptRequest(PromptRequest),
5286 ExtMethodRequest(ExtRequest),
5293}
5294
5295impl ClientRequest {
5296 #[must_use]
5298 pub fn method(&self) -> &str {
5299 match self {
5300 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
5301 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
5302 #[cfg(feature = "unstable_llm_providers")]
5303 Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
5304 #[cfg(feature = "unstable_llm_providers")]
5305 Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
5306 #[cfg(feature = "unstable_llm_providers")]
5307 Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
5308 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
5309 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
5310 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
5311 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
5312 Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
5313 #[cfg(feature = "unstable_session_fork")]
5314 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
5315 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
5316 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
5317 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
5318 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
5319 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
5320 Self::ExtMethodRequest(ext_request) => &ext_request.method,
5321 }
5322 }
5323}
5324
5325#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5332#[derive(Clone, Debug, Serialize, Deserialize)]
5333#[serde(untagged)]
5334#[cfg_attr(feature = "schemars", schemars(inline))]
5335#[non_exhaustive]
5336#[allow(clippy::large_enum_variant)]
5337pub enum AgentResponse {
5338 InitializeResponse(InitializeResponse),
5340 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
5342 #[cfg(feature = "unstable_llm_providers")]
5344 ListProvidersResponse(ListProvidersResponse),
5345 #[cfg(feature = "unstable_llm_providers")]
5347 SetProviderResponse(#[serde(default)] SetProviderResponse),
5348 #[cfg(feature = "unstable_llm_providers")]
5350 DisableProviderResponse(#[serde(default)] DisableProviderResponse),
5351 LogoutResponse(#[serde(default)] LogoutResponse),
5353 NewSessionResponse(NewSessionResponse),
5355 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5357 ListSessionsResponse(ListSessionsResponse),
5359 DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
5361 #[cfg(feature = "unstable_session_fork")]
5363 ForkSessionResponse(ForkSessionResponse),
5364 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5366 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5368 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
5370 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5372 PromptResponse(PromptResponse),
5374 ExtMethodResponse(ExtResponse),
5376}
5377
5378#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5385#[derive(Clone, Debug, Serialize, Deserialize)]
5386#[serde(untagged)]
5387#[cfg_attr(feature = "schemars", schemars(inline))]
5388#[non_exhaustive]
5389#[allow(clippy::large_enum_variant)]
5390pub enum ClientNotification {
5391 CancelNotification(CancelNotification),
5403 #[cfg(feature = "unstable_mcp_over_acp")]
5409 MessageMcpNotification(MessageMcpNotification),
5410 ExtNotification(ExtNotification),
5417}
5418
5419impl ClientNotification {
5420 #[must_use]
5422 pub fn method(&self) -> &str {
5423 match self {
5424 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5425 #[cfg(feature = "unstable_mcp_over_acp")]
5426 Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5427 Self::ExtNotification(ext_notification) => &ext_notification.method,
5428 }
5429 }
5430}
5431
5432#[serde_as]
5436#[skip_serializing_none]
5437#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5438#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5439#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME)))]
5440#[serde(rename_all = "camelCase")]
5441#[non_exhaustive]
5442pub struct CancelNotification {
5443 pub session_id: SessionId,
5445 #[serde_as(deserialize_as = "DefaultOnError")]
5451 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5452 #[serde(default)]
5453 #[serde(rename = "_meta")]
5454 pub meta: Option<Meta>,
5455}
5456
5457impl CancelNotification {
5458 #[must_use]
5460 pub fn new(session_id: impl Into<SessionId>) -> Self {
5461 Self {
5462 session_id: session_id.into(),
5463 meta: None,
5464 }
5465 }
5466
5467 #[must_use]
5473 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5474 self.meta = meta.into_option();
5475 self
5476 }
5477}
5478
5479#[cfg(test)]
5480mod test_serialization {
5481 use super::*;
5482 use serde_json::json;
5483
5484 fn test_meta() -> Meta {
5485 json!({ "source": "test" }).as_object().unwrap().clone()
5486 }
5487
5488 fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
5489 serde_json::to_string(value)
5490 .unwrap()
5491 .matches("\"_meta\"")
5492 .count()
5493 }
5494
5495 #[test]
5498 fn prompt_response_has_no_error_stop_reason() {
5499 assert_eq!(
5500 serde_json::from_value::<PromptResponse>(json!({ "stopReason": "end_turn" }))
5501 .unwrap()
5502 .stop_reason,
5503 StopReason::EndTurn
5504 );
5505 assert!(
5506 serde_json::from_value::<PromptResponse>(json!({ "stopReason": "error" })).is_err()
5507 );
5508 }
5509
5510 #[test]
5511 fn test_initialize_capabilities_default_on_malformed_values() {
5512 let request: InitializeRequest = serde_json::from_value(json!({
5513 "protocolVersion": 1,
5514 "clientCapabilities": false
5515 }))
5516 .unwrap();
5517 assert_eq!(request.client_capabilities, ClientCapabilities::default());
5518
5519 let response: InitializeResponse = serde_json::from_value(json!({
5520 "protocolVersion": 1,
5521 "agentCapabilities": false
5522 }))
5523 .unwrap();
5524 assert_eq!(response.agent_capabilities, AgentCapabilities::default());
5525 }
5526
5527 #[test]
5528 fn test_agent_capabilities_default_on_malformed_values() {
5529 let capabilities: AgentCapabilities = serde_json::from_value(json!({
5530 "loadSession": "yes",
5531 "promptCapabilities": {
5532 "image": "yes",
5533 "audio": true,
5534 "embeddedContext": {}
5535 },
5536 "mcpCapabilities": {
5537 "http": "yes",
5538 "sse": true
5539 },
5540 "sessionCapabilities": false,
5541 "auth": false
5542 }))
5543 .unwrap();
5544
5545 assert!(!capabilities.load_session);
5546 assert!(!capabilities.prompt_capabilities.image);
5547 assert!(capabilities.prompt_capabilities.audio);
5548 assert!(!capabilities.prompt_capabilities.embedded_context);
5549 assert!(!capabilities.mcp_capabilities.http);
5550 assert!(capabilities.mcp_capabilities.sse);
5551 assert_eq!(
5552 capabilities.session_capabilities,
5553 SessionCapabilities::default()
5554 );
5555 assert_eq!(capabilities.auth, AgentAuthCapabilities::default());
5556 }
5557
5558 #[test]
5559 fn test_mcp_server_stdio_serialization() {
5560 let server = McpServer::Stdio(
5561 McpServerStdio::new("test-server", "/usr/bin/server")
5562 .args(vec!["--port".to_string(), "3000".to_string()])
5563 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5564 );
5565
5566 let json = serde_json::to_value(&server).unwrap();
5567 assert_eq!(
5568 json,
5569 json!({
5570 "name": "test-server",
5571 "command": "/usr/bin/server",
5572 "args": ["--port", "3000"],
5573 "env": [
5574 {
5575 "name": "API_KEY",
5576 "value": "secret123"
5577 }
5578 ]
5579 })
5580 );
5581
5582 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5583 match deserialized {
5584 McpServer::Stdio(McpServerStdio {
5585 name,
5586 command,
5587 args,
5588 env,
5589 meta: _,
5590 }) => {
5591 assert_eq!(name, "test-server");
5592 assert_eq!(command, PathBuf::from("/usr/bin/server"));
5593 assert_eq!(args, vec!["--port", "3000"]);
5594 assert_eq!(env.len(), 1);
5595 assert_eq!(env[0].name, "API_KEY");
5596 assert_eq!(env[0].value, "secret123");
5597 }
5598 _ => panic!("Expected Stdio variant"),
5599 }
5600 }
5601
5602 #[test]
5603 fn test_mcp_server_http_serialization() {
5604 let server = McpServer::Http(
5605 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5606 HttpHeader::new("Authorization", "Bearer token123"),
5607 HttpHeader::new("Content-Type", "application/json"),
5608 ]),
5609 );
5610
5611 let json = serde_json::to_value(&server).unwrap();
5612 assert_eq!(
5613 json,
5614 json!({
5615 "type": "http",
5616 "name": "http-server",
5617 "url": "https://api.example.com",
5618 "headers": [
5619 {
5620 "name": "Authorization",
5621 "value": "Bearer token123"
5622 },
5623 {
5624 "name": "Content-Type",
5625 "value": "application/json"
5626 }
5627 ]
5628 })
5629 );
5630
5631 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5632 match deserialized {
5633 McpServer::Http(McpServerHttp {
5634 name,
5635 url,
5636 headers,
5637 meta: _,
5638 }) => {
5639 assert_eq!(name, "http-server");
5640 assert_eq!(url, "https://api.example.com");
5641 assert_eq!(headers.len(), 2);
5642 assert_eq!(headers[0].name, "Authorization");
5643 assert_eq!(headers[0].value, "Bearer token123");
5644 assert_eq!(headers[1].name, "Content-Type");
5645 assert_eq!(headers[1].value, "application/json");
5646 }
5647 _ => panic!("Expected Http variant"),
5648 }
5649 }
5650
5651 #[cfg(feature = "unstable_mcp_over_acp")]
5652 #[test]
5653 fn test_mcp_server_acp_serialization() {
5654 let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id"));
5655
5656 let json = serde_json::to_value(&server).unwrap();
5657 assert_eq!(
5658 json,
5659 json!({
5660 "type": "acp",
5661 "name": "project-tools",
5662 "serverId": "project-tools-id"
5663 })
5664 );
5665
5666 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5667 match deserialized {
5668 McpServer::Acp(McpServerAcp {
5669 name,
5670 server_id: id,
5671 meta: _,
5672 }) => {
5673 assert_eq!(name, "project-tools");
5674 assert_eq!(id, McpServerAcpId::new("project-tools-id"));
5675 }
5676 _ => panic!("Expected Acp variant"),
5677 }
5678 }
5679
5680 #[cfg(feature = "unstable_mcp_over_acp")]
5681 #[test]
5682 fn test_client_mcp_message_method_names() {
5683 use serde_json::json;
5684
5685 assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5686
5687 let notification =
5688 MessageMcpNotification::new("server-1", "req-1", "notifications/progress");
5689 assert_eq!(
5690 ClientNotification::MessageMcpNotification(notification.clone()).method(),
5691 "mcp/message"
5692 );
5693 assert_eq!(
5694 serde_json::to_value(notification).unwrap(),
5695 json!({
5696 "serverId": "server-1",
5697 "requestId": "req-1",
5698 "method": "notifications/progress"
5699 })
5700 );
5701 let notification: MessageMcpNotification = serde_json::from_value(json!({
5702 "serverId": "server-1", "requestId": "req-1", "method": "notifications/progress",
5703 "params": null, "_meta": null
5704 }))
5705 .unwrap();
5706 assert_eq!(notification.params, None);
5707 assert_eq!(notification.meta, None);
5708 for key in ["serverId", "requestId", "method"] {
5709 let mut value = json!({"serverId":"server-1", "requestId":"req-1", "method":"notifications/progress"});
5710 value.as_object_mut().unwrap().remove(key);
5711 assert!(serde_json::from_value::<MessageMcpNotification>(value).is_err());
5712 }
5713 }
5714
5715 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5716 #[test]
5717 fn test_mcp_server_acp_schema() {
5718 let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap();
5719 assert!(json_contains_entry(
5720 &mcp_server_schema,
5721 "const",
5722 &json!("acp")
5723 ));
5724 assert!(json_contains_entry(
5725 &mcp_server_schema,
5726 "$ref",
5727 &json!("#/$defs/McpServerAcp")
5728 ));
5729
5730 let capabilities_schema =
5731 serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap();
5732 assert!(json_contains_key(&capabilities_schema, "acp"));
5733 }
5734
5735 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5736 fn json_contains_entry(
5737 value: &serde_json::Value,
5738 key: &str,
5739 expected: &serde_json::Value,
5740 ) -> bool {
5741 match value {
5742 serde_json::Value::Object(map) => {
5743 map.get(key) == Some(expected)
5744 || map
5745 .values()
5746 .any(|value| json_contains_entry(value, key, expected))
5747 }
5748 serde_json::Value::Array(values) => values
5749 .iter()
5750 .any(|value| json_contains_entry(value, key, expected)),
5751 _ => false,
5752 }
5753 }
5754
5755 #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
5756 fn json_contains_key(value: &serde_json::Value, key: &str) -> bool {
5757 match value {
5758 serde_json::Value::Object(map) => {
5759 map.contains_key(key) || map.values().any(|value| json_contains_key(value, key))
5760 }
5761 serde_json::Value::Array(values) => {
5762 values.iter().any(|value| json_contains_key(value, key))
5763 }
5764 _ => false,
5765 }
5766 }
5767
5768 #[test]
5769 fn test_mcp_server_sse_serialization() {
5770 let server = McpServer::Sse(
5771 McpServerSse::new("sse-server", "https://sse.example.com/events")
5772 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5773 );
5774
5775 let json = serde_json::to_value(&server).unwrap();
5776 assert_eq!(
5777 json,
5778 json!({
5779 "type": "sse",
5780 "name": "sse-server",
5781 "url": "https://sse.example.com/events",
5782 "headers": [
5783 {
5784 "name": "X-API-Key",
5785 "value": "apikey456"
5786 }
5787 ]
5788 })
5789 );
5790
5791 let deserialized: McpServer = serde_json::from_value(json).unwrap();
5792 match deserialized {
5793 McpServer::Sse(McpServerSse {
5794 name,
5795 url,
5796 headers,
5797 meta: _,
5798 }) => {
5799 assert_eq!(name, "sse-server");
5800 assert_eq!(url, "https://sse.example.com/events");
5801 assert_eq!(headers.len(), 1);
5802 assert_eq!(headers[0].name, "X-API-Key");
5803 assert_eq!(headers[0].value, "apikey456");
5804 }
5805 _ => panic!("Expected Sse variant"),
5806 }
5807 }
5808
5809 #[test]
5810 fn test_session_config_option_category_known_variants() {
5811 assert_eq!(
5813 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5814 json!("mode")
5815 );
5816 assert_eq!(
5817 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5818 json!("model")
5819 );
5820 assert_eq!(
5821 serde_json::to_value(&SessionConfigOptionCategory::ModelConfig).unwrap(),
5822 json!("model_config")
5823 );
5824 assert_eq!(
5825 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5826 json!("thought_level")
5827 );
5828
5829 assert_eq!(
5831 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5832 SessionConfigOptionCategory::Mode
5833 );
5834 assert_eq!(
5835 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5836 SessionConfigOptionCategory::Model
5837 );
5838 assert_eq!(
5839 serde_json::from_str::<SessionConfigOptionCategory>("\"model_config\"").unwrap(),
5840 SessionConfigOptionCategory::ModelConfig
5841 );
5842 assert_eq!(
5843 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5844 SessionConfigOptionCategory::ThoughtLevel
5845 );
5846 }
5847
5848 #[test]
5849 fn test_session_config_option_category_unknown_variants() {
5850 let unknown: SessionConfigOptionCategory =
5852 serde_json::from_str("\"some_future_category\"").unwrap();
5853 assert_eq!(
5854 unknown,
5855 SessionConfigOptionCategory::Other("some_future_category".to_string())
5856 );
5857
5858 let json = serde_json::to_value(&unknown).unwrap();
5860 assert_eq!(json, json!("some_future_category"));
5861 }
5862
5863 #[test]
5864 fn test_session_config_option_category_custom_categories() {
5865 let custom: SessionConfigOptionCategory =
5867 serde_json::from_str("\"_my_custom_category\"").unwrap();
5868 assert_eq!(
5869 custom,
5870 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5871 );
5872
5873 let json = serde_json::to_value(&custom).unwrap();
5875 assert_eq!(json, json!("_my_custom_category"));
5876
5877 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5879 assert_eq!(
5880 deserialized,
5881 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5882 );
5883 }
5884
5885 #[test]
5886 fn test_auth_method_agent_serialization() {
5887 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5888
5889 let json = serde_json::to_value(&method).unwrap();
5890 assert_eq!(
5891 json,
5892 json!({
5893 "id": "default-auth",
5894 "name": "Default Auth"
5895 })
5896 );
5897 assert!(!json.as_object().unwrap().contains_key("description"));
5899 assert!(!json.as_object().unwrap().contains_key("type"));
5901
5902 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5903 match deserialized {
5904 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5905 assert_eq!(id.0.as_ref(), "default-auth");
5906 assert_eq!(name, "Default Auth");
5907 }
5908 _ => panic!("Expected Agent variant"),
5909 }
5910 }
5911
5912 #[test]
5913 fn test_auth_method_explicit_agent_deserialization() {
5914 let json = json!({
5916 "id": "agent-auth",
5917 "name": "Agent Auth",
5918 "type": "agent"
5919 });
5920
5921 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5922 assert!(matches!(deserialized, AuthMethod::Agent(_)));
5923 }
5924
5925 #[test]
5926 fn test_session_delete_serialization() {
5927 assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5928 assert_eq!(
5929 ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5930 "session/delete"
5931 );
5932 assert_eq!(
5933 serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5934 json!({
5935 "sessionId": "sess_abc123"
5936 })
5937 );
5938 assert_eq!(
5939 serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5940 json!({})
5941 );
5942 assert_eq!(
5943 serde_json::to_value(
5944 SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5945 )
5946 .unwrap(),
5947 json!({
5948 "delete": {}
5949 })
5950 );
5951 }
5952 #[test]
5953 fn test_session_additional_directories_serialization() {
5954 assert_eq!(
5955 serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5956 json!({
5957 "cwd": "/home/user/project",
5958 "mcpServers": []
5959 })
5960 );
5961 assert_eq!(
5962 serde_json::to_value(
5963 NewSessionRequest::new("/home/user/project").additional_directories(vec![
5964 PathBuf::from("/home/user/shared-lib"),
5965 PathBuf::from("/home/user/product-docs"),
5966 ])
5967 )
5968 .unwrap(),
5969 json!({
5970 "cwd": "/home/user/project",
5971 "additionalDirectories": [
5972 "/home/user/shared-lib",
5973 "/home/user/product-docs"
5974 ],
5975 "mcpServers": []
5976 })
5977 );
5978 assert_eq!(
5979 serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5980 json!({
5981 "sessionId": "sess_abc123",
5982 "cwd": "/home/user/project"
5983 })
5984 );
5985 assert_eq!(
5986 serde_json::to_value(
5987 SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5988 PathBuf::from("/home/user/shared-lib"),
5989 PathBuf::from("/home/user/product-docs"),
5990 ])
5991 )
5992 .unwrap(),
5993 json!({
5994 "sessionId": "sess_abc123",
5995 "cwd": "/home/user/project",
5996 "additionalDirectories": [
5997 "/home/user/shared-lib",
5998 "/home/user/product-docs"
5999 ]
6000 })
6001 );
6002 assert_eq!(
6003 serde_json::from_value::<SessionInfo>(json!({
6004 "sessionId": "sess_abc123",
6005 "cwd": "/home/user/project"
6006 }))
6007 .unwrap()
6008 .additional_directories,
6009 Vec::<PathBuf>::new()
6010 );
6011 }
6012 #[test]
6013 fn test_session_additional_directories_capabilities_serialization() {
6014 assert_eq!(
6015 serde_json::to_value(
6016 SessionCapabilities::new()
6017 .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
6018 )
6019 .unwrap(),
6020 json!({
6021 "additionalDirectories": {}
6022 })
6023 );
6024 }
6025
6026 #[cfg(feature = "unstable_session_system_prompt")]
6027 #[test]
6028 fn test_session_system_prompt_capabilities_serialization() {
6029 assert_eq!(
6030 serde_json::to_value(
6031 SessionCapabilities::new().system_prompt(SessionSystemPromptCapabilities::new())
6032 )
6033 .unwrap(),
6034 json!({ "systemPrompt": {} })
6035 );
6036 assert_eq!(
6037 serde_json::to_value(
6038 SessionCapabilities::new().system_prompt(
6039 SessionSystemPromptCapabilities::new().mode(
6040 SessionSystemPromptModeCapabilities::new()
6041 .override_(SessionSystemPromptOverrideCapabilities::new())
6042 )
6043 )
6044 )
6045 .unwrap(),
6046 json!({ "systemPrompt": { "mode": { "override": {} } } })
6047 );
6048 assert_eq!(
6049 serde_json::from_value::<SessionCapabilities>(
6050 json!({ "systemPrompt": { "mode": { "override": {} } } })
6051 )
6052 .unwrap()
6053 .system_prompt
6054 .and_then(|capabilities| capabilities.mode)
6055 .and_then(|mode| mode.override_),
6056 Some(SessionSystemPromptOverrideCapabilities::new())
6057 );
6058
6059 assert_eq!(
6061 serde_json::from_value::<SessionCapabilities>(json!({ "systemPrompt": "yes" }))
6062 .unwrap()
6063 .system_prompt,
6064 None
6065 );
6066 assert_eq!(
6067 serde_json::from_value::<SessionCapabilities>(
6068 json!({ "systemPrompt": { "mode": { "override": true } } })
6069 )
6070 .unwrap()
6071 .system_prompt,
6072 Some(
6073 SessionSystemPromptCapabilities::new()
6074 .mode(SessionSystemPromptModeCapabilities::new())
6075 )
6076 );
6077 assert_eq!(
6078 serde_json::from_value::<SessionCapabilities>(
6079 json!({ "systemPrompt": { "mode": "override" } })
6080 )
6081 .unwrap()
6082 .system_prompt,
6083 Some(SessionSystemPromptCapabilities::new())
6084 );
6085 }
6086
6087 #[cfg(feature = "unstable_session_system_prompt")]
6088 #[test]
6089 fn test_system_prompt_lifecycle_request_serialization() {
6090 let system_prompt = SystemPrompt::new(vec![ContentBlock::from(
6091 "You are a code review specialist.",
6092 )]);
6093 let system_prompt_json = json!({
6094 "mode": "append",
6095 "content": [{ "type": "text", "text": "You are a code review specialist." }]
6096 });
6097
6098 let request =
6099 NewSessionRequest::new("/home/user/project").system_prompt(system_prompt.clone());
6100 let request_json = json!({
6101 "cwd": "/home/user/project",
6102 "mcpServers": [],
6103 "systemPrompt": system_prompt_json
6104 });
6105 assert_eq!(serde_json::to_value(&request).unwrap(), request_json);
6106 assert_eq!(
6107 serde_json::from_value::<NewSessionRequest>(request_json).unwrap(),
6108 request
6109 );
6110
6111 assert_eq!(
6112 serde_json::to_value(
6113 LoadSessionRequest::new("sess_abc123", "/home/user/project")
6114 .system_prompt(system_prompt.clone())
6115 )
6116 .unwrap()["systemPrompt"],
6117 system_prompt_json
6118 );
6119 assert_eq!(
6120 serde_json::to_value(
6121 ResumeSessionRequest::new("sess_abc123", "/home/user/project")
6122 .system_prompt(system_prompt.clone())
6123 )
6124 .unwrap()["systemPrompt"],
6125 system_prompt_json
6126 );
6127 #[cfg(feature = "unstable_session_fork")]
6128 assert_eq!(
6129 serde_json::to_value(
6130 ForkSessionRequest::new("sess_abc123", "/home/user/project")
6131 .system_prompt(system_prompt.clone())
6132 )
6133 .unwrap()["systemPrompt"],
6134 system_prompt_json
6135 );
6136
6137 let override_prompt =
6138 SystemPrompt::new(vec![ContentBlock::from("...")]).mode(SystemPromptMode::Override);
6139 let override_json = json!({
6140 "mode": "override",
6141 "content": [{ "type": "text", "text": "..." }]
6142 });
6143 assert_eq!(
6144 serde_json::to_value(&override_prompt).unwrap(),
6145 override_json
6146 );
6147 assert_eq!(
6148 serde_json::from_value::<SystemPrompt>(override_json).unwrap(),
6149 override_prompt
6150 );
6151 }
6152
6153 #[cfg(feature = "unstable_session_system_prompt")]
6156 #[test]
6157 fn test_system_prompt_new_defaults_to_append() {
6158 let system_prompt = SystemPrompt::new(vec![ContentBlock::from("...")]);
6159 assert_eq!(system_prompt.mode, SystemPromptMode::Append);
6160 assert_eq!(
6161 serde_json::to_value(&system_prompt).unwrap(),
6162 json!({ "mode": "append", "content": [{ "type": "text", "text": "..." }] })
6163 );
6164 }
6165
6166 #[cfg(feature = "unstable_session_system_prompt")]
6170 #[test]
6171 fn test_system_prompt_preserves_unknown_modes() {
6172 for mode in ["_vendor_mode", "prepend"] {
6173 let system_prompt_json =
6174 json!({ "mode": mode, "content": [{ "type": "text", "text": "..." }] });
6175 let system_prompt: SystemPrompt =
6176 serde_json::from_value(system_prompt_json.clone()).unwrap();
6177 assert_eq!(
6178 system_prompt.mode,
6179 SystemPromptMode::Other(mode.to_string())
6180 );
6181 assert_eq!(
6182 serde_json::to_value(&system_prompt).unwrap(),
6183 system_prompt_json
6184 );
6185 }
6186 }
6187
6188 #[cfg(feature = "unstable_session_system_prompt")]
6192 fn assert_system_prompt_is_strict<T>(base: &serde_json::Value)
6193 where
6194 T: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
6195 {
6196 let name = std::any::type_name::<T>();
6197 let with = |system_prompt: serde_json::Value| {
6198 let mut request = base.clone();
6199 request["systemPrompt"] = system_prompt;
6200 serde_json::from_value::<T>(request)
6201 };
6202
6203 for system_prompt in [
6204 json!("You are a code review specialist."),
6205 json!({ "content": [{ "type": "text", "text": "..." }] }),
6206 json!({ "mode": null, "content": [{ "type": "text", "text": "..." }] }),
6207 json!({ "mode": 1, "content": [{ "type": "text", "text": "..." }] }),
6208 json!({ "mode": "append" }),
6209 json!({ "mode": "append", "content": "..." }),
6210 json!({ "mode": "append", "content": [{ "type": "text" }] }),
6211 json!({ "mode": "append", "content": [{ "type": "video", "uri": "..." }] }),
6212 ] {
6213 assert!(
6214 with(system_prompt.clone()).is_err(),
6215 "{name}.systemPrompt: {system_prompt}"
6216 );
6217 }
6218
6219 assert_eq!(
6220 with(serde_json::Value::Null).unwrap(),
6221 serde_json::from_value::<T>(base.clone()).unwrap(),
6222 "{name}.systemPrompt"
6223 );
6224 }
6225
6226 #[cfg(feature = "unstable_session_system_prompt")]
6227 #[test]
6228 fn test_session_setup_requests_reject_malformed_system_prompts() {
6229 assert!(
6230 serde_json::to_value(NewSessionRequest::new("/repo"))
6231 .unwrap()
6232 .get("systemPrompt")
6233 .is_none()
6234 );
6235 assert_system_prompt_is_strict::<NewSessionRequest>(&json!({
6236 "cwd": "/repo",
6237 "mcpServers": []
6238 }));
6239 assert_system_prompt_is_strict::<LoadSessionRequest>(&json!({
6240 "sessionId": "sess-1",
6241 "cwd": "/repo",
6242 "mcpServers": []
6243 }));
6244 assert_system_prompt_is_strict::<ResumeSessionRequest>(&json!({
6245 "sessionId": "sess-1",
6246 "cwd": "/repo"
6247 }));
6248 #[cfg(feature = "unstable_session_fork")]
6249 assert_system_prompt_is_strict::<ForkSessionRequest>(&json!({
6250 "sessionId": "sess-1",
6251 "cwd": "/repo"
6252 }));
6253 }
6254
6255 #[test]
6256 fn test_auth_method_terminal_serialization() {
6257 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
6258
6259 let json = serde_json::to_value(&method).unwrap();
6260 assert_eq!(
6261 json,
6262 json!({
6263 "id": "tui-auth",
6264 "name": "Terminal Auth",
6265 "type": "terminal"
6266 })
6267 );
6268 assert!(!json.as_object().unwrap().contains_key("args"));
6270 assert!(!json.as_object().unwrap().contains_key("env"));
6271
6272 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6273 match deserialized {
6274 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
6275 assert_eq!(args, Vec::<String>::new());
6276 assert!(env.is_empty());
6277 }
6278 _ => panic!("Expected Terminal variant"),
6279 }
6280 }
6281
6282 #[test]
6283 fn test_auth_method_terminal_with_args_and_env_serialization() {
6284 use std::collections::HashMap;
6285
6286 let mut env = HashMap::new();
6287 env.insert("TERM".to_string(), "xterm-256color".to_string());
6288
6289 let method = AuthMethod::Terminal(
6290 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
6291 .args(vec!["--interactive".to_string(), "--color".to_string()])
6292 .env(env),
6293 );
6294
6295 let json = serde_json::to_value(&method).unwrap();
6296 assert_eq!(
6297 json,
6298 json!({
6299 "id": "tui-auth",
6300 "name": "Terminal Auth",
6301 "type": "terminal",
6302 "args": ["--interactive", "--color"],
6303 "env": {
6304 "TERM": "xterm-256color"
6305 }
6306 })
6307 );
6308
6309 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
6310 match deserialized {
6311 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
6312 assert_eq!(args, vec!["--interactive", "--color"]);
6313 assert_eq!(env.len(), 1);
6314 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
6315 }
6316 _ => panic!("Expected Terminal variant"),
6317 }
6318 }
6319
6320 #[test]
6321 fn test_session_config_option_value_id_serialize() {
6322 let val = SessionConfigOptionValue::value_id("model-1");
6323 let json = serde_json::to_value(&val).unwrap();
6324 assert_eq!(json, json!({ "value": "model-1" }));
6326 assert!(!json.as_object().unwrap().contains_key("type"));
6327 }
6328
6329 #[test]
6330 fn test_session_config_option_value_boolean_serialize() {
6331 let val = SessionConfigOptionValue::boolean(true);
6332 let json = serde_json::to_value(&val).unwrap();
6333 assert_eq!(json, json!({ "type": "boolean", "value": true }));
6334 }
6335
6336 #[test]
6337 fn test_session_config_option_value_deserialize_no_type() {
6338 let json = json!({ "value": "model-1" });
6340 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6341 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
6342 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
6343 }
6344
6345 #[test]
6346 fn test_session_config_option_value_deserialize_boolean() {
6347 let json = json!({ "type": "boolean", "value": true });
6348 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6349 assert_eq!(val, SessionConfigOptionValue::boolean(true));
6350 assert_eq!(val.as_bool(), Some(true));
6351 }
6352
6353 #[test]
6354 fn test_session_config_option_value_deserialize_boolean_false() {
6355 let json = json!({ "type": "boolean", "value": false });
6356 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6357 assert_eq!(val, SessionConfigOptionValue::boolean(false));
6358 assert_eq!(val.as_bool(), Some(false));
6359 }
6360
6361 #[test]
6362 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
6363 let json = json!({ "type": "text", "value": "freeform input" });
6365 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6366 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
6367 }
6368
6369 #[test]
6370 fn test_session_config_option_value_roundtrip_value_id() {
6371 let original = SessionConfigOptionValue::value_id("option-a");
6372 let json = serde_json::to_value(&original).unwrap();
6373 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6374 assert_eq!(original, roundtripped);
6375 }
6376
6377 #[test]
6378 fn test_session_config_option_value_roundtrip_boolean() {
6379 let original = SessionConfigOptionValue::boolean(false);
6380 let json = serde_json::to_value(&original).unwrap();
6381 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6382 assert_eq!(original, roundtripped);
6383 }
6384
6385 #[test]
6386 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
6387 let json = json!({ "type": "boolean", "value": "not a bool" });
6389 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
6390 assert!(result.is_ok());
6392 assert_eq!(
6393 result.unwrap().as_value_id().unwrap().to_string(),
6394 "not a bool"
6395 );
6396 }
6397
6398 #[test]
6399 fn test_session_config_option_value_from_impls() {
6400 let from_str: SessionConfigOptionValue = "model-1".into();
6401 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
6402
6403 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
6404 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
6405
6406 let from_bool: SessionConfigOptionValue = true.into();
6407 assert_eq!(from_bool.as_bool(), Some(true));
6408 }
6409
6410 #[test]
6411 fn test_set_session_config_option_request_value_id() {
6412 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
6413 let json = serde_json::to_value(&req).unwrap();
6414 assert_eq!(
6415 json,
6416 json!({
6417 "sessionId": "sess_1",
6418 "configId": "model",
6419 "value": "model-1"
6420 })
6421 );
6422 assert!(!json.as_object().unwrap().contains_key("type"));
6424 }
6425
6426 #[test]
6427 fn test_set_session_config_option_request_boolean() {
6428 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
6429 let json = serde_json::to_value(&req).unwrap();
6430 assert_eq!(
6431 json,
6432 json!({
6433 "sessionId": "sess_1",
6434 "configId": "brave_mode",
6435 "type": "boolean",
6436 "value": true
6437 })
6438 );
6439 }
6440
6441 #[test]
6442 fn test_set_session_config_option_request_deserialize_no_type() {
6443 let json = json!({
6445 "sessionId": "sess_1",
6446 "configId": "model",
6447 "value": "model-1"
6448 });
6449 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6450 assert_eq!(req.session_id.to_string(), "sess_1");
6451 assert_eq!(req.config_id.to_string(), "model");
6452 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
6453 }
6454
6455 #[test]
6456 fn test_set_session_config_option_request_deserialize_boolean() {
6457 let json = json!({
6458 "sessionId": "sess_1",
6459 "configId": "brave_mode",
6460 "type": "boolean",
6461 "value": true
6462 });
6463 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6464 assert_eq!(req.value.as_bool(), Some(true));
6465 }
6466
6467 #[test]
6468 fn test_set_session_config_option_request_roundtrip_value_id() {
6469 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
6470 let json = serde_json::to_value(&original).unwrap();
6471 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6472 assert_eq!(original, roundtripped);
6473 }
6474
6475 #[test]
6476 fn test_set_session_config_option_request_roundtrip_boolean() {
6477 let original = SetSessionConfigOptionRequest::new("s", "c", false);
6478 let json = serde_json::to_value(&original).unwrap();
6479 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6480 assert_eq!(original, roundtripped);
6481 }
6482
6483 #[test]
6484 fn test_session_config_boolean_serialization() {
6485 let cfg = SessionConfigBoolean::new(true);
6486 let json = serde_json::to_value(&cfg).unwrap();
6487 assert_eq!(json, json!({ "currentValue": true }));
6488
6489 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6490 assert!(deserialized.current_value);
6491 }
6492
6493 #[test]
6494 fn test_session_config_option_boolean_variant() {
6495 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6496 .description("Skip confirmation prompts")
6497 .meta(test_meta());
6498 assert_eq!(serialized_meta_key_count(&opt), 1);
6499
6500 let json = serde_json::to_value(&opt).unwrap();
6501 assert_eq!(
6502 json,
6503 json!({
6504 "id": "brave_mode",
6505 "name": "Brave Mode",
6506 "description": "Skip confirmation prompts",
6507 "type": "boolean",
6508 "currentValue": false,
6509 "_meta": {
6510 "source": "test"
6511 }
6512 })
6513 );
6514
6515 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6516 assert_eq!(deserialized.id.to_string(), "brave_mode");
6517 assert_eq!(deserialized.name, "Brave Mode");
6518 match deserialized.kind {
6519 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6520 _ => panic!("Expected Boolean kind"),
6521 }
6522 }
6523
6524 #[test]
6525 fn test_session_config_option_select_still_works() {
6526 let opt = SessionConfigOption::select(
6528 "model",
6529 "Model",
6530 "model-1",
6531 vec![
6532 SessionConfigSelectOption::new("model-1", "Model 1"),
6533 SessionConfigSelectOption::new("model-2", "Model 2"),
6534 ],
6535 )
6536 .meta(test_meta());
6537 assert_eq!(serialized_meta_key_count(&opt), 1);
6538
6539 let json = serde_json::to_value(&opt).unwrap();
6540 assert_eq!(json["type"], "select");
6541 assert_eq!(json["currentValue"], "model-1");
6542 assert_eq!(json["options"].as_array().unwrap().len(), 2);
6543 assert_eq!(json["_meta"]["source"], "test");
6544
6545 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6546 match deserialized.kind {
6547 SessionConfigKind::Select(ref s) => {
6548 assert_eq!(s.current_value.to_string(), "model-1");
6549 }
6550 _ => panic!("Expected Select kind"),
6551 }
6552 }
6553
6554 #[cfg(feature = "unstable_llm_providers")]
6555 #[test]
6556 fn test_llm_protocol_known_variants() {
6557 assert_eq!(
6558 serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6559 json!("anthropic")
6560 );
6561 assert_eq!(
6562 serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6563 json!("openai")
6564 );
6565 assert_eq!(
6566 serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6567 json!("azure")
6568 );
6569 assert_eq!(
6570 serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6571 json!("vertex")
6572 );
6573 assert_eq!(
6574 serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6575 json!("bedrock")
6576 );
6577
6578 assert_eq!(
6579 serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6580 LlmProtocol::Anthropic
6581 );
6582 assert_eq!(
6583 serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6584 LlmProtocol::OpenAi
6585 );
6586 assert_eq!(
6587 serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6588 LlmProtocol::Azure
6589 );
6590 assert_eq!(
6591 serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6592 LlmProtocol::Vertex
6593 );
6594 assert_eq!(
6595 serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6596 LlmProtocol::Bedrock
6597 );
6598 }
6599
6600 #[cfg(feature = "unstable_llm_providers")]
6601 #[test]
6602 fn test_llm_protocol_unknown_variant() {
6603 let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6604 assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6605
6606 let json = serde_json::to_value(&unknown).unwrap();
6607 assert_eq!(json, json!("cohere"));
6608 }
6609
6610 #[cfg(feature = "unstable_llm_providers")]
6611 #[test]
6612 fn test_provider_current_config_serialization() {
6613 let config =
6614 ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6615
6616 let json = serde_json::to_value(&config).unwrap();
6617 assert_eq!(
6618 json,
6619 json!({
6620 "apiType": "anthropic",
6621 "baseUrl": "https://api.anthropic.com"
6622 })
6623 );
6624
6625 let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6626 assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6627 assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6628 }
6629
6630 #[cfg(feature = "unstable_llm_providers")]
6631 #[test]
6632 fn test_provider_info_with_current_config() {
6633 let info = ProviderInfo::new(
6634 "main",
6635 vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6636 true,
6637 Some(ProviderCurrentConfig::new(
6638 LlmProtocol::Anthropic,
6639 "https://api.anthropic.com",
6640 )),
6641 );
6642
6643 let json = serde_json::to_value(&info).unwrap();
6644 assert_eq!(
6645 json,
6646 json!({
6647 "providerId": "main",
6648 "supported": ["anthropic", "openai"],
6649 "required": true,
6650 "current": {
6651 "apiType": "anthropic",
6652 "baseUrl": "https://api.anthropic.com"
6653 }
6654 })
6655 );
6656
6657 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6658 assert_eq!(deserialized.provider_id.to_string(), "main");
6659 assert_eq!(deserialized.supported.len(), 2);
6660 assert!(deserialized.required);
6661 assert!(deserialized.current.is_some());
6662 assert_eq!(
6663 deserialized.current.as_ref().unwrap().api_type,
6664 LlmProtocol::Anthropic
6665 );
6666 }
6667
6668 #[cfg(feature = "unstable_llm_providers")]
6669 #[test]
6670 fn test_provider_info_disabled() {
6671 let info = ProviderInfo::new(
6672 "secondary",
6673 vec![LlmProtocol::OpenAi],
6674 false,
6675 None::<ProviderCurrentConfig>,
6676 );
6677
6678 let json = serde_json::to_value(&info).unwrap();
6679 assert_eq!(
6680 json,
6681 json!({
6682 "providerId": "secondary",
6683 "supported": ["openai"],
6684 "required": false
6685 })
6686 );
6687
6688 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6689 assert_eq!(deserialized.provider_id.to_string(), "secondary");
6690 assert!(!deserialized.required);
6691 assert!(deserialized.current.is_none());
6692 }
6693
6694 #[cfg(feature = "unstable_llm_providers")]
6695 #[test]
6696 fn test_provider_info_missing_current_defaults_to_none() {
6697 let json = json!({
6699 "providerId": "main",
6700 "supported": ["anthropic"],
6701 "required": true
6702 });
6703 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6704 assert!(deserialized.current.is_none());
6705 }
6706
6707 #[cfg(feature = "unstable_llm_providers")]
6708 #[test]
6709 fn test_provider_info_explicit_null_current_decodes_to_none() {
6710 let json = json!({
6714 "providerId": "main",
6715 "supported": ["anthropic"],
6716 "required": true,
6717 "current": null
6718 });
6719 let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6720 assert!(deserialized.current.is_none());
6721 }
6722
6723 #[cfg(feature = "unstable_llm_providers")]
6724 #[test]
6725 fn test_list_providers_response_serialization() {
6726 let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6727 "main",
6728 vec![LlmProtocol::Anthropic],
6729 true,
6730 Some(ProviderCurrentConfig::new(
6731 LlmProtocol::Anthropic,
6732 "https://api.anthropic.com",
6733 )),
6734 )]);
6735
6736 let json = serde_json::to_value(&response).unwrap();
6737 assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6738 assert_eq!(json["providers"][0]["providerId"], "main");
6739
6740 let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6741 assert_eq!(deserialized.providers.len(), 1);
6742 }
6743
6744 #[cfg(feature = "unstable_llm_providers")]
6745 #[test]
6746 fn test_set_provider_request_serialization() {
6747 use std::collections::HashMap;
6748
6749 let mut headers = HashMap::new();
6750 headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6751
6752 let request =
6753 SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6754 .headers(headers);
6755
6756 let json = serde_json::to_value(&request).unwrap();
6757 assert_eq!(
6758 json,
6759 json!({
6760 "providerId": "main",
6761 "apiType": "openai",
6762 "baseUrl": "https://api.openai.com/v1",
6763 "headers": {
6764 "Authorization": "Bearer sk-test"
6765 }
6766 })
6767 );
6768
6769 let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6770 assert_eq!(deserialized.provider_id.to_string(), "main");
6771 assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6772 assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6773 assert_eq!(deserialized.headers.len(), 1);
6774 assert_eq!(
6775 deserialized.headers.get("Authorization").unwrap(),
6776 "Bearer sk-test"
6777 );
6778 }
6779
6780 #[cfg(feature = "unstable_llm_providers")]
6781 #[test]
6782 fn test_set_provider_request_omits_empty_headers() {
6783 let request =
6784 SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6785
6786 let json = serde_json::to_value(&request).unwrap();
6787 assert!(!json.as_object().unwrap().contains_key("headers"));
6789 }
6790
6791 #[cfg(feature = "unstable_llm_providers")]
6792 #[test]
6793 fn test_disable_provider_request_serialization() {
6794 let request = DisableProviderRequest::new("secondary");
6795
6796 let json = serde_json::to_value(&request).unwrap();
6797 assert_eq!(json, json!({ "providerId": "secondary" }));
6798
6799 let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6800 assert_eq!(deserialized.provider_id.to_string(), "secondary");
6801 }
6802
6803 #[cfg(feature = "unstable_llm_providers")]
6804 #[test]
6805 fn test_providers_capabilities_serialization() {
6806 let caps = ProvidersCapabilities::new();
6807
6808 let json = serde_json::to_value(&caps).unwrap();
6809 assert_eq!(json, json!({}));
6810
6811 let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6812 assert!(deserialized.meta.is_none());
6813 }
6814
6815 #[cfg(feature = "unstable_llm_providers")]
6816 #[test]
6817 fn test_agent_capabilities_with_providers() {
6818 let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6819
6820 let json = serde_json::to_value(&caps).unwrap();
6821 assert_eq!(json["providers"], json!({}));
6822
6823 let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6824 assert!(deserialized.providers.is_some());
6825 }
6826
6827 #[test]
6828 fn prompt_request_rejects_malformed_content_block() {
6829 use serde_json::json;
6830
6831 assert!(
6832 serde_json::from_value::<PromptRequest>(json!({
6833 "sessionId": "sess-1",
6834 "prompt": [{"type": "text"}]
6835 }))
6836 .is_err()
6837 );
6838 }
6839
6840 #[test]
6841 fn prompt_request_rejects_non_array_prompt() {
6842 use serde_json::json;
6843
6844 assert!(
6845 serde_json::from_value::<PromptRequest>(json!({
6846 "sessionId": "sess-1",
6847 "prompt": "hello"
6848 }))
6849 .is_err()
6850 );
6851 }
6852
6853 fn assert_session_setup_lists_are_strict<T>(base: &serde_json::Value)
6854 where
6855 T: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
6856 {
6857 let name = std::any::type_name::<T>();
6858 let with = |field: &str, value: serde_json::Value| {
6859 let mut request = base.clone();
6860 request[field] = value;
6861 serde_json::from_value::<T>(request)
6862 };
6863
6864 for (field, value) in [
6865 (
6867 "mcpServers",
6868 json!([
6869 {"name": "github", "command": "/usr/bin/gh-mcp", "args": [], "env": [{"name": "GITHUB_TOKEN", "value": null}]},
6870 {"name": "fs", "command": "/usr/bin/fs-mcp", "args": [], "env": []}
6871 ]),
6872 ),
6873 ("mcpServers", json!({"name": "fs"})),
6874 ("additionalDirectories", json!(["/repo/lib", 42])),
6875 ("additionalDirectories", json!("/repo/lib")),
6876 ] {
6877 assert!(
6878 with(field, value.clone()).is_err(),
6879 "{name}.{field}: {value}"
6880 );
6881 }
6882
6883 let empty = serde_json::from_value::<T>(base.clone()).unwrap();
6884 for field in ["mcpServers", "additionalDirectories"] {
6885 assert_eq!(
6886 with(field, serde_json::Value::Null).unwrap(),
6887 empty,
6888 "{name}.{field}"
6889 );
6890 }
6891 }
6892
6893 #[test]
6894 fn session_setup_requests_reject_malformed_mcp_servers_and_directories() {
6895 assert_session_setup_lists_are_strict::<NewSessionRequest>(&json!({
6896 "cwd": "/repo",
6897 "mcpServers": []
6898 }));
6899 assert_session_setup_lists_are_strict::<LoadSessionRequest>(&json!({
6900 "sessionId": "sess-1",
6901 "cwd": "/repo",
6902 "mcpServers": []
6903 }));
6904 assert_session_setup_lists_are_strict::<ResumeSessionRequest>(&json!({
6905 "sessionId": "sess-1",
6906 "cwd": "/repo"
6907 }));
6908 #[cfg(feature = "unstable_session_fork")]
6909 assert_session_setup_lists_are_strict::<ForkSessionRequest>(&json!({
6910 "sessionId": "sess-1",
6911 "cwd": "/repo"
6912 }));
6913 }
6914
6915 #[test]
6916 fn mcp_server_lists_treat_null_as_empty() {
6917 let servers: Vec<McpServer> = serde_json::from_value(json!([
6918 {"name": "fs", "command": "/usr/bin/fs-mcp", "args": null, "env": null},
6919 {"type": "http", "name": "api", "url": "https://example.com/mcp", "headers": null},
6920 {"type": "sse", "name": "events", "url": "https://example.com/sse", "headers": null}
6921 ]))
6922 .unwrap();
6923
6924 assert_eq!(
6925 servers,
6926 vec![
6927 McpServer::Stdio(McpServerStdio::new("fs", "/usr/bin/fs-mcp")),
6928 McpServer::Http(McpServerHttp::new("api", "https://example.com/mcp")),
6929 McpServer::Sse(McpServerSse::new("events", "https://example.com/sse")),
6930 ]
6931 );
6932 }
6933
6934 #[test]
6935 fn terminal_auth_methods_reject_malformed_launch_config() {
6936 let response: InitializeResponse = serde_json::from_value(json!({
6940 "protocolVersion": 1,
6941 "authMethods": [
6942 {"type": "terminal", "id": "bad-args", "name": "Log in", "args": ["auth", "--port", 8123]},
6943 {"type": "terminal", "id": "bad-env", "name": "Log in", "env": {"AUTH_MODE": "device", "DEBUG": 1}},
6944 {"type": "terminal", "id": "null-config", "name": "Log in", "args": null, "env": null},
6945 {"id": "agent", "name": "Agent login"}
6946 ]
6947 }))
6948 .unwrap();
6949
6950 assert_eq!(
6951 response.auth_methods,
6952 vec![
6953 AuthMethod::Terminal(AuthMethodTerminal::new("null-config", "Log in")),
6954 AuthMethod::Agent(AuthMethodAgent::new("agent", "Agent login")),
6955 ]
6956 );
6957 assert!(
6958 serde_json::from_value::<AuthMethod>(json!({
6959 "type": "terminal",
6960 "id": "bad-args",
6961 "name": "Log in",
6962 "args": ["auth", 8123]
6963 }))
6964 .is_err()
6965 );
6966 }
6967}