use std::time::Duration;
use chrono::Utc;
use terraphim_agent_evolution::{
workflows::{WorkflowInput, WorkflowParameters, WorkflowPattern},
*,
};
struct TestDataFactory;
impl TestDataFactory {
fn create_simple_workflow_input() -> WorkflowInput {
WorkflowInput {
task_id: "simple_task".to_string(),
agent_id: "test_agent".to_string(),
prompt: "What is the capital of France?".to_string(),
context: None,
parameters: WorkflowParameters::default(),
timestamp: Utc::now(),
}
}
fn create_complex_workflow_input() -> WorkflowInput {
WorkflowInput {
task_id: "complex_task".to_string(),
agent_id: "test_agent".to_string(),
prompt: "Analyze the comprehensive economic, social, and environmental impacts of renewable energy adoption in developing countries, including policy recommendations".to_string(),
context: Some("Focus on solar and wind energy technologies".to_string()),
parameters: WorkflowParameters::default(),
timestamp: Utc::now(),
}
}
fn create_comparison_workflow_input() -> WorkflowInput {
WorkflowInput {
task_id: "comparison_task".to_string(),
agent_id: "test_agent".to_string(),
prompt: "Compare and contrast React vs Vue.js for building modern web applications"
.to_string(),
context: None,
parameters: WorkflowParameters::default(),
timestamp: Utc::now(),
}
}
fn create_research_workflow_input() -> WorkflowInput {
WorkflowInput {
task_id: "research_task".to_string(),
agent_id: "test_agent".to_string(),
prompt: "Research and analyze the current state of quantum computing technology and its potential applications in cryptography".to_string(),
context: Some("Include both theoretical foundations and practical implementations".to_string()),
parameters: WorkflowParameters::default(),
timestamp: Utc::now(),
}
}
fn create_quality_critical_workflow_input() -> WorkflowInput {
WorkflowInput {
task_id: "quality_critical_task".to_string(),
agent_id: "test_agent".to_string(),
prompt: "Write a formal research proposal for investigating the effects of artificial intelligence on healthcare outcomes".to_string(),
context: Some("Must meet academic standards with proper methodology and citations".to_string()),
parameters: WorkflowParameters::default(),
timestamp: Utc::now(),
}
}
fn create_step_by_step_workflow_input() -> WorkflowInput {
WorkflowInput {
task_id: "step_by_step_task".to_string(),
agent_id: "test_agent".to_string(),
prompt: "Analyze the quarterly sales data and provide actionable recommendations for improving performance".to_string(),
context: Some("Break down the analysis into clear steps with supporting data".to_string()),
parameters: WorkflowParameters::default(),
timestamp: Utc::now(),
}
}
}
#[tokio::test]
async fn test_prompt_chaining_analysis_e2e() {
let adapter = LlmAdapterFactory::create_mock("test");
let chaining = workflows::prompt_chaining::PromptChaining::new(adapter);
let workflow_input = TestDataFactory::create_step_by_step_workflow_input();
let result = chaining.execute(workflow_input).await.unwrap();
assert!(result.metadata.success);
assert_eq!(result.metadata.pattern_used, "prompt_chaining");
eprintln!(
"DEBUG: Analysis execution trace length: {}",
result.execution_trace.len()
);
eprintln!(
"DEBUG: Analysis step IDs: {:?}",
result
.execution_trace
.iter()
.map(|s| &s.step_id)
.collect::<Vec<_>>()
);
assert!(result.execution_trace.len() >= 2); assert!(result.execution_trace.iter().all(|step| step.success));
assert!(result.metadata.quality_score.unwrap_or(0.0) > 0.0);
assert!(result.metadata.execution_time > Duration::from_millis(0));
assert!(!result.result.is_empty());
assert!(result.result.len() > 50); }
#[tokio::test]
async fn test_prompt_chaining_context_preservation() {
let adapter = LlmAdapterFactory::create_mock("test");
let config = workflows::prompt_chaining::ChainConfig {
max_chain_length: 3,
preserve_context: true,
quality_check: true,
step_timeout: Duration::from_secs(30),
};
let chaining = workflows::prompt_chaining::PromptChaining::with_config(adapter, config);
let workflow_input = TestDataFactory::create_complex_workflow_input();
let result = chaining.execute(workflow_input).await.unwrap();
assert!(result.metadata.success);
assert!(result.execution_trace.len() >= 2);
for i in 1..result.execution_trace.len() {
let current_step = &result.execution_trace[i];
assert!(current_step.success);
assert!(!current_step.input.is_empty());
}
}
#[tokio::test]
async fn test_prompt_chaining_generation_chain() {
let adapter = LlmAdapterFactory::create_mock("test");
let chaining = workflows::prompt_chaining::PromptChaining::new(adapter);
let generation_input = WorkflowInput {
task_id: "generation_task".to_string(),
agent_id: "test_agent".to_string(),
prompt: "Generate a comprehensive marketing strategy for a new sustainable product"
.to_string(),
context: None,
parameters: WorkflowParameters::default(),
timestamp: Utc::now(),
};
let result = chaining.execute(generation_input).await.unwrap();
assert!(result.metadata.success);
assert!(result.execution_trace.len() >= 2);
let step_ids: Vec<_> = result.execution_trace.iter().map(|s| &s.step_id).collect();
assert!(
step_ids
.iter()
.any(|id| id.contains("understand_task") || id.contains("execute_task"))
);
}
#[tokio::test]
async fn test_routing_simple_task_optimization() {
let primary_adapter = LlmAdapterFactory::create_mock("primary");
let routing = workflows::routing::Routing::new(primary_adapter)
.add_route("fast".to_string(), LlmAdapterFactory::create_mock("fast"))
.add_route(
"accurate".to_string(),
LlmAdapterFactory::create_mock("accurate"),
);
let simple_input = TestDataFactory::create_simple_workflow_input();
let result = routing.execute(simple_input).await.unwrap();
assert!(result.metadata.success);
assert_eq!(result.metadata.pattern_used, "routing");
assert!(result.execution_trace.len() >= 2); assert!(
result
.execution_trace
.iter()
.any(|s| s.step_id == "route_selection")
);
assert!(
result
.execution_trace
.iter()
.any(|s| s.step_id == "task_execution")
);
assert!(result.metadata.resources_used.llm_calls <= 2);
}
#[tokio::test]
async fn test_routing_complex_task_quality_focus() {
let primary_adapter = LlmAdapterFactory::create_mock("primary");
let _config = workflows::routing::RouteConfig {
enable_cost_optimization: true,
enable_performance_routing: true,
enable_domain_routing: true,
fallback_enabled: true,
routing_timeout: Duration::from_secs(30),
};
let routing = workflows::routing::Routing::new(primary_adapter)
.add_route(
"openai_gpt35".to_string(),
LlmAdapterFactory::create_mock("basic"),
)
.add_route(
"openai_gpt4".to_string(),
LlmAdapterFactory::create_mock("premium"),
);
let complex_input = TestDataFactory::create_complex_workflow_input();
let result = routing.execute(complex_input).await.unwrap();
assert!(result.metadata.success);
assert!(result.metadata.quality_score.unwrap_or(0.0) > 0.7);
}
#[tokio::test]
async fn test_routing_fallback_strategy() {
let primary_adapter = LlmAdapterFactory::create_mock("primary");
let routing = workflows::routing::Routing::new(primary_adapter).add_route(
"fallback".to_string(),
LlmAdapterFactory::create_mock("fallback"),
);
let workflow_input = TestDataFactory::create_simple_workflow_input();
let result = routing.execute(workflow_input).await.unwrap();
assert!(result.metadata.success);
assert!(
result
.execution_trace
.iter()
.any(|s| s.step_id.contains("route_selection"))
);
}
#[tokio::test]
async fn test_parallelization_comparison_task_e2e() {
let adapter = LlmAdapterFactory::create_mock("test");
let _config = workflows::parallelization::ParallelConfig {
max_parallel_tasks: 3,
task_timeout: Duration::from_secs(60),
aggregation_strategy: workflows::parallelization::AggregationStrategy::Synthesis,
failure_threshold: 0.5,
retry_failed_tasks: false,
};
let parallelization = workflows::parallelization::Parallelization::new(adapter);
let comparison_input = TestDataFactory::create_comparison_workflow_input();
let result = parallelization.execute(comparison_input).await.unwrap();
assert!(result.metadata.success);
assert_eq!(result.metadata.pattern_used, "parallelization");
assert!(result.execution_trace.len() >= 3);
assert!(
result
.execution_trace
.iter()
.any(|s| matches!(s.step_type, workflows::StepType::Parallel))
);
assert!(
result
.execution_trace
.iter()
.any(|s| matches!(s.step_type, workflows::StepType::Aggregation))
);
let task_descriptions: Vec<_> = result.execution_trace.iter().map(|s| &s.step_id).collect();
assert!(
task_descriptions
.iter()
.any(|id| id.contains("analysis_perspective")
|| id.contains("practical_perspective")
|| id.contains("creative_perspective"))
);
assert!(result.metadata.resources_used.parallel_tasks >= 2);
}
#[tokio::test]
async fn test_parallelization_research_decomposition() {
let adapter = LlmAdapterFactory::create_mock("test");
let parallelization = workflows::parallelization::Parallelization::new(adapter);
let research_input = TestDataFactory::create_research_workflow_input();
let result = parallelization.execute(research_input).await.unwrap();
assert!(result.metadata.success);
assert!(result.execution_trace.len() >= 4);
let step_ids: Vec<_> = result.execution_trace.iter().map(|s| &s.step_id).collect();
eprintln!("DEBUG: Research step IDs: {:?}", step_ids);
assert!(step_ids.iter().any(|id| id.contains("analysis_perspective")
|| id.contains("practical_perspective")
|| id.contains("creative_perspective")));
}
#[tokio::test]
async fn test_parallelization_aggregation_strategies() {
let adapter = LlmAdapterFactory::create_mock("test");
let strategies = vec![
workflows::parallelization::AggregationStrategy::Concatenation,
workflows::parallelization::AggregationStrategy::BestResult,
workflows::parallelization::AggregationStrategy::StructuredCombination,
];
for strategy in strategies {
let _config = workflows::parallelization::ParallelConfig {
aggregation_strategy: strategy.clone(),
..Default::default()
};
let parallelization = workflows::parallelization::Parallelization::new(adapter.clone());
let workflow_input = TestDataFactory::create_comparison_workflow_input();
let result = parallelization.execute(workflow_input).await.unwrap();
assert!(result.metadata.success);
assert!(!result.result.is_empty());
assert!(
result
.execution_trace
.iter()
.any(|s| matches!(s.step_type, workflows::StepType::Aggregation))
);
}
}
#[tokio::test]
async fn test_orchestrator_workers_sequential_execution() {
let orchestrator_adapter = LlmAdapterFactory::create_mock("orchestrator");
let orchestrator =
workflows::orchestrator_workers::OrchestratorWorkers::new(orchestrator_adapter)
.add_worker(
workflows::orchestrator_workers::WorkerRole::Analyst,
LlmAdapterFactory::create_mock("analyst"),
)
.add_worker(
workflows::orchestrator_workers::WorkerRole::Writer,
LlmAdapterFactory::create_mock("writer"),
)
.add_worker(
workflows::orchestrator_workers::WorkerRole::Reviewer,
LlmAdapterFactory::create_mock("reviewer"),
);
let complex_input = TestDataFactory::create_complex_workflow_input();
let result = orchestrator.execute(complex_input).await.unwrap();
assert!(result.metadata.success);
assert_eq!(result.metadata.pattern_used, "orchestrator_workers");
assert!(
result
.execution_trace
.iter()
.any(|s| s.step_id == "orchestrator_planning")
);
let worker_steps: Vec<_> = result
.execution_trace
.iter()
.filter(|s| s.step_id.contains("task"))
.collect();
assert!(worker_steps.len() >= 3);
assert!(
result
.execution_trace
.iter()
.any(|s| s.step_id == "final_synthesis")
);
assert!(result.metadata.resources_used.llm_calls >= 4); }
#[tokio::test]
async fn test_orchestrator_workers_parallel_coordinated() {
let orchestrator_adapter = LlmAdapterFactory::create_mock("orchestrator");
let _config = workflows::orchestrator_workers::OrchestrationConfig {
coordination_strategy:
workflows::orchestrator_workers::CoordinationStrategy::ParallelCoordinated,
max_workers: 5,
quality_gate_threshold: 0.7,
..Default::default()
};
let orchestrator =
workflows::orchestrator_workers::OrchestratorWorkers::new(orchestrator_adapter)
.add_worker(
workflows::orchestrator_workers::WorkerRole::Researcher,
LlmAdapterFactory::create_mock("researcher"),
)
.add_worker(
workflows::orchestrator_workers::WorkerRole::Analyst,
LlmAdapterFactory::create_mock("analyst"),
)
.add_worker(
workflows::orchestrator_workers::WorkerRole::Synthesizer,
LlmAdapterFactory::create_mock("synthesizer"),
);
let research_input = TestDataFactory::create_research_workflow_input();
let result = orchestrator.execute(research_input).await.unwrap();
assert!(result.metadata.success);
assert!(result.metadata.execution_time < Duration::from_secs(300));
let parallel_steps = result
.execution_trace
.iter()
.filter(|s| s.step_id.contains("task"))
.count();
assert!(parallel_steps >= 2);
}
#[tokio::test]
async fn test_orchestrator_workers_quality_gate() {
let orchestrator_adapter = LlmAdapterFactory::create_mock("orchestrator");
let _config = workflows::orchestrator_workers::OrchestrationConfig {
quality_gate_threshold: 0.8, enable_worker_feedback: true,
..Default::default()
};
let orchestrator =
workflows::orchestrator_workers::OrchestratorWorkers::new(orchestrator_adapter)
.add_worker(
workflows::orchestrator_workers::WorkerRole::Writer,
LlmAdapterFactory::create_mock("writer"),
)
.add_worker(
workflows::orchestrator_workers::WorkerRole::Reviewer,
LlmAdapterFactory::create_mock("reviewer"),
);
let quality_input = TestDataFactory::create_quality_critical_workflow_input();
let result = orchestrator.execute(quality_input).await.unwrap();
assert!(result.metadata.success);
assert!(result.metadata.quality_score.unwrap_or(0.0) >= 0.7);
assert!(
result
.execution_trace
.iter()
.any(|s| s.step_id.contains("review") || s.step_id.contains("quality"))
);
}
#[tokio::test]
async fn test_evaluator_optimizer_iterative_improvement() {
let adapter = LlmAdapterFactory::create_mock("test");
let _config = workflows::evaluator_optimizer::OptimizationConfig {
max_iterations: 3,
quality_threshold: 0.85,
improvement_threshold: 0.05,
evaluation_criteria: vec![
workflows::evaluator_optimizer::EvaluationCriterion::Accuracy,
workflows::evaluator_optimizer::EvaluationCriterion::Completeness,
workflows::evaluator_optimizer::EvaluationCriterion::Clarity,
],
optimization_strategy: workflows::evaluator_optimizer::OptimizationStrategy::Incremental,
early_stopping: true,
};
let evaluator = workflows::evaluator_optimizer::EvaluatorOptimizer::new(adapter);
let quality_critical_input = TestDataFactory::create_quality_critical_workflow_input();
let result = evaluator.execute(quality_critical_input).await.unwrap();
assert!(result.metadata.success);
assert_eq!(result.metadata.pattern_used, "evaluator_optimizer");
assert!(!result.execution_trace.is_empty()); assert!(
result
.execution_trace
.iter()
.any(|s| s.step_id == "initial_generation")
);
assert!(result.metadata.quality_score.unwrap_or(0.0) > 0.7);
}
#[tokio::test]
async fn test_evaluator_optimizer_early_stopping() {
let adapter = LlmAdapterFactory::create_mock("high_quality"); let _config = workflows::evaluator_optimizer::OptimizationConfig {
max_iterations: 5,
quality_threshold: 0.7, early_stopping: true,
..Default::default()
};
let evaluator = workflows::evaluator_optimizer::EvaluatorOptimizer::new(adapter);
let workflow_input = TestDataFactory::create_simple_workflow_input();
let result = evaluator.execute(workflow_input).await.unwrap();
assert!(result.metadata.success);
assert!(result.execution_trace.len() <= 3); assert!(result.metadata.quality_score.unwrap_or(0.0) >= 0.7);
}
#[tokio::test]
async fn test_evaluator_optimizer_max_iterations() {
let adapter = LlmAdapterFactory::create_mock("test");
let _config = workflows::evaluator_optimizer::OptimizationConfig {
max_iterations: 2, quality_threshold: 0.95, early_stopping: false,
..Default::default()
};
let evaluator = workflows::evaluator_optimizer::EvaluatorOptimizer::new(adapter);
let workflow_input = TestDataFactory::create_complex_workflow_input();
let result = evaluator.execute(workflow_input).await.unwrap();
assert!(result.metadata.success);
let optimization_iterations = result
.execution_trace
.iter()
.filter(|s| s.step_id.contains("optimization_iteration"))
.count();
assert!(optimization_iterations <= 2);
}
#[tokio::test]
async fn test_evaluator_optimizer_different_strategies() {
let adapter = LlmAdapterFactory::create_mock("test");
let strategies = vec![
workflows::evaluator_optimizer::OptimizationStrategy::Incremental,
workflows::evaluator_optimizer::OptimizationStrategy::Adaptive,
workflows::evaluator_optimizer::OptimizationStrategy::Complete,
];
for strategy in strategies {
let _config = workflows::evaluator_optimizer::OptimizationConfig {
optimization_strategy: strategy.clone(),
max_iterations: 2,
..Default::default()
};
let evaluator = workflows::evaluator_optimizer::EvaluatorOptimizer::new(adapter.clone());
let workflow_input = TestDataFactory::create_quality_critical_workflow_input();
let result = evaluator.execute(workflow_input).await.unwrap();
assert!(result.metadata.success);
assert!(!result.result.is_empty());
assert!(result.metadata.quality_score.unwrap_or(0.0) > 0.0);
}
}
#[tokio::test]
async fn test_evolution_workflow_manager_integration() {
let mut manager = EvolutionWorkflowManager::new("e2e_test_agent".to_string());
let simple_result = manager
.execute_task(
"simple_integration".to_string(),
"What is 2 + 2?".to_string(),
None,
)
.await
.unwrap();
let complex_result = manager
.execute_task(
"complex_integration".to_string(),
"Analyze the impact of machine learning on software development productivity"
.to_string(),
Some("Include both benefits and challenges".to_string()),
)
.await
.unwrap();
assert!(!simple_result.is_empty());
assert!(!complex_result.is_empty());
let evolution_system = manager.evolution_system();
let tasks_state = &&evolution_system.tasks.current_state;
assert_eq!(tasks_state.completed_tasks(), 2);
let lessons_state = &&evolution_system.lessons.current_state;
assert!(!lessons_state.success_patterns.is_empty());
let memory_state = &&evolution_system.memory.current_state;
assert!(!memory_state.short_term.is_empty());
}
#[tokio::test]
async fn test_pattern_selection_logic() {
let mut manager = EvolutionWorkflowManager::new("pattern_selection_agent".to_string());
let test_cases = vec![
("Simple question", "What is the weather like?"),
(
"Step-by-step analysis",
"Analyze this data step by step and provide recommendations",
),
(
"Comparison task",
"Compare and contrast Python vs JavaScript for web development",
),
(
"Complex research",
"Research the comprehensive impact of AI on healthcare systems",
),
(
"Quality-critical writing",
"Write a formal academic paper on climate change effects",
),
];
for (description, prompt) in test_cases {
let result = manager
.execute_task(
format!("test_{}", description.replace(" ", "_")),
prompt.to_string(),
None,
)
.await;
assert!(result.is_ok(), "Failed for task: {}", description);
let result = result.unwrap();
assert!(!result.is_empty(), "Empty result for task: {}", description);
}
let lessons = &manager.evolution_system().lessons.current_state;
assert!(lessons.success_patterns.len() >= 3); }
#[tokio::test]
async fn test_workflow_performance_characteristics() {
use std::time::Instant;
let mut manager = EvolutionWorkflowManager::new("performance_test_agent".to_string());
let start_simple = Instant::now();
let simple_result = manager
.execute_task("perf_simple".to_string(), "Hello".to_string(), None)
.await
.unwrap();
let simple_duration = start_simple.elapsed();
let start_complex = Instant::now();
let complex_result = manager.execute_task(
"perf_complex".to_string(),
"Perform a comprehensive analysis of global economic trends and their implications for emerging markets".to_string(),
None,
).await.unwrap();
let complex_duration = start_complex.elapsed();
assert!(!simple_result.is_empty());
assert!(!complex_result.is_empty());
assert!(simple_duration < Duration::from_secs(10)); assert!(complex_duration < Duration::from_secs(60));
println!("Simple task took: {:?}", simple_duration);
println!("Complex task took: {:?}", complex_duration);
}
#[tokio::test]
async fn test_error_handling_and_recovery() {
let adapter = LlmAdapterFactory::create_mock("test");
let empty_input = WorkflowInput {
task_id: "empty_test".to_string(),
agent_id: "test_agent".to_string(),
prompt: "".to_string(),
context: None,
parameters: WorkflowParameters::default(),
timestamp: Utc::now(),
};
let patterns: Vec<Box<dyn WorkflowPattern>> = vec![
Box::new(workflows::prompt_chaining::PromptChaining::new(
adapter.clone(),
)),
Box::new(workflows::routing::Routing::new(adapter.clone())),
Box::new(workflows::parallelization::Parallelization::new(
adapter.clone(),
)),
Box::new(workflows::orchestrator_workers::OrchestratorWorkers::new(
adapter.clone(),
)),
Box::new(workflows::evaluator_optimizer::EvaluatorOptimizer::new(
adapter.clone(),
)),
];
for pattern in patterns {
let result = pattern.execute(empty_input.clone()).await;
match result {
Ok(output) => {
assert!(output.metadata.success || !output.result.is_empty());
}
Err(e) => {
assert!(!e.to_string().is_empty());
}
}
}
}