"""
Farnsworth Evolution Tools - MCP Tool Implementations for Evolution Operations
Provides evolution and feedback capabilities:
- Fitness tracking and feedback
- Evolution metrics
- System improvement triggers
"""
from dataclasses import dataclass
from typing import Optional, Any
from datetime import datetime
from loguru import logger
@dataclass
class EvolutionToolResult:
"""Result from an evolution tool operation."""
success: bool
data: Any = None
error: Optional[str] = None
def to_dict(self) -> dict:
result = {"success": self.success}
if self.data is not None:
result["data"] = self.data
if self.error:
result["error"] = self.error
return result
class EvolutionTools:
"""
Evolution tool implementations for the MCP server.
Provides access to the evolution system for feedback and improvement.
"""
def __init__(self, fitness_tracker, genetic_optimizer=None, behavior_mutator=None):
self.fitness = fitness_tracker
self.optimizer = genetic_optimizer
self.mutator = behavior_mutator
async def record_feedback(
self,
feedback_type: str,
value: float,
context: Optional[dict] = None,
) -> EvolutionToolResult:
"""
Record explicit feedback for system improvement.
Args:
feedback_type: Type of feedback ("satisfaction", "quality", "speed")
value: Feedback value (0-1 scale)
context: Optional context about the feedback
Returns:
EvolutionToolResult
"""
try:
# Map feedback types to internal metrics
metric_map = {
"satisfaction": "user_satisfaction",
"quality": "task_success",
"speed": "efficiency",
"helpfulness": "user_satisfaction",
"accuracy": "task_success",
}
metric_name = metric_map.get(feedback_type, feedback_type)
self.fitness.record(metric_name, value)
return EvolutionToolResult(
success=True,
data={
"recorded": True,
"metric": metric_name,
"value": value,
"current_fitness": self.fitness.get_weighted_fitness(),
},
)
except Exception as e:
logger.error(f"Record feedback failed: {e}")
return EvolutionToolResult(success=False, error=str(e))
async def record_task_result(
self,
success: bool,
tokens_used: int = 0,
time_seconds: float = 0.0,
user_rating: Optional[float] = None,
) -> EvolutionToolResult:
"""
Record a task completion result for fitness tracking.
Args:
success: Whether the task was successful
tokens_used: Number of tokens consumed
time_seconds: Task execution time
user_rating: Optional user rating (0-1)
Returns:
EvolutionToolResult
"""
try:
self.fitness.record_task_outcome(
success=success,
tokens_used=tokens_used,
time_seconds=time_seconds,
user_feedback=user_rating,
)
return EvolutionToolResult(
success=True,
data={
"recorded": True,
"current_fitness": self.fitness.get_current_fitness(),
},
)
except Exception as e:
logger.error(f"Record task result failed: {e}")
return EvolutionToolResult(success=False, error=str(e))
async def get_fitness_metrics(self) -> EvolutionToolResult:
"""
Get current fitness metrics and trends.
Returns:
EvolutionToolResult with fitness data
"""
try:
stats = self.fitness.get_stats()
return EvolutionToolResult(
success=True,
data={
"current_fitness": self.fitness.get_current_fitness(),
"weighted_fitness": self.fitness.get_weighted_fitness(),
"metrics": stats.get("current_fitness", {}),
"trends": stats.get("trends", {}),
"sample_counts": stats.get("sample_counts", {}),
},
)
except Exception as e:
logger.error(f"Get fitness metrics failed: {e}")
return EvolutionToolResult(success=False, error=str(e))
async def get_leaderboard(self, top_k: int = 10) -> EvolutionToolResult:
"""
Get top performing configurations/genomes.
Returns:
EvolutionToolResult with leaderboard
"""
try:
leaderboard = self.fitness.get_leaderboard(top_k)
return EvolutionToolResult(
success=True,
data={
"leaderboard": [
{"genome_id": gid, "fitness": score}
for gid, score in leaderboard
],
},
)
except Exception as e:
logger.error(f"Get leaderboard failed: {e}")
return EvolutionToolResult(success=False, error=str(e))
async def trigger_evolution(self, generations: int = 1) -> EvolutionToolResult:
"""
Trigger evolution cycle.
Args:
generations: Number of generations to evolve
Returns:
EvolutionToolResult with evolution results
"""
try:
if self.optimizer is None:
return EvolutionToolResult(
success=False,
error="Genetic optimizer not configured",
)
# Run evolution
result = await self.optimizer.run(generations=generations)
return EvolutionToolResult(
success=True,
data={
"generations_run": result.generations_run,
"best_fitness": result.best_genome.total_fitness(),
"duration_seconds": result.duration_seconds,
},
)
except Exception as e:
logger.error(f"Trigger evolution failed: {e}")
return EvolutionToolResult(success=False, error=str(e))
async def get_behavior_params(self) -> EvolutionToolResult:
"""
Get current behavioral parameters.
Returns:
EvolutionToolResult with behavior configuration
"""
try:
if self.mutator is None:
return EvolutionToolResult(
success=False,
error="Behavior mutator not configured",
)
return EvolutionToolResult(
success=True,
data={
"behavior_params": self.mutator.get_behavior_params(),
"team_config": self.mutator.get_team_config(),
"generation": self.mutator.generation,
},
)
except Exception as e:
logger.error(f"Get behavior params failed: {e}")
return EvolutionToolResult(success=False, error=str(e))
async def evolve_behavior(self) -> EvolutionToolResult:
"""
Trigger behavior evolution.
Returns:
EvolutionToolResult with new behavior configuration
"""
try:
if self.mutator is None:
return EvolutionToolResult(
success=False,
error="Behavior mutator not configured",
)
self.mutator.evolve_generation()
return EvolutionToolResult(
success=True,
data={
"new_generation": self.mutator.generation,
"new_behavior": self.mutator.get_behavior_params(),
"new_team": self.mutator.get_team_config(),
},
)
except Exception as e:
logger.error(f"Evolve behavior failed: {e}")
return EvolutionToolResult(success=False, error=str(e))
async def get_improvement_suggestions(self) -> EvolutionToolResult:
"""
Get AI-generated improvement suggestions based on metrics.
Returns:
EvolutionToolResult with suggestions
"""
try:
current = self.fitness.get_current_fitness()
trends = {name: self.fitness.get_trend(name) for name in current.keys()}
suggestions = []
# Analyze metrics and generate suggestions
if current.get("task_success", 0) < 0.7:
suggestions.append({
"area": "task_success",
"issue": "Low task success rate",
"suggestion": "Consider enabling cascade inference or switching to a more capable model",
})
if current.get("efficiency", 0) < 0.5:
suggestions.append({
"area": "efficiency",
"issue": "High token usage",
"suggestion": "Enable speculative decoding or use a smaller draft model",
})
if current.get("user_satisfaction", 0) < 0.6:
suggestions.append({
"area": "user_satisfaction",
"issue": "Low user satisfaction",
"suggestion": "Review recent feedback and adjust response style or verbosity",
})
# Check trends
for metric, trend in trends.items():
if trend < -0.1:
suggestions.append({
"area": metric,
"issue": f"Declining {metric}",
"suggestion": f"Investigate recent changes affecting {metric}",
})
return EvolutionToolResult(
success=True,
data={
"suggestions": suggestions,
"current_metrics": current,
"trends": trends,
},
)
except Exception as e:
logger.error(f"Get improvement suggestions failed: {e}")
return EvolutionToolResult(success=False, error=str(e))