1use std::{path::PathBuf, sync::Arc};
7
8use derive_more::{Display, From};
9use serde::{Deserialize, Serialize};
10use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
11
12use super::{
13 CompleteElicitationNotification, CreateElicitationRequest, CreateElicitationResponse,
14 ElicitationCapabilities,
15};
16use crate::{IntoMaybeUndefined, IntoOption, MaybeUndefined, SkipListener};
17
18use super::{
19 ContentBlock, EnvVariable, ExtNotification, ExtRequest, ExtResponse, Meta, Plan,
20 SessionConfigOption, SessionId, SessionModeId, ToolCall, ToolCallUpdate,
21};
22#[cfg(feature = "unstable_plan_operations")]
23use super::{PlanCapabilities, PlanRemoved, PlanUpdate};
24
25#[cfg(feature = "unstable_mcp_over_acp")]
26use super::mcp::{
27 ConnectMcpRequest, ConnectMcpResponse, DisconnectMcpRequest, DisconnectMcpResponse,
28 MCP_CONNECT_METHOD_NAME, MCP_DISCONNECT_METHOD_NAME, MCP_MESSAGE_METHOD_NAME,
29 MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
30};
31
32#[cfg(feature = "unstable_nes")]
33use super::{ClientNesCapabilities, PositionEncodingKind};
34
35#[serde_as]
43#[skip_serializing_none]
44#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
45#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
46#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION)))]
47#[serde(rename_all = "camelCase")]
48#[non_exhaustive]
49pub struct SessionNotification {
50 pub session_id: SessionId,
52 pub update: SessionUpdate,
54 #[serde_as(deserialize_as = "DefaultOnError")]
60 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
61 #[serde(default)]
62 #[serde(rename = "_meta")]
63 pub meta: Option<Meta>,
64}
65
66impl SessionNotification {
67 #[must_use]
69 pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
70 Self {
71 session_id: session_id.into(),
72 update,
73 meta: None,
74 }
75 }
76
77 #[must_use]
83 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
84 self.meta = meta.into_option();
85 self
86 }
87}
88
89#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
95#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
96#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
97#[cfg_attr(feature = "schemars", schemars(extend("discriminator" = {"propertyName": "sessionUpdate"})))]
98#[non_exhaustive]
99pub enum SessionUpdate {
100 UserMessageChunk(ContentChunk),
102 AgentMessageChunk(ContentChunk),
104 AgentThoughtChunk(ContentChunk),
106 ToolCall(ToolCall),
108 ToolCallUpdate(ToolCallUpdate),
110 Plan(Plan),
113 #[cfg(feature = "unstable_plan_operations")]
119 PlanUpdate(PlanUpdate),
120 #[cfg(feature = "unstable_plan_operations")]
126 PlanRemoved(PlanRemoved),
127 AvailableCommandsUpdate(AvailableCommandsUpdate),
129 CurrentModeUpdate(CurrentModeUpdate),
133 ConfigOptionUpdate(ConfigOptionUpdate),
135 SessionInfoUpdate(SessionInfoUpdate),
137 UsageUpdate(UsageUpdate),
139 #[cfg(feature = "unstable_session_compaction")]
148 CompactionUpdate(CompactionUpdate),
149 #[cfg(feature = "unstable_session_compaction")]
158 CompactionSummaryChunk(CompactionSummaryChunk),
159}
160
161#[cfg(feature = "unstable_session_compaction")]
167#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
168#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
169#[serde(transparent)]
170#[from(Arc<str>, String, &'static str)]
171#[non_exhaustive]
172pub struct CompactionId(pub Arc<str>);
173
174#[cfg(feature = "unstable_session_compaction")]
175impl CompactionId {
176 #[must_use]
178 pub fn new(id: impl Into<Arc<str>>) -> Self {
179 Self(id.into())
180 }
181}
182
183#[cfg(feature = "unstable_session_compaction")]
189#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
190#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
191#[serde(rename_all = "snake_case")]
192#[non_exhaustive]
193pub enum CompactionStatus {
194 InProgress,
196 Completed,
198 Failed,
200 Cancelled,
202 #[serde(untagged)]
207 Other(String),
208}
209
210#[cfg(feature = "unstable_session_compaction")]
224#[serde_as]
225#[skip_serializing_none]
226#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
227#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
228#[serde(rename_all = "camelCase")]
229#[non_exhaustive]
230pub struct CompactionUpdate {
231 pub compaction_id: CompactionId,
233 pub status: CompactionStatus,
235 #[serde_as(deserialize_as = "DefaultOnError<MaybeUndefined<VecSkipError<_, SkipListener>>>")]
237 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
238 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
239 pub summary: MaybeUndefined<Vec<ContentBlock>>,
240 #[serde_as(deserialize_as = "DefaultOnError<MaybeUndefined<_>>")]
242 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
243 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
244 pub error: MaybeUndefined<String>,
245 #[serde_as(deserialize_as = "DefaultOnError<MaybeUndefined<_>>")]
247 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
248 #[serde(
249 rename = "_meta",
250 default,
251 skip_serializing_if = "MaybeUndefined::is_undefined"
252 )]
253 pub meta: MaybeUndefined<Meta>,
254}
255
256#[cfg(feature = "unstable_session_compaction")]
257impl CompactionUpdate {
258 #[must_use]
260 pub fn new(compaction_id: impl Into<CompactionId>, status: CompactionStatus) -> Self {
261 Self {
262 compaction_id: compaction_id.into(),
263 status,
264 summary: MaybeUndefined::Undefined,
265 error: MaybeUndefined::Undefined,
266 meta: MaybeUndefined::Undefined,
267 }
268 }
269
270 #[must_use]
272 pub fn summary(mut self, summary: impl IntoMaybeUndefined<Vec<ContentBlock>>) -> Self {
273 self.summary = summary.into_maybe_undefined();
274 self
275 }
276
277 #[must_use]
279 pub fn error(mut self, error: impl IntoMaybeUndefined<String>) -> Self {
280 self.error = error.into_maybe_undefined();
281 self
282 }
283
284 #[must_use]
286 pub fn meta(mut self, meta: impl IntoMaybeUndefined<Meta>) -> Self {
287 self.meta = meta.into_maybe_undefined();
288 self
289 }
290}
291
292#[cfg(feature = "unstable_session_compaction")]
301#[serde_as]
302#[skip_serializing_none]
303#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
304#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
305#[serde(rename_all = "camelCase")]
306#[non_exhaustive]
307pub struct CompactionSummaryChunk {
308 pub compaction_id: CompactionId,
310 pub content: ContentBlock,
312 #[serde_as(deserialize_as = "DefaultOnError")]
314 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
315 #[serde(default, rename = "_meta")]
316 pub meta: Option<Meta>,
317}
318
319#[cfg(feature = "unstable_session_compaction")]
320impl CompactionSummaryChunk {
321 #[must_use]
323 pub fn new(compaction_id: impl Into<CompactionId>, content: ContentBlock) -> Self {
324 Self {
325 compaction_id: compaction_id.into(),
326 content,
327 meta: None,
328 }
329 }
330
331 #[must_use]
333 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
334 self.meta = meta.into_option();
335 self
336 }
337}
338
339#[serde_as]
343#[skip_serializing_none]
344#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
345#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
346#[serde(rename_all = "camelCase")]
347#[non_exhaustive]
348pub struct CurrentModeUpdate {
349 pub current_mode_id: SessionModeId,
351 #[serde_as(deserialize_as = "DefaultOnError")]
357 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
358 #[serde(default)]
359 #[serde(rename = "_meta")]
360 pub meta: Option<Meta>,
361}
362
363impl CurrentModeUpdate {
364 #[must_use]
366 pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
367 Self {
368 current_mode_id: current_mode_id.into(),
369 meta: None,
370 }
371 }
372
373 #[must_use]
379 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
380 self.meta = meta.into_option();
381 self
382 }
383}
384
385#[serde_as]
387#[skip_serializing_none]
388#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
389#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
390#[serde(rename_all = "camelCase")]
391#[non_exhaustive]
392pub struct ConfigOptionUpdate {
393 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
395 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
396 pub config_options: Vec<SessionConfigOption>,
397 #[serde_as(deserialize_as = "DefaultOnError")]
403 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
404 #[serde(default)]
405 #[serde(rename = "_meta")]
406 pub meta: Option<Meta>,
407}
408
409impl ConfigOptionUpdate {
410 #[must_use]
412 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
413 Self {
414 config_options,
415 meta: None,
416 }
417 }
418
419 #[must_use]
425 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
426 self.meta = meta.into_option();
427 self
428 }
429}
430
431#[serde_as]
436#[skip_serializing_none]
437#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
438#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
439#[serde(rename_all = "camelCase")]
440#[non_exhaustive]
441pub struct SessionInfoUpdate {
442 #[serde_as(deserialize_as = "DefaultOnError")]
444 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
445 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
446 pub title: MaybeUndefined<String>,
447 #[serde_as(deserialize_as = "DefaultOnError")]
449 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
450 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
451 pub updated_at: MaybeUndefined<String>,
452 #[serde_as(deserialize_as = "DefaultOnError")]
458 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
459 #[serde(default)]
460 #[serde(rename = "_meta")]
461 pub meta: Option<Meta>,
462}
463
464impl SessionInfoUpdate {
465 #[must_use]
467 pub fn new() -> Self {
468 Self::default()
469 }
470
471 #[must_use]
473 pub fn title(mut self, title: impl IntoMaybeUndefined<String>) -> Self {
474 self.title = title.into_maybe_undefined();
475 self
476 }
477
478 #[must_use]
480 pub fn updated_at(mut self, updated_at: impl IntoMaybeUndefined<String>) -> Self {
481 self.updated_at = updated_at.into_maybe_undefined();
482 self
483 }
484
485 #[must_use]
491 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
492 self.meta = meta.into_option();
493 self
494 }
495}
496
497#[serde_as]
499#[skip_serializing_none]
500#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
501#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
502#[serde(rename_all = "camelCase")]
503#[non_exhaustive]
504pub struct UsageUpdate {
505 pub used: u64,
507 pub size: u64,
509 #[serde_as(deserialize_as = "DefaultOnError")]
511 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
512 #[serde(default)]
513 pub cost: Option<Cost>,
514 #[serde_as(deserialize_as = "DefaultOnError")]
520 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
521 #[serde(default)]
522 #[serde(rename = "_meta")]
523 pub meta: Option<Meta>,
524}
525
526impl UsageUpdate {
527 #[must_use]
529 pub fn new(used: u64, size: u64) -> Self {
530 Self {
531 used,
532 size,
533 cost: None,
534 meta: None,
535 }
536 }
537
538 #[must_use]
540 pub fn cost(mut self, cost: impl IntoOption<Cost>) -> Self {
541 self.cost = cost.into_option();
542 self
543 }
544
545 #[must_use]
551 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
552 self.meta = meta.into_option();
553 self
554 }
555}
556
557#[serde_as]
559#[skip_serializing_none]
560#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
561#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
562#[serde(rename_all = "camelCase")]
563#[non_exhaustive]
564pub struct Cost {
565 pub amount: f64,
567 pub currency: String,
569 #[serde_as(deserialize_as = "DefaultOnError")]
575 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
576 #[serde(default)]
577 #[serde(rename = "_meta")]
578 pub meta: Option<Meta>,
579}
580
581impl Cost {
582 #[must_use]
584 pub fn new(amount: f64, currency: impl Into<String>) -> Self {
585 Self {
586 amount,
587 currency: currency.into(),
588 meta: None,
589 }
590 }
591
592 #[must_use]
598 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
599 self.meta = meta.into_option();
600 self
601 }
602}
603
604#[serde_as]
606#[skip_serializing_none]
607#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
608#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
609#[serde(rename_all = "camelCase")]
610#[non_exhaustive]
611pub struct ContentChunk {
612 pub content: ContentBlock,
614 #[serde_as(deserialize_as = "DefaultOnError")]
619 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
620 #[serde(default)]
621 pub message_id: Option<MessageId>,
622 #[serde_as(deserialize_as = "DefaultOnError")]
628 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
629 #[serde(default)]
630 #[serde(rename = "_meta")]
631 pub meta: Option<Meta>,
632}
633
634impl ContentChunk {
635 #[must_use]
637 pub fn new(content: ContentBlock) -> Self {
638 Self {
639 content,
640 message_id: None,
641 meta: None,
642 }
643 }
644
645 #[must_use]
650 pub fn message_id(mut self, message_id: impl IntoOption<MessageId>) -> Self {
651 self.message_id = message_id.into_option();
652 self
653 }
654
655 #[must_use]
661 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
662 self.meta = meta.into_option();
663 self
664 }
665}
666
667#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
669#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
670#[serde(transparent)]
671#[from(Arc<str>, String, &'static str)]
672#[non_exhaustive]
673pub struct MessageId(pub Arc<str>);
674
675impl MessageId {
676 #[must_use]
678 pub fn new(id: impl Into<Arc<str>>) -> Self {
679 Self(id.into())
680 }
681}
682
683impl IntoOption<MessageId> for &str {
684 fn into_option(self) -> Option<MessageId> {
685 Some(MessageId::new(self))
686 }
687}
688
689#[serde_as]
691#[skip_serializing_none]
692#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
693#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
694#[serde(rename_all = "camelCase")]
695#[non_exhaustive]
696pub struct AvailableCommandsUpdate {
697 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
699 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
700 pub available_commands: Vec<AvailableCommand>,
701 #[serde_as(deserialize_as = "DefaultOnError")]
707 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
708 #[serde(default)]
709 #[serde(rename = "_meta")]
710 pub meta: Option<Meta>,
711}
712
713impl AvailableCommandsUpdate {
714 #[must_use]
716 pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
717 Self {
718 available_commands,
719 meta: None,
720 }
721 }
722
723 #[must_use]
729 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
730 self.meta = meta.into_option();
731 self
732 }
733}
734
735#[serde_as]
737#[skip_serializing_none]
738#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
739#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
740#[serde(rename_all = "camelCase")]
741#[non_exhaustive]
742pub struct AvailableCommand {
743 pub name: String,
745 pub description: String,
747 #[serde_as(deserialize_as = "DefaultOnError")]
749 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
750 #[serde(default)]
751 pub input: Option<AvailableCommandInput>,
752 #[serde_as(deserialize_as = "DefaultOnError")]
758 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
759 #[serde(default)]
760 #[serde(rename = "_meta")]
761 pub meta: Option<Meta>,
762}
763
764impl AvailableCommand {
765 #[must_use]
767 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
768 Self {
769 name: name.into(),
770 description: description.into(),
771 input: None,
772 meta: None,
773 }
774 }
775
776 #[must_use]
778 pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
779 self.input = input.into_option();
780 self
781 }
782
783 #[must_use]
789 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
790 self.meta = meta.into_option();
791 self
792 }
793}
794
795#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
797#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
798#[serde(untagged, rename_all = "camelCase")]
799#[non_exhaustive]
800pub enum AvailableCommandInput {
801 Unstructured(UnstructuredCommandInput),
803}
804
805#[serde_as]
807#[skip_serializing_none]
808#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
809#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
810#[serde(rename_all = "camelCase")]
811#[non_exhaustive]
812pub struct UnstructuredCommandInput {
813 pub hint: String,
815 #[serde_as(deserialize_as = "DefaultOnError")]
821 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
822 #[serde(default)]
823 #[serde(rename = "_meta")]
824 pub meta: Option<Meta>,
825}
826
827impl UnstructuredCommandInput {
828 #[must_use]
830 pub fn new(hint: impl Into<String>) -> Self {
831 Self {
832 hint: hint.into(),
833 meta: None,
834 }
835 }
836
837 #[must_use]
843 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
844 self.meta = meta.into_option();
845 self
846 }
847}
848
849#[serde_as]
857#[skip_serializing_none]
858#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
859#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
860#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME)))]
861#[serde(rename_all = "camelCase")]
862#[non_exhaustive]
863pub struct RequestPermissionRequest {
864 pub session_id: SessionId,
866 pub tool_call: ToolCallUpdate,
868 pub options: Vec<PermissionOption>,
870 #[serde_as(deserialize_as = "DefaultOnError")]
876 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
877 #[serde(default)]
878 #[serde(rename = "_meta")]
879 pub meta: Option<Meta>,
880}
881
882impl RequestPermissionRequest {
883 #[must_use]
885 pub fn new(
886 session_id: impl Into<SessionId>,
887 tool_call: ToolCallUpdate,
888 options: Vec<PermissionOption>,
889 ) -> Self {
890 Self {
891 session_id: session_id.into(),
892 tool_call,
893 options,
894 meta: None,
895 }
896 }
897
898 #[must_use]
904 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
905 self.meta = meta.into_option();
906 self
907 }
908}
909
910#[serde_as]
912#[skip_serializing_none]
913#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
914#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
915#[serde(rename_all = "camelCase")]
916#[non_exhaustive]
917pub struct PermissionOption {
918 pub option_id: PermissionOptionId,
920 pub name: String,
922 pub kind: PermissionOptionKind,
924 #[serde_as(deserialize_as = "DefaultOnError")]
930 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
931 #[serde(default)]
932 #[serde(rename = "_meta")]
933 pub meta: Option<Meta>,
934}
935
936impl PermissionOption {
937 #[must_use]
939 pub fn new(
940 option_id: impl Into<PermissionOptionId>,
941 name: impl Into<String>,
942 kind: PermissionOptionKind,
943 ) -> Self {
944 Self {
945 option_id: option_id.into(),
946 name: name.into(),
947 kind,
948 meta: None,
949 }
950 }
951
952 #[must_use]
958 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
959 self.meta = meta.into_option();
960 self
961 }
962}
963
964#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
966#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
967#[serde(transparent)]
968#[from(Arc<str>, String, &'static str)]
969#[non_exhaustive]
970pub struct PermissionOptionId(pub Arc<str>);
971
972impl PermissionOptionId {
973 #[must_use]
975 pub fn new(id: impl Into<Arc<str>>) -> Self {
976 Self(id.into())
977 }
978}
979
980#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
984#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
985#[serde(rename_all = "snake_case")]
986#[non_exhaustive]
987pub enum PermissionOptionKind {
988 AllowOnce,
990 AllowAlways,
992 RejectOnce,
994 RejectAlways,
996}
997
998#[serde_as]
1000#[skip_serializing_none]
1001#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1002#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1003#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME)))]
1004#[serde(rename_all = "camelCase")]
1005#[non_exhaustive]
1006pub struct RequestPermissionResponse {
1007 pub outcome: RequestPermissionOutcome,
1010 #[serde_as(deserialize_as = "DefaultOnError")]
1016 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1017 #[serde(default)]
1018 #[serde(rename = "_meta")]
1019 pub meta: Option<Meta>,
1020}
1021
1022impl RequestPermissionResponse {
1023 #[must_use]
1025 pub fn new(outcome: RequestPermissionOutcome) -> Self {
1026 Self {
1027 outcome,
1028 meta: None,
1029 }
1030 }
1031
1032 #[must_use]
1038 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1039 self.meta = meta.into_option();
1040 self
1041 }
1042}
1043
1044#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1046#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1047#[serde(tag = "outcome", rename_all = "snake_case")]
1048#[cfg_attr(feature = "schemars", schemars(extend("discriminator" = {"propertyName": "outcome"})))]
1049#[non_exhaustive]
1050pub enum RequestPermissionOutcome {
1051 Cancelled,
1059 #[serde(rename_all = "camelCase")]
1061 Selected(SelectedPermissionOutcome),
1062}
1063
1064#[serde_as]
1066#[skip_serializing_none]
1067#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1068#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1069#[serde(rename_all = "camelCase")]
1070#[non_exhaustive]
1071pub struct SelectedPermissionOutcome {
1072 pub option_id: PermissionOptionId,
1074 #[serde_as(deserialize_as = "DefaultOnError")]
1080 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1081 #[serde(default)]
1082 #[serde(rename = "_meta")]
1083 pub meta: Option<Meta>,
1084}
1085
1086impl SelectedPermissionOutcome {
1087 #[must_use]
1089 pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
1090 Self {
1091 option_id: option_id.into(),
1092 meta: None,
1093 }
1094 }
1095
1096 #[must_use]
1102 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1103 self.meta = meta.into_option();
1104 self
1105 }
1106}
1107
1108#[serde_as]
1114#[skip_serializing_none]
1115#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1116#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1117#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME)))]
1118#[serde(rename_all = "camelCase")]
1119#[non_exhaustive]
1120pub struct WriteTextFileRequest {
1121 pub session_id: SessionId,
1123 pub path: PathBuf,
1125 pub content: String,
1127 #[serde_as(deserialize_as = "DefaultOnError")]
1133 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1134 #[serde(default)]
1135 #[serde(rename = "_meta")]
1136 pub meta: Option<Meta>,
1137}
1138
1139impl WriteTextFileRequest {
1140 #[must_use]
1142 pub fn new(
1143 session_id: impl Into<SessionId>,
1144 path: impl Into<PathBuf>,
1145 content: impl Into<String>,
1146 ) -> Self {
1147 Self {
1148 session_id: session_id.into(),
1149 path: path.into(),
1150 content: content.into(),
1151 meta: None,
1152 }
1153 }
1154
1155 #[must_use]
1161 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1162 self.meta = meta.into_option();
1163 self
1164 }
1165}
1166
1167#[serde_as]
1169#[skip_serializing_none]
1170#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1171#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1172#[serde(rename_all = "camelCase")]
1173#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME)))]
1174#[non_exhaustive]
1175pub struct WriteTextFileResponse {
1176 #[serde_as(deserialize_as = "DefaultOnError")]
1182 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1183 #[serde(default)]
1184 #[serde(rename = "_meta")]
1185 pub meta: Option<Meta>,
1186}
1187
1188impl WriteTextFileResponse {
1189 #[must_use]
1191 pub fn new() -> Self {
1192 Self::default()
1193 }
1194
1195 #[must_use]
1201 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1202 self.meta = meta.into_option();
1203 self
1204 }
1205}
1206
1207#[serde_as]
1213#[skip_serializing_none]
1214#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1215#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1216#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME)))]
1217#[serde(rename_all = "camelCase")]
1218#[non_exhaustive]
1219pub struct ReadTextFileRequest {
1220 pub session_id: SessionId,
1222 pub path: PathBuf,
1224 #[serde_as(deserialize_as = "DefaultOnError")]
1226 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1227 #[serde(default)]
1228 pub line: Option<u32>,
1229 #[serde_as(deserialize_as = "DefaultOnError")]
1231 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1232 #[serde(default)]
1233 pub limit: Option<u32>,
1234 #[serde_as(deserialize_as = "DefaultOnError")]
1240 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1241 #[serde(default)]
1242 #[serde(rename = "_meta")]
1243 pub meta: Option<Meta>,
1244}
1245
1246impl ReadTextFileRequest {
1247 #[must_use]
1249 pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
1250 Self {
1251 session_id: session_id.into(),
1252 path: path.into(),
1253 line: None,
1254 limit: None,
1255 meta: None,
1256 }
1257 }
1258
1259 #[must_use]
1261 pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
1262 self.line = line.into_option();
1263 self
1264 }
1265
1266 #[must_use]
1268 pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
1269 self.limit = limit.into_option();
1270 self
1271 }
1272
1273 #[must_use]
1279 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1280 self.meta = meta.into_option();
1281 self
1282 }
1283}
1284
1285#[serde_as]
1287#[skip_serializing_none]
1288#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1289#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1290#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME)))]
1291#[serde(rename_all = "camelCase")]
1292#[non_exhaustive]
1293pub struct ReadTextFileResponse {
1294 pub content: String,
1296 #[serde_as(deserialize_as = "DefaultOnError")]
1302 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1303 #[serde(default)]
1304 #[serde(rename = "_meta")]
1305 pub meta: Option<Meta>,
1306}
1307
1308impl ReadTextFileResponse {
1309 #[must_use]
1311 pub fn new(content: impl Into<String>) -> Self {
1312 Self {
1313 content: content.into(),
1314 meta: None,
1315 }
1316 }
1317
1318 #[must_use]
1324 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1325 self.meta = meta.into_option();
1326 self
1327 }
1328}
1329
1330#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1334#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
1335#[serde(transparent)]
1336#[from(Arc<str>, String, &'static str)]
1337#[non_exhaustive]
1338pub struct TerminalId(pub Arc<str>);
1339
1340impl TerminalId {
1341 #[must_use]
1343 pub fn new(id: impl Into<Arc<str>>) -> Self {
1344 Self(id.into())
1345 }
1346}
1347
1348#[serde_as]
1350#[skip_serializing_none]
1351#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1352#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1353#[serde(rename_all = "camelCase")]
1354#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME)))]
1355#[non_exhaustive]
1356pub struct CreateTerminalRequest {
1357 pub session_id: SessionId,
1359 pub command: String,
1361 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1363 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1364 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1365 pub args: Vec<String>,
1366 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1368 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1369 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1370 pub env: Vec<EnvVariable>,
1371 #[serde_as(deserialize_as = "DefaultOnError")]
1373 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1374 #[serde(default)]
1375 pub cwd: Option<PathBuf>,
1376 #[serde_as(deserialize_as = "DefaultOnError")]
1385 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1386 #[serde(default)]
1387 pub output_byte_limit: Option<u64>,
1388 #[serde_as(deserialize_as = "DefaultOnError")]
1394 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1395 #[serde(default)]
1396 #[serde(rename = "_meta")]
1397 pub meta: Option<Meta>,
1398}
1399
1400impl CreateTerminalRequest {
1401 #[must_use]
1403 pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
1404 Self {
1405 session_id: session_id.into(),
1406 command: command.into(),
1407 args: Vec::new(),
1408 env: Vec::new(),
1409 cwd: None,
1410 output_byte_limit: None,
1411 meta: None,
1412 }
1413 }
1414
1415 #[must_use]
1417 pub fn args(mut self, args: Vec<String>) -> Self {
1418 self.args = args;
1419 self
1420 }
1421
1422 #[must_use]
1424 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
1425 self.env = env;
1426 self
1427 }
1428
1429 #[must_use]
1431 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1432 self.cwd = cwd.into_option();
1433 self
1434 }
1435
1436 #[must_use]
1445 pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
1446 self.output_byte_limit = output_byte_limit.into_option();
1447 self
1448 }
1449
1450 #[must_use]
1456 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1457 self.meta = meta.into_option();
1458 self
1459 }
1460}
1461
1462#[serde_as]
1464#[skip_serializing_none]
1465#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1466#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1467#[serde(rename_all = "camelCase")]
1468#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME)))]
1469#[non_exhaustive]
1470pub struct CreateTerminalResponse {
1471 pub terminal_id: TerminalId,
1473 #[serde_as(deserialize_as = "DefaultOnError")]
1479 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1480 #[serde(default)]
1481 #[serde(rename = "_meta")]
1482 pub meta: Option<Meta>,
1483}
1484
1485impl CreateTerminalResponse {
1486 #[must_use]
1488 pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
1489 Self {
1490 terminal_id: terminal_id.into(),
1491 meta: None,
1492 }
1493 }
1494
1495 #[must_use]
1501 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1502 self.meta = meta.into_option();
1503 self
1504 }
1505}
1506
1507#[serde_as]
1509#[skip_serializing_none]
1510#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1511#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1512#[serde(rename_all = "camelCase")]
1513#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME)))]
1514#[non_exhaustive]
1515pub struct TerminalOutputRequest {
1516 pub session_id: SessionId,
1518 pub terminal_id: TerminalId,
1520 #[serde_as(deserialize_as = "DefaultOnError")]
1526 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1527 #[serde(default)]
1528 #[serde(rename = "_meta")]
1529 pub meta: Option<Meta>,
1530}
1531
1532impl TerminalOutputRequest {
1533 #[must_use]
1535 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1536 Self {
1537 session_id: session_id.into(),
1538 terminal_id: terminal_id.into(),
1539 meta: None,
1540 }
1541 }
1542
1543 #[must_use]
1549 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1550 self.meta = meta.into_option();
1551 self
1552 }
1553}
1554
1555#[serde_as]
1557#[skip_serializing_none]
1558#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1559#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1560#[serde(rename_all = "camelCase")]
1561#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME)))]
1562#[non_exhaustive]
1563pub struct TerminalOutputResponse {
1564 pub output: String,
1566 pub truncated: bool,
1568 #[serde_as(deserialize_as = "DefaultOnError")]
1570 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1571 #[serde(default)]
1572 pub exit_status: Option<TerminalExitStatus>,
1573 #[serde_as(deserialize_as = "DefaultOnError")]
1579 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1580 #[serde(default)]
1581 #[serde(rename = "_meta")]
1582 pub meta: Option<Meta>,
1583}
1584
1585impl TerminalOutputResponse {
1586 #[must_use]
1588 pub fn new(output: impl Into<String>, truncated: bool) -> Self {
1589 Self {
1590 output: output.into(),
1591 truncated,
1592 exit_status: None,
1593 meta: None,
1594 }
1595 }
1596
1597 #[must_use]
1599 pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
1600 self.exit_status = exit_status.into_option();
1601 self
1602 }
1603
1604 #[must_use]
1610 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1611 self.meta = meta.into_option();
1612 self
1613 }
1614}
1615
1616#[serde_as]
1618#[skip_serializing_none]
1619#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1620#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1621#[serde(rename_all = "camelCase")]
1622#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME)))]
1623#[non_exhaustive]
1624pub struct ReleaseTerminalRequest {
1625 pub session_id: SessionId,
1627 pub terminal_id: TerminalId,
1629 #[serde_as(deserialize_as = "DefaultOnError")]
1635 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1636 #[serde(default)]
1637 #[serde(rename = "_meta")]
1638 pub meta: Option<Meta>,
1639}
1640
1641impl ReleaseTerminalRequest {
1642 #[must_use]
1644 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1645 Self {
1646 session_id: session_id.into(),
1647 terminal_id: terminal_id.into(),
1648 meta: None,
1649 }
1650 }
1651
1652 #[must_use]
1658 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1659 self.meta = meta.into_option();
1660 self
1661 }
1662}
1663
1664#[serde_as]
1666#[skip_serializing_none]
1667#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1668#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1669#[serde(rename_all = "camelCase")]
1670#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME)))]
1671#[non_exhaustive]
1672pub struct ReleaseTerminalResponse {
1673 #[serde_as(deserialize_as = "DefaultOnError")]
1679 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1680 #[serde(default)]
1681 #[serde(rename = "_meta")]
1682 pub meta: Option<Meta>,
1683}
1684
1685impl ReleaseTerminalResponse {
1686 #[must_use]
1688 pub fn new() -> Self {
1689 Self::default()
1690 }
1691
1692 #[must_use]
1698 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1699 self.meta = meta.into_option();
1700 self
1701 }
1702}
1703
1704#[serde_as]
1706#[skip_serializing_none]
1707#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1708#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1709#[serde(rename_all = "camelCase")]
1710#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME)))]
1711#[non_exhaustive]
1712pub struct KillTerminalRequest {
1713 pub session_id: SessionId,
1715 pub terminal_id: TerminalId,
1717 #[serde_as(deserialize_as = "DefaultOnError")]
1723 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1724 #[serde(default)]
1725 #[serde(rename = "_meta")]
1726 pub meta: Option<Meta>,
1727}
1728
1729impl KillTerminalRequest {
1730 #[must_use]
1732 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1733 Self {
1734 session_id: session_id.into(),
1735 terminal_id: terminal_id.into(),
1736 meta: None,
1737 }
1738 }
1739
1740 #[must_use]
1746 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1747 self.meta = meta.into_option();
1748 self
1749 }
1750}
1751
1752#[serde_as]
1754#[skip_serializing_none]
1755#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1756#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1757#[serde(rename_all = "camelCase")]
1758#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME)))]
1759#[non_exhaustive]
1760pub struct KillTerminalResponse {
1761 #[serde_as(deserialize_as = "DefaultOnError")]
1767 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1768 #[serde(default)]
1769 #[serde(rename = "_meta")]
1770 pub meta: Option<Meta>,
1771}
1772
1773impl KillTerminalResponse {
1774 #[must_use]
1776 pub fn new() -> Self {
1777 Self::default()
1778 }
1779
1780 #[must_use]
1786 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1787 self.meta = meta.into_option();
1788 self
1789 }
1790}
1791
1792#[serde_as]
1794#[skip_serializing_none]
1795#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1796#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1797#[serde(rename_all = "camelCase")]
1798#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME)))]
1799#[non_exhaustive]
1800pub struct WaitForTerminalExitRequest {
1801 pub session_id: SessionId,
1803 pub terminal_id: TerminalId,
1805 #[serde_as(deserialize_as = "DefaultOnError")]
1811 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1812 #[serde(default)]
1813 #[serde(rename = "_meta")]
1814 pub meta: Option<Meta>,
1815}
1816
1817impl WaitForTerminalExitRequest {
1818 #[must_use]
1820 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1821 Self {
1822 session_id: session_id.into(),
1823 terminal_id: terminal_id.into(),
1824 meta: None,
1825 }
1826 }
1827
1828 #[must_use]
1834 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1835 self.meta = meta.into_option();
1836 self
1837 }
1838}
1839
1840#[serde_as]
1842#[skip_serializing_none]
1843#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1844#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1845#[serde(rename_all = "camelCase")]
1846#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME)))]
1847#[non_exhaustive]
1848pub struct WaitForTerminalExitResponse {
1849 #[serde(flatten)]
1851 pub exit_status: TerminalExitStatus,
1852 #[serde_as(deserialize_as = "DefaultOnError")]
1858 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1859 #[serde(default)]
1860 #[serde(rename = "_meta")]
1861 pub meta: Option<Meta>,
1862}
1863
1864impl WaitForTerminalExitResponse {
1865 #[must_use]
1867 pub fn new(exit_status: TerminalExitStatus) -> Self {
1868 Self {
1869 exit_status,
1870 meta: None,
1871 }
1872 }
1873
1874 #[must_use]
1880 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1881 self.meta = meta.into_option();
1882 self
1883 }
1884}
1885
1886#[serde_as]
1888#[skip_serializing_none]
1889#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1890#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1891#[serde(rename_all = "camelCase")]
1892#[non_exhaustive]
1893pub struct TerminalExitStatus {
1894 #[serde_as(deserialize_as = "DefaultOnError")]
1896 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1897 #[serde(default)]
1898 pub exit_code: Option<u32>,
1899 #[serde_as(deserialize_as = "DefaultOnError")]
1901 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1902 #[serde(default)]
1903 pub signal: Option<String>,
1904 #[serde_as(deserialize_as = "DefaultOnError")]
1910 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1911 #[serde(default)]
1912 #[serde(rename = "_meta")]
1913 pub meta: Option<Meta>,
1914}
1915
1916impl TerminalExitStatus {
1917 #[must_use]
1919 pub fn new() -> Self {
1920 Self::default()
1921 }
1922
1923 #[must_use]
1925 pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1926 self.exit_code = exit_code.into_option();
1927 self
1928 }
1929
1930 #[must_use]
1932 pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1933 self.signal = signal.into_option();
1934 self
1935 }
1936
1937 #[must_use]
1943 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1944 self.meta = meta.into_option();
1945 self
1946 }
1947}
1948
1949#[serde_as]
1958#[skip_serializing_none]
1959#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1960#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1961#[serde(rename_all = "camelCase")]
1962#[non_exhaustive]
1963pub struct ClientCapabilities {
1964 #[serde_as(deserialize_as = "DefaultOnError")]
1967 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1968 #[serde(default)]
1969 pub fs: FileSystemCapabilities,
1970 #[serde_as(deserialize_as = "DefaultOnError")]
1972 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1973 #[serde(default)]
1974 pub terminal: bool,
1975 #[serde_as(deserialize_as = "DefaultOnError")]
1980 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1981 #[serde(default)]
1982 pub session: Option<ClientSessionCapabilities>,
1983 #[cfg(feature = "unstable_plan_operations")]
1992 #[serde_as(deserialize_as = "DefaultOnError")]
1993 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1994 #[serde(default)]
1995 pub plan: Option<PlanCapabilities>,
1996 #[serde_as(deserialize_as = "DefaultOnError")]
2000 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2001 #[serde(default)]
2002 pub auth: AuthCapabilities,
2003 #[serde_as(deserialize_as = "DefaultOnError")]
2009 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2010 #[serde(default)]
2011 pub elicitation: Option<ElicitationCapabilities>,
2012 #[cfg(feature = "unstable_nes")]
2021 #[serde_as(deserialize_as = "DefaultOnError")]
2022 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2023 #[serde(default)]
2024 pub nes: Option<ClientNesCapabilities>,
2025 #[cfg(feature = "unstable_nes")]
2031 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2032 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2033 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2034 pub position_encodings: Vec<PositionEncodingKind>,
2035
2036 #[serde_as(deserialize_as = "DefaultOnError")]
2042 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2043 #[serde(default)]
2044 #[serde(rename = "_meta")]
2045 pub meta: Option<Meta>,
2046}
2047
2048impl ClientCapabilities {
2049 #[must_use]
2051 pub fn new() -> Self {
2052 Self::default()
2053 }
2054
2055 #[must_use]
2058 pub fn fs(mut self, fs: FileSystemCapabilities) -> Self {
2059 self.fs = fs;
2060 self
2061 }
2062
2063 #[must_use]
2065 pub fn terminal(mut self, terminal: bool) -> Self {
2066 self.terminal = terminal;
2067 self
2068 }
2069
2070 #[must_use]
2072 pub fn session(mut self, session: impl IntoOption<ClientSessionCapabilities>) -> Self {
2073 self.session = session.into_option();
2074 self
2075 }
2076
2077 #[cfg(feature = "unstable_plan_operations")]
2086 #[must_use]
2087 pub fn plan(mut self, plan: impl IntoOption<PlanCapabilities>) -> Self {
2088 self.plan = plan.into_option();
2089 self
2090 }
2091
2092 #[must_use]
2096 pub fn auth(mut self, auth: AuthCapabilities) -> Self {
2097 self.auth = auth;
2098 self
2099 }
2100
2101 #[must_use]
2104 pub fn elicitation(mut self, elicitation: impl IntoOption<ElicitationCapabilities>) -> Self {
2105 self.elicitation = elicitation.into_option();
2106 self
2107 }
2108
2109 #[cfg(feature = "unstable_nes")]
2113 #[must_use]
2114 pub fn nes(mut self, nes: impl IntoOption<ClientNesCapabilities>) -> Self {
2115 self.nes = nes.into_option();
2116 self
2117 }
2118
2119 #[cfg(feature = "unstable_nes")]
2123 #[must_use]
2124 pub fn position_encodings(mut self, position_encodings: Vec<PositionEncodingKind>) -> Self {
2125 self.position_encodings = position_encodings;
2126 self
2127 }
2128
2129 #[must_use]
2135 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2136 self.meta = meta.into_option();
2137 self
2138 }
2139}
2140
2141#[serde_as]
2143#[skip_serializing_none]
2144#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2145#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2146#[serde(rename_all = "camelCase")]
2147#[non_exhaustive]
2148pub struct ClientSessionCapabilities {
2149 #[cfg(feature = "unstable_session_compaction")]
2156 #[serde_as(deserialize_as = "DefaultOnError")]
2157 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2158 #[serde(default)]
2159 pub compaction: Option<CompactionCapabilities>,
2160 #[serde_as(deserialize_as = "DefaultOnError")]
2165 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2166 #[serde(default)]
2167 pub config_options: Option<SessionConfigOptionsCapabilities>,
2168 #[serde_as(deserialize_as = "DefaultOnError")]
2174 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2175 #[serde(default)]
2176 #[serde(rename = "_meta")]
2177 pub meta: Option<Meta>,
2178}
2179
2180impl ClientSessionCapabilities {
2181 #[must_use]
2183 pub fn new() -> Self {
2184 Self::default()
2185 }
2186
2187 #[cfg(feature = "unstable_session_compaction")]
2189 #[must_use]
2190 pub fn compaction(mut self, compaction: impl IntoOption<CompactionCapabilities>) -> Self {
2191 self.compaction = compaction.into_option();
2192 self
2193 }
2194
2195 #[must_use]
2200 pub fn config_options(
2201 mut self,
2202 config_options: impl IntoOption<SessionConfigOptionsCapabilities>,
2203 ) -> Self {
2204 self.config_options = config_options.into_option();
2205 self
2206 }
2207
2208 #[must_use]
2214 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2215 self.meta = meta.into_option();
2216 self
2217 }
2218}
2219
2220#[cfg(feature = "unstable_session_compaction")]
2226#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2227#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2228#[serde(rename_all = "camelCase")]
2229#[non_exhaustive]
2230pub struct CompactionCapabilities {}
2231
2232#[cfg(feature = "unstable_session_compaction")]
2233impl CompactionCapabilities {
2234 #[must_use]
2236 pub fn new() -> Self {
2237 Self {}
2238 }
2239}
2240
2241#[serde_as]
2243#[skip_serializing_none]
2244#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2245#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2246#[serde(rename_all = "camelCase")]
2247#[non_exhaustive]
2248pub struct SessionConfigOptionsCapabilities {
2249 #[serde_as(deserialize_as = "DefaultOnError")]
2256 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2257 #[serde(default)]
2258 pub boolean: Option<BooleanConfigOptionCapabilities>,
2259 #[serde_as(deserialize_as = "DefaultOnError")]
2265 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2266 #[serde(default)]
2267 #[serde(rename = "_meta")]
2268 pub meta: Option<Meta>,
2269}
2270
2271impl SessionConfigOptionsCapabilities {
2272 #[must_use]
2274 pub fn new() -> Self {
2275 Self::default()
2276 }
2277
2278 #[must_use]
2285 pub fn boolean(mut self, boolean: impl IntoOption<BooleanConfigOptionCapabilities>) -> Self {
2286 self.boolean = boolean.into_option();
2287 self
2288 }
2289
2290 #[must_use]
2296 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2297 self.meta = meta.into_option();
2298 self
2299 }
2300}
2301
2302#[serde_as]
2306#[skip_serializing_none]
2307#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2308#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2309#[non_exhaustive]
2310pub struct BooleanConfigOptionCapabilities {
2311 #[serde_as(deserialize_as = "DefaultOnError")]
2317 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2318 #[serde(default)]
2319 #[serde(rename = "_meta")]
2320 pub meta: Option<Meta>,
2321}
2322
2323impl BooleanConfigOptionCapabilities {
2324 #[must_use]
2326 pub fn new() -> Self {
2327 Self::default()
2328 }
2329
2330 #[must_use]
2336 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2337 self.meta = meta.into_option();
2338 self
2339 }
2340}
2341
2342#[serde_as]
2348#[skip_serializing_none]
2349#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2350#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2351#[serde(rename_all = "camelCase")]
2352#[non_exhaustive]
2353pub struct AuthCapabilities {
2354 #[serde_as(deserialize_as = "DefaultOnError")]
2360 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2361 #[serde(default)]
2362 pub terminal: bool,
2363 #[serde_as(deserialize_as = "DefaultOnError")]
2369 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2370 #[serde(default)]
2371 #[serde(rename = "_meta")]
2372 pub meta: Option<Meta>,
2373}
2374
2375impl AuthCapabilities {
2376 #[must_use]
2378 pub fn new() -> Self {
2379 Self::default()
2380 }
2381
2382 #[must_use]
2389 pub fn terminal(mut self, terminal: bool) -> Self {
2390 self.terminal = terminal;
2391 self
2392 }
2393
2394 #[must_use]
2400 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2401 self.meta = meta.into_option();
2402 self
2403 }
2404}
2405
2406#[serde_as]
2410#[skip_serializing_none]
2411#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2412#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2413#[serde(rename_all = "camelCase")]
2414#[non_exhaustive]
2415pub struct FileSystemCapabilities {
2416 #[serde_as(deserialize_as = "DefaultOnError")]
2418 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2419 #[serde(default)]
2420 pub read_text_file: bool,
2421 #[serde_as(deserialize_as = "DefaultOnError")]
2423 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2424 #[serde(default)]
2425 pub write_text_file: bool,
2426 #[serde_as(deserialize_as = "DefaultOnError")]
2432 #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2433 #[serde(default)]
2434 #[serde(rename = "_meta")]
2435 pub meta: Option<Meta>,
2436}
2437
2438impl FileSystemCapabilities {
2439 #[must_use]
2441 pub fn new() -> Self {
2442 Self::default()
2443 }
2444
2445 #[must_use]
2447 pub fn read_text_file(mut self, read_text_file: bool) -> Self {
2448 self.read_text_file = read_text_file;
2449 self
2450 }
2451
2452 #[must_use]
2454 pub fn write_text_file(mut self, write_text_file: bool) -> Self {
2455 self.write_text_file = write_text_file;
2456 self
2457 }
2458
2459 #[must_use]
2465 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2466 self.meta = meta.into_option();
2467 self
2468 }
2469}
2470
2471#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2477#[non_exhaustive]
2478pub struct ClientMethodNames {
2479 pub session_request_permission: &'static str,
2481 pub session_update: &'static str,
2483 pub fs_write_text_file: &'static str,
2485 pub fs_read_text_file: &'static str,
2487 pub terminal_create: &'static str,
2489 pub terminal_output: &'static str,
2491 pub terminal_release: &'static str,
2493 pub terminal_wait_for_exit: &'static str,
2495 pub terminal_kill: &'static str,
2497 #[cfg(feature = "unstable_mcp_over_acp")]
2499 pub mcp_connect: &'static str,
2500 #[cfg(feature = "unstable_mcp_over_acp")]
2502 pub mcp_message: &'static str,
2503 #[cfg(feature = "unstable_mcp_over_acp")]
2505 pub mcp_disconnect: &'static str,
2506 pub elicitation_create: &'static str,
2508 pub elicitation_complete: &'static str,
2510}
2511
2512pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
2514 session_update: SESSION_UPDATE_NOTIFICATION,
2515 session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
2516 fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
2517 fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
2518 terminal_create: TERMINAL_CREATE_METHOD_NAME,
2519 terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
2520 terminal_release: TERMINAL_RELEASE_METHOD_NAME,
2521 terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
2522 terminal_kill: TERMINAL_KILL_METHOD_NAME,
2523 #[cfg(feature = "unstable_mcp_over_acp")]
2524 mcp_connect: MCP_CONNECT_METHOD_NAME,
2525 #[cfg(feature = "unstable_mcp_over_acp")]
2526 mcp_message: MCP_MESSAGE_METHOD_NAME,
2527 #[cfg(feature = "unstable_mcp_over_acp")]
2528 mcp_disconnect: MCP_DISCONNECT_METHOD_NAME,
2529 elicitation_create: ELICITATION_CREATE_METHOD_NAME,
2530 elicitation_complete: ELICITATION_COMPLETE_NOTIFICATION,
2531};
2532
2533pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
2535pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
2537pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
2539pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
2541pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
2543pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
2545pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
2547pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
2549pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
2551pub(crate) const ELICITATION_CREATE_METHOD_NAME: &str = "elicitation/create";
2553pub(crate) const ELICITATION_COMPLETE_NOTIFICATION: &str = "elicitation/complete";
2555
2556#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2563#[derive(Clone, Debug, Serialize, Deserialize)]
2564#[serde(untagged)]
2565#[cfg_attr(feature = "schemars", schemars(inline))]
2566#[non_exhaustive]
2567#[allow(clippy::large_enum_variant)]
2568pub enum AgentRequest {
2569 WriteTextFileRequest(WriteTextFileRequest),
2576 ReadTextFileRequest(ReadTextFileRequest),
2583 RequestPermissionRequest(RequestPermissionRequest),
2594 CreateTerminalRequest(CreateTerminalRequest),
2609 TerminalOutputRequest(TerminalOutputRequest),
2616 ReleaseTerminalRequest(ReleaseTerminalRequest),
2629 WaitForTerminalExitRequest(WaitForTerminalExitRequest),
2633 KillTerminalRequest(KillTerminalRequest),
2646 CreateElicitationRequest(CreateElicitationRequest),
2650 #[cfg(feature = "unstable_mcp_over_acp")]
2656 ConnectMcpRequest(ConnectMcpRequest),
2657 #[cfg(feature = "unstable_mcp_over_acp")]
2663 MessageMcpRequest(MessageMcpRequest),
2664 #[cfg(feature = "unstable_mcp_over_acp")]
2670 DisconnectMcpRequest(DisconnectMcpRequest),
2671 ExtMethodRequest(ExtRequest),
2679}
2680
2681impl AgentRequest {
2682 #[must_use]
2684 pub fn method(&self) -> &str {
2685 match self {
2686 Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
2687 Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
2688 Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
2689 Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
2690 Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
2691 Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
2692 Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
2693 Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
2694 Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create,
2695 #[cfg(feature = "unstable_mcp_over_acp")]
2696 Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect,
2697 #[cfg(feature = "unstable_mcp_over_acp")]
2698 Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message,
2699 #[cfg(feature = "unstable_mcp_over_acp")]
2700 Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect,
2701 Self::ExtMethodRequest(ext_request) => &ext_request.method,
2702 }
2703 }
2704}
2705
2706#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2713#[derive(Clone, Debug, Serialize, Deserialize)]
2714#[serde(untagged)]
2715#[cfg_attr(feature = "schemars", schemars(inline))]
2716#[non_exhaustive]
2717pub enum ClientResponse {
2718 WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
2720 ReadTextFileResponse(ReadTextFileResponse),
2722 RequestPermissionResponse(RequestPermissionResponse),
2724 CreateTerminalResponse(CreateTerminalResponse),
2726 TerminalOutputResponse(TerminalOutputResponse),
2728 ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
2730 WaitForTerminalExitResponse(WaitForTerminalExitResponse),
2732 KillTerminalResponse(#[serde(default)] KillTerminalResponse),
2734 CreateElicitationResponse(CreateElicitationResponse),
2736 #[cfg(feature = "unstable_mcp_over_acp")]
2738 ConnectMcpResponse(ConnectMcpResponse),
2739 #[cfg(feature = "unstable_mcp_over_acp")]
2741 DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
2742 #[cfg(feature = "unstable_mcp_over_acp")]
2744 MessageMcpResponse(MessageMcpResponse),
2745 ExtMethodResponse(ExtResponse),
2747}
2748
2749#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2756#[derive(Clone, Debug, Serialize, Deserialize)]
2757#[serde(untagged)]
2758#[expect(clippy::large_enum_variant)]
2759#[cfg_attr(feature = "schemars", schemars(inline))]
2760#[non_exhaustive]
2761pub enum AgentNotification {
2762 SessionNotification(SessionNotification),
2774 CompleteElicitationNotification(CompleteElicitationNotification),
2778 #[cfg(feature = "unstable_mcp_over_acp")]
2784 MessageMcpNotification(MessageMcpNotification),
2785 ExtNotification(ExtNotification),
2793}
2794
2795impl AgentNotification {
2796 #[must_use]
2798 pub fn method(&self) -> &str {
2799 match self {
2800 Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
2801 Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete,
2802 #[cfg(feature = "unstable_mcp_over_acp")]
2803 Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message,
2804 Self::ExtNotification(ext_notification) => &ext_notification.method,
2805 }
2806 }
2807}
2808
2809#[cfg(test)]
2810mod tests {
2811 use super::*;
2812
2813 #[cfg(feature = "unstable_session_compaction")]
2814 #[test]
2815 fn compaction_updates_preserve_patch_and_open_status_semantics() {
2816 use serde_json::json;
2817
2818 assert_eq!(
2819 serde_json::to_value(SessionUpdate::CompactionUpdate(CompactionUpdate::new(
2820 "cmp_001",
2821 CompactionStatus::InProgress,
2822 )))
2823 .unwrap(),
2824 json!({
2825 "sessionUpdate": "compaction_update",
2826 "compactionId": "cmp_001",
2827 "status": "in_progress"
2828 })
2829 );
2830
2831 let SessionUpdate::CompactionUpdate(update) = serde_json::from_value(json!({
2832 "sessionUpdate": "compaction_update",
2833 "compactionId": "cmp_001",
2834 "status": "paused",
2835 "summary": null,
2836 "error": "waiting"
2837 }))
2838 .unwrap() else {
2839 panic!("expected compaction update");
2840 };
2841 assert_eq!(update.status, CompactionStatus::Other("paused".into()));
2842 assert!(update.summary.is_null());
2843 assert_eq!(update.error.value().map(String::as_str), Some("waiting"));
2844 assert!(update.meta.is_undefined());
2845 }
2846
2847 #[cfg(feature = "unstable_session_compaction")]
2848 #[test]
2849 fn compaction_chunk_and_v1_capability_serialize() {
2850 use serde_json::json;
2851
2852 assert_eq!(
2853 serde_json::to_value(SessionUpdate::CompactionSummaryChunk(
2854 CompactionSummaryChunk::new(
2855 "cmp_001",
2856 ContentBlock::Text(crate::v1::TextContent::new("retained")),
2857 ),
2858 ))
2859 .unwrap(),
2860 json!({
2861 "sessionUpdate": "compaction_summary_chunk",
2862 "compactionId": "cmp_001",
2863 "content": { "type": "text", "text": "retained" }
2864 })
2865 );
2866 assert_eq!(
2867 serde_json::to_value(
2868 ClientSessionCapabilities::new().compaction(CompactionCapabilities::new())
2869 )
2870 .unwrap(),
2871 json!({ "compaction": {} })
2872 );
2873 let absent: ClientSessionCapabilities = serde_json::from_value(json!({})).unwrap();
2874 let null: ClientSessionCapabilities =
2875 serde_json::from_value(json!({ "compaction": null })).unwrap();
2876 assert!(absent.compaction.is_none());
2877 assert!(null.compaction.is_none());
2878 }
2879
2880 #[test]
2881 fn test_elicitation_capability_semantics() {
2882 use serde_json::json;
2883
2884 let unsupported: ClientCapabilities = serde_json::from_value(json!({})).unwrap();
2885 assert!(unsupported.elicitation.is_none());
2886
2887 let null: ClientCapabilities =
2888 serde_json::from_value(json!({ "elicitation": null })).unwrap();
2889 assert!(null.elicitation.is_none());
2890
2891 let malformed: ClientCapabilities =
2892 serde_json::from_value(json!({ "elicitation": false })).unwrap();
2893 assert!(malformed.elicitation.is_none());
2894
2895 let empty: ClientCapabilities =
2896 serde_json::from_value(json!({ "elicitation": {} })).unwrap();
2897 let empty = empty.elicitation.expect("present capability");
2898 assert!(!empty.supports_form());
2899 assert!(!empty.supports_url());
2900
2901 let form_only: ClientCapabilities = serde_json::from_value(json!({
2902 "elicitation": { "form": {} }
2903 }))
2904 .unwrap();
2905 let form_only = form_only.elicitation.expect("advertised capability");
2906 assert!(form_only.supports_form());
2907 assert!(!form_only.supports_url());
2908
2909 let url_only: ClientCapabilities = serde_json::from_value(json!({
2910 "elicitation": { "url": {} }
2911 }))
2912 .unwrap();
2913 let url_only = url_only.elicitation.expect("advertised capability");
2914 assert!(!url_only.supports_form());
2915 assert!(url_only.supports_url());
2916
2917 let both: ClientCapabilities = serde_json::from_value(json!({
2918 "elicitation": { "form": {}, "url": {} }
2919 }))
2920 .unwrap();
2921 let both = both.elicitation.expect("advertised capability");
2922 assert!(both.supports_form());
2923 assert!(both.supports_url());
2924 }
2925
2926 #[test]
2927 fn test_elicitation_method_routing_and_envelopes() {
2928 use serde_json::json;
2929
2930 assert_eq!(CLIENT_METHOD_NAMES.elicitation_create, "elicitation/create");
2931 assert_eq!(
2932 CLIENT_METHOD_NAMES.elicitation_complete,
2933 "elicitation/complete"
2934 );
2935
2936 let request = AgentRequest::CreateElicitationRequest(CreateElicitationRequest::new(
2937 crate::v1::ElicitationFormMode::new(
2938 crate::v1::ElicitationSessionScope::new("sess_1"),
2939 crate::v1::ElicitationSchema::new(),
2940 ),
2941 "Choose a value",
2942 ));
2943 assert_eq!(request.method(), "elicitation/create");
2944 let method = Arc::from(request.method());
2945 let request = crate::v1::JsonRpcMessage::wrap(crate::v1::Request {
2946 id: crate::v1::RequestId::Number(7),
2947 method,
2948 params: Some(request),
2949 });
2950 assert_eq!(
2951 serde_json::to_value(request).unwrap(),
2952 json!({
2953 "jsonrpc": "2.0",
2954 "id": 7,
2955 "method": "elicitation/create",
2956 "params": {
2957 "mode": "form",
2958 "sessionId": "sess_1",
2959 "message": "Choose a value",
2960 "requestedSchema": { "type": "object", "properties": {} }
2961 }
2962 })
2963 );
2964
2965 let notification = AgentNotification::CompleteElicitationNotification(
2966 CompleteElicitationNotification::new("elic_1"),
2967 );
2968 assert_eq!(notification.method(), "elicitation/complete");
2969 let method = Arc::from(notification.method());
2970 let notification = crate::v1::JsonRpcMessage::wrap(crate::v1::Notification {
2971 method,
2972 params: Some(notification),
2973 });
2974 assert_eq!(
2975 serde_json::to_value(notification).unwrap(),
2976 json!({
2977 "jsonrpc": "2.0",
2978 "method": "elicitation/complete",
2979 "params": { "elicitationId": "elic_1" }
2980 })
2981 );
2982 }
2983
2984 #[test]
2985 fn test_client_capabilities_default_on_malformed_values() {
2986 use serde_json::json;
2987
2988 let capabilities: ClientCapabilities = serde_json::from_value(json!({
2989 "fs": {
2990 "readTextFile": "yes",
2991 "writeTextFile": true
2992 },
2993 "terminal": {}
2994 }))
2995 .unwrap();
2996
2997 assert!(!capabilities.fs.read_text_file);
2998 assert!(capabilities.fs.write_text_file);
2999 assert!(!capabilities.terminal);
3000
3001 let capabilities: ClientCapabilities = serde_json::from_value(json!({
3002 "fs": false
3003 }))
3004 .unwrap();
3005 assert_eq!(capabilities.fs, FileSystemCapabilities::default());
3006
3007 {
3008 let capabilities: ClientCapabilities = serde_json::from_value(json!({
3009 "auth": false
3010 }))
3011 .unwrap();
3012 assert_eq!(capabilities.auth, AuthCapabilities::default());
3013
3014 let capabilities: AuthCapabilities = serde_json::from_value(json!({
3015 "terminal": {}
3016 }))
3017 .unwrap();
3018 assert!(!capabilities.terminal);
3019 }
3020 }
3021
3022 #[test]
3023 fn test_serialization_behavior() {
3024 use serde_json::json;
3025
3026 assert_eq!(
3027 serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
3028 SessionInfoUpdate {
3029 title: MaybeUndefined::Undefined,
3030 updated_at: MaybeUndefined::Undefined,
3031 meta: None
3032 }
3033 );
3034 assert_eq!(
3035 serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
3036 .unwrap(),
3037 SessionInfoUpdate {
3038 title: MaybeUndefined::Null,
3039 updated_at: MaybeUndefined::Null,
3040 meta: None
3041 }
3042 );
3043 assert_eq!(
3044 serde_json::from_value::<SessionInfoUpdate>(
3045 json!({"title": "title", "updatedAt": "timestamp"})
3046 )
3047 .unwrap(),
3048 SessionInfoUpdate {
3049 title: MaybeUndefined::Value("title".to_string()),
3050 updated_at: MaybeUndefined::Value("timestamp".to_string()),
3051 meta: None
3052 }
3053 );
3054
3055 assert_eq!(
3056 serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
3057 json!({})
3058 );
3059 assert_eq!(
3060 serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
3061 json!({"title": "title"})
3062 );
3063 assert_eq!(
3064 serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
3065 json!({"title": null})
3066 );
3067 assert_eq!(
3068 serde_json::to_value(
3069 SessionInfoUpdate::new()
3070 .title("title")
3071 .title(MaybeUndefined::Undefined)
3072 )
3073 .unwrap(),
3074 json!({})
3075 );
3076 }
3077
3078 #[test]
3079 fn test_content_chunk_message_id_serialization() {
3080 use serde_json::json;
3081
3082 assert_eq!(
3083 serde_json::to_value(SessionUpdate::AgentMessageChunk(ContentChunk::new(
3084 ContentBlock::Text(crate::v1::TextContent::new("Hello"))
3085 )))
3086 .unwrap(),
3087 json!({
3088 "sessionUpdate": "agent_message_chunk",
3089 "content": {
3090 "type": "text",
3091 "text": "Hello"
3092 }
3093 })
3094 );
3095
3096 assert_eq!(
3097 serde_json::to_value(SessionUpdate::AgentMessageChunk(
3098 ContentChunk::new(ContentBlock::Text(crate::v1::TextContent::new("Hello")))
3099 .message_id("msg_agent_c42b9")
3100 ))
3101 .unwrap(),
3102 json!({
3103 "sessionUpdate": "agent_message_chunk",
3104 "messageId": "msg_agent_c42b9",
3105 "content": {
3106 "type": "text",
3107 "text": "Hello"
3108 }
3109 })
3110 );
3111
3112 let SessionUpdate::AgentMessageChunk(chunk) = serde_json::from_value(json!({
3113 "sessionUpdate": "agent_message_chunk",
3114 "messageId": null,
3115 "content": {
3116 "type": "text",
3117 "text": "Hello"
3118 }
3119 }))
3120 .unwrap() else {
3121 panic!("expected agent message chunk");
3122 };
3123
3124 assert_eq!(chunk.message_id, None);
3125 }
3126
3127 #[test]
3128 fn test_usage_update_serialization() {
3129 use serde_json::json;
3130
3131 assert_eq!(
3132 serde_json::to_value(SessionUpdate::UsageUpdate(UsageUpdate::new(
3133 53_000, 200_000
3134 )))
3135 .unwrap(),
3136 json!({
3137 "sessionUpdate": "usage_update",
3138 "used": 53000,
3139 "size": 200_000
3140 })
3141 );
3142
3143 assert_eq!(
3144 serde_json::to_value(SessionUpdate::UsageUpdate(
3145 UsageUpdate::new(53_000, 200_000).cost(Cost::new(0.045, "USD"))
3146 ))
3147 .unwrap(),
3148 json!({
3149 "sessionUpdate": "usage_update",
3150 "used": 53000,
3151 "size": 200_000,
3152 "cost": {
3153 "amount": 0.045,
3154 "currency": "USD"
3155 }
3156 })
3157 );
3158
3159 let SessionUpdate::UsageUpdate(update) = serde_json::from_value(json!({
3160 "sessionUpdate": "usage_update",
3161 "used": 53000,
3162 "size": 200_000,
3163 "cost": null
3164 }))
3165 .unwrap() else {
3166 panic!("expected usage update");
3167 };
3168
3169 assert_eq!(update.cost, None);
3170 }
3171
3172 #[cfg(feature = "unstable_nes")]
3173 #[test]
3174 fn test_client_capabilities_position_encodings_serialization() {
3175 use serde_json::json;
3176
3177 let capabilities = ClientCapabilities::new().position_encodings(vec![
3178 PositionEncodingKind::Utf32,
3179 PositionEncodingKind::Utf16,
3180 ]);
3181 let json = serde_json::to_value(&capabilities).unwrap();
3182
3183 assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"]));
3184 }
3185
3186 #[test]
3187 fn test_client_capabilities_boolean_config_options_serialization() {
3188 use serde_json::json;
3189
3190 let capabilities = ClientCapabilities::new().session(
3191 ClientSessionCapabilities::new().config_options(
3192 SessionConfigOptionsCapabilities::new()
3193 .boolean(BooleanConfigOptionCapabilities::new()),
3194 ),
3195 );
3196 let json = serde_json::to_value(&capabilities).unwrap();
3197
3198 assert_eq!(json["session"]["configOptions"]["boolean"], json!({}));
3199
3200 let omitted: ClientCapabilities = serde_json::from_value(json!({})).unwrap();
3201 assert!(omitted.session.is_none());
3202
3203 let null_session: ClientCapabilities = serde_json::from_value(json!({
3204 "session": null
3205 }))
3206 .unwrap();
3207 assert!(null_session.session.is_none());
3208
3209 let null_config_options: ClientCapabilities = serde_json::from_value(json!({
3210 "session": {
3211 "configOptions": null
3212 }
3213 }))
3214 .unwrap();
3215 assert!(
3216 null_config_options
3217 .session
3218 .and_then(|session| session.config_options)
3219 .is_none()
3220 );
3221
3222 let null_boolean: ClientCapabilities = serde_json::from_value(json!({
3223 "session": {
3224 "configOptions": {
3225 "boolean": null
3226 }
3227 }
3228 }))
3229 .unwrap();
3230 assert!(
3231 null_boolean
3232 .session
3233 .and_then(|session| session.config_options)
3234 .and_then(|config_options| config_options.boolean)
3235 .is_none()
3236 );
3237 }
3238
3239 #[cfg(feature = "unstable_plan_operations")]
3240 #[test]
3241 fn test_plan_operations_serialization() {
3242 use serde_json::json;
3243
3244 use crate::v1::{PlanEntry, PlanEntryPriority, PlanEntryStatus, PlanUpdateContent};
3245
3246 let plan_update = SessionUpdate::PlanUpdate(PlanUpdate::new(PlanUpdateContent::items(
3247 "plan-1",
3248 vec![PlanEntry::new(
3249 "Step 1",
3250 PlanEntryPriority::High,
3251 PlanEntryStatus::Pending,
3252 )],
3253 )));
3254
3255 assert_eq!(
3256 serde_json::to_value(plan_update).unwrap(),
3257 json!({
3258 "sessionUpdate": "plan_update",
3259 "plan": {
3260 "type": "items",
3261 "planId": "plan-1",
3262 "entries": [
3263 {
3264 "content": "Step 1",
3265 "priority": "high",
3266 "status": "pending"
3267 }
3268 ]
3269 }
3270 })
3271 );
3272
3273 assert_eq!(
3274 serde_json::to_value(SessionUpdate::PlanRemoved(PlanRemoved::new("plan-1"))).unwrap(),
3275 json!({
3276 "sessionUpdate": "plan_removed",
3277 "planId": "plan-1"
3278 })
3279 );
3280
3281 let capabilities = ClientCapabilities::new().plan(PlanCapabilities::new());
3282 let json = serde_json::to_value(&capabilities).unwrap();
3283 assert_eq!(json["plan"], json!({}));
3284
3285 assert_eq!(
3286 serde_json::from_value::<ClientCapabilities>(json!({ "plan": null }))
3287 .unwrap()
3288 .plan,
3289 None
3290 );
3291 }
3292
3293 #[cfg(feature = "unstable_mcp_over_acp")]
3294 #[test]
3295 fn test_agent_mcp_request_method_names() {
3296 use serde_json::json;
3297
3298 let params: serde_json::Map<String, serde_json::Value> =
3299 [("cursor".to_string(), json!("abc"))].into_iter().collect();
3300
3301 assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect");
3302 assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message");
3303 assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect");
3304
3305 assert_eq!(
3306 AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(),
3307 "mcp/connect"
3308 );
3309 assert_eq!(
3310 AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
3311 .method(),
3312 "mcp/message"
3313 );
3314 assert_eq!(
3315 AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(),
3316 "mcp/disconnect"
3317 );
3318 assert_eq!(
3319 AgentNotification::MessageMcpNotification(MessageMcpNotification::new(
3320 "conn-1",
3321 "notifications/progress"
3322 ))
3323 .method(),
3324 "mcp/message"
3325 );
3326
3327 assert_eq!(
3328 serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(),
3329 json!({ "serverId": "server-1" })
3330 );
3331 assert_eq!(
3332 serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(),
3333 json!({ "connectionId": "conn-1" })
3334 );
3335 assert_eq!(
3336 serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params))
3337 .unwrap(),
3338 json!({
3339 "connectionId": "conn-1",
3340 "method": "tools/list",
3341 "params": { "cursor": "abc" }
3342 })
3343 );
3344 assert_eq!(
3345 serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(),
3346 json!({ "connectionId": "conn-1" })
3347 );
3348 assert_eq!(
3349 serde_json::to_value(MessageMcpNotification::new(
3350 "conn-1",
3351 "notifications/progress"
3352 ))
3353 .unwrap(),
3354 json!({
3355 "connectionId": "conn-1",
3356 "method": "notifications/progress"
3357 })
3358 );
3359
3360 let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({
3361 "connectionId": "conn-1",
3362 "method": "tools/list",
3363 "params": null
3364 }))
3365 .unwrap();
3366 assert_eq!(request_with_null_params.params, None);
3367 }
3368
3369 #[test]
3370 fn request_permission_request_rejects_malformed_options() {
3371 use serde_json::json;
3372
3373 assert!(
3374 serde_json::from_value::<RequestPermissionRequest>(json!({
3375 "sessionId": "sess-1",
3376 "toolCall": {"toolCallId": "tc-1"},
3377 "options": "not-an-array"
3378 }))
3379 .is_err()
3380 );
3381 assert!(
3382 serde_json::from_value::<RequestPermissionRequest>(json!({
3383 "sessionId": "sess-1",
3384 "toolCall": {"toolCallId": "tc-1"},
3385 "options": [{"optionId": "allow"}]
3386 }))
3387 .is_err()
3388 );
3389 }
3390}