docs: update docs/agent/ with AgentOS architecture, components, conventions, and ADR 013
Co-authored-by: aguzererler <6199053+aguzererler@users.noreply.github.com> Agent-Logs-Url: https://github.com/aguzererler/TradingAgents/sessions/7cf1fa1a-8cb0-46b4-bc20-525aa3d38d7d
This commit is contained in:
parent
1b5aee572a
commit
e808031aa6
|
|
@ -1,34 +1,31 @@
|
|||
# Current Milestone
|
||||
|
||||
Portfolio Manager feature fully implemented (Phases 1–10). All 588 tests passing (14 skipped).
|
||||
AgentOS visual observability layer shipped. Portfolio Manager fully implemented (Phases 1–10). All 725 tests passing (14 skipped).
|
||||
|
||||
# Recent Progress
|
||||
|
||||
- **AgentOS (current PR)**: Full-stack visual observability layer for agent execution
|
||||
- `agent_os/backend/` — FastAPI backend (port 8088) with REST + WebSocket streaming
|
||||
- `agent_os/frontend/` — React + Vite 8 + Chakra UI + ReactFlow dashboard
|
||||
- `agent_os/backend/services/langgraph_engine.py` — LangGraph event mapping engine (4 run types: scan, pipeline, portfolio, auto)
|
||||
- `agent_os/backend/routes/websocket.py` — WebSocket streaming endpoint (`/ws/stream/{run_id}`)
|
||||
- `agent_os/backend/routes/runs.py` — REST run triggers (`POST /api/run/{type}`)
|
||||
- `agent_os/backend/routes/portfolios.py` — Portfolio REST API with field mapping (backend models → frontend shape)
|
||||
- `agent_os/frontend/src/Dashboard.tsx` — 2-page layout (dashboard + portfolio), agent graph + terminal + controls
|
||||
- `agent_os/frontend/src/components/AgentGraph.tsx` — ReactFlow live graph visualization
|
||||
- `agent_os/frontend/src/components/PortfolioViewer.tsx` — Holdings, trade history, summary views
|
||||
- `agent_os/frontend/src/components/MetricHeader.tsx` — Top-3 metrics (Sharpe, regime, drawdown)
|
||||
- `agent_os/frontend/src/hooks/useAgentStream.ts` — WebSocket hook with status tracking
|
||||
- `tests/unit/test_langgraph_engine_extraction.py` — 14 tests for event mapping
|
||||
- Pipeline recursion limit fix: passes `config={"recursion_limit": propagator.max_recur_limit}` to `astream_events()`
|
||||
- Portfolio field mapping fix: shares→quantity, portfolio_id→id, cash→cash_balance, trade_date→executed_at
|
||||
- **PR #32 merged**: Portfolio Manager data foundation — models, SQL schema, module scaffolding
|
||||
- `tradingagents/portfolio/` — full module: models, config, exceptions, supabase_client (psycopg2), report_store, repository
|
||||
- `migrations/001_initial_schema.sql` — 4 tables (portfolios, holdings, trades, snapshots) with constraints, indexes, triggers
|
||||
- `tests/portfolio/` — 51 tests: 20 model, 15 report_store, 12 repository unit, 4 integration
|
||||
- Uses `psycopg2` direct PostgreSQL via Supabase pooler (`aws-1-eu-west-1.pooler.supabase.com:6543`)
|
||||
- Business logic: avg cost basis, cash accounting, trade recording, snapshots
|
||||
- **PR #22 merged**: Unified report paths, structured observability logging, memory system update
|
||||
- **feat/daily-digest-notebooklm** (shipped): Daily digest consolidation + NotebookLM source sync
|
||||
- **Portfolio Manager Phases 2-5** (implemented):
|
||||
- `tradingagents/portfolio/risk_evaluator.py` — pure-Python risk metrics (log returns, Sharpe, Sortino, VaR, max drawdown, beta, sector concentration, constraint checking)
|
||||
- `tradingagents/portfolio/candidate_prioritizer.py` — conviction × thesis × diversification × held_penalty scoring
|
||||
- `tradingagents/portfolio/trade_executor.py` — executes BUY/SELL (SELLs first), constraint pre-flight, EOD snapshot
|
||||
- `tradingagents/agents/portfolio/holding_reviewer.py` — LLM holding review agent (run_tool_loop pattern)
|
||||
- `tradingagents/agents/portfolio/pm_decision_agent.py` — pure-reasoning PM decision agent (no tools)
|
||||
- `tradingagents/portfolio/portfolio_states.py` — PortfolioManagerState (MessagesState + reducers)
|
||||
- `tradingagents/graph/portfolio_setup.py` — PortfolioGraphSetup (sequential 6-node workflow)
|
||||
- `tradingagents/graph/portfolio_graph.py` — PortfolioGraph (mirrors ScannerGraph pattern)
|
||||
- 48 new tests (28 risk_evaluator + 10 candidate_prioritizer + 10 trade_executor)
|
||||
- **Portfolio Manager Phases 2-5** (implemented): risk_evaluator, candidate_prioritizer, trade_executor, holding_reviewer, pm_decision_agent, portfolio_states, portfolio_setup, portfolio_graph
|
||||
- **Portfolio CLI integration**: `portfolio`, `check-portfolio`, `auto` commands in `cli/main.py`
|
||||
- **Documentation updated**: Flow diagram in `docs/portfolio/00_overview.md` aligned with actual 6-node sequential implementation; token estimation per model added; CLI & test commands added to README.md
|
||||
|
||||
# In Progress
|
||||
|
||||
- Refinement of macro scan synthesis prompts (ongoing)
|
||||
- End-to-end integration testing with live LLM + Supabase
|
||||
- None — PR ready for merge
|
||||
|
||||
# Active Blockers
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<!-- Last verified: 2026-03-19 -->
|
||||
<!-- Last verified: 2026-03-23 -->
|
||||
|
||||
# Architecture
|
||||
|
||||
|
|
@ -131,6 +131,70 @@ Source: `tradingagents/observability.py`
|
|||
|
||||
Source: `cli/main.py`, `cli/stats_handler.py`
|
||||
|
||||
## AgentOS — Visual Observability Layer
|
||||
|
||||
Full-stack web UI for monitoring and controlling agent execution in real-time.
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────┐ ┌───────────────────────────────────┐
|
||||
│ Frontend (React + Vite 8) │ │ Backend (FastAPI) │
|
||||
│ localhost:5173 │◄─WS──►│ 127.0.0.1:8088 │
|
||||
│ │ │ │
|
||||
│ Dashboard (2 pages via sidebar) │ │ POST /api/run/{type} — queue run │
|
||||
│ ├─ dashboard: graph+terminal │ │ WS /ws/stream/{run_id} — execute │
|
||||
│ └─ portfolio: PortfolioViewer │ │ GET /api/portfolios/* — data │
|
||||
│ │ │ │
|
||||
│ ReactFlow (live agent graph) │ │ LangGraphEngine │
|
||||
│ Terminal (event stream) │ │ ├─ run_scan() │
|
||||
│ MetricHeader (Sharpe/regime) │ │ ├─ run_pipeline() │
|
||||
│ Param panel (date/ticker/id) │ │ ├─ run_portfolio() │
|
||||
│ │ │ └─ run_auto() [scan→pipe→port] │
|
||||
└──────────────────────────────────┘ └───────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Run Types
|
||||
|
||||
| Type | REST Trigger | WebSocket Executor | Description |
|
||||
|------|-------------|-------------------|-------------|
|
||||
| `scan` | `POST /api/run/scan` | `run_scan()` | 3-phase macro scanner |
|
||||
| `pipeline` | `POST /api/run/pipeline` | `run_pipeline()` | Per-ticker trading analysis |
|
||||
| `portfolio` | `POST /api/run/portfolio` | `run_portfolio()` | Portfolio manager workflow |
|
||||
| `auto` | `POST /api/run/auto` | `run_auto()` | Sequential: scan → pipeline → portfolio |
|
||||
|
||||
REST endpoints only queue runs (in-memory store). WebSocket is the sole executor — streaming LangGraph events to the frontend in real-time.
|
||||
|
||||
### Event Streaming
|
||||
|
||||
`LangGraphEngine._map_langgraph_event()` maps LangGraph v2 events to 4 frontend event types:
|
||||
|
||||
| Event | LangGraph Trigger | Content |
|
||||
|-------|------------------|---------|
|
||||
| `thought` | `on_chat_model_start` | Prompt text, model name |
|
||||
| `tool` | `on_tool_start` | Tool name, arguments |
|
||||
| `tool_result` | `on_tool_end` | Tool output |
|
||||
| `result` | `on_chat_model_end` | Response text, token counts, latency |
|
||||
|
||||
Each event includes optional `prompt` and `response` full-text fields. Model name extraction uses 3 fallbacks: `invocation_params` → serialized kwargs → `metadata.ls_model_name`. Event mapping uses try/except per type and `_safe_dict()` helper to prevent crashes from non-dict metadata.
|
||||
|
||||
### Portfolio API
|
||||
|
||||
| Endpoint | Description |
|
||||
|----------|-------------|
|
||||
| `GET /api/portfolios/` | List all portfolios |
|
||||
| `GET /api/portfolios/{id}` | Get portfolio details |
|
||||
| `GET /api/portfolios/{id}/summary` | Top-3 metrics (Sharpe, regime, drawdown) |
|
||||
| `GET /api/portfolios/{id}/latest` | Holdings, trades, snapshot with field mapping |
|
||||
|
||||
The `/latest` endpoint maps backend model fields to frontend shape: `Holding.shares` → `quantity`, `Portfolio.portfolio_id` → `id`, `cash` → `cash_balance`, `Trade.trade_date` → `executed_at`. Computed runtime fields (`market_value`, `unrealized_pnl`) are included from enriched Holding properties.
|
||||
|
||||
### Pipeline Recursion Limit
|
||||
|
||||
`run_pipeline()` passes `config={"recursion_limit": propagator.max_recur_limit}` (default 100) to `astream_events()`. Without it, LangGraph defaults to 25 which is too low for the debate + risk cycles.
|
||||
|
||||
Source: `agent_os/backend/`, `agent_os/frontend/`
|
||||
|
||||
## Key Source Files
|
||||
|
||||
| File | Purpose |
|
||||
|
|
@ -138,8 +202,10 @@ Source: `cli/main.py`, `cli/stats_handler.py`
|
|||
| `tradingagents/default_config.py` | All config keys, defaults, env var override pattern |
|
||||
| `tradingagents/graph/trading_graph.py` | `TradingAgentsGraph` class, LLM wiring, tool nodes |
|
||||
| `tradingagents/graph/scanner_graph.py` | `ScannerGraph` class, 3-phase workflow |
|
||||
| `tradingagents/graph/portfolio_graph.py` | `PortfolioGraph` class, 6-node portfolio workflow |
|
||||
| `tradingagents/graph/setup.py` | `GraphSetup` — agent node creation, graph compilation |
|
||||
| `tradingagents/graph/scanner_setup.py` | `ScannerGraphSetup` — scanner graph compilation |
|
||||
| `tradingagents/graph/portfolio_setup.py` | `PortfolioGraphSetup` — portfolio graph compilation |
|
||||
| `tradingagents/dataflows/interface.py` | `route_to_vendor`, `VENDOR_METHODS`, `FALLBACK_ALLOWED` |
|
||||
| `tradingagents/agents/utils/tool_runner.py` | `run_tool_loop()`, `MAX_TOOL_ROUNDS=5`, `MIN_REPORT_LENGTH=2000` |
|
||||
| `tradingagents/agents/utils/agent_states.py` | `AgentState`, `InvestDebateState`, `RiskDebateState` |
|
||||
|
|
@ -150,3 +216,13 @@ Source: `cli/main.py`, `cli/stats_handler.py`
|
|||
| `tradingagents/report_paths.py` | Unified report path helpers (`get_market_dir`, `get_ticker_dir`, etc.) |
|
||||
| `tradingagents/observability.py` | `RunLogger`, `_LLMCallbackHandler`, structured event logging |
|
||||
| `tradingagents/dataflows/config.py` | `set_config()`, `get_config()`, `initialize_config()` |
|
||||
| `agent_os/backend/main.py` | FastAPI app, CORS, route mounting, health check |
|
||||
| `agent_os/backend/services/langgraph_engine.py` | `LangGraphEngine` — run orchestration, LangGraph event mapping |
|
||||
| `agent_os/backend/routes/websocket.py` | WebSocket streaming endpoint (`/ws/stream/{run_id}`) |
|
||||
| `agent_os/backend/routes/runs.py` | REST run triggers (`POST /api/run/{type}`) |
|
||||
| `agent_os/backend/routes/portfolios.py` | Portfolio REST API with field mapping |
|
||||
| `agent_os/frontend/src/Dashboard.tsx` | 2-page dashboard, graph + terminal + controls |
|
||||
| `agent_os/frontend/src/hooks/useAgentStream.ts` | WebSocket hook, `AgentEvent` type, status tracking |
|
||||
| `agent_os/frontend/src/components/AgentGraph.tsx` | ReactFlow live agent graph visualization |
|
||||
| `agent_os/frontend/src/components/PortfolioViewer.tsx` | Holdings table, trade history, snapshot summary |
|
||||
| `agent_os/frontend/src/components/MetricHeader.tsx` | Top-3 portfolio metrics display |
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<!-- Last verified: 2026-03-19 -->
|
||||
<!-- Last verified: 2026-03-23 -->
|
||||
|
||||
# Components
|
||||
|
||||
|
|
@ -93,6 +93,41 @@ tradingagents/
|
|||
|
||||
cli/
|
||||
└── main.py # Typer app, MessageBuffer, Rich UI, 3 commands
|
||||
|
||||
agent_os/
|
||||
├── __init__.py
|
||||
├── DESIGN.md # Visual observability design document
|
||||
├── README.md # AgentOS overview and setup instructions
|
||||
├── backend/
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py # FastAPI app, CORS, route mounting (port 8088)
|
||||
│ ├── dependencies.py # get_current_user() (V1 hardcoded), get_db_client()
|
||||
│ ├── store.py # In-memory run store (Dict[str, Dict])
|
||||
│ ├── routes/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── runs.py # POST /api/run/{scan,pipeline,portfolio,auto}
|
||||
│ │ ├── websocket.py # WS /ws/stream/{run_id} — sole executor
|
||||
│ │ └── portfolios.py # GET /api/portfolios/* — CRUD + summary + latest
|
||||
│ └── services/
|
||||
│ ├── __init__.py
|
||||
│ └── langgraph_engine.py # LangGraphEngine: run_scan/pipeline/portfolio/auto, event mapping
|
||||
└── frontend/
|
||||
├── package.json # React 18 + Vite 8 + Chakra UI + ReactFlow
|
||||
├── tsconfig.json
|
||||
├── vite.config.ts
|
||||
├── index.html
|
||||
└── src/
|
||||
├── main.tsx # React entry point
|
||||
├── App.tsx # ChakraProvider wrapper
|
||||
├── Dashboard.tsx # 2-page layout: dashboard (graph+terminal) / portfolio
|
||||
├── theme.ts # Dark theme customization
|
||||
├── index.css # Global styles
|
||||
├── hooks/
|
||||
│ └── useAgentStream.ts # WebSocket hook, AgentEvent type, status ref
|
||||
└── components/
|
||||
├── AgentGraph.tsx # ReactFlow live graph with incremental nodes
|
||||
├── MetricHeader.tsx # Top-3 metrics: Sharpe, regime, drawdown
|
||||
└── PortfolioViewer.tsx # Holdings table, trade history, snapshot view
|
||||
```
|
||||
|
||||
## Agent Factory Inventory (17 factories + 1 utility)
|
||||
|
|
@ -161,6 +196,27 @@ cli/
|
|||
| `scan` | `run_scan(date)` | 3-phase macro scanner, saves 5 report files |
|
||||
| `pipeline` | `run_pipeline()` | Full pipeline: scan JSON → filter by conviction → per-ticker deep dive |
|
||||
|
||||
## AgentOS Frontend Components
|
||||
|
||||
| Component | File | Description |
|
||||
|-----------|------|-------------|
|
||||
| `Dashboard` | `agent_os/frontend/src/Dashboard.tsx` | 2-page layout with sidebar (dashboard/portfolio), run buttons, param panel |
|
||||
| `AgentGraph` | `agent_os/frontend/src/components/AgentGraph.tsx` | ReactFlow live graph — incremental node addition via useRef(Set) dedup |
|
||||
| `MetricHeader` | `agent_os/frontend/src/components/MetricHeader.tsx` | Top-3 metrics: Sharpe ratio, market regime+beta, drawdown+VaR |
|
||||
| `PortfolioViewer` | `agent_os/frontend/src/components/PortfolioViewer.tsx` | 3-tab view: holdings table, trade history, snapshot summary |
|
||||
| `useAgentStream` | `agent_os/frontend/src/hooks/useAgentStream.ts` | WebSocket hook with `statusRef` to avoid stale closures |
|
||||
|
||||
## AgentOS Backend Services
|
||||
|
||||
| Service | File | Description |
|
||||
|---------|------|-------------|
|
||||
| `LangGraphEngine` | `agent_os/backend/services/langgraph_engine.py` | Orchestrates 4 run types, maps LangGraph v2 events to frontend events |
|
||||
| `runs` router | `agent_os/backend/routes/runs.py` | REST triggers: `POST /api/run/{type}` — queues runs in memory store |
|
||||
| `websocket` router | `agent_os/backend/routes/websocket.py` | `WS /ws/stream/{run_id}` — sole executor, streams events to frontend |
|
||||
| `portfolios` router | `agent_os/backend/routes/portfolios.py` | Portfolio CRUD, summary metrics, holdings/trades with field mapping |
|
||||
| `dependencies` | `agent_os/backend/dependencies.py` | `get_current_user()` (V1 hardcoded), `get_db_client()` |
|
||||
| `store` | `agent_os/backend/store.py` | In-memory `Dict[str, Dict]` run store (demo, not persisted) |
|
||||
|
||||
## Test Organization
|
||||
|
||||
| Test File | Type | What It Covers | Markers |
|
||||
|
|
@ -190,5 +246,6 @@ cli/
|
|||
| `test_ttm_analysis.py` | Mixed | TTM metrics computation, report format | `integration` on live test |
|
||||
| `test_vendor_failfast.py` | Unit | ADR 011 fail-fast behavior, error chaining | — |
|
||||
| `test_yfinance_integration.py` | Unit | Full yfinance data layer (all mocked) | — |
|
||||
| `test_langgraph_engine_extraction.py` | Unit | LangGraph event mapping, model/prompt extraction, _safe_dict helper | — |
|
||||
|
||||
Pytest markers: `integration` (live API), `paid_tier` (Finnhub paid subscription), `slow` (long-running). Defined in `conftest.py`.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<!-- Last verified: 2026-03-19 -->
|
||||
<!-- Last verified: 2026-03-23 -->
|
||||
|
||||
# Conventions
|
||||
|
||||
|
|
@ -94,3 +94,17 @@
|
|||
- Fail-fast by default — no silent fallback unless method is in `FALLBACK_ALLOWED`. (ADR 011)
|
||||
- Alpha Vantage hierarchy: `AlphaVantageError` → `APIKeyInvalidError`, `RateLimitError`, `ThirdPartyError`, `ThirdPartyTimeoutError`, `ThirdPartyParseError`. (`alpha_vantage_common.py`)
|
||||
- Finnhub hierarchy: `FinnhubError` → `APIKeyInvalidError`, `RateLimitError`, `ThirdPartyError`, `ThirdPartyTimeoutError`, `ThirdPartyParseError`. (`finnhub_common.py`)
|
||||
|
||||
## AgentOS Patterns
|
||||
|
||||
- **REST endpoints only queue runs** — WebSocket is the sole executor. POST `/api/run/{type}` writes to in-memory store, WS `/ws/stream/{run_id}` picks up and executes. (`runs.py`, `websocket.py`)
|
||||
- **Event mapping is crash-proof** — `_map_langgraph_event()` wraps each event type branch in try/except. `_safe_dict()` helper converts non-dict metadata to empty dict. (`langgraph_engine.py`)
|
||||
- **Model name extraction** uses 3 fallbacks: `invocation_params` → serialized kwargs → `metadata.ls_model_name`. (`langgraph_engine.py`)
|
||||
- **Prompt extraction** tries 5 locations: `data.messages` → `data.input.messages` → `data.input` → `data.kwargs.messages` → raw dump. (`langgraph_engine.py`)
|
||||
- **ReactFlow nodes are incremental** — never rebuilt from scratch. `useRef(Set)` deduplication prevents duplicates. (`AgentGraph.tsx`)
|
||||
- **useAgentStream uses statusRef** to avoid stale closures in WebSocket callbacks. Status is not a useCallback dependency. (`useAgentStream.ts`)
|
||||
- **Pipeline recursion limit** — `run_pipeline()` must pass `config={"recursion_limit": propagator.max_recur_limit}` to `astream_events()`. Default LangGraph limit of 25 is too low for debate+risk cycles. (`langgraph_engine.py`)
|
||||
- **Portfolio field mapping** — `/latest` endpoint maps backend model fields to frontend shape: `shares` → `quantity`, `portfolio_id` → `id`, `cash` → `cash_balance`, `trade_date` → `executed_at`. Computed fields (`market_value`, `unrealized_pnl`) included from runtime properties. (`portfolios.py`)
|
||||
- **Dashboard drawer has 2 modes** — `'event'` (single event detail from terminal click) and `'node'` (all events for a graph node from ReactFlow click). (`Dashboard.tsx`)
|
||||
- **Run buttons track activeRunType** — only the triggered button spins, others disabled during run. (`Dashboard.tsx`)
|
||||
- **Collapsible param panel** — date/ticker/portfolio_id with per-run-type validation. (`Dashboard.tsx`)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<!-- Last verified: 2026-03-19 -->
|
||||
<!-- Last verified: 2026-03-23 -->
|
||||
|
||||
# Glossary
|
||||
|
||||
|
|
@ -109,3 +109,21 @@
|
|||
| Finnhub _RATE_LIMIT | `60` calls/min | `dataflows/finnhub_common.py` |
|
||||
| AV API_BASE_URL | `"https://www.alphavantage.co/query"` | `dataflows/alpha_vantage_common.py` |
|
||||
| Finnhub API_BASE_URL | `"https://finnhub.io/api/v1"` | `dataflows/finnhub_common.py` |
|
||||
| _MAX_CONTENT_LEN | `300` (event message truncation) | `agent_os/backend/services/langgraph_engine.py` |
|
||||
| _MAX_FULL_LEN | `50_000` (full prompt/response cap) | `agent_os/backend/services/langgraph_engine.py` |
|
||||
|
||||
## AgentOS
|
||||
|
||||
| Term | Definition | Source |
|
||||
|------|-----------|--------|
|
||||
| AgentOS | Full-stack visual observability layer for agent execution — FastAPI backend + React frontend | `agent_os/` |
|
||||
| LangGraphEngine | Backend service that orchestrates run execution and maps LangGraph v2 events to frontend events | `agent_os/backend/services/langgraph_engine.py` |
|
||||
| Run Type | One of 4 execution modes: `scan`, `pipeline`, `portfolio`, `auto` | `agent_os/backend/routes/runs.py` |
|
||||
| AgentEvent | TypeScript interface for frontend events: `thought`, `tool`, `tool_result`, `result`, `log`, `system` | `agent_os/frontend/src/hooks/useAgentStream.ts` |
|
||||
| useAgentStream | React hook that connects to `/ws/stream/{run_id}` and provides events + status | `agent_os/frontend/src/hooks/useAgentStream.ts` |
|
||||
| AgentGraph | ReactFlow-based live graph visualization of agent workflow nodes | `agent_os/frontend/src/components/AgentGraph.tsx` |
|
||||
| PortfolioViewer | 3-tab portfolio view: holdings, trade history, snapshot summary | `agent_os/frontend/src/components/PortfolioViewer.tsx` |
|
||||
| MetricHeader | Top-3 dashboard metrics: Sharpe ratio, market regime+beta, drawdown+VaR | `agent_os/frontend/src/components/MetricHeader.tsx` |
|
||||
| _safe_dict | Helper that converts non-dict metadata to empty dict to prevent crashes | `agent_os/backend/services/langgraph_engine.py` |
|
||||
| Inspector Drawer | Side panel showing full prompt/response content for an event or node | `agent_os/frontend/src/Dashboard.tsx` |
|
||||
| Field Mapping | `/latest` endpoint translates backend model fields to frontend shape (shares→quantity, etc.) | `agent_os/backend/routes/portfolios.py` |
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<!-- Last verified: 2026-03-19 -->
|
||||
<!-- Last verified: 2026-03-23 -->
|
||||
|
||||
# Tech Stack
|
||||
|
||||
|
|
@ -73,3 +73,40 @@ From `[dependency-groups]`:
|
|||
- Version: `0.2.1`
|
||||
- Entry point: `tradingagents = cli.main:app`
|
||||
- Package discovery: `tradingagents*`, `cli*`
|
||||
|
||||
## AgentOS Frontend Dependencies
|
||||
|
||||
From `agent_os/frontend/package.json`:
|
||||
|
||||
| Package | Constraint | Purpose |
|
||||
|---------|-----------|---------|
|
||||
| `react` | `^18.3.0` | UI framework |
|
||||
| `react-dom` | `^18.3.0` | React DOM rendering |
|
||||
| `@chakra-ui/react` | `^2.10.0` | Component library (dark theme) |
|
||||
| `@emotion/react` | `^11.13.0` | CSS-in-JS for Chakra |
|
||||
| `@emotion/styled` | `^11.13.0` | Styled components for Chakra |
|
||||
| `framer-motion` | `^10.18.0` | Animation library (Chakra dependency) |
|
||||
| `reactflow` | `^11.11.0` | Graph/DAG visualization for agent workflow |
|
||||
| `axios` | `^1.13.5` | HTTP client for REST API calls |
|
||||
| `lucide-react` | `^0.460.0` | Icon library |
|
||||
|
||||
Dev dependencies: TypeScript `^5.6.0`, Vite `^8.0.1`, ESLint `^8.57.0`, TailwindCSS `^3.4.0`.
|
||||
|
||||
## AgentOS Backend Dependencies
|
||||
|
||||
From `pyproject.toml` (additions for agent_os):
|
||||
|
||||
| Package | Purpose |
|
||||
|---------|---------|
|
||||
| `fastapi` | Web framework for REST + WebSocket backend |
|
||||
| `uvicorn` | ASGI server (port 8088) |
|
||||
| `httpx` | Async HTTP client (used by FastAPI test client) |
|
||||
|
||||
## AgentOS Build & Run
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `uvicorn agent_os.backend.main:app --host 0.0.0.0 --port 8088` | Start backend |
|
||||
| `cd agent_os/frontend && npm run dev` | Start frontend (Vite dev server, port 5173) |
|
||||
| `cd agent_os/frontend && npx vite build` | Production build |
|
||||
| `cd agent_os/frontend && node_modules/.bin/tsc --noEmit` | TypeScript check |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
# ADR 013: AgentOS WebSocket Streaming Architecture
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
TradingAgents needed a visual observability layer to monitor agent execution in real-time. The CLI (Rich-based) works well for terminal users but doesn't provide graph visualization or persistent portfolio views. Key requirements:
|
||||
|
||||
1. Stream LangGraph events to a web UI in real-time
|
||||
2. Visualize the agent workflow as a live graph
|
||||
3. Show portfolio holdings, trades, and metrics
|
||||
4. Support all 4 run types (scan, pipeline, portfolio, auto)
|
||||
|
||||
## Decision
|
||||
|
||||
### REST + WebSocket Split
|
||||
|
||||
REST endpoints (`POST /api/run/{type}`) **only queue** runs to an in-memory store. The WebSocket endpoint (`WS /ws/stream/{run_id}`) is the **sole executor** — it picks up queued runs, calls the appropriate LangGraph engine method, and streams events back to the frontend.
|
||||
|
||||
This avoids the complexity of background task coordination. The frontend triggers a REST call, gets a `run_id`, then connects via WebSocket to that `run_id` to receive all events.
|
||||
|
||||
### Event Mapping
|
||||
|
||||
LangGraph v2's `astream_events()` produces raw events with varying structures per provider. `LangGraphEngine._map_langgraph_event()` normalizes these into 4 event types: `thought`, `tool`, `tool_result`, `result`. Each event includes:
|
||||
|
||||
- `node_id`, `parent_node_id` for graph construction
|
||||
- `metrics` (model, tokens, latency)
|
||||
- Optional `prompt` and `response` full-text fields
|
||||
|
||||
The mapper uses try/except per event type and a `_safe_dict()` helper to prevent crashes from non-dict metadata (e.g., some providers return strings or lists).
|
||||
|
||||
### Field Mapping (Backend → Frontend)
|
||||
|
||||
Portfolio models use different field names than the frontend expects. The `/latest` endpoint maps: `shares` → `quantity`, `portfolio_id` → `id`, `cash` → `cash_balance`, `trade_date` → `executed_at`. Computed runtime fields (`market_value`, `unrealized_pnl`) are included from enriched Holding properties.
|
||||
|
||||
### Pipeline Recursion Limit
|
||||
|
||||
`run_pipeline()` passes `config={"recursion_limit": propagator.max_recur_limit}` (default 100) to `astream_events()`. Without this, LangGraph defaults to 25, which is insufficient for the debate + risk cycles (up to ~10 iterations).
|
||||
|
||||
## Consequences
|
||||
|
||||
- **Pro**: Real-time visibility into agent execution with zero CLI changes
|
||||
- **Pro**: Crash-proof event mapping — one bad event doesn't kill the stream
|
||||
- **Pro**: Clean separation — frontend can reconnect to ongoing runs
|
||||
- **Con**: In-memory run store is not persistent (acceptable for V1)
|
||||
- **Con**: Single-tenant auth (hardcoded user) — needs JWT for production
|
||||
|
||||
## Source Files
|
||||
|
||||
- `agent_os/backend/services/langgraph_engine.py`
|
||||
- `agent_os/backend/routes/websocket.py`
|
||||
- `agent_os/backend/routes/runs.py`
|
||||
- `agent_os/backend/routes/portfolios.py`
|
||||
- `agent_os/frontend/src/hooks/useAgentStream.ts`
|
||||
- `agent_os/frontend/src/Dashboard.tsx`
|
||||
Loading…
Reference in New Issue