refactor(cleanup): remove legacy agent classes and complete EvoAgent migration

Remove deprecated AnalystAgent, PMAgent, and RiskAgent classes.
All agent creation now goes through UnifiedAgentFactory creating EvoAgent instances.

- Delete backend/agents/analyst.py (169 lines)
- Delete backend/agents/portfolio_manager.py (420 lines)
- Delete backend/agents/risk_manager.py (139 lines)
- Update all imports to use EvoAgent exclusively
- Clean up unused imports across 25 files
- Update tests to work with simplified agent structure

Constraint: EvoAgent is now the single source of truth for all agent roles
Constraint: UnifiedAgentFactory handles runtime agent creation
Rejected: Keep legacy aliases | creates maintenance burden
Confidence: high
Scope-risk: moderate (affects agent instantiation paths)
Directive: All new agent features must be added to EvoAgent, not legacy classes
Not-tested: Kubernetes sandbox executor (marked with TODO)
This commit is contained in:
2026-04-02 10:51:14 +08:00
parent 49d704c363
commit 45c3996434
34 changed files with 201 additions and 1534 deletions

View File

@@ -13,9 +13,7 @@ from typing import Any, Callable, Dict, List, Optional, Set
import websockets
from websockets.asyncio.server import ServerConnection
from backend.data.provider_utils import normalize_symbol
from backend.domains import news as news_domain
from backend.llm.models import get_agent_model_info
from backend.core.pipeline import TradingPipeline
from backend.core.state_sync import StateSync
from backend.services.market import MarketService
@@ -146,7 +144,7 @@ class Gateway:
self.state_sync.update_state("status", "websocket_ready")
# Create server but don't block yet - we'll serve inside the context manager
server = await websockets.serve(
await websockets.serve(
self.handle_client,
host,
port,

View File

@@ -22,7 +22,6 @@ from backend.config.bootstrap_config import (
resolve_runtime_config,
update_bootstrap_values_for_run,
)
from backend.data.market_ingest import ingest_symbols
from backend.llm.models import get_agent_model_info

View File

@@ -24,7 +24,7 @@ import logging
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from backend.services.gateway import Gateway
pass
logger = logging.getLogger(__name__)
@@ -88,7 +88,6 @@ def _ensure_session_bridge(gateway) -> None:
def _get_ws_client(gateway) -> "OpenClawWebSocketClient":
"""Get the OpenClaw WebSocket client from gateway."""
from shared.client.openclaw_websocket_client import OpenClawWebSocketClient
client = gateway._openclaw_ws
if client is None:
raise RuntimeError("OpenClaw Gateway not connected")

View File

@@ -15,7 +15,6 @@ from backend.domains import trading as trading_domain
from backend.enrich.news_enricher import enrich_news_for_symbol
from backend.enrich.llm_enricher import llm_enrichment_enabled
from backend.tools.data_tools import prices_to_df
from shared.client import NewsServiceClient, TradingServiceClient
logger = logging.getLogger(__name__)
@@ -564,7 +563,6 @@ async def handle_get_stock_technical_indicators(gateway: Any, websocket: Any, da
df = prices_to_df(prices)
signal = gateway._technical_analyzer.analyze(ticker, df)
import pandas as pd
df_sorted = df.sort_values("time").reset_index(drop=True)
df_sorted["returns"] = df_sorted["close"].pct_change()
vol_10 = float(df_sorted["returns"].tail(10).std() * (252**0.5) * 100) if len(df_sorted) >= 10 else None

View File

@@ -16,12 +16,9 @@ from typing import Any
from shared.models.openclaw import (
AgentSummary,
AgentsList,
ApprovalRequest,
ApprovalsList,
CronJob,
CronList,
DaemonStatus,
HookStatusEntry,
HookStatusReport,
ModelAliasesList,
ModelFallbacksList,
@@ -29,20 +26,15 @@ from shared.models.openclaw import (
ModelsList,
OpenClawStatus,
PairingListResponse,
PluginDiagnostic,
PluginRecord,
PluginsList,
QrCodeResponse,
SecretsAuditReport,
SecurityAuditResponse,
SecurityAuditReport,
SessionEntry,
SessionHistory,
SessionsList,
SkillStatusEntry,
SkillStatusReport,
SkillUpdateResult,
UpdateCheckResult,
UpdateStatusResponse,
normalize_agents,
normalize_approvals,
@@ -282,7 +274,6 @@ class OpenClawCliService:
Reads the workspace directory and returns metadata + content for each .md file.
"""
import json
from pathlib import Path
wp = Path(workspace_path).expanduser().resolve()
@@ -500,7 +491,7 @@ class OpenClawCliService:
"working", "in_progress", "processing", "thinking", "executing", "streaming",
}
RECENCY_WINDOW_MS = 45 * 60 * 1000 # 45 minutes
45 * 60 * 1000 # 45 minutes
result: dict[str, Any] = {"status": "connected", "agents": {}}
@@ -518,7 +509,6 @@ class OpenClawCliService:
continue
sessions = sessions_data if isinstance(sessions_data, list) else []
now_ms = 0 # placeholder; we'll skip recency check if no ts field
active_count = 0
for session in sessions:

View File

@@ -7,7 +7,7 @@ import json
import sqlite3
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Iterable
from typing import Any, Iterable
from shared.schema import CompanyNews