Skip to main content

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}