1use super::conditions::{CompareOp, Condition, EvalConditions, TimeoutBehavior};
6use super::milestone::{Milestone, PartialConfig};
7use super::types::*;
8
9pub fn builtin_scenarios() -> Vec<EvalScenario> {
11 vec![
12 resource_gathering(),
13 task_queue_processing(),
14 coordination_stress(),
15 ]
16}
17
18pub fn resource_gathering() -> EvalScenario {
23 EvalScenario {
24 meta: ScenarioMeta {
25 name: "Resource Gathering".to_string(),
26 version: "1.0.0".to_string(),
27 id: ScenarioId::new("builtin:resource_gathering:v1"),
28 description: "Multiple agents coordinate to collect resources in a grid world"
29 .to_string(),
30 tags: vec![
31 "coordination".to_string(),
32 "basic".to_string(),
33 "resource".to_string(),
34 ],
35 },
36 task: TaskConfig::default(),
37 llm: LlmConfig::default(),
38 manager: ManagerConfig::default(),
39 batch_processor: BatchProcessorConfig::default(),
40 dependency_graph: None,
41 actions: ScenarioActions::default(),
42 app_config: AppConfigTemplate {
43 tick_duration_ms: 10,
44 max_ticks: 500,
45 management_strategy: ManagementStrategyConfig::IntervalBased { max_interval: 20 },
46 enable_exploration: false,
47 },
48 environment: EnvironmentConfig {
49 env_type: "grid_world".to_string(),
50 params: serde_json::json!({
51 "width": 10,
52 "height": 10,
53 "resource_count": 5,
54 "obstacle_density": 0.1
55 }),
56 initial_state: Some(InitialStateConfig::SeededRandom {}),
57 },
58 agents: AgentsConfig {
59 workers: vec![WorkerTemplate {
60 id_pattern: "gatherer_{i}".to_string(),
61 count: 4,
62 role: "gatherer".to_string(),
63 config: serde_json::json!({
64 "speed": 1.0,
65 "capacity": 2
66 }),
67 }],
68 managers: vec![ManagerTemplate {
69 id: Some("coordinator".to_string()),
70 id_pattern: None,
71 count: 1,
72 role: "coordinator".to_string(),
73 activation: ManagerActivationConfig::Hybrid {
74 interval: 10,
75 triggers: vec!["resource_found".to_string(), "collision".to_string()],
76 },
77 config: serde_json::Value::Null,
78 }],
79 },
80 conditions: EvalConditions {
81 success: vec![
82 Condition::new(
83 "all_resources_collected",
84 "environment.resources_collected",
85 CompareOp::Gte,
86 5,
87 ),
88 Condition::new("within_time_limit", "tick", CompareOp::Lte, 400),
89 ],
90 failure: vec![Condition::new(
91 "deadlock_detected",
92 "coordination.deadlock_count",
93 CompareOp::Gte,
94 3,
95 )],
96 on_timeout: TimeoutBehavior::MilestoneScore,
97 },
98 milestones: vec![
99 Milestone::new(
100 "first_collection",
101 Condition::new(
102 "first",
103 "environment.resources_collected",
104 CompareOp::Gte,
105 1,
106 ),
107 0.15,
108 )
109 .with_description("Collect the first resource"),
110 Milestone::new(
111 "half_collected",
112 Condition::new("half", "environment.resources_collected", CompareOp::Gte, 3),
113 0.25,
114 )
115 .with_description("Collect half of the resources"),
116 Milestone::new(
117 "efficiency_bonus",
118 Condition::new("efficiency", "tick", CompareOp::Lte, 300),
119 0.20,
120 )
121 .with_description("Complete within 300 ticks")
122 .with_partial(PartialConfig::Linear {
123 min: Some(300.0),
124 max: Some(400.0),
125 descending: true, }),
127 Milestone::new(
128 "all_collected",
129 Condition::new("all", "environment.resources_collected", CompareOp::Gte, 5),
130 0.40,
131 )
132 .with_description("Collect all resources"),
133 ],
134 variants: Vec::new(),
135 }
136}
137
138pub fn task_queue_processing() -> EvalScenario {
143 EvalScenario {
144 meta: ScenarioMeta {
145 name: "Task Queue Processing".to_string(),
146 version: "1.0.0".to_string(),
147 id: ScenarioId::new("builtin:task_queue:v1"),
148 description: "Process tasks from a queue with varying complexity".to_string(),
149 tags: vec![
150 "throughput".to_string(),
151 "latency".to_string(),
152 "basic".to_string(),
153 ],
154 },
155 task: TaskConfig::default(),
156 llm: LlmConfig::default(),
157 manager: ManagerConfig::default(),
158 batch_processor: BatchProcessorConfig::default(),
159 dependency_graph: None,
160 actions: ScenarioActions::default(),
161 app_config: AppConfigTemplate {
162 tick_duration_ms: 10,
163 max_ticks: 1000,
164 management_strategy: ManagementStrategyConfig::EventDriven {
165 triggers: vec!["task_completed".to_string(), "queue_empty".to_string()],
166 },
167 enable_exploration: false,
168 },
169 environment: EnvironmentConfig {
170 env_type: "task_queue".to_string(),
171 params: serde_json::json!({
172 "initial_tasks": 100,
173 "task_complexity": {
174 "min": 1,
175 "max": 10
176 },
177 "arrival_rate": 0.0 }),
179 initial_state: Some(InitialStateConfig::SeededRandom {}),
180 },
181 agents: AgentsConfig {
182 workers: vec![WorkerTemplate {
183 id_pattern: "processor_{i}".to_string(),
184 count: 4,
185 role: "processor".to_string(),
186 config: serde_json::json!({
187 "processing_speed": 1.0
188 }),
189 }],
190 managers: vec![ManagerTemplate {
191 id: Some("scheduler".to_string()),
192 id_pattern: None,
193 count: 1,
194 role: "scheduler".to_string(),
195 activation: ManagerActivationConfig::Event {
196 triggers: vec!["task_completed".to_string()],
197 },
198 config: serde_json::Value::Null,
199 }],
200 },
201 conditions: EvalConditions {
202 success: vec![Condition::new(
203 "all_tasks_processed",
204 "task.completed_count",
205 CompareOp::Gte,
206 100,
207 )],
208 failure: vec![Condition::new(
209 "task_timeout",
210 "task.timeout_count",
211 CompareOp::Gte,
212 10,
213 )],
214 on_timeout: TimeoutBehavior::PartialSuccess,
215 },
216 milestones: vec![
217 Milestone::new(
218 "quarter_processed",
219 Condition::new("quarter", "task.completed_count", CompareOp::Gte, 25),
220 0.10,
221 ),
222 Milestone::new(
223 "half_processed",
224 Condition::new("half", "task.completed_count", CompareOp::Gte, 50),
225 0.20,
226 ),
227 Milestone::new(
228 "three_quarter_processed",
229 Condition::new("three_quarter", "task.completed_count", CompareOp::Gte, 75),
230 0.30,
231 ),
232 Milestone::new(
233 "all_processed",
234 Condition::new("all", "task.completed_count", CompareOp::Gte, 100),
235 0.40,
236 ),
237 ],
238 variants: Vec::new(),
239 }
240}
241
242pub fn coordination_stress() -> EvalScenario {
247 EvalScenario {
248 meta: ScenarioMeta {
249 name: "Coordination Stress Test".to_string(),
250 version: "1.0.0".to_string(),
251 id: ScenarioId::new("builtin:coordination_stress:v1"),
252 description: "High-load scenario with many agents and frequent events".to_string(),
253 tags: vec![
254 "stress".to_string(),
255 "scalability".to_string(),
256 "advanced".to_string(),
257 ],
258 },
259 task: TaskConfig::default(),
260 llm: LlmConfig::default(),
261 manager: ManagerConfig::default(),
262 batch_processor: BatchProcessorConfig::default(),
263 dependency_graph: None,
264 actions: ScenarioActions::default(),
265 app_config: AppConfigTemplate {
266 tick_duration_ms: 5, max_ticks: 2000,
268 management_strategy: ManagementStrategyConfig::Hybrid {
269 max_interval: 10,
270 triggers: vec!["conflict".to_string(), "resource_contention".to_string()],
271 },
272 enable_exploration: false,
273 },
274 environment: EnvironmentConfig {
275 env_type: "multi_resource".to_string(),
276 params: serde_json::json!({
277 "width": 20,
278 "height": 20,
279 "resource_types": 3,
280 "resources_per_type": 10,
281 "dynamic_spawning": true,
282 "spawn_interval": 50
283 }),
284 initial_state: Some(InitialStateConfig::SeededRandom {}),
285 },
286 agents: AgentsConfig {
287 workers: vec![
288 WorkerTemplate {
289 id_pattern: "collector_a_{i}".to_string(),
290 count: 4,
291 role: "collector_type_a".to_string(),
292 config: serde_json::json!({
293 "target_resource": "type_a",
294 "speed": 1.2
295 }),
296 },
297 WorkerTemplate {
298 id_pattern: "collector_b_{i}".to_string(),
299 count: 4,
300 role: "collector_type_b".to_string(),
301 config: serde_json::json!({
302 "target_resource": "type_b",
303 "speed": 1.0
304 }),
305 },
306 WorkerTemplate {
307 id_pattern: "collector_c_{i}".to_string(),
308 count: 4,
309 role: "collector_type_c".to_string(),
310 config: serde_json::json!({
311 "target_resource": "type_c",
312 "speed": 0.8
313 }),
314 },
315 ],
316 managers: vec![
317 ManagerTemplate {
318 id: Some("global_coordinator".to_string()),
319 id_pattern: None,
320 count: 1,
321 role: "coordinator".to_string(),
322 activation: ManagerActivationConfig::Interval { interval: 20 },
323 config: serde_json::json!({
324 "strategy": "load_balancing"
325 }),
326 },
327 ManagerTemplate {
328 id: Some("conflict_resolver".to_string()),
329 id_pattern: None,
330 count: 1,
331 role: "resolver".to_string(),
332 activation: ManagerActivationConfig::Event {
333 triggers: vec!["conflict".to_string()],
334 },
335 config: serde_json::json!({
336 "strategy": "priority_based"
337 }),
338 },
339 ],
340 },
341 conditions: EvalConditions {
342 success: vec![
343 Condition::new(
344 "total_collected",
345 "environment.total_collected",
346 CompareOp::Gte,
347 50,
348 ),
349 Condition::new(
350 "low_conflict_rate",
351 "coordination.conflict_rate",
352 CompareOp::Lte,
353 0.1,
354 ),
355 ],
356 failure: vec![
357 Condition::new(
358 "system_overload",
359 "performance.tick_miss_rate",
360 CompareOp::Gte,
361 0.2,
362 ),
363 Condition::new(
364 "excessive_conflicts",
365 "coordination.conflict_count",
366 CompareOp::Gte,
367 100,
368 ),
369 ],
370 on_timeout: TimeoutBehavior::MilestoneScore,
371 },
372 milestones: vec![
373 Milestone::new(
374 "system_stable",
375 Condition::new("stable", "performance.tick_miss_rate", CompareOp::Lte, 0.05),
376 0.20,
377 )
378 .with_description("System remains stable under load"),
379 Milestone::new(
380 "efficient_coordination",
381 Condition::new(
382 "efficient",
383 "coordination.conflict_rate",
384 CompareOp::Lte,
385 0.05,
386 ),
387 0.25,
388 )
389 .with_description("Low conflict rate maintained"),
390 Milestone::new(
391 "good_throughput",
392 Condition::new(
393 "throughput",
394 "environment.total_collected",
395 CompareOp::Gte,
396 30,
397 ),
398 0.25,
399 )
400 .with_description("Achieve good throughput"),
401 Milestone::new(
402 "excellent_throughput",
403 Condition::new(
404 "excellent",
405 "environment.total_collected",
406 CompareOp::Gte,
407 50,
408 ),
409 0.30,
410 )
411 .with_description("Achieve excellent throughput"),
412 ],
413 variants: Vec::new(),
414 }
415}
416
417#[cfg(test)]
418mod tests {
419 use super::*;
420
421 #[test]
422 fn test_builtin_scenarios_exist() {
423 let scenarios = builtin_scenarios();
424 assert_eq!(scenarios.len(), 3);
425 }
426
427 #[test]
428 fn test_resource_gathering_scenario() {
429 let scenario = resource_gathering();
430 assert_eq!(scenario.meta.name, "Resource Gathering");
431 assert_eq!(scenario.agents.workers.len(), 1);
432 assert_eq!(scenario.agents.workers[0].count, 4);
433 assert_eq!(scenario.milestones.len(), 4);
434 }
435
436 #[test]
437 fn test_scenario_serialization_json() {
438 let scenario = resource_gathering();
440 let json_str = serde_json::to_string_pretty(&scenario).unwrap();
441
442 let deserialized: EvalScenario = serde_json::from_str(&json_str).unwrap();
444 assert_eq!(deserialized.meta.name, scenario.meta.name);
445 assert_eq!(deserialized.milestones.len(), scenario.milestones.len());
446 }
447
448 #[test]
449 fn test_scenario_ids_unique() {
450 let scenarios = builtin_scenarios();
451 let ids: std::collections::HashSet<_> = scenarios.iter().map(|s| &s.meta.id).collect();
452 assert_eq!(ids.len(), scenarios.len(), "Scenario IDs must be unique");
453 }
454}