1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6pub mod fleet;
7pub mod runtime;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Envelope<T> {
11 pub request_id: String,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub thread_id: Option<String>,
14 pub body: T,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
18#[serde(rename_all = "snake_case")]
19pub enum ThreadStatus {
20 Running,
21 Idle,
22 Completed,
23 Failed,
24 Paused,
25 Archived,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
29#[serde(rename_all = "snake_case")]
30pub enum SessionSource {
31 Interactive,
32 Resume,
33 Fork,
34 Api,
35 Unknown,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct Thread {
40 pub id: String,
41 pub preview: String,
42 pub ephemeral: bool,
43 pub model_provider: String,
44 pub created_at: i64,
45 pub updated_at: i64,
46 pub status: ThreadStatus,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub path: Option<PathBuf>,
49 pub cwd: PathBuf,
50 pub cli_version: String,
51 pub source: SessionSource,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub name: Option<String>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
57#[serde(rename_all = "snake_case")]
58pub enum ThreadGoalStatus {
59 Active,
60 Paused,
61 Blocked,
62 UsageLimited,
63 BudgetLimited,
64 Complete,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
68pub struct ThreadGoal {
69 pub thread_id: String,
70 pub goal_id: String,
71 pub objective: String,
72 pub status: ThreadGoalStatus,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub token_budget: Option<i64>,
75 pub tokens_used: i64,
76 pub time_used_seconds: i64,
77 pub created_at: i64,
78 pub updated_at: i64,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct ThreadStartParams {
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub model: Option<String>,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub model_provider: Option<String>,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub cwd: Option<PathBuf>,
89 #[serde(default)]
90 pub persist_extended_history: bool,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct ThreadResumeParams {
95 pub thread_id: String,
96 #[serde(skip_serializing_if = "Option::is_none")]
97 pub history: Option<Vec<Value>>,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub path: Option<PathBuf>,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub model: Option<String>,
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub model_provider: Option<String>,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub cwd: Option<PathBuf>,
106 #[serde(skip_serializing_if = "Option::is_none")]
107 pub approval_policy: Option<String>,
108 #[serde(skip_serializing_if = "Option::is_none")]
109 pub sandbox: Option<String>,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub config: Option<Value>,
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub base_instructions: Option<String>,
114 #[serde(skip_serializing_if = "Option::is_none")]
115 pub developer_instructions: Option<String>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub personality: Option<String>,
118 #[serde(default)]
119 pub persist_extended_history: bool,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct ThreadForkParams {
124 pub thread_id: String,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub path: Option<PathBuf>,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub model: Option<String>,
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub model_provider: Option<String>,
131 #[serde(skip_serializing_if = "Option::is_none")]
132 pub cwd: Option<PathBuf>,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub approval_policy: Option<String>,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub sandbox: Option<String>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub config: Option<Value>,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub base_instructions: Option<String>,
141 #[serde(skip_serializing_if = "Option::is_none")]
142 pub developer_instructions: Option<String>,
143 #[serde(default)]
144 pub persist_extended_history: bool,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct ThreadListParams {
149 #[serde(default)]
150 pub include_archived: bool,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub limit: Option<usize>,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct ThreadReadParams {
157 pub thread_id: String,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct ThreadSetNameParams {
162 pub thread_id: String,
163 pub name: String,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct ThreadGoalSetParams {
168 pub thread_id: String,
169 pub objective: String,
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub token_budget: Option<i64>,
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct ThreadGoalGetParams {
176 pub thread_id: String,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct ThreadGoalClearParams {
181 pub thread_id: String,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
185#[serde(tag = "kind", rename_all = "snake_case")]
186pub enum ThreadRequest {
187 Create {
188 #[serde(default)]
189 metadata: Value,
190 },
191 Start(ThreadStartParams),
192 Resume(ThreadResumeParams),
193 Fork(ThreadForkParams),
194 List(ThreadListParams),
195 Read(ThreadReadParams),
196 SetName(ThreadSetNameParams),
197 GoalSet(ThreadGoalSetParams),
198 GoalGet(ThreadGoalGetParams),
199 GoalClear(ThreadGoalClearParams),
200 Archive {
201 thread_id: String,
202 },
203 Unarchive {
204 thread_id: String,
205 },
206 Message {
207 thread_id: String,
208 input: String,
209 },
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct ThreadResponse {
215 pub thread_id: String,
217 pub status: String,
219 #[serde(skip_serializing_if = "Option::is_none")]
221 pub thread: Option<Thread>,
222 #[serde(default)]
224 pub threads: Vec<Thread>,
225 #[serde(skip_serializing_if = "Option::is_none")]
227 pub goal: Option<ThreadGoal>,
228 #[serde(skip_serializing_if = "Option::is_none")]
230 pub model: Option<String>,
231 #[serde(skip_serializing_if = "Option::is_none")]
233 pub model_provider: Option<String>,
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub cwd: Option<PathBuf>,
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub approval_policy: Option<String>,
240 #[serde(skip_serializing_if = "Option::is_none")]
242 pub sandbox: Option<String>,
243 #[serde(default)]
245 pub events: Vec<EventFrame>,
246 #[serde(default)]
248 pub data: Value,
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize)]
253#[serde(tag = "kind", rename_all = "snake_case")]
254pub enum AppRequest {
255 Capabilities,
257 ConfigGet { key: String },
259 ConfigSet { key: String, value: String },
261 ConfigUnset { key: String },
263 ConfigList,
265 Models,
267 ThreadLoadedList,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
273pub struct AppResponse {
274 pub ok: bool,
276 pub data: Value,
278 #[serde(default)]
280 pub events: Vec<EventFrame>,
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct PromptRequest {
286 #[serde(skip_serializing_if = "Option::is_none")]
288 pub thread_id: Option<String>,
289 pub prompt: String,
291 #[serde(skip_serializing_if = "Option::is_none")]
293 pub model: Option<String>,
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct PromptResponse {
299 pub output: String,
301 pub model: String,
303 #[serde(default)]
305 pub events: Vec<EventFrame>,
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
310#[serde(rename_all = "snake_case")]
311pub enum AskForApproval {
312 UnlessTrusted,
314 OnFailure,
316 OnRequest,
318 Reject {
320 sandbox_approval: bool,
321 rules: bool,
322 mcp_elicitations: bool,
323 },
324 Never,
326}
327
328#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
330#[serde(rename_all = "snake_case")]
331pub enum ToolKind {
332 Function,
334 Mcp,
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct LocalShellParams {
341 pub command: String,
343 #[serde(skip_serializing_if = "Option::is_none")]
345 pub cwd: Option<String>,
346 #[serde(skip_serializing_if = "Option::is_none")]
348 pub timeout_ms: Option<u64>,
349}
350
351#[derive(Debug, Clone, Serialize, Deserialize)]
353#[serde(tag = "type", rename_all = "snake_case")]
354pub enum ToolPayload {
355 Function { arguments: String },
357 Custom { input: String },
359 LocalShell { params: LocalShellParams },
361 Mcp {
363 server: String,
364 tool: String,
365 raw_arguments: Value,
366 #[serde(skip_serializing_if = "Option::is_none")]
367 raw_tool_call_id: Option<String>,
368 },
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize)]
373#[serde(tag = "type", rename_all = "snake_case")]
374pub enum ToolOutput {
375 Function {
377 #[serde(skip_serializing_if = "Option::is_none")]
379 body: Option<Value>,
380 success: bool,
382 },
383 Mcp {
385 result: Value,
387 },
388}
389
390#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
392#[serde(rename_all = "snake_case")]
393pub enum NetworkPolicyRuleAction {
394 Allow,
396 Deny,
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
402pub struct NetworkPolicyAmendment {
403 pub host: String,
405 pub action: NetworkPolicyRuleAction,
407}
408
409#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
411#[serde(tag = "type", rename_all = "snake_case")]
412pub enum ReviewDecision {
413 Approved,
415 ApprovedExecpolicyAmendment,
417 ApprovedForSession,
419 NetworkPolicyAmendment {
421 host: String,
422 action: NetworkPolicyRuleAction,
423 },
424 Denied,
426 Abort,
428}
429
430#[derive(Debug, Clone, Serialize, Deserialize)]
432#[serde(rename_all = "snake_case")]
433pub enum McpStartupStatus {
434 Starting,
436 Ready,
438 Failed { error: String },
440 Cancelled,
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize)]
446pub struct McpStartupUpdateEvent {
447 pub server_name: String,
449 pub status: McpStartupStatus,
451}
452
453#[derive(Debug, Clone, Serialize, Deserialize)]
455pub struct McpStartupFailure {
456 pub server_name: String,
458 pub error: String,
460}
461
462#[derive(Debug, Clone, Serialize, Deserialize)]
464pub struct McpStartupCompleteEvent {
465 pub ready: Vec<String>,
467 pub failed: Vec<McpStartupFailure>,
469 pub cancelled: Vec<String>,
471}
472
473#[derive(Debug, Clone, Serialize, Deserialize)]
475pub struct NetworkApprovalContext {
476 pub host: String,
478 pub protocol: String,
480}
481
482#[derive(Debug, Clone, Serialize, Deserialize)]
484pub struct ExecApprovalRequestEvent {
485 pub call_id: String,
487 pub approval_id: String,
489 pub turn_id: String,
491 pub command: String,
493 pub cwd: String,
495 pub reason: String,
497 #[serde(default, skip_serializing_if = "Option::is_none")]
499 pub matched_rule: Option<Box<str>>,
500 #[serde(skip_serializing_if = "Option::is_none")]
502 pub network_approval_context: Option<NetworkApprovalContext>,
503 #[serde(default)]
505 pub proposed_execpolicy_amendment: Vec<String>,
506 #[serde(default)]
508 pub proposed_network_policy_amendments: Vec<NetworkPolicyAmendment>,
509 #[serde(default)]
511 pub additional_permissions: Vec<String>,
512 #[serde(default)]
514 pub available_decisions: Vec<ReviewDecision>,
515}
516
517#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
519#[serde(rename_all = "snake_case")]
520pub enum ResponseChannel {
521 #[default]
523 Text,
524 Reasoning,
526}
527
528impl ResponseChannel {
529 pub const fn is_text(&self) -> bool {
531 matches!(self, ResponseChannel::Text)
532 }
533}
534
535#[derive(Debug, Clone, Serialize, Deserialize)]
537pub struct ApprovalDecisionRequest {
538 pub decision: String,
540 #[serde(default)]
542 pub remember: bool,
543}
544
545#[derive(Debug, Clone, Serialize, Deserialize)]
551#[serde(tag = "event", rename_all = "snake_case")]
552pub enum EventFrame {
553 ResponseStart { response_id: String },
555 ResponseDelta {
557 response_id: String,
558 delta: String,
559 #[serde(default, skip_serializing_if = "ResponseChannel::is_text")]
560 channel: ResponseChannel,
561 },
562 ResponseEnd { response_id: String },
564 ToolCallStart {
566 response_id: String,
567 tool_name: String,
568 arguments: Value,
569 },
570 ToolCallResult {
572 response_id: String,
573 tool_name: String,
574 output: Value,
575 },
576 McpStartupUpdate { update: McpStartupUpdateEvent },
578 McpStartupComplete { summary: McpStartupCompleteEvent },
580 McpToolCallBegin {
582 server_name: String,
583 tool_name: String,
584 },
585 McpToolCallEnd {
587 server_name: String,
588 tool_name: String,
589 ok: bool,
590 },
591 ExecApprovalRequest { request: ExecApprovalRequestEvent },
593 ApplyPatchApprovalRequest { request: ExecApprovalRequestEvent },
595 ElicitationRequest {
597 server_name: String,
598 request_id: String,
599 prompt: String,
600 },
601 ExecCommandBegin { command: String, cwd: String },
603 ExecCommandOutputDelta { command: String, delta: String },
605 ExecCommandEnd { command: String, exit_code: i32 },
607 PatchApplyBegin { path: String },
609 PatchApplyEnd { path: String, ok: bool },
611 TurnStarted { turn_id: String },
613 TurnComplete { turn_id: String },
615 TurnAborted { turn_id: String, reason: String },
617 ThreadGoalUpdated { goal: ThreadGoal },
619 ThreadGoalCleared { thread_id: String },
621 Error {
623 response_id: String,
624 message: String,
625 },
626}