1use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6
7pub const MAX_WAIT_SECONDS: u64 = 3_600;
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(deny_unknown_fields)]
13pub struct SourceRange {
14 pub file: PathBuf,
15 pub start: u64,
16 pub end: u64,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(deny_unknown_fields)]
23pub struct SubagentToolRequest {
24 pub request_id: String,
25 pub created_at_ms: i64,
26 pub action: SubagentToolAction,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30#[serde(
31 tag = "action",
32 content = "params",
33 rename_all = "snake_case",
34 deny_unknown_fields
35)]
36pub enum SubagentToolAction {
37 ListProfiles,
38 Spawn {
39 task_name: String,
40 instructions: String,
41 #[serde(default, skip_serializing_if = "Option::is_none")]
42 profile_id: Option<String>,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
44 model: Option<String>,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 effort: Option<String>,
47 #[serde(default)]
48 working_directory: PathBuf,
49 #[serde(default, skip_serializing_if = "Option::is_none")]
50 context: Option<String>,
51 #[serde(default, skip_serializing_if = "Vec::is_empty")]
52 files: Vec<SourceRange>,
53 },
54 ListAgents,
55 SendInput {
56 child_session_id: String,
57 message: String,
58 },
59 WaitAgents {
60 child_session_ids: Vec<String>,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 timeout_seconds: Option<u64>,
63 },
64 InterruptAgent {
65 child_session_id: String,
66 },
67 CloseAgent {
68 child_session_id: String,
69 },
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73#[serde(deny_unknown_fields)]
74pub struct SubagentToolResult {
75 pub request_id: String,
76 pub completed_at_ms: i64,
77 pub is_error: bool,
78 pub message: String,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
83#[serde(deny_unknown_fields)]
84pub struct SubagentRecord {
85 pub child_session_id: String,
86 pub parent_session_id: String,
87 pub task_name: String,
88 pub profile_id: String,
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 pub model: Option<String>,
91 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub effort: Option<String>,
93 pub working_directory: PathBuf,
94 pub initial_prompt: String,
96 pub request_key: String,
97 pub created_at: String,
98 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub delivered_turn: Option<u64>,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
104#[serde(rename_all = "snake_case")]
105pub enum SubagentStatus {
106 Preparing,
107 Running,
108 InputRequired,
109 Completed,
110 Failed,
111 Interrupted,
112 Stopped,
113}
114
115impl SubagentRecord {
116 #[must_use]
117 pub fn is_child(&self, session_id: &str) -> bool {
118 self.child_session_id == session_id
119 }
120}