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 ConfigReload,
292 Models,
294 ThreadLoadedList,
296 SubmitUserInput {
301 request_id: String,
302 answers: Vec<UserInputAnswerEvent>,
303 },
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct AppResponse {
309 pub ok: bool,
311 pub data: Value,
313 #[serde(default)]
315 pub events: Vec<EventFrame>,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct PromptRequest {
321 #[serde(skip_serializing_if = "Option::is_none")]
323 pub thread_id: Option<String>,
324 pub prompt: String,
326 #[serde(skip_serializing_if = "Option::is_none")]
328 pub model: Option<String>,
329}
330
331#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct PromptResponse {
334 pub output: String,
336 pub model: String,
338 #[serde(default)]
340 pub events: Vec<EventFrame>,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
345#[serde(rename_all = "snake_case")]
346pub enum AskForApproval {
347 UnlessTrusted,
349 OnFailure,
351 OnRequest,
353 Reject {
355 sandbox_approval: bool,
356 rules: bool,
357 mcp_elicitations: bool,
358 },
359 Never,
361}
362
363#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
365#[serde(rename_all = "snake_case")]
366pub enum ToolKind {
367 Function,
369 Mcp,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
375pub struct LocalShellParams {
376 pub command: String,
378 #[serde(skip_serializing_if = "Option::is_none")]
380 pub cwd: Option<String>,
381 #[serde(skip_serializing_if = "Option::is_none")]
383 pub timeout_ms: Option<u64>,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
388#[serde(tag = "type", rename_all = "snake_case")]
389pub enum ToolPayload {
390 Function { arguments: String },
392 Custom { input: String },
394 LocalShell { params: LocalShellParams },
396 Mcp {
398 server: String,
399 tool: String,
400 raw_arguments: Value,
401 #[serde(skip_serializing_if = "Option::is_none")]
402 raw_tool_call_id: Option<String>,
403 },
404}
405
406#[derive(Debug, Clone, Serialize, Deserialize)]
408#[serde(tag = "type", rename_all = "snake_case")]
409pub enum ToolOutput {
410 Function {
412 #[serde(skip_serializing_if = "Option::is_none")]
414 body: Option<Value>,
415 success: bool,
417 },
418 Mcp {
420 result: Value,
422 },
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
427#[serde(rename_all = "snake_case")]
428pub enum NetworkPolicyRuleAction {
429 Allow,
431 Deny,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
437pub struct NetworkPolicyAmendment {
438 pub host: String,
440 pub action: NetworkPolicyRuleAction,
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
446#[serde(tag = "type", rename_all = "snake_case")]
447pub enum ReviewDecision {
448 Approved,
450 ApprovedExecpolicyAmendment,
452 ApprovedForSession,
454 NetworkPolicyAmendment {
456 host: String,
457 action: NetworkPolicyRuleAction,
458 },
459 Denied,
461 Abort,
463}
464
465#[derive(Debug, Clone, Serialize, Deserialize)]
467#[serde(rename_all = "snake_case")]
468pub enum McpStartupStatus {
469 Starting,
471 Ready,
473 Failed { error: String },
475 Cancelled,
477}
478
479#[derive(Debug, Clone, Serialize, Deserialize)]
481pub struct McpStartupUpdateEvent {
482 pub server_name: String,
484 pub status: McpStartupStatus,
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize)]
490pub struct McpStartupFailure {
491 pub server_name: String,
493 pub error: String,
495}
496
497#[derive(Debug, Clone, Serialize, Deserialize)]
499pub struct McpStartupCompleteEvent {
500 pub ready: Vec<String>,
502 pub failed: Vec<McpStartupFailure>,
504 pub cancelled: Vec<String>,
506}
507
508#[derive(Debug, Clone, Serialize, Deserialize)]
510pub struct NetworkApprovalContext {
511 pub host: String,
513 pub protocol: String,
515}
516
517#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
524pub struct UserInputOptionEvent {
525 pub label: String,
527 pub description: String,
529}
530
531#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
533pub struct UserInputQuestionEvent {
534 pub header: String,
536 pub id: String,
538 pub question: String,
540 pub options: Vec<UserInputOptionEvent>,
542 #[serde(default)]
544 pub allow_free_text: bool,
545 #[serde(default)]
547 pub multi_select: bool,
548}
549
550#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
556pub struct UserInputRequestEvent {
557 pub call_id: String,
559 pub turn_id: String,
561 pub request_id: String,
563 pub questions: Vec<UserInputQuestionEvent>,
565}
566
567#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
569pub struct UserInputAnswerEvent {
570 pub id: String,
572 pub label: String,
574 pub value: String,
576}
577
578#[derive(Debug, Clone, Serialize, Deserialize)]
580pub struct ExecApprovalRequestEvent {
581 pub call_id: String,
583 pub approval_id: String,
585 pub turn_id: String,
587 pub command: String,
589 pub cwd: String,
591 pub reason: String,
593 #[serde(default, skip_serializing_if = "Option::is_none")]
595 pub matched_rule: Option<Box<str>>,
596 #[serde(skip_serializing_if = "Option::is_none")]
598 pub network_approval_context: Option<NetworkApprovalContext>,
599 #[serde(default)]
601 pub proposed_execpolicy_amendment: Vec<String>,
602 #[serde(default)]
604 pub proposed_network_policy_amendments: Vec<NetworkPolicyAmendment>,
605 #[serde(default)]
607 pub additional_permissions: Vec<String>,
608 #[serde(default)]
610 pub available_decisions: Vec<ReviewDecision>,
611}
612
613#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
615#[serde(rename_all = "snake_case")]
616pub enum ResponseChannel {
617 #[default]
619 Text,
620 Reasoning,
622}
623
624impl ResponseChannel {
625 pub const fn is_text(&self) -> bool {
627 matches!(self, ResponseChannel::Text)
628 }
629}
630
631#[derive(Debug, Clone, Serialize, Deserialize)]
633pub struct ApprovalDecisionRequest {
634 pub decision: String,
636 #[serde(default)]
638 pub remember: bool,
639}
640
641#[derive(Debug, Clone, Serialize, Deserialize)]
647#[serde(tag = "event", rename_all = "snake_case")]
648pub enum EventFrame {
649 ResponseStart { response_id: String },
651 ResponseDelta {
653 response_id: String,
654 delta: String,
655 #[serde(default, skip_serializing_if = "ResponseChannel::is_text")]
656 channel: ResponseChannel,
657 },
658 ResponseEnd { response_id: String },
660 ToolCallStart {
662 response_id: String,
663 tool_name: String,
664 arguments: Value,
665 },
666 ToolCallResult {
668 response_id: String,
669 tool_name: String,
670 output: Value,
671 },
672 McpStartupUpdate { update: McpStartupUpdateEvent },
674 McpStartupComplete { summary: McpStartupCompleteEvent },
676 McpToolCallBegin {
678 server_name: String,
679 tool_name: String,
680 },
681 McpToolCallEnd {
683 server_name: String,
684 tool_name: String,
685 ok: bool,
686 },
687 ExecApprovalRequest { request: ExecApprovalRequestEvent },
689 ApplyPatchApprovalRequest { request: ExecApprovalRequestEvent },
691 UserInputRequest { request: UserInputRequestEvent },
696 ElicitationRequest {
698 server_name: String,
699 request_id: String,
700 prompt: String,
701 },
702 ExecCommandBegin { command: String, cwd: String },
704 ExecCommandOutputDelta { command: String, delta: String },
706 ExecCommandEnd { command: String, exit_code: i32 },
708 PatchApplyBegin { path: String },
710 PatchApplyEnd { path: String, ok: bool },
712 TurnStarted { turn_id: String },
714 TurnComplete { turn_id: String },
716 TurnAborted { turn_id: String, reason: String },
718 ThreadGoalUpdated { goal: ThreadGoal },
720 ThreadGoalCleared { thread_id: String },
722 Error {
724 response_id: String,
725 message: String,
726 },
727}