1pub mod cache;
13pub mod collapse_controller;
14pub mod executor;
15pub mod kubernetes_executor;
16pub mod orchestrator;
17pub mod rate_limiter;
18pub mod remote_subtask;
19pub mod result_store;
20pub mod subtask;
21
22pub use cache::{CacheConfig, CacheStats, SwarmCache};
23pub use collapse_controller::{
24 BranchEvaluation, BranchObservation, BranchRuntimeState, CoherenceScore, CollapseController,
25 CollapsePolicy, CollapseTick, KillDecision,
26};
27pub use executor::{SwarmExecutor, run_agent_loop};
28pub use orchestrator::Orchestrator;
29pub use rate_limiter::{AdaptiveRateLimiter, RateLimitInfo, RateLimitStats};
30pub use result_store::{ResultStore, ResultStoreContext, SharedResult, SubTaskStoreHandle};
31pub use subtask::{SubAgent, SubTask, SubTaskContext, SubTaskResult, SubTaskStatus};
32
33use anyhow::Result;
34use async_trait::async_trait;
35
36#[async_trait]
41pub trait Actor: Send + Sync {
42 fn actor_id(&self) -> &str;
44
45 fn actor_status(&self) -> ActorStatus;
47
48 async fn initialize(&mut self) -> Result<()>;
50
51 async fn shutdown(&mut self) -> Result<()>;
53}
54
55#[async_trait]
60pub trait Handler<M>: Actor {
61 type Response: Send + Sync;
63
64 async fn handle(&mut self, message: M) -> Result<Self::Response>;
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum ActorStatus {
71 Initializing,
73 Ready,
75 Busy,
77 Paused,
79 ShuttingDown,
81 Stopped,
83}
84
85impl std::fmt::Display for ActorStatus {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 ActorStatus::Initializing => write!(f, "initializing"),
89 ActorStatus::Ready => write!(f, "ready"),
90 ActorStatus::Busy => write!(f, "busy"),
91 ActorStatus::Paused => write!(f, "paused"),
92 ActorStatus::ShuttingDown => write!(f, "shutting_down"),
93 ActorStatus::Stopped => write!(f, "stopped"),
94 }
95 }
96}
97
98#[derive(Debug, Clone)]
100pub enum SwarmMessage {
101 ExecuteTask {
103 task_id: String,
104 instruction: String,
105 },
106 Progress {
108 task_id: String,
109 progress: f32,
110 message: String,
111 },
112 TaskCompleted { task_id: String, result: String },
114 TaskFailed { task_id: String, error: String },
116 ToolRequest {
118 tool_id: String,
119 arguments: serde_json::Value,
120 },
121 ToolResponse {
123 tool_id: String,
124 result: crate::tool::ToolResult,
125 },
126}
127
128use serde::{Deserialize, Serialize};
129
130pub const MAX_SUBAGENTS: usize = 100;
132
133pub const MAX_TOOL_CALLS: usize = 1500;
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct SwarmConfig {
139 pub max_subagents: usize,
141
142 pub max_steps_per_subagent: usize,
144
145 pub max_total_steps: usize,
147
148 pub subagent_timeout_secs: u64,
150
151 pub parallel_enabled: bool,
153
154 pub critical_path_threshold: usize,
156
157 pub model: Option<String>,
159
160 pub max_concurrent_requests: usize,
162
163 pub request_delay_ms: u64,
165
166 pub worktree_enabled: bool,
168
169 pub worktree_auto_merge: bool,
171
172 pub working_dir: Option<String>,
174
175 #[serde(default)]
177 pub execution_mode: ExecutionMode,
178
179 #[serde(default = "default_k8s_pod_budget")]
181 pub k8s_pod_budget: usize,
182
183 #[serde(default)]
185 pub k8s_subagent_image: Option<String>,
186}
187
188#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
190#[serde(rename_all = "snake_case")]
191pub enum ExecutionMode {
192 LocalThread,
194 KubernetesPod,
196}
197
198impl ExecutionMode {
199 pub fn from_cli_value(value: &str) -> Self {
200 match value {
201 "k8s" | "kubernetes" | "kubernetes-pod" | "pod" => Self::KubernetesPod,
202 _ => Self::LocalThread,
203 }
204 }
205}
206
207impl Default for ExecutionMode {
208 fn default() -> Self {
209 Self::LocalThread
210 }
211}
212
213fn default_k8s_pod_budget() -> usize {
214 8
215}
216
217impl Default for SwarmConfig {
218 fn default() -> Self {
219 Self {
220 max_subagents: MAX_SUBAGENTS,
221 max_steps_per_subagent: 100,
222 max_total_steps: MAX_TOOL_CALLS,
223 subagent_timeout_secs: 600, parallel_enabled: true,
225 critical_path_threshold: 10,
226 model: Some("zai/glm-5".to_string()),
227 max_concurrent_requests: 3, request_delay_ms: 1000, worktree_enabled: true, worktree_auto_merge: true, working_dir: None,
232 execution_mode: ExecutionMode::LocalThread,
233 k8s_pod_budget: 8,
234 k8s_subagent_image: None,
235 }
236 }
237}
238
239#[derive(Debug, Clone, Default, Serialize, Deserialize)]
241pub struct SwarmStats {
242 pub subagents_spawned: usize,
244
245 pub subagents_completed: usize,
247
248 pub subagents_failed: usize,
250
251 pub total_tool_calls: usize,
253
254 pub critical_path_length: usize,
256
257 pub execution_time_ms: u64,
259
260 pub sequential_time_estimate_ms: u64,
262
263 pub speedup_factor: f64,
265
266 pub stages: Vec<StageStats>,
268
269 pub rate_limit_stats: RateLimitStats,
271}
272
273#[derive(Debug, Clone, Default, Serialize, Deserialize)]
275pub struct StageStats {
276 pub stage: usize,
278
279 pub subagent_count: usize,
281
282 pub max_steps: usize,
284
285 pub total_steps: usize,
287
288 pub execution_time_ms: u64,
290}
291
292impl SwarmStats {
293 pub fn calculate_speedup(&mut self) {
295 if self.execution_time_ms > 0 {
296 self.speedup_factor =
297 self.sequential_time_estimate_ms as f64 / self.execution_time_ms as f64;
298 }
299 }
300
301 pub fn calculate_critical_path(&mut self) {
303 self.critical_path_length = self.stages.iter().map(|s| s.max_steps).sum();
304 }
305}
306
307#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
309#[serde(rename_all = "snake_case")]
310pub enum DecompositionStrategy {
311 Automatic,
313
314 ByDomain,
316
317 ByData,
319
320 ByStage,
322
323 None,
325}
326
327impl Default for DecompositionStrategy {
328 fn default() -> Self {
329 Self::Automatic
330 }
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct SwarmResult {
336 pub success: bool,
338
339 pub result: String,
341
342 pub subtask_results: Vec<SubTaskResult>,
344
345 pub stats: SwarmStats,
347
348 pub artifacts: Vec<SwarmArtifact>,
350
351 pub error: Option<String>,
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct SwarmArtifact {
358 pub artifact_type: String,
360
361 pub name: String,
363
364 pub content: String,
366
367 pub source_subagent: Option<String>,
369
370 pub mime_type: Option<String>,
372}