1use serde::{Deserialize, Serialize};
7
8use crate::messages::{RateLimitStatus, TaskUsage};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct SubagentCard {
18 pub name: String,
21 pub dispatch_id: String,
24 pub agent_type: Option<String>,
28 pub running: bool,
30 pub failed: bool,
34 pub backgrounded: bool,
38 pub ended_at_ms: Option<u64>,
41 pub calls: usize,
44 pub tail: Vec<SubagentCall>,
46 pub usage: Option<TaskUsage>,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52pub struct SubagentCall {
53 pub name: String,
55 pub title: String,
57 pub status: SubagentCallStatus,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
63#[serde(rename_all = "snake_case")]
64pub enum SubagentCallStatus {
65 Pending,
66 InProgress,
67 Completed,
68 Failed,
69 Killed,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73pub struct ModeInfo {
74 pub id: String,
75 pub name: String,
76 pub description: Option<String>,
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
80pub struct ModeState {
81 pub current_mode_id: String,
82 pub current_mode_name: String,
83 pub available_modes: Vec<ModeInfo>,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub struct AvailableCommand {
88 pub name: String,
89 pub description: String,
90 pub input_hint: Option<String>,
91}
92
93impl AvailableCommand {
94 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
95 Self { name: name.into(), description: description.into(), input_hint: None }
96 }
97
98 pub fn input_hint(mut self, input_hint: impl Into<String>) -> Self {
99 self.input_hint = Some(input_hint.into());
100 self
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
105pub struct AvailableAgent {
106 pub name: String,
107 pub description: String,
108 pub model: Option<String>,
109}
110
111impl AvailableAgent {
112 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
113 Self { name: name.into(), description: description.into(), model: None }
114 }
115
116 pub fn model(mut self, model: impl Into<String>) -> Self {
117 self.model = Some(model.into());
118 self
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
123pub enum EffortLevel {
124 #[serde(rename = "low")]
125 Low,
126 #[serde(rename = "medium")]
127 Medium,
128 #[serde(rename = "high")]
129 High,
130 #[serde(rename = "xhigh")]
131 Xhigh,
132 #[serde(rename = "max")]
133 Max,
134}
135
136impl EffortLevel {
137 pub const fn as_stored(self) -> &'static str {
138 match self {
139 Self::Low => "low",
140 Self::Medium => "medium",
141 Self::High => "high",
142 Self::Xhigh => "xhigh",
143 Self::Max => "max",
144 }
145 }
146
147 pub const fn label(self) -> &'static str {
148 match self {
149 Self::Low => "Low",
150 Self::Medium => "Medium",
151 Self::High => "High",
152 Self::Xhigh => "Extra High",
153 Self::Max => "Max",
154 }
155 }
156
157 pub const fn description(self) -> &'static str {
158 match self {
159 Self::Low => "Fastest responses",
160 Self::Medium => "Balanced speed and depth",
161 Self::High => "Deeper reasoning",
162 Self::Xhigh => "Extra-high reasoning",
163 Self::Max => "Maximum reasoning",
164 }
165 }
166
167 pub fn from_stored(value: &str) -> Option<Self> {
168 match value {
169 "low" => Some(Self::Low),
170 "medium" => Some(Self::Medium),
171 "high" => Some(Self::High),
172 "xhigh" | "extra_high" => Some(Self::Xhigh),
173 "max" => Some(Self::Max),
174 _ => None,
175 }
176 }
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
180pub struct AvailableModel {
181 pub id: String,
182 pub display_name: String,
183 pub description: Option<String>,
184 pub supports_effort: bool,
185 #[serde(default)]
186 pub supported_effort_levels: Vec<EffortLevel>,
187 pub supports_adaptive_thinking: Option<bool>,
188 pub supports_auto_mode: Option<bool>,
189}
190
191impl AvailableModel {
192 pub fn new(id: impl Into<String>, display_name: impl Into<String>) -> Self {
193 Self {
194 id: id.into(),
195 display_name: display_name.into(),
196 description: None,
197 supports_effort: false,
198 supported_effort_levels: Vec::new(),
199 supports_adaptive_thinking: None,
200 supports_auto_mode: None,
201 }
202 }
203
204 pub fn description(mut self, description: impl Into<String>) -> Self {
205 self.description = Some(description.into());
206 self
207 }
208
209 pub fn supports_effort(mut self, supports_effort: bool) -> Self {
210 self.supports_effort = supports_effort;
211 self
212 }
213
214 pub fn supported_effort_levels(mut self, supported_effort_levels: Vec<EffortLevel>) -> Self {
215 self.supported_effort_levels = supported_effort_levels;
216 self
217 }
218
219 pub fn supports_adaptive_thinking(mut self, supports_adaptive_thinking: Option<bool>) -> Self {
220 self.supports_adaptive_thinking = supports_adaptive_thinking;
221 self
222 }
223
224 pub fn supports_auto_mode(mut self, supports_auto_mode: Option<bool>) -> Self {
225 self.supports_auto_mode = supports_auto_mode;
226 self
227 }
228}
229
230#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
231pub struct CurrentModel {
232 pub requested_id: Option<String>,
233 pub resolved_id: String,
234 pub display_name_short: String,
235 pub display_name_long: String,
236 pub catalog_id: Option<String>,
237 pub supports_effort: bool,
238 #[serde(default)]
239 pub supported_effort_levels: Vec<EffortLevel>,
240 pub supports_auto_mode: Option<bool>,
241 pub supports_adaptive_thinking: Option<bool>,
242 pub is_authoritative: bool,
243}
244
245impl CurrentModel {
246 pub fn new(
247 resolved_id: impl Into<String>,
248 display_name_short: impl Into<String>,
249 display_name_long: impl Into<String>,
250 ) -> Self {
251 Self {
252 requested_id: None,
253 resolved_id: resolved_id.into(),
254 display_name_short: display_name_short.into(),
255 display_name_long: display_name_long.into(),
256 catalog_id: None,
257 supports_effort: false,
258 supported_effort_levels: Vec::new(),
259 supports_auto_mode: None,
260 supports_adaptive_thinking: None,
261 is_authoritative: false,
262 }
263 }
264
265 pub fn requested_id(mut self, requested_id: impl Into<String>) -> Self {
266 self.requested_id = Some(requested_id.into());
267 self
268 }
269
270 pub fn catalog_id(mut self, catalog_id: impl Into<String>) -> Self {
271 self.catalog_id = Some(catalog_id.into());
272 self
273 }
274
275 pub fn supports_effort(mut self, supports_effort: bool) -> Self {
276 self.supports_effort = supports_effort;
277 self
278 }
279
280 pub fn supported_effort_levels(mut self, supported_effort_levels: Vec<EffortLevel>) -> Self {
281 self.supported_effort_levels = supported_effort_levels;
282 self
283 }
284
285 pub fn supports_adaptive_thinking(mut self, supports_adaptive_thinking: Option<bool>) -> Self {
286 self.supports_adaptive_thinking = supports_adaptive_thinking;
287 self
288 }
289
290 pub fn supports_auto_mode(mut self, supports_auto_mode: Option<bool>) -> Self {
291 self.supports_auto_mode = supports_auto_mode;
292 self
293 }
294
295 pub fn authoritative(mut self, is_authoritative: bool) -> Self {
296 self.is_authoritative = is_authoritative;
297 self
298 }
299}
300
301#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
302#[serde(rename_all = "snake_case")]
303pub enum ApiRetryError {
304 AuthenticationFailed,
305 BillingError,
306 RateLimit,
307 InvalidRequest,
308 ServerError,
309 MaxOutputTokens,
310 #[serde(other)]
311 Unknown,
312}
313
314#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
315#[serde(rename_all = "snake_case")]
316pub enum RuntimeSessionState {
317 Idle,
318 Running,
319 RequiresAction,
320}
321
322#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
328#[serde(rename_all = "snake_case")]
329pub enum MachineTurn {
330 Handoff,
331 Compacting,
332}
333
334#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
335pub struct SettingsParseErrorUpdate {
336 pub file: Option<String>,
337 pub path: String,
338 pub message: String,
339}
340
341#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
342pub struct RateLimitUpdate {
343 pub status: RateLimitStatus,
344 pub resets_at: Option<f64>,
345 pub utilization: Option<f64>,
346 pub rate_limit_type: Option<String>,
347 pub overage_status: Option<RateLimitStatus>,
348 pub overage_resets_at: Option<f64>,
349 pub overage_disabled_reason: Option<String>,
350 pub is_using_overage: Option<bool>,
351 pub surpassed_threshold: Option<f64>,
352}
353
354#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
355pub struct ApiRetryUpdate {
356 pub attempt: u64,
357 pub max_retries: u64,
358 pub retry_delay_ms: u64,
359 pub error_status: Option<u16>,
360 pub error: ApiRetryError,
361}
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
366#[serde(rename_all = "snake_case")]
367pub enum TerminalReason {
368 BlockingLimit,
369 RapidRefillBreaker,
370 PromptTooLong,
371 ImageError,
372 ModelError,
373 AbortedStreaming,
374 AbortedTools,
375 StopHookPrevented,
376 HookStopped,
377 ToolDeferred,
378 MaxTurns,
379 Completed,
380 #[serde(other)]
381 Unknown,
382}
383
384impl TerminalReason {
385 pub const fn as_stored(self) -> &'static str {
386 match self {
387 Self::BlockingLimit => "blocking_limit",
388 Self::RapidRefillBreaker => "rapid_refill_breaker",
389 Self::PromptTooLong => "prompt_too_long",
390 Self::ImageError => "image_error",
391 Self::ModelError => "model_error",
392 Self::AbortedStreaming => "aborted_streaming",
393 Self::AbortedTools => "aborted_tools",
394 Self::StopHookPrevented => "stop_hook_prevented",
395 Self::HookStopped => "hook_stopped",
396 Self::ToolDeferred => "tool_deferred",
397 Self::MaxTurns => "max_turns",
398 Self::Completed => "completed",
399 Self::Unknown => "unknown",
400 }
401 }
402}
403
404#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
409pub enum SessionLifecycleState {
410 #[default]
413 Sleeping,
414 Spawning,
417 Idle,
419 Running,
421 Attention,
425 AuthRequired,
428 Failed,
432 Restarting,
436 LoggedOut,
439}
440
441#[derive(Debug, Default)]
446pub struct SessionTurnState {
447 pub tool_calls: std::collections::HashMap<String, crate::session_update::ToolCall>,
450 pub task_tool_use_ids: std::collections::HashMap<String, String>,
454
455 pub model_id: String,
457 pub requested_model_id: Option<String>,
459 pub resolved_runtime_model_id: Option<String>,
461
462 pub mode: Option<crate::permission::PermissionMode>,
466 pub supported_mode_ids: Vec<crate::permission::PermissionMode>,
468 pub runtime_unavailable_mode_ids: Vec<crate::permission::PermissionMode>,
470 pub mode_state: Option<ModeState>,
472
473 pub agents_emitted_this_turn: bool,
477
478 pub last_assistant_error: Option<String>,
482}
483
484#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
490#[serde(rename_all = "snake_case")]
491pub enum MonitorStatus {
492 Running,
496 Stopped,
498 Completed,
502 TimedOut,
505}
506
507impl MonitorStatus {
508 pub const fn is_terminal(self) -> bool {
510 !matches!(self, Self::Running)
511 }
512}
513
514#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
518pub struct MonitorRecord {
519 pub tool_use_id: String,
522 pub task_id: Option<String>,
527 pub description: String,
529 pub command: String,
531 pub persistent: bool,
534 pub timeout_ms: u64,
536 pub status: MonitorStatus,
537 pub output_file: Option<String>,
540 pub ended_at: Option<std::time::SystemTime>,
545}