refactor: Fix code quality issues identified in analysis

1. Rename factory.py's EvoAgent data class to AgentConfig
   - Avoids naming conflict with base/evo_agent.py's EvoAgent

2. Export pipeline_runner functions in backend/core/__init__.py
   - Add create_agents, create_long_term_memory, stop_gateway

3. Consolidate PromptLoader to singleton pattern
   - Add get_prompt_loader() singleton function
   - Update all usages to use singleton

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 01:07:53 +08:00
parent 5b925fbe02
commit 06a23c32a4
14 changed files with 505 additions and 203 deletions

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
"""Agent Factory - Dynamic creation and management of EvoAgents."""
"""Agent Factory - Dynamic creation and management of AgentConfigs."""
import logging
import shutil
@@ -37,8 +37,8 @@ class RoleConfig:
self.constraints = []
class EvoAgent:
"""Represents a configured agent instance."""
class AgentConfig:
"""Represents a configured agent instance (data class)."""
def __init__(
self,
@@ -185,7 +185,7 @@ class AgentFactory:
model_config: Optional[ModelConfig] = None,
role_config: Optional[RoleConfig] = None,
clone_from: Optional[str] = None,
) -> EvoAgent:
) -> AgentConfig:
"""Create a new agent.
Args:
@@ -197,7 +197,7 @@ class AgentFactory:
clone_from: Path to existing agent to clone from (optional)
Returns:
EvoAgent instance
AgentConfig instance
Raises:
ValueError: If agent already exists or workspace doesn't exist
@@ -234,7 +234,7 @@ class AgentFactory:
config_path = agent_dir / "agent.yaml"
self._write_agent_yaml(config_path, agent_id, agent_type, model_config)
return EvoAgent(
return AgentConfig(
agent_id=agent_id,
agent_type=agent_type,
workspace_id=workspace_id,
@@ -267,7 +267,7 @@ class AgentFactory:
new_agent_id: str,
target_workspace_id: Optional[str] = None,
model_config: Optional[ModelConfig] = None,
) -> EvoAgent:
) -> AgentConfig:
"""Clone an existing agent.
Args:
@@ -278,7 +278,7 @@ class AgentFactory:
model_config: Optional new model configuration
Returns:
EvoAgent instance for the cloned agent
AgentConfig instance for the cloned agent
"""
target_workspace_id = target_workspace_id or source_workspace_id
source_dir = self.workspaces_root / source_workspace_id / "agents" / source_agent_id

View File

@@ -6,10 +6,10 @@ from typing import Any, Optional
from .agent_workspace import load_agent_workspace_config
from backend.config.bootstrap_config import get_bootstrap_config_for_run
from .prompt_loader import PromptLoader
from .prompt_loader import get_prompt_loader
from .skills_manager import SkillsManager
_prompt_loader = PromptLoader()
_prompt_loader = get_prompt_loader()
def _read_file_if_exists(path: Path) -> str:

View File

@@ -10,6 +10,17 @@ from typing import Any, Dict, Optional
import yaml
# Singleton instance
_prompt_loader_instance: Optional["PromptLoader"] = None
def get_prompt_loader() -> "PromptLoader":
"""Get the singleton PromptLoader instance."""
global _prompt_loader_instance
if _prompt_loader_instance is None:
_prompt_loader_instance = PromptLoader()
return _prompt_loader_instance
class PromptLoader:
"""Unified Prompt loader"""

View File

@@ -29,7 +29,7 @@ from rich.table import Table
from dotenv import load_dotenv
from backend.agents.agent_workspace import load_agent_workspace_config
from backend.agents.prompt_loader import PromptLoader
from backend.agents.prompt_loader import get_prompt_loader
from backend.agents.skills_manager import SkillsManager
from backend.agents.team_pipeline_config import (
ensure_team_pipeline_config,
@@ -55,7 +55,7 @@ team_app = typer.Typer(help="Inspect and manage run-scoped team pipeline config.
app.add_typer(team_app, name="team")
console = Console()
_prompt_loader = PromptLoader()
_prompt_loader = get_prompt_loader()
load_dotenv()

View File

@@ -3,5 +3,12 @@
from .pipeline import TradingPipeline
from .state_sync import StateSync
from .pipeline_runner import create_agents, create_long_term_memory, stop_gateway
__all__ = ["TradingPipeline", "StateSync"]
__all__ = [
"TradingPipeline",
"StateSync",
"create_agents",
"create_long_term_memory",
"stop_gateway",
]

View File

@@ -30,7 +30,7 @@ from backend.agents.team_pipeline_config import (
from backend.agents import AnalystAgent
from backend.agents.toolkit_factory import create_agent_toolkit
from backend.agents.workspace_manager import WorkspaceManager
from backend.agents.prompt_loader import PromptLoader
from backend.agents.prompt_loader import get_prompt_loader
from backend.llm.models import get_agent_formatter, get_agent_model
from backend.config.constants import ANALYST_TYPES
@@ -1623,7 +1623,7 @@ class TradingPipeline:
config_name = getattr(self.pm, "config", {}).get("config_name", "default")
project_root = Path(__file__).resolve().parents[2]
personas = PromptLoader().load_yaml_config("analyst", "personas")
personas = get_prompt_loader().load_yaml_config("analyst", "personas")
persona = personas.get(analyst_type, {})
WorkspaceManager(project_root=project_root).ensure_agent_assets(
config_name=config_name,

View File

@@ -17,7 +17,7 @@ from typing import Any, Dict, Optional, Callable
from backend.agents import AnalystAgent, PMAgent, RiskAgent
from backend.agents.skills_manager import SkillsManager
from backend.agents.toolkit_factory import create_agent_toolkit, load_agent_profiles
from backend.agents.prompt_loader import PromptLoader
from backend.agents.prompt_loader import get_prompt_loader
from backend.agents.workspace_manager import WorkspaceManager
from backend.config.constants import ANALYST_TYPES
from backend.core.pipeline import TradingPipeline
@@ -36,7 +36,7 @@ from backend.services.storage import StorageService
from backend.services.gateway import Gateway
from backend.utils.settlement import SettlementCoordinator
_prompt_loader = PromptLoader()
_prompt_loader = get_prompt_loader()
# Global gateway reference for cleanup
_gateway_instance: Optional[Gateway] = None

View File

@@ -22,7 +22,7 @@ load_dotenv()
from backend.agents import AnalystAgent, PMAgent, RiskAgent
from backend.agents.skills_manager import SkillsManager
from backend.agents.toolkit_factory import create_agent_toolkit, load_agent_profiles
from backend.agents.prompt_loader import PromptLoader
from backend.agents.prompt_loader import get_prompt_loader
from backend.agents.workspace_manager import WorkspaceManager
from backend.config.constants import ANALYST_TYPES
from backend.core.pipeline import TradingPipeline
@@ -40,7 +40,7 @@ from backend.services.storage import StorageService
from backend.utils.settlement import SettlementCoordinator
logger = logging.getLogger(__name__)
_prompt_loader = PromptLoader()
_prompt_loader = get_prompt_loader()
async def run_gateway(

View File

@@ -16,7 +16,7 @@ from dotenv import load_dotenv
from backend.agents import AnalystAgent, PMAgent, RiskAgent
from backend.agents.skills_manager import SkillsManager
from backend.agents.toolkit_factory import create_agent_toolkit, load_agent_profiles
from backend.agents.prompt_loader import PromptLoader
from backend.agents.prompt_loader import get_prompt_loader
from backend.agents.workspace_manager import WorkspaceManager
from backend.config.bootstrap_config import resolve_runtime_config
from backend.config.constants import ANALYST_TYPES
@@ -38,7 +38,7 @@ load_dotenv()
logger = logging.getLogger(__name__)
loguru.logger.disable("flowllm")
loguru.logger.disable("reme_ai")
_prompt_loader = PromptLoader()
_prompt_loader = get_prompt_loader()
def _get_run_dir(config_name: str) -> Path: