mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-17 07:57:19 -05:00
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
348 lines
8.1 KiB
Python
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
|