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:
@@ -2,31 +2,23 @@
|
||||
"""Unified Agent Factory - Centralized agent creation for 大时代.
|
||||
|
||||
This module provides a unified factory for creating all agent types (analysts,
|
||||
risk manager, portfolio manager) with consistent configuration. It replaces
|
||||
the scattered agent creation logic in main.py, pipeline.py, and pipeline_runner.py.
|
||||
risk manager, portfolio manager) as EvoAgent instances with consistent
|
||||
configuration. It replaces the scattered agent creation logic in main.py,
|
||||
pipeline.py, and pipeline_runner.py.
|
||||
|
||||
Key features:
|
||||
- Single entry point for all agent creation
|
||||
- Automatic EvoAgent vs Legacy Agent selection based on _resolve_evo_agent_ids()
|
||||
- Creates EvoAgent instances for all agent roles
|
||||
- Consistent parameter handling across all agent types
|
||||
- Support for workspace-driven configuration
|
||||
- Long-term memory integration
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Optional, Protocol, TypeVar, Union
|
||||
from typing import Any, Optional, Protocol
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from backend.agents.base.evo_agent import EvoAgent
|
||||
from backend.agents.analyst import AnalystAgent
|
||||
from backend.agents.risk_manager import RiskAgent
|
||||
from backend.agents.portfolio_manager import PMAgent
|
||||
|
||||
# Type aliases for agent types
|
||||
AgentType = Union["EvoAgent", "AnalystAgent", "RiskAgent", "PMAgent"]
|
||||
T = TypeVar("T")
|
||||
from backend.agents.base.evo_agent import EvoAgent
|
||||
|
||||
|
||||
class AgentFactoryProtocol(Protocol):
|
||||
@@ -39,7 +31,7 @@ class AgentFactoryProtocol(Protocol):
|
||||
formatter: Any,
|
||||
active_skill_dirs: Optional[list[Path]] = None,
|
||||
long_term_memory: Optional[Any] = None,
|
||||
) -> AnalystAgent | EvoAgent: ...
|
||||
) -> EvoAgent: ...
|
||||
|
||||
def create_risk_manager(
|
||||
self,
|
||||
@@ -47,7 +39,7 @@ class AgentFactoryProtocol(Protocol):
|
||||
formatter: Any,
|
||||
active_skill_dirs: Optional[list[Path]] = None,
|
||||
long_term_memory: Optional[Any] = None,
|
||||
) -> RiskAgent | EvoAgent: ...
|
||||
) -> EvoAgent: ...
|
||||
|
||||
def create_portfolio_manager(
|
||||
self,
|
||||
@@ -57,18 +49,14 @@ class AgentFactoryProtocol(Protocol):
|
||||
margin_requirement: float,
|
||||
active_skill_dirs: Optional[list[Path]] = None,
|
||||
long_term_memory: Optional[Any] = None,
|
||||
) -> PMAgent | EvoAgent: ...
|
||||
) -> EvoAgent: ...
|
||||
|
||||
|
||||
class UnifiedAgentFactory:
|
||||
"""Unified factory for creating agents with consistent configuration.
|
||||
"""Unified factory for creating EvoAgent instances with consistent configuration.
|
||||
|
||||
This factory centralizes agent creation logic and automatically selects
|
||||
between EvoAgent (new) and Legacy Agent based on the EVO_AGENT_IDS
|
||||
environment variable configuration.
|
||||
|
||||
By default, all supported roles use EvoAgent. Set EVO_AGENT_IDS=legacy
|
||||
to disable EvoAgent entirely.
|
||||
This factory centralizes agent creation logic and creates EvoAgent instances
|
||||
for all agent roles (analysts, risk manager, portfolio manager).
|
||||
|
||||
Example:
|
||||
factory = UnifiedAgentFactory(
|
||||
@@ -103,7 +91,6 @@ class UnifiedAgentFactory:
|
||||
config_name: str,
|
||||
skills_manager: Any,
|
||||
toolkit_factory: Optional[Any] = None,
|
||||
evo_agent_ids: Optional[set[str]] = None,
|
||||
):
|
||||
"""Initialize the agent factory.
|
||||
|
||||
@@ -111,49 +98,11 @@ class UnifiedAgentFactory:
|
||||
config_name: Run configuration name (e.g., "smoke_fullstack")
|
||||
skills_manager: SkillsManager instance for skill/asset management
|
||||
toolkit_factory: Optional factory function for creating toolkits
|
||||
evo_agent_ids: Optional set of agent IDs to use EvoAgent.
|
||||
If None, uses _resolve_evo_agent_ids() default.
|
||||
"""
|
||||
self.config_name = config_name
|
||||
self.skills_manager = skills_manager
|
||||
self.toolkit_factory = toolkit_factory
|
||||
|
||||
# Determine which agents should use EvoAgent
|
||||
if evo_agent_ids is not None:
|
||||
self._evo_agent_ids = evo_agent_ids
|
||||
else:
|
||||
self._evo_agent_ids = self._resolve_evo_agent_ids()
|
||||
|
||||
def _resolve_evo_agent_ids(self) -> set[str]:
|
||||
"""Return agent ids selected to use EvoAgent.
|
||||
|
||||
By default, all supported roles use EvoAgent.
|
||||
EVO_AGENT_IDS can be used to limit to specific roles.
|
||||
"""
|
||||
from backend.config.constants import ANALYST_TYPES
|
||||
|
||||
all_supported = set(ANALYST_TYPES) | {"risk_manager", "portfolio_manager"}
|
||||
|
||||
raw = os.getenv("EVO_AGENT_IDS", "")
|
||||
if not raw.strip():
|
||||
# Default: all supported roles use EvoAgent
|
||||
return all_supported
|
||||
|
||||
if raw.strip().lower() in ("legacy", "old", "none"):
|
||||
return set()
|
||||
|
||||
requested = {item.strip() for item in raw.split(",") if item.strip()}
|
||||
return {
|
||||
agent_id
|
||||
for agent_id in requested
|
||||
if agent_id in ANALYST_TYPES
|
||||
or agent_id in {"risk_manager", "portfolio_manager"}
|
||||
}
|
||||
|
||||
def _should_use_evo_agent(self, agent_id: str) -> bool:
|
||||
"""Check if an agent should use EvoAgent."""
|
||||
return agent_id in self._evo_agent_ids
|
||||
|
||||
def _create_toolkit(
|
||||
self,
|
||||
agent_type: str,
|
||||
@@ -202,10 +151,8 @@ class UnifiedAgentFactory:
|
||||
agent_config: Any,
|
||||
long_term_memory: Optional[Any] = None,
|
||||
extra_kwargs: Optional[dict[str, Any]] = None,
|
||||
) -> "EvoAgent":
|
||||
) -> EvoAgent:
|
||||
"""Create an EvoAgent instance."""
|
||||
from backend.agents.base.evo_agent import EvoAgent
|
||||
|
||||
workspace_dir = self.skills_manager.get_agent_asset_dir(
|
||||
self.config_name, agent_id
|
||||
)
|
||||
@@ -239,7 +186,7 @@ class UnifiedAgentFactory:
|
||||
formatter: Any,
|
||||
active_skill_dirs: Optional[list[Path]] = None,
|
||||
long_term_memory: Optional[Any] = None,
|
||||
) -> "AnalystAgent | EvoAgent":
|
||||
) -> EvoAgent:
|
||||
"""Create an analyst agent.
|
||||
|
||||
Args:
|
||||
@@ -250,31 +197,16 @@ class UnifiedAgentFactory:
|
||||
long_term_memory: Optional long-term memory instance
|
||||
|
||||
Returns:
|
||||
AnalystAgent or EvoAgent instance
|
||||
EvoAgent instance
|
||||
"""
|
||||
toolkit = self._create_toolkit(analyst_type, active_skill_dirs)
|
||||
|
||||
if self._should_use_evo_agent(analyst_type):
|
||||
agent_config = self._load_agent_config(analyst_type)
|
||||
return self._create_evo_agent(
|
||||
agent_id=analyst_type,
|
||||
model=model,
|
||||
formatter=formatter,
|
||||
toolkit=toolkit,
|
||||
agent_config=agent_config,
|
||||
long_term_memory=long_term_memory,
|
||||
)
|
||||
|
||||
# Legacy path
|
||||
from backend.agents.analyst import AnalystAgent
|
||||
|
||||
return AnalystAgent(
|
||||
analyst_type=analyst_type,
|
||||
toolkit=toolkit,
|
||||
agent_config = self._load_agent_config(analyst_type)
|
||||
return self._create_evo_agent(
|
||||
agent_id=analyst_type,
|
||||
model=model,
|
||||
formatter=formatter,
|
||||
agent_id=analyst_type,
|
||||
config={"config_name": self.config_name},
|
||||
toolkit=toolkit,
|
||||
agent_config=agent_config,
|
||||
long_term_memory=long_term_memory,
|
||||
)
|
||||
|
||||
@@ -284,7 +216,7 @@ class UnifiedAgentFactory:
|
||||
formatter: Any,
|
||||
active_skill_dirs: Optional[list[Path]] = None,
|
||||
long_term_memory: Optional[Any] = None,
|
||||
) -> "RiskAgent | EvoAgent":
|
||||
) -> EvoAgent:
|
||||
"""Create a risk manager agent.
|
||||
|
||||
Args:
|
||||
@@ -294,31 +226,17 @@ class UnifiedAgentFactory:
|
||||
long_term_memory: Optional long-term memory instance
|
||||
|
||||
Returns:
|
||||
RiskAgent or EvoAgent instance
|
||||
EvoAgent instance
|
||||
"""
|
||||
toolkit = self._create_toolkit("risk_manager", active_skill_dirs)
|
||||
|
||||
if self._should_use_evo_agent("risk_manager"):
|
||||
agent_config = self._load_agent_config("risk_manager")
|
||||
return self._create_evo_agent(
|
||||
agent_id="risk_manager",
|
||||
model=model,
|
||||
formatter=formatter,
|
||||
toolkit=toolkit,
|
||||
agent_config=agent_config,
|
||||
long_term_memory=long_term_memory,
|
||||
)
|
||||
|
||||
# Legacy path
|
||||
from backend.agents.risk_manager import RiskAgent
|
||||
|
||||
return RiskAgent(
|
||||
agent_config = self._load_agent_config("risk_manager")
|
||||
return self._create_evo_agent(
|
||||
agent_id="risk_manager",
|
||||
model=model,
|
||||
formatter=formatter,
|
||||
name="risk_manager",
|
||||
config={"config_name": self.config_name},
|
||||
long_term_memory=long_term_memory,
|
||||
toolkit=toolkit,
|
||||
agent_config=agent_config,
|
||||
long_term_memory=long_term_memory,
|
||||
)
|
||||
|
||||
def create_portfolio_manager(
|
||||
@@ -329,7 +247,7 @@ class UnifiedAgentFactory:
|
||||
margin_requirement: float,
|
||||
active_skill_dirs: Optional[list[Path]] = None,
|
||||
long_term_memory: Optional[Any] = None,
|
||||
) -> "PMAgent | EvoAgent":
|
||||
) -> EvoAgent:
|
||||
"""Create a portfolio manager agent.
|
||||
|
||||
Args:
|
||||
@@ -341,52 +259,34 @@ class UnifiedAgentFactory:
|
||||
long_term_memory: Optional long-term memory instance
|
||||
|
||||
Returns:
|
||||
PMAgent or EvoAgent instance
|
||||
EvoAgent instance
|
||||
"""
|
||||
if self._should_use_evo_agent("portfolio_manager"):
|
||||
agent_config = self._load_agent_config("portfolio_manager")
|
||||
agent_config = self._load_agent_config("portfolio_manager")
|
||||
|
||||
# For PM, toolkit is created after agent (needs owner reference)
|
||||
from backend.agents.base.evo_agent import EvoAgent
|
||||
# For PM, toolkit is created after agent (needs owner reference)
|
||||
workspace_dir = self.skills_manager.get_agent_asset_dir(
|
||||
self.config_name, "portfolio_manager"
|
||||
)
|
||||
|
||||
workspace_dir = self.skills_manager.get_agent_asset_dir(
|
||||
self.config_name, "portfolio_manager"
|
||||
)
|
||||
|
||||
agent = EvoAgent(
|
||||
agent_id="portfolio_manager",
|
||||
config_name=self.config_name,
|
||||
workspace_dir=workspace_dir,
|
||||
model=model,
|
||||
formatter=formatter,
|
||||
skills_manager=self.skills_manager,
|
||||
prompt_files=getattr(agent_config, "prompt_files", ["SOUL.md"]),
|
||||
initial_cash=initial_cash,
|
||||
margin_requirement=margin_requirement,
|
||||
long_term_memory=long_term_memory,
|
||||
)
|
||||
agent.toolkit = self._create_toolkit(
|
||||
"portfolio_manager", active_skill_dirs, owner=agent
|
||||
)
|
||||
setattr(agent, "run_id", self.config_name)
|
||||
# Keep workspace_id for backward compatibility
|
||||
setattr(agent, "workspace_id", self.config_name)
|
||||
return agent
|
||||
|
||||
# Legacy path
|
||||
from backend.agents.portfolio_manager import PMAgent
|
||||
|
||||
return PMAgent(
|
||||
name="portfolio_manager",
|
||||
agent = EvoAgent(
|
||||
agent_id="portfolio_manager",
|
||||
config_name=self.config_name,
|
||||
workspace_dir=workspace_dir,
|
||||
model=model,
|
||||
formatter=formatter,
|
||||
skills_manager=self.skills_manager,
|
||||
prompt_files=getattr(agent_config, "prompt_files", ["SOUL.md"]),
|
||||
initial_cash=initial_cash,
|
||||
margin_requirement=margin_requirement,
|
||||
config={"config_name": self.config_name},
|
||||
long_term_memory=long_term_memory,
|
||||
toolkit_factory=self.toolkit_factory,
|
||||
toolkit_factory_kwargs={"active_skill_dirs": active_skill_dirs or []},
|
||||
)
|
||||
agent.toolkit = self._create_toolkit(
|
||||
"portfolio_manager", active_skill_dirs, owner=agent
|
||||
)
|
||||
setattr(agent, "run_id", self.config_name)
|
||||
# Keep workspace_id for backward compatibility
|
||||
setattr(agent, "workspace_id", self.config_name)
|
||||
return agent
|
||||
|
||||
|
||||
# Singleton factory instance cache
|
||||
|
||||
Reference in New Issue
Block a user