1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
4#[serde(rename_all = "camelCase")]
5#[serde(default)]
6pub struct StatusSurfaceState {
7 pub kind: String,
8 pub header: String,
9 pub details: Option<String>,
10 pub inline_message: Option<String>,
11 pub interrupt_visible: bool,
12 pub revision: i64,
13}
14
15#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "camelCase")]
17#[serde(default)]
18pub struct RenderPlanStep {
19 pub step: String,
20 pub status: String,
21}
22
23#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
24#[serde(rename_all = "camelCase")]
25#[serde(default)]
26pub struct ExecCommandLine {
27 pub label: String,
28 pub text: String,
29}
30
31#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
32#[serde(rename_all = "camelCase")]
33#[serde(default)]
34pub struct FileChangeLine {
35 pub path: String,
36 pub summary: String,
37 pub diff: Option<String>,
38}
39
40#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
41#[serde(rename_all = "camelCase")]
42#[serde(default)]
43pub struct ThreadRenderSnapshot {
44 pub runtime_id: String,
45 pub thread_id: String,
46 pub revision: i64,
47 pub status_surface: Option<StatusSurfaceState>,
48 #[serde(default)]
49 pub nodes: Vec<ThreadRenderNode>,
50}
51
52#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
53#[serde(rename_all = "camelCase")]
54#[serde(default)]
55pub struct ThreadRenderPatch {
56 pub runtime_id: String,
57 pub thread_id: String,
58 pub snapshot: ThreadRenderSnapshot,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
62#[serde(tag = "type", rename_all = "snake_case")]
63pub enum ThreadRenderNode {
64 UserMessage {
65 id: String,
66 turn_id: Option<String>,
67 item_id: Option<String>,
68 text: String,
69 },
70 AssistantMarkdown {
71 id: String,
72 turn_id: Option<String>,
73 item_id: Option<String>,
74 text: String,
75 phase: Option<String>,
76 streaming: bool,
77 },
78 FinalSeparator {
79 id: String,
80 turn_id: Option<String>,
81 },
82 ReasoningSummary {
83 id: String,
84 turn_id: Option<String>,
85 item_id: Option<String>,
86 title: String,
87 text: String,
88 },
89 PlanUpdate {
90 id: String,
91 turn_id: Option<String>,
92 item_id: Option<String>,
93 title: String,
94 explanation: Option<String>,
95 #[serde(default)]
96 steps: Vec<RenderPlanStep>,
97 streaming: bool,
98 },
99 ProposedPlan {
100 id: String,
101 turn_id: Option<String>,
102 item_id: Option<String>,
103 title: String,
104 text: String,
105 },
106 ExecGroup {
107 id: String,
108 turn_id: Option<String>,
109 item_id: Option<String>,
110 title: String,
111 #[serde(default)]
112 kind: String,
113 state: String,
114 #[serde(default)]
115 commands: Vec<ExecCommandLine>,
116 output_text: Option<String>,
117 exit_code: Option<i64>,
118 },
119 FileChange {
120 id: String,
121 turn_id: Option<String>,
122 item_id: Option<String>,
123 title: String,
124 state: String,
125 #[serde(default)]
126 changes: Vec<FileChangeLine>,
127 },
128 McpToolCall {
129 id: String,
130 turn_id: Option<String>,
131 item_id: Option<String>,
132 title: String,
133 state: String,
134 subtitle: String,
135 detail: Option<String>,
136 },
137 DynamicToolCall {
138 id: String,
139 turn_id: Option<String>,
140 item_id: Option<String>,
141 title: String,
142 state: String,
143 subtitle: String,
144 detail: Option<String>,
145 },
146 WebSearch {
147 id: String,
148 turn_id: Option<String>,
149 item_id: Option<String>,
150 title: String,
151 state: String,
152 detail: Option<String>,
153 },
154 TerminalInteraction {
155 id: String,
156 turn_id: Option<String>,
157 item_id: Option<String>,
158 title: String,
159 command: Option<String>,
160 stdin: String,
161 waited: bool,
162 },
163 CollabEvent {
164 id: String,
165 turn_id: Option<String>,
166 item_id: Option<String>,
167 title: String,
168 #[serde(default)]
169 detail_lines: Vec<String>,
170 },
171 HookEvent {
172 id: String,
173 turn_id: Option<String>,
174 item_id: Option<String>,
175 title: String,
176 state: String,
177 #[serde(default)]
178 detail_lines: Vec<String>,
179 },
180 ApprovalReview {
181 id: String,
182 turn_id: Option<String>,
183 item_id: Option<String>,
184 title: String,
185 state: String,
186 #[serde(default)]
187 detail_lines: Vec<String>,
188 },
189 InfoNotice {
190 id: String,
191 turn_id: Option<String>,
192 item_id: Option<String>,
193 title: String,
194 detail: Option<String>,
195 },
196 ViewImage {
197 id: String,
198 turn_id: Option<String>,
199 item_id: Option<String>,
200 title: String,
201 path: String,
202 },
203 ImageGeneration {
204 id: String,
205 turn_id: Option<String>,
206 item_id: Option<String>,
207 title: String,
208 state: String,
209 prompt: Option<String>,
210 result: String,
211 saved_path: Option<String>,
212 },
213}
214
215impl Default for ThreadRenderNode {
216 fn default() -> Self {
217 Self::InfoNotice {
218 id: String::new(),
219 turn_id: None,
220 item_id: None,
221 title: String::new(),
222 detail: None,
223 }
224 }
225}