feat: deploy infrastructure + disk/drive, calendar, presentation, workspaces, onboarding, demo user
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
"""MetaAgent — Orchestrator agent for VoIdea.
|
||||
|
||||
Configurable from admin panel:
|
||||
- cron_schedule: str (default "0 9 * * 1,4")
|
||||
- weights: dict[agent_name, float]
|
||||
- sources_count: int (default 10)
|
||||
- auto_create: bool (default True)
|
||||
|
||||
Runs a subset of agents based on weights and collects reports.
|
||||
"""
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from app.agents.base import AgentResult, AgentStatus, AgentTrigger, BaseAgent
|
||||
from app.agents.registry import registry
|
||||
|
||||
|
||||
DEFAULT_CONFIG: dict[str, Any] = {
|
||||
"cron_schedule": "0 9 * * 1,4",
|
||||
"weights": {},
|
||||
"sources_count": 10,
|
||||
"auto_create": True,
|
||||
}
|
||||
|
||||
|
||||
class MetaAgent(BaseAgent):
|
||||
"""Orchestrator agent that coordinates other agents."""
|
||||
|
||||
name = "meta_agent"
|
||||
version = "1.0.0"
|
||||
description = "Orchestrates other agents based on configurable schedule and weights"
|
||||
triggers = [
|
||||
AgentTrigger.MANUAL,
|
||||
AgentTrigger.CRON,
|
||||
AgentTrigger.API,
|
||||
]
|
||||
|
||||
def __init__(self, config: dict[str, Any] | None = None):
|
||||
super().__init__()
|
||||
self._config = {**DEFAULT_CONFIG, **(config or {})}
|
||||
|
||||
@property
|
||||
def config(self) -> dict[str, Any]:
|
||||
return self._config
|
||||
|
||||
@config.setter
|
||||
def config(self, value: dict[str, Any]) -> None:
|
||||
self._config = {**DEFAULT_CONFIG, **value}
|
||||
|
||||
async def run(self, context: dict[str, Any] | None = None) -> AgentResult:
|
||||
"""Execute meta-agent orchestration.
|
||||
|
||||
Context can contain:
|
||||
- action: str (orchestrate | report | status) — default "orchestrate"
|
||||
- target_agents: list[str] — subset of agents to run (default: all)
|
||||
- sources_count: int — override config
|
||||
"""
|
||||
await self.set_running("orchestration")
|
||||
|
||||
try:
|
||||
action = (context or {}).get("action", "orchestrate")
|
||||
|
||||
if action == "status":
|
||||
return await self._get_status()
|
||||
elif action == "report":
|
||||
return await self._generate_report()
|
||||
else:
|
||||
return await self._orchestrate(context or {})
|
||||
|
||||
except Exception as e:
|
||||
await self.set_error(str(e))
|
||||
return AgentResult(
|
||||
success=False,
|
||||
message=f"MetaAgent failed: {str(e)}",
|
||||
errors=[str(e)],
|
||||
)
|
||||
|
||||
async def health_check(self) -> bool:
|
||||
return True
|
||||
|
||||
async def _orchestrate(self, context: dict[str, Any]) -> AgentResult:
|
||||
"""Run target agents and collect results."""
|
||||
target_agents: list[str] | None = context.get("target_agents")
|
||||
sources_count = context.get("sources_count", self._config["sources_count"])
|
||||
weights = self._config.get("weights", {})
|
||||
|
||||
all_agents = registry.list_agents()
|
||||
if not all_agents:
|
||||
await self.set_idle()
|
||||
return AgentResult(
|
||||
success=True,
|
||||
message="No agents registered",
|
||||
data={"orchestrated": 0},
|
||||
)
|
||||
|
||||
candidates = []
|
||||
for a in all_agents:
|
||||
name = a["name"]
|
||||
if name == self.name:
|
||||
continue
|
||||
weight = weights.get(name, 1.0)
|
||||
if weight <= 0:
|
||||
continue
|
||||
candidates.append((name, weight))
|
||||
|
||||
if not candidates:
|
||||
candidates = [(a["name"], 1.0) for a in all_agents if a["name"] != self.name]
|
||||
|
||||
if target_agents:
|
||||
candidates = [c for c in candidates if c[0] in target_agents]
|
||||
|
||||
max_sources = min(sources_count, len(candidates))
|
||||
selected = candidates[:max_sources]
|
||||
|
||||
results: dict[str, Any] = {}
|
||||
for name, _weight in selected:
|
||||
try:
|
||||
result = await registry.run_agent(name, {"trigger": "meta_agent"})
|
||||
results[name] = {
|
||||
"success": result.success,
|
||||
"message": result.message,
|
||||
"duration_ms": result.duration_ms,
|
||||
}
|
||||
except Exception as e:
|
||||
results[name] = {
|
||||
"success": False,
|
||||
"message": str(e),
|
||||
}
|
||||
|
||||
success_count = sum(1 for r in results.values() if r["success"])
|
||||
total_duration = sum(r.get("duration_ms", 0) for r in results.values())
|
||||
|
||||
await self.set_idle()
|
||||
return AgentResult(
|
||||
success=True,
|
||||
message=f"Orchestrated {len(results)} agents ({success_count} ok)",
|
||||
data={
|
||||
"orchestrated": len(results),
|
||||
"success_count": success_count,
|
||||
"agents": results,
|
||||
"total_duration_ms": total_duration,
|
||||
"config": {
|
||||
"cron_schedule": self._config["cron_schedule"],
|
||||
"sources_count": sources_count,
|
||||
"auto_create": self._config["auto_create"],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
async def _generate_report(self) -> AgentResult:
|
||||
"""Generate summary report of all agent statuses."""
|
||||
all_agents = registry.list_agents()
|
||||
metrics = registry.get_metrics_all()
|
||||
|
||||
return AgentResult(
|
||||
success=True,
|
||||
message=f"Report: {len(all_agents)} agents",
|
||||
data={
|
||||
"agents": all_agents,
|
||||
"metrics": metrics,
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
},
|
||||
)
|
||||
|
||||
async def _get_status(self) -> AgentResult:
|
||||
return AgentResult(
|
||||
success=True,
|
||||
message="Meta-agent operational",
|
||||
data={
|
||||
"status": self.status.value,
|
||||
"config": self._config,
|
||||
"last_run": self._last_run.isoformat() if self._last_run else None,
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user