vtcode_desktop_protocol/interaction.rs
1//! Runtime interaction request/response DTOs.
2
3use serde::{Deserialize, Serialize};
4
5/// Host hotkey signalled back to the service mid-interaction.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8pub enum InteractionHotkey {
9 /// Open the pending plan draft in the service-configured external editor.
10 LaunchEditor,
11}
12
13/// User response to a pending runtime interaction.
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct InteractionResponse {
17 /// Session owning the interaction.
18 pub session_id: String,
19 /// Turn that raised the interaction.
20 pub turn_id: String,
21 /// Opaque interaction identity provided by the service.
22 pub interaction_id: String,
23 /// Opaque choice identity provided by the service, if selecting an option.
24 pub choice_id: Option<String>,
25 /// Opaque identities selected for each step in a wizard interaction.
26 #[serde(default)]
27 pub choice_ids: Vec<String>,
28 /// Free-form answer for text questions.
29 pub text: Option<String>,
30 /// Free-form answers for each ordered wizard step.
31 #[serde(default)]
32 pub answer_texts: Vec<Option<String>>,
33 /// Whether the interaction was explicitly cancelled by the user.
34 #[serde(default)]
35 pub cancelled: bool,
36 /// Host hotkey signal for a mid-interaction action. `None` for ordinary
37 /// choice/cancel responses; `Some` asks the service to act mid-interaction
38 /// (e.g. open the plan editor) and follow up with a new request.
39 #[serde(default)]
40 pub hotkey: Option<InteractionHotkey>,
41}
42
43/// Interaction request sent from the service to the desktop client.
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub struct InteractionRequest {
47 /// Session owning the interaction.
48 pub session_id: String,
49 /// Turn that raised the interaction.
50 pub turn_id: String,
51 /// Opaque interaction identity.
52 pub interaction_id: String,
53 /// Kind of interaction required.
54 pub kind: InteractionKind,
55 /// Whether the runtime expects an ordered wizard response.
56 #[serde(default)]
57 pub wizard: bool,
58 /// Dialog title or question prompt.
59 pub title: String,
60 /// Supporting text shown by the client.
61 pub details: Vec<String>,
62 /// Available choices, preserving each runtime's opaque identity.
63 pub choices: Vec<InteractionChoice>,
64 /// Ordered multi-step questions when the runtime request is a wizard.
65 #[serde(default)]
66 pub steps: Vec<InteractionStep>,
67 /// Optional selected choice identity.
68 pub selected_choice_id: Option<String>,
69 /// Optional selected choice identities, one per wizard step.
70 #[serde(default)]
71 pub selected_choice_ids: Vec<String>,
72 /// Full plan markdown for `PlanApproval` prompts, normalized the same
73 /// way as the transcript copy. `None` for other kinds and for payloads
74 /// from older services; clients hide plan-expansion UI rather than
75 /// guessing.
76 #[serde(default)]
77 pub plan_markdown: Option<String>,
78}
79
80/// One ordered step in a question or approval wizard.
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct InteractionStep {
84 /// Step label.
85 pub title: String,
86 /// Question or instruction for this step.
87 pub question: String,
88 /// Choices preserving exact service-issued identities.
89 pub choices: Vec<InteractionChoice>,
90 /// Optional selected identity.
91 pub selected_choice_id: Option<String>,
92 /// Whether the client may submit a free-form answer.
93 pub allow_freeform: bool,
94}
95
96/// Interaction category understood by native clients.
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
98#[serde(rename_all = "snake_case")]
99pub enum InteractionKind {
100 /// A tool or policy approval decision.
101 Approval,
102 /// Plan approval decision.
103 PlanApproval,
104 /// User-facing question requiring a response.
105 Question,
106 /// Non-security choice picker.
107 Choice,
108 /// Unsupported or informational transient request.
109 Other,
110}
111
112/// One display label paired with a stable opaque identity.
113#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
114#[serde(rename_all = "camelCase")]
115pub struct InteractionChoice {
116 /// Opaque identity returned unchanged by the client.
117 pub id: String,
118 /// User-facing label.
119 pub label: String,
120 /// Optional supporting description.
121 pub description: Option<String>,
122 /// Whether the service recommends this option.
123 pub recommended: bool,
124}