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}
38
39#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
40#[serde(rename_all = "camelCase")]
41#[serde(default)]
42pub struct ThreadRenderSnapshot {
43 pub runtime_id: String,
44 pub thread_id: String,
45 pub revision: i64,
46 pub status_surface: Option<StatusSurfaceState>,
47 #[serde(default)]
48 pub nodes: Vec<ThreadRenderNode>,
49}
50
51#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
52#[serde(rename_all = "camelCase")]
53#[serde(default)]
54pub struct ThreadRenderPatch {
55 pub runtime_id: String,
56 pub thread_id: String,
57 pub snapshot: ThreadRenderSnapshot,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
61#[serde(tag = "type", rename_all = "snake_case")]
62pub enum ThreadRenderNode {
63 UserMessage {
64 id: String,
65 turn_id: Option<String>,
66 item_id: Option<String>,
67 text: String,
68 },
69 AssistantMarkdown {
70 id: String,
71 turn_id: Option<String>,
72 item_id: Option<String>,
73 text: String,
74 phase: Option<String>,
75 streaming: bool,
76 },
77 FinalSeparator {
78 id: String,
79 turn_id: Option<String>,
80 },
81 ReasoningSummary {
82 id: String,
83 turn_id: Option<String>,
84 item_id: Option<String>,
85 title: String,
86 text: String,
87 },
88 PlanUpdate {
89 id: String,
90 turn_id: Option<String>,
91 item_id: Option<String>,
92 title: String,
93 explanation: Option<String>,
94 #[serde(default)]
95 steps: Vec<RenderPlanStep>,
96 streaming: bool,
97 },
98 ProposedPlan {
99 id: String,
100 turn_id: Option<String>,
101 item_id: Option<String>,
102 title: String,
103 text: String,
104 },
105 ExecGroup {
106 id: String,
107 turn_id: Option<String>,
108 item_id: Option<String>,
109 title: String,
110 state: String,
111 #[serde(default)]
112 commands: Vec<ExecCommandLine>,
113 output_text: Option<String>,
114 exit_code: Option<i64>,
115 },
116 FileChange {
117 id: String,
118 turn_id: Option<String>,
119 item_id: Option<String>,
120 title: String,
121 state: String,
122 #[serde(default)]
123 changes: Vec<FileChangeLine>,
124 },
125 McpToolCall {
126 id: String,
127 turn_id: Option<String>,
128 item_id: Option<String>,
129 title: String,
130 state: String,
131 subtitle: String,
132 detail: Option<String>,
133 },
134 DynamicToolCall {
135 id: String,
136 turn_id: Option<String>,
137 item_id: Option<String>,
138 title: String,
139 state: String,
140 subtitle: String,
141 detail: Option<String>,
142 },
143 WebSearch {
144 id: String,
145 turn_id: Option<String>,
146 item_id: Option<String>,
147 title: String,
148 state: String,
149 detail: Option<String>,
150 },
151 CollabEvent {
152 id: String,
153 turn_id: Option<String>,
154 item_id: Option<String>,
155 title: String,
156 #[serde(default)]
157 detail_lines: Vec<String>,
158 },
159 InfoNotice {
160 id: String,
161 turn_id: Option<String>,
162 item_id: Option<String>,
163 title: String,
164 detail: Option<String>,
165 },
166 ViewImage {
167 id: String,
168 turn_id: Option<String>,
169 item_id: Option<String>,
170 title: String,
171 path: String,
172 },
173 ImageGeneration {
174 id: String,
175 turn_id: Option<String>,
176 item_id: Option<String>,
177 title: String,
178 state: String,
179 prompt: Option<String>,
180 result: String,
181 saved_path: Option<String>,
182 },
183}
184
185impl Default for ThreadRenderNode {
186 fn default() -> Self {
187 Self::InfoNotice {
188 id: String::new(),
189 turn_id: None,
190 item_id: None,
191 title: String::new(),
192 detail: None,
193 }
194 }
195}