feat(agent): complete EvoAgent integration for all 6 agent roles

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
This commit is contained in:
2026-04-02 00:55:08 +08:00
parent 0fa413380c
commit 16b54d5ccc
73 changed files with 9454 additions and 904 deletions

101
README.md
View File

@@ -39,22 +39,41 @@ The frontend exposes the trading room, runtime controls, logs, approvals, agent
## Current Architecture
The repository is currently in a transition from a modular monolith to split service surfaces. The split-service path is the default local development mode.
The repository uses a **split-service runtime model** for local development and is the default supported path.
Current app surfaces:
### Runtime vs Design-Time
- `backend.apps.agent_service` on `:8000`: control plane for workspaces, agents, skills, and guard/approval APIs
- `backend.apps.trading_service` on `:8001`: read-only trading data APIs
- `backend.apps.news_service` on `:8002`: read-only explain/news APIs
- `backend.apps.runtime_service` on `:8003`: runtime lifecycle APIs
- `backend.apps.openclaw_service` on `:8004`: read-only OpenClaw facade
- WebSocket gateway on `:8765`: live event/feed channel for the frontend
- **runtime** — the active execution layer (scheduler, gateway, pipeline, approvals during a live run)
- **run** — one concrete execution instance (`runs/<run_id>/`)
- **design-time** — configuration and control-plane concepts before a specific runtime is launched
- **workspace** — the design-time registry exposed by `agent_service` (`workspaces/`)
The most important runtime path today is:
### Service Surfaces
`frontend -> runtime_service/control APIs -> gateway/runtime manager -> market service + pipeline + storage`
| Service | Port | Responsibility |
|---------|------|----------------|
| `backend.apps.agent_service` | `:8000` | Control plane for workspaces, agents, skills, and guard/approval APIs |
| `backend.apps.trading_service` | `:8001` | Read-only trading data APIs |
| `backend.apps.news_service` | `:8002` | Read-only explain/news APIs |
| `backend.apps.runtime_service` | `:8003` | Runtime lifecycle APIs |
| `backend.apps.openclaw_service` | `:8004` | Read-only OpenClaw facade |
| WebSocket gateway | `:8765` | Live event/feed channel for the frontend |
Reference notes for the migration live in [services/README.md](./services/README.md).
### Active Runtime Path
```
frontend -> runtime_service/control APIs -> gateway/runtime manager -> market service + pipeline + storage
```
Runtime state is stored in `runs/<run_id>/` — this is the **runtime source of truth**. The `workspaces/` directory is the **design-time registry**, not the runtime execution path.
### Documentation
- [docs/current-architecture.md](./docs/current-architecture.md) — canonical architecture facts
- [services/README.md](./services/README.md) — service boundaries and migration details
- [docs/current-architecture.excalidraw](./docs/current-architecture.excalidraw) — visual diagram
- [docs/development-roadmap.md](./docs/development-roadmap.md) — next-step execution plan
- [docs/terminology.md](./docs/terminology.md) — consistent terminology guide
---
@@ -114,6 +133,9 @@ MODEL_NAME=qwen3-max-preview
# memory (optional unless --enable-memory is used)
MEMORY_API_KEY=
# experimental: switch selected analyst / risk roles to EvoAgent
EVO_AGENT_IDS=
```
Notes:
@@ -121,6 +143,52 @@ Notes:
- `FINNHUB_API_KEY` is required for live mode.
- `POLYGON_API_KEY` enables long-lived market-store ingestion and refresh helpers.
- `MEMORY_API_KEY` is only required when long-term memory is enabled.
- `EVO_AGENT_IDS` currently supports analyst roles plus `risk_manager` and `portfolio_manager`, and is intended for staged rollout.
### Skill Sandbox Security | 技能沙盒安全
Skill scripts can be executed in multiple sandbox modes controlled by `SKILL_SANDBOX_MODE`:
| Mode | Description | Use Case |
|------|-------------|----------|
| `none` | Direct execution, no isolation | Development only (default) |
| `docker` | Docker container isolation | Production with Docker |
| `kubernetes` | Kubernetes Pod isolation | Enterprise (reserved) |
Default configuration (development):
```bash
SKILL_SANDBOX_MODE=none
```
For production with Docker isolation:
```bash
SKILL_SANDBOX_MODE=docker
SKILL_SANDBOX_MEMORY_LIMIT=512m
SKILL_SANDBOX_CPU_LIMIT=1.0
SKILL_SANDBOX_NETWORK=none
```
When running in `none` mode, a runtime security warning is displayed on first skill execution as a reminder that scripts execute directly without isolation.
Smoke test for a specific staged EvoAgent rollout target:
```bash
python3 scripts/smoke_evo_runtime.py --agent-id fundamentals_analyst
```
This script starts a temporary runtime, verifies the gateway log contains the
selected `EvoAgent`, checks `runtime_state.json`, validates the approval wake-up
path, and then stops the runtime.
You can also include it in the local release check:
```bash
./scripts/check-prod-env.sh --smoke-evo
```
Without `EVO_AGENT_IDS`, this release check now runs
`fundamentals_analyst`, `risk_manager`, and `portfolio_manager`
smoke paths by default.
For a production-style local start flow, you can also use:
@@ -128,6 +196,9 @@ For a production-style local start flow, you can also use:
./start.sh
```
The checked-in `production` label in the deploy scripts is only an example run
label. It should not be treated as a canonical root-level runtime directory.
### 3. Start the stack
Recommended local development flow:
@@ -159,6 +230,7 @@ python -m uvicorn backend.apps.agent_service:app --host 0.0.0.0 --port 8000 --re
python -m uvicorn backend.apps.trading_service:app --host 0.0.0.0 --port 8001 --reload
python -m uvicorn backend.apps.news_service:app --host 0.0.0.0 --port 8002 --reload
python -m uvicorn backend.apps.runtime_service:app --host 0.0.0.0 --port 8003 --reload
# compatibility gateway path, not the recommended primary dev entrypoint
python -m backend.main --mode live --host 0.0.0.0 --port 8765
```
@@ -208,6 +280,11 @@ unzip ret_data.zip -d backend/data
- `runs/<run_id>/BOOTSTRAP.md` stores run-specific bootstrap values and prompt body
- `runs/<run_id>/state/runtime_state.json` stores runtime snapshot state
- `runs/<run_id>/team_dashboard/*.json` is a compatibility/export layer for dashboard consumers, not the primary runtime source of truth
- `ENABLE_DASHBOARD_COMPAT_EXPORTS=false` can disable those compatibility JSON exports in controlled environments while keeping runtime state persistence intact
Legacy root-level directories such as `live/`, `production/`, and `backtest/`
should be treated as historical compatibility artifacts, not the default runtime
location for new work.
Optional retention control:
@@ -304,7 +381,7 @@ trigger_time: "09:30"
enable_memory: false
```
Initialize a run workspace with:
Initialize run-scoped assets with:
```bash
evotraders init-workspace --config-name my_run