Migrate all agent roles from Legacy to EvoAgent architecture: - fundamentals_analyst, technical_analyst, sentiment_analyst, valuation_analyst - risk_manager, portfolio_manager Key changes: - EvoAgent now supports Portfolio Manager compatibility methods (_make_decision, get_decisions, get_portfolio_state, load_portfolio_state, update_portfolio) - Add UnifiedAgentFactory for centralized agent creation - ToolGuard with batch approval API and WebSocket broadcast - Legacy agents marked deprecated (AnalystAgent, RiskAgent, PMAgent) - Remove backend/agents/compat.py migration shim - Add run_id alongside workspace_id for semantic clarity - Complete integration test coverage (13 tests) - All smoke tests passing for 6 agent roles Constraint: Must maintain backward compatibility with existing run configs Constraint: Memory support must work with EvoAgent (no fallback to Legacy) Rejected: Separate PM implementation for EvoAgent | unified approach cleaner Confidence: high Scope-risk: broad Directive: EVO_AGENT_IDS env var still respected but defaults to all roles Not-tested: Kubernetes sandbox mode for skill execution
110 lines
3.5 KiB
Python
110 lines
3.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Agent control-plane FastAPI surface."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from contextlib import asynccontextmanager
|
|
from pathlib import Path
|
|
from typing import AsyncGenerator
|
|
|
|
from fastapi import FastAPI
|
|
|
|
from backend.apps.cors import add_cors_middleware
|
|
|
|
from backend.api import agents_router, guard_router, workspaces_router
|
|
from backend.agents import AgentFactory, WorkspaceManager, get_registry
|
|
|
|
# Global instances (initialized on startup)
|
|
agent_factory: AgentFactory | None = None
|
|
workspace_manager: WorkspaceManager | None = None
|
|
|
|
|
|
def _build_scope_payload(project_root: Path) -> dict[str, object]:
|
|
return {
|
|
"design_time_registry": {
|
|
"root": str(project_root / "workspaces"),
|
|
"meaning": "Persistent control-plane workspace registry",
|
|
},
|
|
"runtime_assets": {
|
|
"root": str(project_root / "runs"),
|
|
"meaning": "Run-scoped runtime state and agent assets",
|
|
},
|
|
"agent_route_note": (
|
|
"On `/api/workspaces/{workspace_id}/agents/...`, design-time CRUD "
|
|
"routes still use `workspaces/`, while profile/skills/file routes "
|
|
"use `workspace_id` as a run id under `runs/<run_id>/`."
|
|
),
|
|
}
|
|
|
|
|
|
def create_app(project_root: Path | None = None) -> FastAPI:
|
|
"""Create the agent control-plane app."""
|
|
resolved_project_root = project_root or Path(__file__).resolve().parents[2]
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(_app: FastAPI) -> AsyncGenerator[None, None]:
|
|
"""Initialize design-time workspace and registry state for the control plane."""
|
|
global agent_factory, workspace_manager
|
|
|
|
workspace_manager = WorkspaceManager(project_root=resolved_project_root)
|
|
agent_factory = AgentFactory(project_root=resolved_project_root)
|
|
agent_factory.workspaces_root.mkdir(parents=True, exist_ok=True)
|
|
|
|
registry = get_registry()
|
|
print("✓ 大时代 API started")
|
|
print(f" - Design workspaces root: {agent_factory.workspaces_root}")
|
|
print(f" - Registered agents: {registry.get_agent_count()}")
|
|
|
|
yield
|
|
|
|
print("✓ 大时代 API shutting down")
|
|
|
|
app = FastAPI(
|
|
title="大时代 Agent Service",
|
|
description="REST API for the 大时代 multi-agent control plane",
|
|
version="0.1.0",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
add_cors_middleware(app)
|
|
|
|
@app.get("/health")
|
|
async def health_check() -> dict[str, object]:
|
|
"""Health check endpoint."""
|
|
registry = get_registry()
|
|
return {
|
|
"status": "healthy",
|
|
"version": "0.1.0",
|
|
"agents_registered": registry.get_agent_count(),
|
|
"workspaces_available": (
|
|
len(workspace_manager.list_workspaces())
|
|
if workspace_manager
|
|
else 0
|
|
),
|
|
"scope_roots": _build_scope_payload(resolved_project_root),
|
|
}
|
|
|
|
@app.get("/api/status")
|
|
async def api_status() -> dict[str, object]:
|
|
"""Get API status and registry information."""
|
|
registry = get_registry()
|
|
return {
|
|
"status": "operational",
|
|
"registry": registry.get_stats(),
|
|
"scope": _build_scope_payload(resolved_project_root),
|
|
}
|
|
|
|
app.include_router(workspaces_router)
|
|
app.include_router(agents_router)
|
|
app.include_router(guard_router)
|
|
return app
|
|
|
|
|
|
app = create_app()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
|
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|