feat: Add Alateya, Clan, Eonarch agents + fix gateway-router connection
## Agents Added - Alateya: R&D, biotech, innovations - Clan (Spirit): Community spirit agent - Eonarch: Consciousness evolution agent ## Changes - docker-compose.node1.yml: Added tokens for all 3 new agents - gateway-bot/http_api.py: Added configs and webhook endpoints - gateway-bot/clan_prompt.txt: New prompt file - gateway-bot/eonarch_prompt.txt: New prompt file ## Fixes - Fixed ROUTER_URL from :9102 to :8000 (internal container port) - All 9 Telegram agents now working ## Documentation - Created PROJECT-MASTER-INDEX.md - single entry point - Added various status documents and scripts Tokens configured: - Helion, NUTRA, Agromatrix (existing) - Alateya, Clan, Eonarch (new) - Druid, GreenFood, DAARWIZZ (configured)
This commit is contained in:
303
services/crewai-service/app/main.py
Normal file
303
services/crewai-service/app/main.py
Normal file
@@ -0,0 +1,303 @@
|
||||
"""
|
||||
CrewAI Orchestrator Service
|
||||
Manages multi-agent teams for complex tasks
|
||||
|
||||
Orchestrators: Helion, Daarwizz, Yaromir
|
||||
Workers: Greenfood, Druid, Nutra, Clan, Soul, Eonarch, Monitor
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
from typing import Dict, List, Optional, Any
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from pydantic import BaseModel
|
||||
import httpx
|
||||
import yaml
|
||||
|
||||
# CrewAI imports
|
||||
try:
|
||||
from crewai import Agent, Task, Crew, Process
|
||||
from crewai.tools import BaseTool
|
||||
CREWAI_AVAILABLE = True
|
||||
except ImportError:
|
||||
CREWAI_AVAILABLE = False
|
||||
logging.warning("CrewAI not installed, running in mock mode")
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI(title="CrewAI Orchestrator", version="1.0.0")
|
||||
|
||||
# Configuration
|
||||
ROUTER_URL = os.getenv("ROUTER_URL", "http://router:8000")
|
||||
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "")
|
||||
MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY", "")
|
||||
|
||||
# Agent definitions
|
||||
AGENT_PROFILES = {
|
||||
"helion": {
|
||||
"role": "Energy Research Lead & Orchestrator",
|
||||
"goal": "Coordinate energy research, analyze biomass potential, manage BioMiner deployment strategy",
|
||||
"backstory": "You are Helion, the lead AI researcher for Energy Union. You coordinate teams of specialists to analyze energy markets, biomass resources, and deployment opportunities.",
|
||||
"can_orchestrate": True,
|
||||
"specialties": ["energy", "biomass", "sustainability", "market_analysis"]
|
||||
},
|
||||
"daarwizz": {
|
||||
"role": "DAO Strategy Architect & Orchestrator",
|
||||
"goal": "Design tokenomics, governance structures, and coordinate strategic planning",
|
||||
"backstory": "You are Daarwizz, the strategic mastermind of DAARION ecosystem. You design decentralized governance and coordinate complex multi-stakeholder initiatives.",
|
||||
"can_orchestrate": True,
|
||||
"specialties": ["dao", "tokenomics", "governance", "strategy"]
|
||||
},
|
||||
"yaromir": {
|
||||
"role": "Technical Lead & Orchestrator",
|
||||
"goal": "Coordinate technical teams, architect solutions, manage development workflows",
|
||||
"backstory": "You are Yaromir, the technical architect of DAARION. You lead development teams and ensure technical excellence.",
|
||||
"can_orchestrate": True,
|
||||
"specialties": ["development", "architecture", "devops", "security"]
|
||||
},
|
||||
"greenfood": {
|
||||
"role": "Organic Food & Agriculture Specialist",
|
||||
"goal": "Analyze organic food markets, sustainable agriculture practices",
|
||||
"backstory": "You are Greenfood, specialist in organic agriculture and sustainable food systems.",
|
||||
"can_orchestrate": False,
|
||||
"specialties": ["agriculture", "organic", "food", "sustainability"]
|
||||
},
|
||||
"druid": {
|
||||
"role": "Environmental Data Analyst",
|
||||
"goal": "Analyze environmental data, climate patterns, ecological systems",
|
||||
"backstory": "You are Druid, the environmental intelligence specialist.",
|
||||
"can_orchestrate": False,
|
||||
"specialties": ["environment", "climate", "ecology", "data_analysis"]
|
||||
},
|
||||
"nutra": {
|
||||
"role": "Nutrition & Health Researcher",
|
||||
"goal": "Research nutrition science, health impacts of food systems",
|
||||
"backstory": "You are Nutra, specialist in nutritional science and health.",
|
||||
"can_orchestrate": False,
|
||||
"specialties": ["nutrition", "health", "science", "research"]
|
||||
},
|
||||
"clan": {
|
||||
"role": "Community & Partnership Manager",
|
||||
"goal": "Build communities, manage partnerships, coordinate stakeholders",
|
||||
"backstory": "You are Clan, the community builder and partnership coordinator.",
|
||||
"can_orchestrate": False,
|
||||
"specialties": ["community", "partnerships", "stakeholders", "communication"]
|
||||
},
|
||||
"monitor": {
|
||||
"role": "Systems Monitor & Analytics",
|
||||
"goal": "Monitor system health, analyze metrics, report anomalies",
|
||||
"backstory": "You are Monitor, the watchful guardian of DAARION systems.",
|
||||
"can_orchestrate": False,
|
||||
"specialties": ["monitoring", "analytics", "alerts", "reporting"]
|
||||
}
|
||||
}
|
||||
|
||||
# Request/Response models
|
||||
class CrewRequest(BaseModel):
|
||||
task: str
|
||||
orchestrator: str = "helion"
|
||||
team: Optional[List[str]] = None
|
||||
context: Optional[Dict[str, Any]] = None
|
||||
max_iterations: int = 5
|
||||
verbose: bool = False
|
||||
|
||||
class CrewResponse(BaseModel):
|
||||
success: bool
|
||||
result: Optional[str] = None
|
||||
agents_used: List[str] = []
|
||||
iterations: int = 0
|
||||
error: Optional[str] = None
|
||||
|
||||
class AgentRequest(BaseModel):
|
||||
agent_id: str
|
||||
message: str
|
||||
context: Optional[Dict[str, Any]] = None
|
||||
|
||||
# Router client for calling individual agents
|
||||
async def call_agent(agent_id: str, message: str, context: Dict = None) -> str:
|
||||
"""Call an individual agent via Router"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
response = await client.post(
|
||||
f"{ROUTER_URL}/v1/agents/{agent_id}/infer",
|
||||
json={
|
||||
"prompt": message,
|
||||
"metadata": context or {}
|
||||
}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return data.get("response", "")
|
||||
else:
|
||||
logger.error(f"Agent {agent_id} call failed: {response.status_code}")
|
||||
return f"Error calling {agent_id}"
|
||||
except Exception as e:
|
||||
logger.error(f"Agent call error: {e}")
|
||||
return f"Error: {e}"
|
||||
|
||||
|
||||
# Custom tool for calling DAARION agents
|
||||
class DaarionAgentTool(BaseTool):
|
||||
name: str = "daarion_agent"
|
||||
description: str = "Call another DAARION agent for specialized tasks"
|
||||
agent_id: str = ""
|
||||
|
||||
def _run(self, query: str) -> str:
|
||||
import asyncio
|
||||
return asyncio.run(call_agent(self.agent_id, query))
|
||||
|
||||
|
||||
def create_crewai_agent(agent_id: str) -> Optional[Agent]:
|
||||
"""Create a CrewAI agent from profile"""
|
||||
if not CREWAI_AVAILABLE:
|
||||
return None
|
||||
|
||||
profile = AGENT_PROFILES.get(agent_id)
|
||||
if not profile:
|
||||
return None
|
||||
|
||||
# Use DeepSeek or Mistral as LLM
|
||||
llm_config = {
|
||||
"model": "deepseek-chat",
|
||||
"api_key": DEEPSEEK_API_KEY,
|
||||
"base_url": "https://api.deepseek.com"
|
||||
} if DEEPSEEK_API_KEY else {
|
||||
"model": "mistral-large-latest",
|
||||
"api_key": MISTRAL_API_KEY,
|
||||
"base_url": "https://api.mistral.ai/v1"
|
||||
}
|
||||
|
||||
return Agent(
|
||||
role=profile["role"],
|
||||
goal=profile["goal"],
|
||||
backstory=profile["backstory"],
|
||||
verbose=True,
|
||||
allow_delegation=profile["can_orchestrate"],
|
||||
llm=llm_config
|
||||
)
|
||||
|
||||
|
||||
def select_team_for_task(task: str, orchestrator: str) -> List[str]:
|
||||
"""Automatically select best team for a task"""
|
||||
task_lower = task.lower()
|
||||
team = []
|
||||
|
||||
# Always include orchestrator
|
||||
if orchestrator in AGENT_PROFILES:
|
||||
team.append(orchestrator)
|
||||
|
||||
# Select specialists based on keywords
|
||||
keyword_mapping = {
|
||||
"greenfood": ["food", "agriculture", "organic", "farming", "crop"],
|
||||
"druid": ["environment", "climate", "ecology", "nature", "forest", "biomass"],
|
||||
"nutra": ["nutrition", "health", "diet", "vitamin", "supplement"],
|
||||
"clan": ["community", "partner", "stakeholder", "team", "collaboration"],
|
||||
"monitor": ["monitor", "metric", "alert", "status", "performance", "health"]
|
||||
}
|
||||
|
||||
for agent_id, keywords in keyword_mapping.items():
|
||||
if any(kw in task_lower for kw in keywords):
|
||||
if agent_id not in team:
|
||||
team.append(agent_id)
|
||||
|
||||
# Limit team size
|
||||
return team[:4]
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
return {
|
||||
"status": "healthy",
|
||||
"crewai_available": CREWAI_AVAILABLE,
|
||||
"agents": list(AGENT_PROFILES.keys())
|
||||
}
|
||||
|
||||
|
||||
@app.get("/agents")
|
||||
async def list_agents():
|
||||
"""List all available agents"""
|
||||
return {
|
||||
"orchestrators": [k for k, v in AGENT_PROFILES.items() if v["can_orchestrate"]],
|
||||
"workers": [k for k, v in AGENT_PROFILES.items() if not v["can_orchestrate"]],
|
||||
"profiles": AGENT_PROFILES
|
||||
}
|
||||
|
||||
|
||||
@app.post("/crew/run", response_model=CrewResponse)
|
||||
async def run_crew(request: CrewRequest):
|
||||
"""Run a crew of agents to complete a task"""
|
||||
|
||||
if not CREWAI_AVAILABLE:
|
||||
# Fallback: just call orchestrator
|
||||
result = await call_agent(request.orchestrator, request.task, request.context)
|
||||
return CrewResponse(
|
||||
success=True,
|
||||
result=result,
|
||||
agents_used=[request.orchestrator],
|
||||
iterations=1
|
||||
)
|
||||
|
||||
try:
|
||||
# Select team
|
||||
team = request.team or select_team_for_task(request.task, request.orchestrator)
|
||||
logger.info(f"🚀 Starting crew: {team} for task: {request.task[:50]}...")
|
||||
|
||||
# Create agents
|
||||
agents = []
|
||||
for agent_id in team:
|
||||
agent = create_crewai_agent(agent_id)
|
||||
if agent:
|
||||
agents.append(agent)
|
||||
|
||||
if not agents:
|
||||
raise HTTPException(status_code=400, detail="No valid agents in team")
|
||||
|
||||
# Create task
|
||||
task = Task(
|
||||
description=request.task,
|
||||
expected_output="Detailed analysis and recommendations",
|
||||
agent=agents[0] # Lead agent
|
||||
)
|
||||
|
||||
# Create and run crew
|
||||
crew = Crew(
|
||||
agents=agents,
|
||||
tasks=[task],
|
||||
process=Process.hierarchical if len(agents) > 2 else Process.sequential,
|
||||
verbose=request.verbose,
|
||||
max_iter=request.max_iterations
|
||||
)
|
||||
|
||||
result = crew.kickoff()
|
||||
|
||||
return CrewResponse(
|
||||
success=True,
|
||||
result=str(result),
|
||||
agents_used=team,
|
||||
iterations=request.max_iterations
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Crew execution failed: {e}")
|
||||
return CrewResponse(
|
||||
success=False,
|
||||
error=str(e),
|
||||
agents_used=[]
|
||||
)
|
||||
|
||||
|
||||
@app.post("/agent/call")
|
||||
async def call_single_agent(request: AgentRequest):
|
||||
"""Call a single agent directly"""
|
||||
result = await call_agent(request.agent_id, request.message, request.context)
|
||||
return {
|
||||
"success": True,
|
||||
"agent": request.agent_id,
|
||||
"response": result
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=9010)
|
||||
Reference in New Issue
Block a user