1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6pub mod fleet;
7pub mod runtime;
8pub mod workroom;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct Envelope<T> {
12 pub request_id: String,
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub thread_id: Option<String>,
15 pub body: T,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
19#[serde(rename_all = "snake_case")]
20pub enum ThreadStatus {
21 Running,
22 Idle,
23 Completed,
24 Failed,
25 Paused,
26 Archived,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
30#[serde(rename_all = "snake_case")]
31pub enum SessionSource {
32 Interactive,
33 Resume,
34 Fork,
35 Api,
36 Unknown,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct Thread {
41 pub id: String,
42 pub preview: String,
43 pub ephemeral: bool,
44 pub model_provider: String,
45 pub created_at: i64,
46 pub updated_at: i64,
47 pub status: ThreadStatus,
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub path: Option<PathBuf>,
50 pub cwd: PathBuf,
51 pub cli_version: String,
52 pub source: SessionSource,
53 #[serde(skip_serializing_if = "Option::is_none")]
54 pub name: Option<String>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
58#[serde(rename_all = "snake_case")]
59pub enum ThreadGoalStatus {
60 Active,
61 Paused,
62 Blocked,
63 UsageLimited,
64 BudgetLimited,
65 Complete,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
69pub struct ThreadGoal {
70 pub thread_id: String,
71 pub goal_id: String,
72 pub objective: String,
73 pub status: ThreadGoalStatus,
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub token_budget: Option<i64>,
76 pub tokens_used: i64,
77 pub time_used_seconds: i64,
78 pub continuation_count: i64,
79 pub created_at: i64,
80 pub updated_at: i64,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct ThreadStartParams {
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub model: Option<String>,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub model_provider: Option<String>,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub cwd: Option<PathBuf>,
91 #[serde(default)]
92 pub persist_extended_history: bool,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct ThreadResumeParams {
97 pub thread_id: String,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub history: Option<Vec<Value>>,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub path: Option<PathBuf>,
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub model: Option<String>,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub model_provider: Option<String>,
106 #[serde(skip_serializing_if = "Option::is_none")]
107 pub cwd: Option<PathBuf>,
108 #[serde(skip_serializing_if = "Option::is_none")]
109 pub approval_policy: Option<String>,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub sandbox: Option<String>,
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub config: Option<Value>,
114 #[serde(skip_serializing_if = "Option::is_none")]
115 pub base_instructions: Option<String>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub developer_instructions: Option<String>,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub personality: Option<String>,
120 #[serde(default)]
121 pub persist_extended_history: bool,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct ThreadForkParams {
126 pub thread_id: String,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub path: Option<PathBuf>,
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub model: Option<String>,
131 #[serde(skip_serializing_if = "Option::is_none")]
132 pub model_provider: Option<String>,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub cwd: Option<PathBuf>,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub approval_policy: Option<String>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub sandbox: Option<String>,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub config: Option<Value>,
141 #[serde(skip_serializing_if = "Option::is_none")]
142 pub base_instructions: Option<String>,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub developer_instructions: Option<String>,
145 #[serde(default)]
146 pub persist_extended_history: bool,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct ThreadListParams {
151 #[serde(default)]
152 pub include_archived: bool,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub limit: Option<usize>,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct ThreadReadParams {
159 pub thread_id: String,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct ThreadSetNameParams {
164 pub thread_id: String,
165 pub name: String,
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct ThreadGoalSetParams {
170 pub thread_id: String,
171 pub objective: String,
172 #[serde(skip_serializing_if = "Option::is_none")]
173 pub token_budget: Option<i64>,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct ThreadGoalGetParams {
178 pub thread_id: String,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct ThreadGoalClearParams {
183 pub thread_id: String,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct ThreadGoalProgressParams {
188 pub thread_id: String,
189 #[serde(default)]
190 pub token_delta: i64,
191 #[serde(default)]
192 pub time_delta_seconds: i64,
193 #[serde(default)]
194 pub record_continuation: bool,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198#[serde(tag = "kind", rename_all = "snake_case")]
199pub enum ThreadRequest {
200 Create {
201 #[serde(default)]
202 metadata: Value,
203 },
204 Start(ThreadStartParams),
205 Resume(ThreadResumeParams),
206 Fork(ThreadForkParams),
207 List(ThreadListParams),
208 Read(ThreadReadParams),
209 SetName(ThreadSetNameParams),
210 GoalSet(ThreadGoalSetParams),
211 GoalGet(ThreadGoalGetParams),
212 GoalClear(ThreadGoalClearParams),
213 GoalRecordProgress(ThreadGoalProgressParams),
214 Archive {
215 thread_id: String,
216 },
217 Unarchive {
218 thread_id: String,
219 },
220 Message {
221 thread_id: String,
222 input: String,
223 },
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct ThreadResponse {
229 pub thread_id: String,
231 pub status: String,
233 #[serde(skip_serializing_if = "Option::is_none")]
235 pub thread: Option<Thread>,
236 #[serde(default)]
238 pub threads: Vec<Thread>,
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub goal: Option<ThreadGoal>,
242 #[serde(skip_serializing_if = "Option::is_none")]
244 pub model: Option<String>,
245 #[serde(skip_serializing_if = "Option::is_none")]
247 pub model_provider: Option<String>,
248 #[serde(skip_serializing_if = "Option::is_none")]
250 pub cwd: Option<PathBuf>,
251 #[serde(skip_serializing_if = "Option::is_none")]
253 pub approval_policy: Option<String>,
254 #[serde(skip_serializing_if = "Option::is_none")]
256 pub sandbox: Option<String>,
257 #[serde(default)]
259 pub events: Vec<EventFrame>,
260 #[serde(default)]
262 pub data: Value,
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize)]
267#[serde(tag = "kind", rename_all = "snake_case")]
268pub enum AppRequest {
269 Capabilities,
271 ConfigGet { key: String },
273 ConfigSet { key: String, value: String },
275 ConfigUnset { key: String },
277 ConfigList,
279 Models,
281 ThreadLoadedList,
283 SubmitUserInput {
288 request_id: String,
289 answers: Vec<UserInputAnswerEvent>,
290 },
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct AppResponse {
296 pub ok: bool,
298 pub data: Value,
300 #[serde(default)]
302 pub events: Vec<EventFrame>,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct PromptRequest {
308 #[serde(skip_serializing_if = "Option::is_none")]
310 pub thread_id: Option<String>,
311 pub prompt: String,
313 #[serde(skip_serializing_if = "Option::is_none")]
315 pub model: Option<String>,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct PromptResponse {
321 pub output: String,
323 pub model: String,
325 #[serde(default)]
327 pub events: Vec<EventFrame>,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
332#[serde(rename_all = "snake_case")]
333pub enum AskForApproval {
334 UnlessTrusted,
336 OnFailure,
338 OnRequest,
340 Reject {
342 sandbox_approval: bool,
343 rules: bool,
344 mcp_elicitations: bool,
345 },
346 Never,
348}
349
350#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
352#[serde(rename_all = "snake_case")]
353pub enum ToolKind {
354 Function,
356 Mcp,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize)]
362pub struct LocalShellParams {
363 pub command: String,
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub cwd: Option<String>,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub timeout_ms: Option<u64>,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
375#[serde(tag = "type", rename_all = "snake_case")]
376pub enum ToolPayload {
377 Function { arguments: String },
379 Custom { input: String },
381 LocalShell { params: LocalShellParams },
383 Mcp {
385 server: String,
386 tool: String,
387 raw_arguments: Value,
388 #[serde(skip_serializing_if = "Option::is_none")]
389 raw_tool_call_id: Option<String>,
390 },
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize)]
395#[serde(tag = "type", rename_all = "snake_case")]
396pub enum ToolOutput {
397 Function {
399 #[serde(skip_serializing_if = "Option::is_none")]
401 body: Option<Value>,
402 success: bool,
404 },
405 Mcp {
407 result: Value,
409 },
410}
411
412#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
414#[serde(rename_all = "snake_case")]
415pub enum NetworkPolicyRuleAction {
416 Allow,
418 Deny,
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
424pub struct NetworkPolicyAmendment {
425 pub host: String,
427 pub action: NetworkPolicyRuleAction,
429}
430
431#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
433#[serde(tag = "type", rename_all = "snake_case")]
434pub enum ReviewDecision {
435 Approved,
437 ApprovedExecpolicyAmendment,
439 ApprovedForSession,
441 NetworkPolicyAmendment {
443 host: String,
444 action: NetworkPolicyRuleAction,
445 },
446 Denied,
448 Abort,
450}
451
452#[derive(Debug, Clone, Serialize, Deserialize)]
454#[serde(rename_all = "snake_case")]
455pub enum McpStartupStatus {
456 Starting,
458 Ready,
460 Failed { error: String },
462 Cancelled,
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize)]
468pub struct McpStartupUpdateEvent {
469 pub server_name: String,
471 pub status: McpStartupStatus,
473}
474
475#[derive(Debug, Clone, Serialize, Deserialize)]
477pub struct McpStartupFailure {
478 pub server_name: String,
480 pub error: String,
482}
483
484#[derive(Debug, Clone, Serialize, Deserialize)]
486pub struct McpStartupCompleteEvent {
487 pub ready: Vec<String>,
489 pub failed: Vec<McpStartupFailure>,
491 pub cancelled: Vec<String>,
493}
494
495#[derive(Debug, Clone, Serialize, Deserialize)]
497pub struct NetworkApprovalContext {
498 pub host: String,
500 pub protocol: String,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
511pub struct UserInputOptionEvent {
512 pub label: String,
514 pub description: String,
516}
517
518#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
520pub struct UserInputQuestionEvent {
521 pub header: String,
523 pub id: String,
525 pub question: String,
527 pub options: Vec<UserInputOptionEvent>,
529 #[serde(default)]
531 pub allow_free_text: bool,
532 #[serde(default)]
534 pub multi_select: bool,
535}
536
537#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
543pub struct UserInputRequestEvent {
544 pub call_id: String,
546 pub turn_id: String,
548 pub request_id: String,
550 pub questions: Vec<UserInputQuestionEvent>,
552}
553
554#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
556pub struct UserInputAnswerEvent {
557 pub id: String,
559 pub label: String,
561 pub value: String,
563}
564
565#[derive(Debug, Clone, Serialize, Deserialize)]
567pub struct ExecApprovalRequestEvent {
568 pub call_id: String,
570 pub approval_id: String,
572 pub turn_id: String,
574 pub command: String,
576 pub cwd: String,
578 pub reason: String,
580 #[serde(default, skip_serializing_if = "Option::is_none")]
582 pub matched_rule: Option<Box<str>>,
583 #[serde(skip_serializing_if = "Option::is_none")]
585 pub network_approval_context: Option<NetworkApprovalContext>,
586 #[serde(default)]
588 pub proposed_execpolicy_amendment: Vec<String>,
589 #[serde(default)]
591 pub proposed_network_policy_amendments: Vec<NetworkPolicyAmendment>,
592 #[serde(default)]
594 pub additional_permissions: Vec<String>,
595 #[serde(default)]
597 pub available_decisions: Vec<ReviewDecision>,
598}
599
600#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
602#[serde(rename_all = "snake_case")]
603pub enum ResponseChannel {
604 #[default]
606 Text,
607 Reasoning,
609}
610
611impl ResponseChannel {
612 pub const fn is_text(&self) -> bool {
614 matches!(self, ResponseChannel::Text)
615 }
616}
617
618#[derive(Debug, Clone, Serialize, Deserialize)]
620pub struct ApprovalDecisionRequest {
621 pub decision: String,
623 #[serde(default)]
625 pub remember: bool,
626}
627
628#[derive(Debug, Clone, Serialize, Deserialize)]
634#[serde(tag = "event", rename_all = "snake_case")]
635pub enum EventFrame {
636 ResponseStart { response_id: String },
638 ResponseDelta {
640 response_id: String,
641 delta: String,
642 #[serde(default, skip_serializing_if = "ResponseChannel::is_text")]
643 channel: ResponseChannel,
644 },
645 ResponseEnd { response_id: String },
647 ToolCallStart {
649 response_id: String,
650 tool_name: String,
651 arguments: Value,
652 },
653 ToolCallResult {
655 response_id: String,
656 tool_name: String,
657 output: Value,
658 },
659 McpStartupUpdate { update: McpStartupUpdateEvent },
661 McpStartupComplete { summary: McpStartupCompleteEvent },
663 McpToolCallBegin {
665 server_name: String,
666 tool_name: String,
667 },
668 McpToolCallEnd {
670 server_name: String,
671 tool_name: String,
672 ok: bool,
673 },
674 ExecApprovalRequest { request: ExecApprovalRequestEvent },
676 ApplyPatchApprovalRequest { request: ExecApprovalRequestEvent },
678 UserInputRequest { request: UserInputRequestEvent },
683 ElicitationRequest {
685 server_name: String,
686 request_id: String,
687 prompt: String,
688 },
689 ExecCommandBegin { command: String, cwd: String },
691 ExecCommandOutputDelta { command: String, delta: String },
693 ExecCommandEnd { command: String, exit_code: i32 },
695 PatchApplyBegin { path: String },
697 PatchApplyEnd { path: String, ok: bool },
699 TurnStarted { turn_id: String },
701 TurnComplete { turn_id: String },
703 TurnAborted { turn_id: String, reason: String },
705 ThreadGoalUpdated { goal: ThreadGoal },
707 ThreadGoalCleared { thread_id: String },
709 Error {
711 response_id: String,
712 message: String,
713 },
714}