rustant_core/multi/
mod.rs1pub mod isolation;
7pub mod messaging;
8pub mod orchestrator;
9pub mod routing;
10pub mod spawner;
11
12pub use isolation::{AgentContext, AgentStatus, ResourceLimits};
13pub use messaging::{AgentEnvelope, AgentPayload, MessageBus, MessagePriority};
14pub use orchestrator::{AgentOrchestrator, TaskHandler};
15pub use routing::{AgentRoute, AgentRouter};
16pub use spawner::AgentSpawner;
17
18#[cfg(test)]
19mod tests {
20 use super::*;
21 use crate::channels::ChannelType;
22 use std::collections::HashMap;
23 use uuid::Uuid;
24
25 #[test]
26 fn test_multi_module_exports() {
27 let bus = MessageBus::new(100);
29 assert_eq!(bus.pending_count_all(), 0);
30 }
31
32 #[test]
33 fn test_channel_to_agent_to_node_flow() {
34 let agent_id = Uuid::new_v4();
36 let mut router = AgentRouter::new();
37 router.add_route(AgentRoute {
38 priority: 1,
39 target_agent_id: agent_id,
40 conditions: vec![routing::RouteCondition::ChannelType(ChannelType::Telegram)],
41 });
42
43 let req = routing::RouteRequest::new()
45 .with_channel(ChannelType::Telegram)
46 .with_message("run shell ls");
47 let target = router.route(&req).unwrap();
48 assert_eq!(target, agent_id);
49
50 let mut bus = MessageBus::new(100);
52 bus.register(agent_id);
53
54 let from = Uuid::new_v4();
55 let mut args = HashMap::new();
56 args.insert("channel_type".into(), "Telegram".into());
57 let envelope = AgentEnvelope::new(
58 from,
59 agent_id,
60 AgentPayload::TaskRequest {
61 description: "run shell ls".into(),
62 args,
63 },
64 );
65 bus.send(envelope).unwrap();
66
67 let received = bus.receive(&agent_id).unwrap();
69 match &received.payload {
70 AgentPayload::TaskRequest { description, args } => {
71 assert_eq!(description, "run shell ls");
72 assert_eq!(args.get("channel_type").unwrap(), "Telegram");
73 }
74 _ => panic!("Expected TaskRequest"),
75 }
76 }
77
78 #[test]
79 fn test_multi_agent_delegation() {
80 let mut spawner = AgentSpawner::default();
82 let parent = spawner.spawn("parent").unwrap();
83 let child = spawner.spawn_child("child", parent).unwrap();
84
85 let mut bus = MessageBus::new(100);
86 bus.register(parent);
87 bus.register(child);
88
89 let task = AgentEnvelope::new(
91 parent,
92 child,
93 AgentPayload::TaskRequest {
94 description: "analyze code".into(),
95 args: HashMap::new(),
96 },
97 );
98 let correlation = task.id;
99 bus.send(task).unwrap();
100
101 let received = bus.receive(&child).unwrap();
103 assert_eq!(received.from, parent);
104
105 let response = AgentEnvelope::new(
107 child,
108 parent,
109 AgentPayload::TaskResult {
110 success: true,
111 output: "Analysis complete".into(),
112 },
113 )
114 .with_correlation(correlation);
115 bus.send(response).unwrap();
116
117 let result = bus.receive(&parent).unwrap();
119 assert_eq!(result.correlation_id, Some(correlation));
120 match &result.payload {
121 AgentPayload::TaskResult { success, output } => {
122 assert!(success);
123 assert_eq!(output, "Analysis complete");
124 }
125 _ => panic!("Expected TaskResult"),
126 }
127 }
128
129 #[test]
130 fn test_agent_fact_sharing() {
131 let mut spawner = AgentSpawner::default();
133 let agent_a = spawner.spawn("agent-a").unwrap();
134 let agent_b = spawner.spawn("agent-b").unwrap();
135
136 let mut bus = MessageBus::new(100);
137 bus.register(agent_a);
138 bus.register(agent_b);
139
140 let fact = AgentEnvelope::new(
142 agent_a,
143 agent_b,
144 AgentPayload::FactShare {
145 key: "project.language".into(),
146 value: "Rust".into(),
147 },
148 );
149 bus.send(fact).unwrap();
150
151 let received = bus.receive(&agent_b).unwrap();
153 assert_eq!(received.from, agent_a);
154 match &received.payload {
155 AgentPayload::FactShare { key, value } => {
156 assert_eq!(key, "project.language");
157 assert_eq!(value, "Rust");
158 }
159 _ => panic!("Expected FactShare"),
160 }
161 }
162
163 #[test]
164 fn test_full_lifecycle() {
165 let mut spawner = AgentSpawner::default();
167 let supervisor = spawner.spawn("supervisor").unwrap();
168 let worker1 = spawner.spawn_child("worker-1", supervisor).unwrap();
169 let worker2 = spawner.spawn_child("worker-2", supervisor).unwrap();
170 assert_eq!(spawner.agent_count(), 3);
171
172 let mut router = AgentRouter::new().with_default(supervisor);
174 router.add_route(AgentRoute {
175 priority: 1,
176 target_agent_id: worker1,
177 conditions: vec![routing::RouteCondition::TaskPrefix("code:".into())],
178 });
179 router.add_route(AgentRoute {
180 priority: 1,
181 target_agent_id: worker2,
182 conditions: vec![routing::RouteCondition::TaskPrefix("test:".into())],
183 });
184
185 let req1 = routing::RouteRequest::new().with_task("code:refactor");
187 let req2 = routing::RouteRequest::new().with_task("test:unit");
188 let req3 = routing::RouteRequest::new().with_task("deploy:prod");
189
190 assert_eq!(router.route(&req1), Some(worker1));
191 assert_eq!(router.route(&req2), Some(worker2));
192 assert_eq!(router.route(&req3), Some(supervisor)); let mut bus = MessageBus::new(100);
196 bus.register(supervisor);
197 bus.register(worker1);
198 bus.register(worker2);
199
200 let task = AgentEnvelope::new(
201 supervisor,
202 worker1,
203 AgentPayload::TaskRequest {
204 description: "code:refactor main.rs".into(),
205 args: HashMap::new(),
206 },
207 );
208 bus.send(task).unwrap();
209 assert_eq!(bus.pending_count(&worker1), 1);
210
211 let removed = spawner.terminate(supervisor);
213 assert_eq!(removed, 3);
214 assert_eq!(spawner.agent_count(), 0);
215
216 assert_eq!(bus.pending_count(&worker1), 1);
218 }
219}