1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Envelope<T> {
8 pub request_id: String,
9 #[serde(skip_serializing_if = "Option::is_none")]
10 pub thread_id: Option<String>,
11 pub body: T,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
15#[serde(rename_all = "snake_case")]
16pub enum ThreadStatus {
17 Running,
18 Idle,
19 Completed,
20 Failed,
21 Paused,
22 Archived,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
26#[serde(rename_all = "snake_case")]
27pub enum SessionSource {
28 Interactive,
29 Resume,
30 Fork,
31 Api,
32 Unknown,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct Thread {
37 pub id: String,
38 pub preview: String,
39 pub ephemeral: bool,
40 pub model_provider: String,
41 pub created_at: i64,
42 pub updated_at: i64,
43 pub status: ThreadStatus,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub path: Option<PathBuf>,
46 pub cwd: PathBuf,
47 pub cli_version: String,
48 pub source: SessionSource,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub name: Option<String>,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct ThreadStartParams {
55 #[serde(skip_serializing_if = "Option::is_none")]
56 pub model: Option<String>,
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub model_provider: Option<String>,
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub cwd: Option<PathBuf>,
61 #[serde(default)]
62 pub persist_extended_history: bool,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct ThreadResumeParams {
67 pub thread_id: String,
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub history: Option<Vec<Value>>,
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub path: Option<PathBuf>,
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub model: Option<String>,
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub model_provider: Option<String>,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub cwd: Option<PathBuf>,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub approval_policy: Option<String>,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub sandbox: Option<String>,
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub config: Option<Value>,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub base_instructions: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub developer_instructions: Option<String>,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub personality: Option<String>,
90 #[serde(default)]
91 pub persist_extended_history: bool,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct ThreadForkParams {
96 pub thread_id: String,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub path: Option<PathBuf>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub model: Option<String>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub model_provider: Option<String>,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub cwd: Option<PathBuf>,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub approval_policy: Option<String>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub sandbox: Option<String>,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub config: Option<Value>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub base_instructions: Option<String>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub developer_instructions: Option<String>,
115 #[serde(default)]
116 pub persist_extended_history: bool,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct ThreadListParams {
121 #[serde(default)]
122 pub include_archived: bool,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub limit: Option<usize>,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct ThreadReadParams {
129 pub thread_id: String,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct ThreadSetNameParams {
134 pub thread_id: String,
135 pub name: String,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
139#[serde(tag = "kind", rename_all = "snake_case")]
140pub enum ThreadRequest {
141 Create {
142 #[serde(default)]
143 metadata: Value,
144 },
145 Start(ThreadStartParams),
146 Resume(ThreadResumeParams),
147 Fork(ThreadForkParams),
148 List(ThreadListParams),
149 Read(ThreadReadParams),
150 SetName(ThreadSetNameParams),
151 Archive {
152 thread_id: String,
153 },
154 Unarchive {
155 thread_id: String,
156 },
157 Message {
158 thread_id: String,
159 input: String,
160 },
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct ThreadResponse {
165 pub thread_id: String,
166 pub status: String,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub thread: Option<Thread>,
169 #[serde(default)]
170 pub threads: Vec<Thread>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub model: Option<String>,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub model_provider: Option<String>,
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub cwd: Option<PathBuf>,
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub approval_policy: Option<String>,
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub sandbox: Option<String>,
181 #[serde(default)]
182 pub events: Vec<EventFrame>,
183 #[serde(default)]
184 pub data: Value,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
188#[serde(tag = "kind", rename_all = "snake_case")]
189pub enum AppRequest {
190 Capabilities,
191 ConfigGet { key: String },
192 ConfigSet { key: String, value: String },
193 ConfigUnset { key: String },
194 ConfigList,
195 Models,
196 ThreadLoadedList,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct AppResponse {
201 pub ok: bool,
202 pub data: Value,
203 #[serde(default)]
204 pub events: Vec<EventFrame>,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct PromptRequest {
209 #[serde(skip_serializing_if = "Option::is_none")]
210 pub thread_id: Option<String>,
211 pub prompt: String,
212 #[serde(skip_serializing_if = "Option::is_none")]
213 pub model: Option<String>,
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct PromptResponse {
218 pub output: String,
219 pub model: String,
220 #[serde(default)]
221 pub events: Vec<EventFrame>,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
225#[serde(rename_all = "snake_case")]
226pub enum AskForApproval {
227 UnlessTrusted,
228 OnFailure,
229 OnRequest,
230 Reject {
231 sandbox_approval: bool,
232 rules: bool,
233 mcp_elicitations: bool,
234 },
235 Never,
236}
237
238#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
239#[serde(rename_all = "snake_case")]
240pub enum ToolKind {
241 Function,
242 Mcp,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct LocalShellParams {
247 pub command: String,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub cwd: Option<String>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub timeout_ms: Option<u64>,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
255#[serde(tag = "type", rename_all = "snake_case")]
256pub enum ToolPayload {
257 Function {
258 arguments: String,
259 },
260 Custom {
261 input: String,
262 },
263 LocalShell {
264 params: LocalShellParams,
265 },
266 Mcp {
267 server: String,
268 tool: String,
269 raw_arguments: Value,
270 #[serde(skip_serializing_if = "Option::is_none")]
271 raw_tool_call_id: Option<String>,
272 },
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize)]
276#[serde(tag = "type", rename_all = "snake_case")]
277pub enum ToolOutput {
278 Function {
279 #[serde(skip_serializing_if = "Option::is_none")]
280 body: Option<Value>,
281 success: bool,
282 },
283 Mcp {
284 result: Value,
285 },
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
289#[serde(rename_all = "snake_case")]
290pub enum NetworkPolicyRuleAction {
291 Allow,
292 Deny,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
296pub struct NetworkPolicyAmendment {
297 pub host: String,
298 pub action: NetworkPolicyRuleAction,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
302#[serde(tag = "type", rename_all = "snake_case")]
303pub enum ReviewDecision {
304 Approved,
305 ApprovedExecpolicyAmendment,
306 ApprovedForSession,
307 NetworkPolicyAmendment {
308 host: String,
309 action: NetworkPolicyRuleAction,
310 },
311 Denied,
312 Abort,
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
316#[serde(rename_all = "snake_case")]
317pub enum McpStartupStatus {
318 Starting,
319 Ready,
320 Failed { error: String },
321 Cancelled,
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct McpStartupUpdateEvent {
326 pub server_name: String,
327 pub status: McpStartupStatus,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
331pub struct McpStartupFailure {
332 pub server_name: String,
333 pub error: String,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct McpStartupCompleteEvent {
338 pub ready: Vec<String>,
339 pub failed: Vec<McpStartupFailure>,
340 pub cancelled: Vec<String>,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
344pub struct NetworkApprovalContext {
345 pub host: String,
346 pub protocol: String,
347}
348
349#[derive(Debug, Clone, Serialize, Deserialize)]
350pub struct ExecApprovalRequestEvent {
351 pub call_id: String,
352 pub approval_id: String,
353 pub turn_id: String,
354 pub command: String,
355 pub cwd: String,
356 pub reason: String,
357 #[serde(skip_serializing_if = "Option::is_none")]
358 pub network_approval_context: Option<NetworkApprovalContext>,
359 #[serde(default)]
360 pub proposed_execpolicy_amendment: Vec<String>,
361 #[serde(default)]
362 pub proposed_network_policy_amendments: Vec<NetworkPolicyAmendment>,
363 #[serde(default)]
364 pub additional_permissions: Vec<String>,
365 #[serde(default)]
366 pub available_decisions: Vec<ReviewDecision>,
367}
368
369#[derive(Debug, Clone, Serialize, Deserialize)]
370#[serde(tag = "event", rename_all = "snake_case")]
371pub enum EventFrame {
372 ResponseStart {
373 response_id: String,
374 },
375 ResponseDelta {
376 response_id: String,
377 delta: String,
378 },
379 ResponseEnd {
380 response_id: String,
381 },
382 ToolCallStart {
383 response_id: String,
384 tool_name: String,
385 arguments: Value,
386 },
387 ToolCallResult {
388 response_id: String,
389 tool_name: String,
390 output: Value,
391 },
392 McpStartupUpdate {
393 update: McpStartupUpdateEvent,
394 },
395 McpStartupComplete {
396 summary: McpStartupCompleteEvent,
397 },
398 McpToolCallBegin {
399 server_name: String,
400 tool_name: String,
401 },
402 McpToolCallEnd {
403 server_name: String,
404 tool_name: String,
405 ok: bool,
406 },
407 ExecApprovalRequest {
408 request: ExecApprovalRequestEvent,
409 },
410 ApplyPatchApprovalRequest {
411 request: ExecApprovalRequestEvent,
412 },
413 ElicitationRequest {
414 server_name: String,
415 request_id: String,
416 prompt: String,
417 },
418 ExecCommandBegin {
419 command: String,
420 cwd: String,
421 },
422 ExecCommandOutputDelta {
423 command: String,
424 delta: String,
425 },
426 ExecCommandEnd {
427 command: String,
428 exit_code: i32,
429 },
430 PatchApplyBegin {
431 path: String,
432 },
433 PatchApplyEnd {
434 path: String,
435 ok: bool,
436 },
437 TurnStarted {
438 turn_id: String,
439 },
440 TurnComplete {
441 turn_id: String,
442 },
443 TurnAborted {
444 turn_id: String,
445 reason: String,
446 },
447 Error {
448 response_id: String,
449 message: String,
450 },
451}