use super::conditions::{CompareOp, Condition, EvalConditions, TimeoutBehavior};
use super::milestone::{Milestone, PartialConfig};
use super::types::*;
pub fn builtin_scenarios() -> Vec<EvalScenario> {
vec![
resource_gathering(),
task_queue_processing(),
coordination_stress(),
]
}
pub fn resource_gathering() -> EvalScenario {
EvalScenario {
meta: ScenarioMeta {
name: "Resource Gathering".to_string(),
version: "1.0.0".to_string(),
id: ScenarioId::new("builtin:resource_gathering:v1"),
description: "Multiple agents coordinate to collect resources in a grid world"
.to_string(),
tags: vec![
"coordination".to_string(),
"basic".to_string(),
"resource".to_string(),
],
},
task: TaskConfig::default(),
llm: LlmConfig::default(),
manager: ManagerConfig::default(),
batch_processor: BatchProcessorConfig::default(),
dependency_graph: None,
actions: ScenarioActions::default(),
app_config: AppConfigTemplate {
tick_duration_ms: 10,
max_ticks: 500,
management_strategy: ManagementStrategyConfig::IntervalBased { max_interval: 20 },
enable_exploration: false,
},
environment: EnvironmentConfig {
env_type: "grid_world".to_string(),
params: serde_json::json!({
"width": 10,
"height": 10,
"resource_count": 5,
"obstacle_density": 0.1
}),
initial_state: Some(InitialStateConfig::SeededRandom {}),
},
agents: AgentsConfig {
workers: vec![WorkerTemplate {
id_pattern: "gatherer_{i}".to_string(),
count: 4,
role: "gatherer".to_string(),
config: serde_json::json!({
"speed": 1.0,
"capacity": 2
}),
}],
managers: vec![ManagerTemplate {
id: Some("coordinator".to_string()),
id_pattern: None,
count: 1,
role: "coordinator".to_string(),
activation: ManagerActivationConfig::Hybrid {
interval: 10,
triggers: vec!["resource_found".to_string(), "collision".to_string()],
},
config: serde_json::Value::Null,
}],
},
conditions: EvalConditions {
success: vec![
Condition::new(
"all_resources_collected",
"environment.resources_collected",
CompareOp::Gte,
5,
),
Condition::new("within_time_limit", "tick", CompareOp::Lte, 400),
],
failure: vec![Condition::new(
"deadlock_detected",
"coordination.deadlock_count",
CompareOp::Gte,
3,
)],
on_timeout: TimeoutBehavior::MilestoneScore,
},
milestones: vec![
Milestone::new(
"first_collection",
Condition::new(
"first",
"environment.resources_collected",
CompareOp::Gte,
1,
),
0.15,
)
.with_description("Collect the first resource"),
Milestone::new(
"half_collected",
Condition::new("half", "environment.resources_collected", CompareOp::Gte, 3),
0.25,
)
.with_description("Collect half of the resources"),
Milestone::new(
"efficiency_bonus",
Condition::new("efficiency", "tick", CompareOp::Lte, 300),
0.20,
)
.with_description("Complete within 300 ticks")
.with_partial(PartialConfig::Linear {
min: Some(300.0),
max: Some(400.0),
descending: true, }),
Milestone::new(
"all_collected",
Condition::new("all", "environment.resources_collected", CompareOp::Gte, 5),
0.40,
)
.with_description("Collect all resources"),
],
variants: Vec::new(),
}
}
pub fn task_queue_processing() -> EvalScenario {
EvalScenario {
meta: ScenarioMeta {
name: "Task Queue Processing".to_string(),
version: "1.0.0".to_string(),
id: ScenarioId::new("builtin:task_queue:v1"),
description: "Process tasks from a queue with varying complexity".to_string(),
tags: vec![
"throughput".to_string(),
"latency".to_string(),
"basic".to_string(),
],
},
task: TaskConfig::default(),
llm: LlmConfig::default(),
manager: ManagerConfig::default(),
batch_processor: BatchProcessorConfig::default(),
dependency_graph: None,
actions: ScenarioActions::default(),
app_config: AppConfigTemplate {
tick_duration_ms: 10,
max_ticks: 1000,
management_strategy: ManagementStrategyConfig::EventDriven {
triggers: vec!["task_completed".to_string(), "queue_empty".to_string()],
},
enable_exploration: false,
},
environment: EnvironmentConfig {
env_type: "task_queue".to_string(),
params: serde_json::json!({
"initial_tasks": 100,
"task_complexity": {
"min": 1,
"max": 10
},
"arrival_rate": 0.0 }),
initial_state: Some(InitialStateConfig::SeededRandom {}),
},
agents: AgentsConfig {
workers: vec![WorkerTemplate {
id_pattern: "processor_{i}".to_string(),
count: 4,
role: "processor".to_string(),
config: serde_json::json!({
"processing_speed": 1.0
}),
}],
managers: vec![ManagerTemplate {
id: Some("scheduler".to_string()),
id_pattern: None,
count: 1,
role: "scheduler".to_string(),
activation: ManagerActivationConfig::Event {
triggers: vec!["task_completed".to_string()],
},
config: serde_json::Value::Null,
}],
},
conditions: EvalConditions {
success: vec![Condition::new(
"all_tasks_processed",
"task.completed_count",
CompareOp::Gte,
100,
)],
failure: vec![Condition::new(
"task_timeout",
"task.timeout_count",
CompareOp::Gte,
10,
)],
on_timeout: TimeoutBehavior::PartialSuccess,
},
milestones: vec![
Milestone::new(
"quarter_processed",
Condition::new("quarter", "task.completed_count", CompareOp::Gte, 25),
0.10,
),
Milestone::new(
"half_processed",
Condition::new("half", "task.completed_count", CompareOp::Gte, 50),
0.20,
),
Milestone::new(
"three_quarter_processed",
Condition::new("three_quarter", "task.completed_count", CompareOp::Gte, 75),
0.30,
),
Milestone::new(
"all_processed",
Condition::new("all", "task.completed_count", CompareOp::Gte, 100),
0.40,
),
],
variants: Vec::new(),
}
}
pub fn coordination_stress() -> EvalScenario {
EvalScenario {
meta: ScenarioMeta {
name: "Coordination Stress Test".to_string(),
version: "1.0.0".to_string(),
id: ScenarioId::new("builtin:coordination_stress:v1"),
description: "High-load scenario with many agents and frequent events".to_string(),
tags: vec![
"stress".to_string(),
"scalability".to_string(),
"advanced".to_string(),
],
},
task: TaskConfig::default(),
llm: LlmConfig::default(),
manager: ManagerConfig::default(),
batch_processor: BatchProcessorConfig::default(),
dependency_graph: None,
actions: ScenarioActions::default(),
app_config: AppConfigTemplate {
tick_duration_ms: 5, max_ticks: 2000,
management_strategy: ManagementStrategyConfig::Hybrid {
max_interval: 10,
triggers: vec!["conflict".to_string(), "resource_contention".to_string()],
},
enable_exploration: false,
},
environment: EnvironmentConfig {
env_type: "multi_resource".to_string(),
params: serde_json::json!({
"width": 20,
"height": 20,
"resource_types": 3,
"resources_per_type": 10,
"dynamic_spawning": true,
"spawn_interval": 50
}),
initial_state: Some(InitialStateConfig::SeededRandom {}),
},
agents: AgentsConfig {
workers: vec![
WorkerTemplate {
id_pattern: "collector_a_{i}".to_string(),
count: 4,
role: "collector_type_a".to_string(),
config: serde_json::json!({
"target_resource": "type_a",
"speed": 1.2
}),
},
WorkerTemplate {
id_pattern: "collector_b_{i}".to_string(),
count: 4,
role: "collector_type_b".to_string(),
config: serde_json::json!({
"target_resource": "type_b",
"speed": 1.0
}),
},
WorkerTemplate {
id_pattern: "collector_c_{i}".to_string(),
count: 4,
role: "collector_type_c".to_string(),
config: serde_json::json!({
"target_resource": "type_c",
"speed": 0.8
}),
},
],
managers: vec![
ManagerTemplate {
id: Some("global_coordinator".to_string()),
id_pattern: None,
count: 1,
role: "coordinator".to_string(),
activation: ManagerActivationConfig::Interval { interval: 20 },
config: serde_json::json!({
"strategy": "load_balancing"
}),
},
ManagerTemplate {
id: Some("conflict_resolver".to_string()),
id_pattern: None,
count: 1,
role: "resolver".to_string(),
activation: ManagerActivationConfig::Event {
triggers: vec!["conflict".to_string()],
},
config: serde_json::json!({
"strategy": "priority_based"
}),
},
],
},
conditions: EvalConditions {
success: vec![
Condition::new(
"total_collected",
"environment.total_collected",
CompareOp::Gte,
50,
),
Condition::new(
"low_conflict_rate",
"coordination.conflict_rate",
CompareOp::Lte,
0.1,
),
],
failure: vec![
Condition::new(
"system_overload",
"performance.tick_miss_rate",
CompareOp::Gte,
0.2,
),
Condition::new(
"excessive_conflicts",
"coordination.conflict_count",
CompareOp::Gte,
100,
),
],
on_timeout: TimeoutBehavior::MilestoneScore,
},
milestones: vec![
Milestone::new(
"system_stable",
Condition::new("stable", "performance.tick_miss_rate", CompareOp::Lte, 0.05),
0.20,
)
.with_description("System remains stable under load"),
Milestone::new(
"efficient_coordination",
Condition::new(
"efficient",
"coordination.conflict_rate",
CompareOp::Lte,
0.05,
),
0.25,
)
.with_description("Low conflict rate maintained"),
Milestone::new(
"good_throughput",
Condition::new(
"throughput",
"environment.total_collected",
CompareOp::Gte,
30,
),
0.25,
)
.with_description("Achieve good throughput"),
Milestone::new(
"excellent_throughput",
Condition::new(
"excellent",
"environment.total_collected",
CompareOp::Gte,
50,
),
0.30,
)
.with_description("Achieve excellent throughput"),
],
variants: Vec::new(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builtin_scenarios_exist() {
let scenarios = builtin_scenarios();
assert_eq!(scenarios.len(), 3);
}
#[test]
fn test_resource_gathering_scenario() {
let scenario = resource_gathering();
assert_eq!(scenario.meta.name, "Resource Gathering");
assert_eq!(scenario.agents.workers.len(), 1);
assert_eq!(scenario.agents.workers[0].count, 4);
assert_eq!(scenario.milestones.len(), 4);
}
#[test]
fn test_scenario_serialization_json() {
let scenario = resource_gathering();
let json_str = serde_json::to_string_pretty(&scenario).unwrap();
let deserialized: EvalScenario = serde_json::from_str(&json_str).unwrap();
assert_eq!(deserialized.meta.name, scenario.meta.name);
assert_eq!(deserialized.milestones.len(), scenario.milestones.len());
}
#[test]
fn test_scenario_ids_unique() {
let scenarios = builtin_scenarios();
let ids: std::collections::HashSet<_> = scenarios.iter().map(|s| &s.meta.id).collect();
assert_eq!(ids.len(), scenarios.len(), "Scenario IDs must be unique");
}
}