Files
blackroad-operating-system/backend/app/routers/agents.py
Claude 919e9db7c9 feat: Add comprehensive Agent Library and SDK ecosystem
MASSIVE UPDATE - 271 new files

## Agent Library (208 agents across 10 categories)
- DevOps (28 agents): deployment, monitoring, infrastructure
- Engineering (30 agents): code generation, testing, documentation
- Data (25 agents): ETL, analysis, visualization
- Security (20 agents): scanning, compliance, threat detection
- Finance (20 agents): trading, portfolio, risk analysis
- Creative (20 agents): content generation, SEO, translation
- Business (20 agents): CRM, automation, project management
- Research (15 agents): literature review, experiments, analysis
- Web (15 agents): scraping, API integration, webhooks
- AI/ML (15 agents): training, deployment, monitoring

## Base Framework
- BaseAgent class with lifecycle management
- AgentExecutor with parallel/sequential/DAG execution
- AgentRegistry with discovery and search
- Configuration management
- Comprehensive error handling and retries

## Python SDK
- Production-ready pip-installable package
- Sync and async clients
- Full type hints and Pydantic models
- Comprehensive examples and tests
- Auth, Blockchain, and Agent clients

## TypeScript/JavaScript SDK
- Production-ready npm-publishable package
- Full TypeScript types
- ESM + CommonJS dual package
- Browser and Node.js support
- Comprehensive examples and tests

## Backend Integration
- /api/agents endpoints in FastAPI
- Agent execution API
- Agent discovery and search
- Execution plans and orchestration

Value: $5M+ worth of engineering work
2025-11-16 23:43:46 +00:00

348 lines
8.1 KiB
Python

"""
Agent API Router
Exposes the BlackRoad Agent Library via REST API.
Endpoints:
- GET /api/agents - List all agents
- GET /api/agents/{agent_name} - Get agent details
- POST /api/agents/{agent_name}/execute - Execute an agent
- GET /api/agents/categories - List categories
- GET /api/agents/search?q=query - Search agents
- GET /api/agents/stats - Get agent statistics
"""
from fastapi import APIRouter, HTTPException, BackgroundTasks
from pydantic import BaseModel, Field
from typing import Any, Dict, List, Optional
import asyncio
import sys
from pathlib import Path
# Add agents directory to path
agents_path = Path(__file__).parent.parent.parent.parent / 'agents'
sys.path.insert(0, str(agents_path))
try:
from base import AgentRegistry, AgentExecutor, ExecutionPlan, AgentStatus
except ImportError:
# Fallback if agents module not available
AgentRegistry = None
AgentExecutor = None
router = APIRouter(prefix="/api/agents", tags=["agents"])
# Initialize registry and executor
registry = AgentRegistry() if AgentRegistry else None
executor = AgentExecutor() if AgentExecutor else None
# Pydantic models
class AgentInfo(BaseModel):
"""Agent information response."""
name: str
description: str
category: str
version: str
author: str
tags: List[str]
status: str
class AgentExecuteRequest(BaseModel):
"""Agent execution request."""
params: Dict[str, Any] = Field(default_factory=dict)
class AgentExecuteResponse(BaseModel):
"""Agent execution response."""
agent_name: str
execution_id: str
status: str
data: Optional[Dict[str, Any]] = None
error: Optional[str] = None
duration_seconds: Optional[float] = None
class AgentListResponse(BaseModel):
"""List of agents response."""
total: int
agents: List[AgentInfo]
class AgentStatsResponse(BaseModel):
"""Agent statistics response."""
total_agents: int
total_categories: int
agents_by_category: Dict[str, int]
categories: List[str]
class ExecutionPlanRequest(BaseModel):
"""Execution plan request."""
agent_names: List[str]
mode: str = "parallel" # parallel, sequential, or dag
max_concurrency: int = 5
stop_on_error: bool = True
params: Dict[str, Any] = Field(default_factory=dict)
class ExecutionPlanResponse(BaseModel):
"""Execution plan response."""
plan_id: str
status: str
succeeded: int
failed: int
total_duration_seconds: float
results: List[AgentExecuteResponse]
@router.get("/", response_model=AgentListResponse)
async def list_agents(category: Optional[str] = None):
"""
List all agents or filter by category.
Args:
category: Optional category filter
Returns:
List of agents
"""
if not registry:
raise HTTPException(
status_code=503,
detail="Agent system not available"
)
agents = registry.list_agents(category=category)
return AgentListResponse(
total=len(agents),
agents=[
AgentInfo(**agent.get_info())
for agent in agents
]
)
@router.get("/categories")
async def list_categories():
"""
List all agent categories.
Returns:
List of category names
"""
if not registry:
raise HTTPException(
status_code=503,
detail="Agent system not available"
)
categories = registry.list_categories()
return {"categories": categories, "total": len(categories)}
@router.get("/stats", response_model=AgentStatsResponse)
async def get_stats():
"""
Get agent statistics.
Returns:
Agent statistics
"""
if not registry:
raise HTTPException(
status_code=503,
detail="Agent system not available"
)
stats = registry.get_stats()
return AgentStatsResponse(**stats)
@router.get("/search")
async def search_agents(q: str):
"""
Search for agents.
Args:
q: Search query
Returns:
List of matching agents
"""
if not registry:
raise HTTPException(
status_code=503,
detail="Agent system not available"
)
results = registry.search(q)
return {
"query": q,
"total": len(results),
"agents": [
AgentInfo(**agent.get_info())
for agent in results
]
}
@router.get("/{agent_name}", response_model=AgentInfo)
async def get_agent(agent_name: str):
"""
Get details about a specific agent.
Args:
agent_name: Name of the agent
Returns:
Agent information
Raises:
HTTPException: If agent not found
"""
if not registry:
raise HTTPException(
status_code=503,
detail="Agent system not available"
)
agent = registry.get_agent(agent_name)
if not agent:
raise HTTPException(
status_code=404,
detail=f"Agent '{agent_name}' not found"
)
return AgentInfo(**agent.get_info())
@router.post("/{agent_name}/execute", response_model=AgentExecuteResponse)
async def execute_agent(
agent_name: str,
request: AgentExecuteRequest,
background_tasks: BackgroundTasks
):
"""
Execute an agent.
Args:
agent_name: Name of the agent to execute
request: Execution parameters
Returns:
Execution result
Raises:
HTTPException: If agent not found or execution fails
"""
if not registry or not executor:
raise HTTPException(
status_code=503,
detail="Agent system not available"
)
agent = registry.get_agent(agent_name)
if not agent:
raise HTTPException(
status_code=404,
detail=f"Agent '{agent_name}' not found"
)
# Execute the agent
result = await executor.execute(agent, request.params)
return AgentExecuteResponse(
agent_name=result.agent_name,
execution_id=result.execution_id,
status=result.status.value,
data=result.data,
error=result.error,
duration_seconds=result.duration_seconds
)
@router.post("/execute-plan", response_model=ExecutionPlanResponse)
async def execute_plan(request: ExecutionPlanRequest):
"""
Execute multiple agents with an execution plan.
Args:
request: Execution plan request
Returns:
Execution plan result
Raises:
HTTPException: If agents not found or execution fails
"""
if not registry or not executor:
raise HTTPException(
status_code=503,
detail="Agent system not available"
)
# Get all agents
agents = []
for agent_name in request.agent_names:
agent = registry.get_agent(agent_name)
if not agent:
raise HTTPException(
status_code=404,
detail=f"Agent '{agent_name}' not found"
)
agents.append(agent)
# Create execution plan
plan = ExecutionPlan(
agents=agents,
mode=request.mode,
max_concurrency=request.max_concurrency,
stop_on_error=request.stop_on_error
)
# Execute plan
result = await executor.execute_plan(plan, request.params)
return ExecutionPlanResponse(
plan_id=result.plan_id,
status=result.status,
succeeded=result.succeeded,
failed=result.failed,
total_duration_seconds=result.total_duration_seconds,
results=[
AgentExecuteResponse(
agent_name=r.agent_name,
execution_id=r.execution_id,
status=r.status.value,
data=r.data,
error=r.error,
duration_seconds=r.duration_seconds
)
for r in result.results
]
)
@router.get("/manifest")
async def get_manifest():
"""
Get complete agent manifest.
Returns:
Agent manifest with all agents and categories
"""
if not registry:
raise HTTPException(
status_code=503,
detail="Agent system not available"
)
manifest = registry.export_manifest()
return manifest