1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6pub mod agent_run;
7pub mod fleet;
8pub mod runtime;
9pub mod workroom;
10
11pub trait Status {
17 fn is_terminal(&self) -> bool;
20
21 fn is_active(&self) -> bool;
24
25 fn is_paused(&self) -> bool;
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct Envelope<T> {
32 pub request_id: String,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub thread_id: Option<String>,
35 pub body: T,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
39#[serde(rename_all = "snake_case")]
40pub enum ThreadStatus {
41 Running,
42 Idle,
43 Completed,
44 Failed,
45 Paused,
46 Archived,
47}
48
49impl Status for ThreadStatus {
50 fn is_terminal(&self) -> bool {
51 matches!(self, Self::Completed | Self::Failed | Self::Archived)
52 }
53 fn is_active(&self) -> bool {
54 matches!(self, Self::Running)
55 }
56 fn is_paused(&self) -> bool {
57 matches!(self, Self::Paused)
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
62#[serde(rename_all = "snake_case")]
63pub enum SessionSource {
64 Interactive,
65 Resume,
66 Fork,
67 Api,
68 Unknown,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct Thread {
73 pub id: String,
74 pub preview: String,
75 pub ephemeral: bool,
76 pub model_provider: String,
77 pub created_at: i64,
78 pub updated_at: i64,
79 pub status: ThreadStatus,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub path: Option<PathBuf>,
82 pub cwd: PathBuf,
83 pub cli_version: String,
84 pub source: SessionSource,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub name: Option<String>,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
90#[serde(rename_all = "snake_case")]
91pub enum ThreadGoalStatus {
92 Active,
93 Paused,
94 Blocked,
95 UsageLimited,
96 BudgetLimited,
97 Complete,
98}
99
100impl Status for ThreadGoalStatus {
101 fn is_terminal(&self) -> bool {
102 matches!(self, Self::Complete)
103 }
104 fn is_active(&self) -> bool {
105 matches!(self, Self::Active)
106 }
107 fn is_paused(&self) -> bool {
108 matches!(self, Self::Paused)
109 }
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
113pub struct ThreadGoal {
114 pub thread_id: String,
115 pub goal_id: String,
116 pub objective: String,
117 pub status: ThreadGoalStatus,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub token_budget: Option<i64>,
120 pub tokens_used: i64,
121 pub time_used_seconds: i64,
122 pub continuation_count: i64,
123 pub created_at: i64,
124 pub updated_at: i64,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct ThreadStartParams {
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(default)]
136 pub persist_extended_history: bool,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct ThreadResumeParams {
141 pub thread_id: String,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub history: Option<Vec<Value>>,
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub path: Option<PathBuf>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub model: Option<String>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub model_provider: Option<String>,
150 #[serde(skip_serializing_if = "Option::is_none")]
151 pub cwd: Option<PathBuf>,
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub approval_policy: Option<String>,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub sandbox: Option<String>,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub config: Option<Value>,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub base_instructions: Option<String>,
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub developer_instructions: Option<String>,
162 #[serde(skip_serializing_if = "Option::is_none")]
163 pub personality: Option<String>,
164 #[serde(default)]
165 pub persist_extended_history: bool,
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct ThreadForkParams {
170 pub thread_id: String,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub path: Option<PathBuf>,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub model: Option<String>,
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub model_provider: Option<String>,
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub cwd: Option<PathBuf>,
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub approval_policy: Option<String>,
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub sandbox: Option<String>,
183 #[serde(skip_serializing_if = "Option::is_none")]
184 pub config: Option<Value>,
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub base_instructions: Option<String>,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub developer_instructions: Option<String>,
189 #[serde(default)]
190 pub persist_extended_history: bool,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct ThreadListParams {
195 #[serde(default)]
196 pub include_archived: bool,
197 #[serde(skip_serializing_if = "Option::is_none")]
198 pub limit: Option<usize>,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct ThreadReadParams {
203 pub thread_id: String,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct ThreadSetNameParams {
208 pub thread_id: String,
209 pub name: String,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct ThreadGoalSetParams {
214 pub thread_id: String,
215 pub objective: String,
216 #[serde(skip_serializing_if = "Option::is_none")]
217 pub token_budget: Option<i64>,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct ThreadGoalGetParams {
222 pub thread_id: String,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct ThreadGoalClearParams {
227 pub thread_id: String,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct ThreadGoalProgressParams {
232 pub thread_id: String,
233 #[serde(default)]
234 pub token_delta: i64,
235 #[serde(default)]
236 pub time_delta_seconds: i64,
237 #[serde(default)]
238 pub record_continuation: bool,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
242#[serde(tag = "kind", rename_all = "snake_case")]
243pub enum ThreadRequest {
244 Create {
245 #[serde(default)]
246 metadata: Value,
247 },
248 Start(ThreadStartParams),
249 Resume(ThreadResumeParams),
250 Fork(ThreadForkParams),
251 List(ThreadListParams),
252 Read(ThreadReadParams),
253 SetName(ThreadSetNameParams),
254 GoalSet(ThreadGoalSetParams),
255 GoalGet(ThreadGoalGetParams),
256 GoalClear(ThreadGoalClearParams),
257 GoalRecordProgress(ThreadGoalProgressParams),
258 Archive {
259 thread_id: String,
260 },
261 Unarchive {
262 thread_id: String,
263 },
264 Message {
265 thread_id: String,
266 input: String,
267 },
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct ThreadResponse {
273 pub thread_id: String,
275 pub status: String,
277 #[serde(skip_serializing_if = "Option::is_none")]
279 pub thread: Option<Thread>,
280 #[serde(default)]
282 pub threads: Vec<Thread>,
283 #[serde(skip_serializing_if = "Option::is_none")]
285 pub goal: Option<ThreadGoal>,
286 #[serde(skip_serializing_if = "Option::is_none")]
288 pub model: Option<String>,
289 #[serde(skip_serializing_if = "Option::is_none")]
291 pub model_provider: Option<String>,
292 #[serde(skip_serializing_if = "Option::is_none")]
294 pub cwd: Option<PathBuf>,
295 #[serde(skip_serializing_if = "Option::is_none")]
297 pub approval_policy: Option<String>,
298 #[serde(skip_serializing_if = "Option::is_none")]
300 pub sandbox: Option<String>,
301 #[serde(default)]
303 pub events: Vec<EventFrame>,
304 #[serde(default)]
306 pub data: Value,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
311#[serde(tag = "kind", rename_all = "snake_case")]
312pub enum AppRequest {
313 Capabilities,
315 ConfigGet { key: String },
317 ConfigSet { key: String, value: String },
319 ConfigUnset { key: String },
321 ConfigList,
323 ConfigReload,
336 Models,
338 ThreadLoadedList,
340 SubmitUserInput {
345 request_id: String,
346 answers: Vec<UserInputAnswerEvent>,
347 },
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize)]
352pub struct AppResponse {
353 pub ok: bool,
355 pub data: Value,
357 #[serde(default)]
359 pub events: Vec<EventFrame>,
360}
361
362#[derive(Debug, Clone, Serialize, Deserialize)]
364pub struct PromptRequest {
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub thread_id: Option<String>,
368 pub prompt: String,
370 #[serde(skip_serializing_if = "Option::is_none")]
372 pub model: Option<String>,
373}
374
375#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct PromptResponse {
378 pub output: String,
380 pub model: String,
382 #[serde(default)]
384 pub events: Vec<EventFrame>,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
389#[serde(rename_all = "snake_case")]
390pub enum AskForApproval {
391 UnlessTrusted,
393 OnFailure,
395 OnRequest,
397 Reject {
399 sandbox_approval: bool,
400 rules: bool,
401 mcp_elicitations: bool,
402 },
403 Never,
405}
406
407#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
409#[serde(rename_all = "snake_case")]
410pub enum ToolKind {
411 Function,
413 Mcp,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
419pub struct LocalShellParams {
420 pub command: String,
422 #[serde(skip_serializing_if = "Option::is_none")]
424 pub cwd: Option<String>,
425 #[serde(skip_serializing_if = "Option::is_none")]
427 pub timeout_ms: Option<u64>,
428}
429
430#[derive(Debug, Clone, Serialize, Deserialize)]
432#[serde(tag = "type", rename_all = "snake_case")]
433pub enum ToolPayload {
434 Function { arguments: String },
436 Custom { input: String },
438 LocalShell { params: LocalShellParams },
440 Mcp {
442 server: String,
443 tool: String,
444 raw_arguments: Value,
445 #[serde(skip_serializing_if = "Option::is_none")]
446 raw_tool_call_id: Option<String>,
447 },
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize)]
452#[serde(tag = "type", rename_all = "snake_case")]
453pub enum ToolOutput {
454 Function {
456 #[serde(skip_serializing_if = "Option::is_none")]
458 body: Option<Value>,
459 success: bool,
461 },
462 Mcp {
464 result: Value,
466 },
467}
468
469#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
471#[serde(rename_all = "snake_case")]
472pub enum NetworkPolicyRuleAction {
473 Allow,
475 Deny,
477}
478
479#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
481pub struct NetworkPolicyAmendment {
482 pub host: String,
484 pub action: NetworkPolicyRuleAction,
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
490#[serde(tag = "type", rename_all = "snake_case")]
491pub enum ReviewDecision {
492 Approved,
494 ApprovedExecpolicyAmendment,
496 ApprovedForSession,
498 NetworkPolicyAmendment {
500 host: String,
501 action: NetworkPolicyRuleAction,
502 },
503 Denied,
505 Abort,
507}
508
509#[derive(Debug, Clone, Serialize, Deserialize)]
511#[serde(rename_all = "snake_case")]
512pub enum McpStartupStatus {
513 Starting,
515 Ready,
517 Failed { error: String },
519 Cancelled,
521}
522
523#[derive(Debug, Clone, Serialize, Deserialize)]
525pub struct McpStartupUpdateEvent {
526 pub server_name: String,
528 pub status: McpStartupStatus,
530}
531
532#[derive(Debug, Clone, Serialize, Deserialize)]
534pub struct McpStartupFailure {
535 pub server_name: String,
537 pub error: String,
539}
540
541#[derive(Debug, Clone, Serialize, Deserialize)]
543pub struct McpStartupCompleteEvent {
544 pub ready: Vec<String>,
546 pub failed: Vec<McpStartupFailure>,
548 pub cancelled: Vec<String>,
550}
551
552#[derive(Debug, Clone, Serialize, Deserialize)]
554pub struct NetworkApprovalContext {
555 pub host: String,
557 pub protocol: String,
559}
560
561#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
568pub struct UserInputOptionEvent {
569 pub label: String,
571 pub description: String,
573}
574
575#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
577pub struct UserInputQuestionEvent {
578 pub header: String,
580 pub id: String,
582 pub question: String,
584 pub options: Vec<UserInputOptionEvent>,
586 #[serde(default)]
588 pub allow_free_text: bool,
589 #[serde(default)]
591 pub multi_select: bool,
592}
593
594#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
600pub struct UserInputRequestEvent {
601 pub call_id: String,
603 pub turn_id: String,
605 pub request_id: String,
607 pub questions: Vec<UserInputQuestionEvent>,
609}
610
611#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
613pub struct UserInputAnswerEvent {
614 pub id: String,
616 pub label: String,
618 pub value: String,
620}
621
622#[derive(Debug, Clone, Serialize, Deserialize)]
624pub struct ExecApprovalRequestEvent {
625 pub call_id: String,
627 pub approval_id: String,
629 pub turn_id: String,
631 pub command: String,
633 pub cwd: String,
635 pub reason: String,
637 #[serde(default, skip_serializing_if = "Option::is_none")]
639 pub matched_rule: Option<Box<str>>,
640 #[serde(skip_serializing_if = "Option::is_none")]
642 pub network_approval_context: Option<NetworkApprovalContext>,
643 #[serde(default)]
645 pub proposed_execpolicy_amendment: Vec<String>,
646 #[serde(default)]
648 pub proposed_network_policy_amendments: Vec<NetworkPolicyAmendment>,
649 #[serde(default)]
651 pub additional_permissions: Vec<String>,
652 #[serde(default)]
654 pub available_decisions: Vec<ReviewDecision>,
655}
656
657#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
659#[serde(rename_all = "snake_case")]
660pub enum ResponseChannel {
661 #[default]
663 Text,
664 Reasoning,
666}
667
668impl ResponseChannel {
669 pub const fn is_text(&self) -> bool {
671 matches!(self, ResponseChannel::Text)
672 }
673}
674
675#[derive(Debug, Clone, Serialize, Deserialize)]
677pub struct ApprovalDecisionRequest {
678 pub decision: String,
680 #[serde(default)]
682 pub remember: bool,
683}
684
685#[derive(Debug, Clone, Serialize, Deserialize)]
691#[serde(tag = "event", rename_all = "snake_case")]
692pub enum EventFrame {
693 ResponseStart { response_id: String },
695 ResponseDelta {
697 response_id: String,
698 delta: String,
699 #[serde(default, skip_serializing_if = "ResponseChannel::is_text")]
700 channel: ResponseChannel,
701 },
702 ResponseEnd { response_id: String },
704 ToolCallStart {
706 response_id: String,
707 tool_name: String,
708 arguments: Value,
709 },
710 ToolCallResult {
712 response_id: String,
713 tool_name: String,
714 output: Value,
715 },
716 McpStartupUpdate { update: McpStartupUpdateEvent },
718 McpStartupComplete { summary: McpStartupCompleteEvent },
720 McpToolCallBegin {
722 server_name: String,
723 tool_name: String,
724 },
725 McpToolCallEnd {
727 server_name: String,
728 tool_name: String,
729 ok: bool,
730 },
731 ExecApprovalRequest { request: ExecApprovalRequestEvent },
733 ApplyPatchApprovalRequest { request: ExecApprovalRequestEvent },
735 UserInputRequest { request: UserInputRequestEvent },
740 ElicitationRequest {
742 server_name: String,
743 request_id: String,
744 prompt: String,
745 },
746 ExecCommandBegin { command: String, cwd: String },
748 ExecCommandOutputDelta { command: String, delta: String },
750 ExecCommandEnd { command: String, exit_code: i32 },
752 PatchApplyBegin { path: String },
754 PatchApplyEnd { path: String, ok: bool },
756 TurnStarted { turn_id: String },
758 TurnComplete { turn_id: String },
760 TurnAborted { turn_id: String, reason: String },
762 ThreadGoalUpdated { goal: ThreadGoal },
764 ThreadGoalCleared { thread_id: String },
766 Error {
768 response_id: String,
769 message: String,
770 },
771}