Commit Graph
65 Commits
Author SHA1 Message Date
shadowinlife 8c2fd3e127 fix: complete env-var migration — CI gate exit 0, 9 schema fields, noqa mechanism
- Add 9 missing env vars to EnvConfig schema (QVERIS_API_KEY,
  VIBE_TRADING_API_URL, OPENAI_MODEL, FUTU_TRADE_PWD_MD5, etc.)
- Migrate 26 os.getenv calls to get_env_config() accessor across 17 files
- Add # noqa: env-gate inline suppression to ci_env_var_gate.py (21 lines)
- Refactor security.py _env_flag_enabled to direct schema access
- Wire CI gate into .github/workflows/test.yml
- Fix api_server.py import of deleted constants
- Restore _legacy.py timeout positive-value validation
- Add reset_env_config() to test_security_auth_api.py for singleton freshness

CI gate: exit 0 (was exit 1 with 54 violations)
Tests: 4953 passed, 4 pre-existing tushare failures, 0 regressions

Co-Authored-By: OpenCode <noreply@opencode.ai>
AI-Model: qwen3.7-max
Co-Authored-By: opencode <noreply@ai-tool.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
AI-Contributed/Feature: 188/188
AI-Contributed/UT: 39/39
2026-07-08 22:42:14 +08:00
shadowinlife 8234058562 refactor: centralize environment variable management with Pydantic schema + CI gate
- Add agent/src/config/env_schema.py: Pydantic models for ~50 env vars across 6 sub-models (LLMConfig, DataConfig, APIConfig, SwarmConfig, AgentTuningConfig, PathConfig)
- Add agent/src/config/accessor.py: thread-safe lazy singleton get_env_config() + unified _parse_bool() + reset_env_config() for test isolation
- Fix TIMEOUT_SECONDS CLI display default (2400 -> 120, matching runtime)
- Fix MAX_RETRIES CLI display default ('(not set)' -> 2, matching runtime)
- Fix VIBE_TRADING_API_KEY server-side alias (security.py now resolves it via get_env_config().api.api_auth_key)
- Fix VIBE_TRADING_CHANNELS_AUTO_START=on silently ignored (unified _parse_bool accepts 'on')
- Migrate 207 scattered os.getenv/os.environ.get calls across 50+ files to centralized accessor
- Convert 12 module-level import-time fixations to lazy accessor pattern (loop.py, swarm_tool.py, _backend.py, worker.py, security.py)
- Add reset_env_config() calls after settings_routes.py env mutations (13 mutation points)
- Replace print('[WARN]...') with logger.warning() in tushare/okx/yfinance loaders
- Add tools/ci_env_var_gate.py: AST-based CI gate preventing new os.getenv calls outside src/config/
- Add tools/test_ci_env_var_gate.py: 18 test cases for the CI gate
- Update tools/ci_grep_gates.sh to call the new env var gate
- Add agent/tests/test_env_schema.py: 81 test cases covering defaults, type coercion, singleton, thread safety, bool parser
- Update agent/.env.example with schema cross-references
- Update agent/tests/conftest.py with reset_env_config autouse fixture

Closes HKUDS/Vibe-Trading#438

Co-Authored-By: OpenCode <noreply@opencode.ai>
AI-Model: alibaba-cn/glm-5.2

Signed-off-by: shadowinlife <shadowinlife@gmail.com>
Co-Authored-By: opencode <noreply@ai-tool.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
AI-Contributed/Feature: 1383/1383
AI-Contributed/UT: 735/735
2026-07-08 19:36:24 +08:00
Haozhe Wu b37da118fb Merge pull request #424 from shadowinlife/refactor/api-server-complete-modular
refactor(api): extract shared infrastructure into focused modules

# Conflicts:
#	agent/api_server.py
2026-07-08 14:18:29 +08:00
Haozhe Wu 035673b065 revert: back out IRR-AGL reliability/governance stack (#405, #416)
Reverts merge commits 0b867a7 (#405) and 474f5e4 (#416), and removes the
now-orphaned #406 artifact metadata store (src/reliability + tests, zero
references left outside its own tests).

Why: the stack wrapped the tool registry in every session path (even
governance mode=off) without exposing the registry surface AgentContext
reads, breaking all session-runtime chats within a day (#433, #431). It
also modified protected core files (src/agent/loop.py, src/session/
service.py), shipped 12 internal-convention docs/ files into the public
tree, and its enforcement layer already has reported bypass paths (#420).
Trading safety stays on the single mandate-gate design (#31, #144).

README news entries for 2026-07-07/07-06 updated accordingly.
2026-07-08 14:15:56 +08:00
Haozhe Wu be117a24b4 feat: QVeris paid data marketplace integration (pluggable, single-commit revertable)
Provider: qveris.ai capability marketplace (search/inspect/execute + usage/ledger).
All logic lives in new files; every touch to an existing file is a tagged
QVERIS-INTEGRATION line so 'git revert' of this commit removes the feature cleanly.

- agent tools: qveris_search / qveris_inspect (free) / qveris_execute
  (paid; preview-by-default, allow_paid gated by per-session credit budget)
- REST: GET/PUT /qveris/config + GET /qveris/status (masked key, signup url)
- CLI: vibe-trading qveris status|enable|disable|usage (+ /qveris slash)
- backtest loader: source="qveris" (explicit-only; structurally excluded
  from every auto fallback chain; granularity-aware capability selection;
  top-3 candidate fallback; provider-named series container parsing;
  truncated-result full-content download)
- frontend: Settings QVeris card (toggle/base URL/key/mode/budget/balance/
  recent usage/referral signup CTA), 5 locales aligned (21 keys)
- skill: qveris SKILL.md + references (rest-api, coverage map) + data-routing row
- README x5: free-vs-premium dual-track data section (QVERIS-START/END)

Live-verified end to end against the real API: CLI enable/status, REST config,
search/inspect/preview-refusal/paid execute (charged 1-2 credits, ledger
reconciled), loader fetched 9 real AAPL daily bars. Full backend suite
5025 passed with no regressions; frontend vitest + tsc clean.
2026-07-08 13:42:31 +08:00
shadowinlife 39627475af refactor(api): extract shared compat layer, fix session service writeback
- Create src/api/_compat.py with shared host_attr/set_host_attr
- Remove duplicated _host_attr from security.py, helpers.py, state.py
- Fix _get_session_service missing _set_host_attr writeback to api_server
- Simplify host-check logic in state.py using _compat helpers
- Change _DEFAULT_CORS_ORIGINS from mutable list to immutable tuple
- Add middleware registration comment in api_server.py
- Expand test coverage: 7 → 33 tests (CORS, path validation, SPA routes,
  dotenv round-trip, compat layer, session service writeback)

Co-Authored-By: OpenCode <noreply@opencode.ai>
AI-Model: qwen3.7-max
Co-Authored-By: opencode <noreply@ai-tool.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
AI-Contributed/Feature: 104/104
AI-Contributed/UT: 199/199
2026-07-07 17:14:04 +08:00
shadowinlife 976a1c71f3 refactor(api): extract shared infrastructure into focused modules (#331)
Move auth/CORS/security helpers, Pydantic models, dotenv/SPA helpers,
and lazy-init service singletons out of api_server.py into four focused
modules under src/api/. api_server.py becomes a thin assembler that
creates the FastAPI app, mounts middleware, registers route modules,
and re-exports symbols for test compatibility.

- security.py: auth deps, CORS parsing, DNS-rebinding guard, loopback
  host validation, shell-tools gating (379 lines)
- models.py: Artifact, BacktestMetrics, RAGSelection, RunInfo,
  RunResponse Pydantic schemas (91 lines)
- helpers.py: path constants, dotenv I/O, SPA deep-link middleware,
  path-parameter validation (188 lines)
- state.py: lazy-init session service and channel runtime (124 lines)

api_server.py: 1,103 → 363 lines. Zero behavior change.
All 171 existing API tests pass unchanged.

Closes #331

Co-Authored-By: OpenCode <noreply@opencode.ai>
AI-Model: alibaba-cn/glm-5.2
Co-Authored-By: opencode <noreply@ai-tool.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
AI-Contributed/Feature: 1718/1718
AI-Contributed/UT: 57/57
2026-07-07 16:36:27 +08:00
Haozhe Wu 474f5e4361 Merge pull request #416 from Elfsa-Miranda/upstream-pr/08-hardening-docs
docs: harden IRR-AGL migration, security, and regression coverage
2026-07-07 13:09:24 +08:00
Haozhe Wu 824c4d8e47 Merge pull request #397 from mustafakamal88/fix/aware-utc-timestamps-395
Use timezone-aware UTC timestamps
2026-07-07 13:06:16 +08:00
mustafa88 c15437c441 Merge main into timezone-aware timestamp fix 2026-07-07 13:03:31 +08:00
Miranda a9835776ad Merge upstream/main into upstream-pr/08-hardening-docs 2026-07-06 23:07:06 +08:00
Dustin Persek f4da7e6523 fix(channels): configure IM reply timeout
Signed-off-by: Dustin Persek <dustin.persek@protonmail.com>
2026-07-06 08:57:32 -04:00
shadowinlife fa52c0069b refactor(api): extract remaining routes into modules
Move runs, scheduled research, swarm, sessions, goals, and live routes from api_server.py into focused src/api route modules.\n\nKeep compatibility re-exports for existing tests and preserve route behavior while reducing api_server.py to the app shell and shared wiring.
2026-07-06 17:07:47 +08:00
Miranda b054afe9de feat: add research cards and reliability panels
Signed-off-by: Miranda <tu07918382691@gmail.com>
2026-07-06 17:02:44 +08:00
Miranda b74a179c53 feat: add governed tool registry and policy decisions
Signed-off-by: Miranda <tu07918382691@gmail.com>
2026-07-06 12:34:24 +08:00
mustafa88 5084e03fd6 Use timezone-aware UTC timestamps 2026-07-04 21:16:11 +01:00
shadowinlife 43be0ca4d1 refactor(api): extract settings routes
Move LLM and data-source settings routes plus their exclusive helpers into src/api/settings_routes.py, preserving existing api_server re-exports for test monkeypatch compatibility.

Local verification: 63 focused settings/security tests passed; compileall, diff check, settings route registration, and monkeypatch target checks passed.
2026-07-04 13:11:06 +08:00
shadowinlife bae9d21828 refactor(api): extract channels routes
Move the IM channel HTTP routes and channel runtime lifecycle wrappers from api_server.py into src/api/channels_routes.py while preserving the existing registration path and test monkeypatch compatibility.

Local verification: 85 focused API/channel tests passed; compileall, diff check, and route duplicate checks passed.
2026-07-04 13:06:21 +08:00
Haozhe Wu 44f8cad928 fix: align Robinhood MCP and env startup 2026-07-03 16:28:24 +08:00
shadowinlife b0baa9c211 refactor(api): extract system routes to src/api/system_routes.py
Move 5 system routes (health, correlation, shutdown, skills, api-info)
and the _terminate_current_process helper from api_server.py into a
self-contained route module following the PR #375 pattern.

- system_routes.py defines HealthResponse locally (no shared modules)
- register_system_routes() resolves _security and
  _require_shutdown_authorization via sys.modules fallback
- Re-exports _terminate_current_process for test monkeypatch compat
- api_server.py: -92 lines (3552 → 3471)

Co-Authored-By: OpenCode <noreply@opencode.ai>
AI-Model: idealab/Qwen3.7-Max-DogFooding
Co-Authored-By: opencode <noreply@ai-tool.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
AI-Contributed/Feature: 270/270
AI-Contributed/UT: 0/0
2026-07-03 08:07:24 +08:00
Haozhe Wu b574af8528 refactor(api): extract upload routes
Refs #331
Refs #358

Original route extraction from #358 by @shadowinlife. Maintainer integration narrows the first API modularization step to the upload and Shadow report routes so no unused duplicate API modules land in main.

Validation:
- PYTHONPATH=agent pytest agent/tests/test_upload_api.py agent/tests/test_upload_security.py agent/tests/test_security_auth_api.py agent/tests/test_settings_api.py agent/tests/test_spa_deep_link.py agent/tests/test_run_card.py -q
- python -m compileall -q agent/api_server.py agent/src/api/uploads_routes.py
- git diff --check
- GitHub Actions CI test passed
2026-07-02 16:12:28 +08:00
Haozhe Wu 3b78745b1f Merge pull request #338 from Robin1987China/safe-bind-default
fix(api): default bind to 127.0.0.1 and warn on non-loopback without API_AUTH_KEY
2026-07-01 14:58:50 +08:00
Robin1987China 3234a82e45 fix(api): default bind to 127.0.0.1 and warn on non-loopback without API_AUTH_KEY
Default the --host bind address to 127.0.0.1 instead of 0.0.0.0 to
match the secure-by-default posture already used in docker-compose.
Add a startup warning when binding to a non-loopback address without
API_AUTH_KEY configured — the existing loopback peer-IP and
DNS-rebinding checks still reject remote requests, but the warning
surfaces the misconfiguration at startup.

Also default the Typer `serve` command's --host to 127.0.0.1 so every
serve entry point agrees (the console script and `python -m cli` already
bound loopback; this covers the `python -m cli.main` path too).

Tests: _is_loopback_bind_host truth table (IPv4/IPv6/hostname/edge),
loopback default, and the warning firing only on a non-loopback bind
without a configured key.

Refs #333

Signed-off-by: Robin1987China <41602358+Robin1987China@users.noreply.github.com>
2026-06-30 19:50:20 +08:00
Haozhe Wu 101306e916 feat: wire IM channel runtime
Merge IM channel runtime wiring, controls, dependency gates, tests, and legacy-name cleanup.
2026-06-30 14:31:26 +08:00
Hinotobi a351a258ae fix(api): allow authenticated remote same-origin UI requests
Follow-up to #293. Allows authenticated remote same-origin browser requests while preserving cross-site rejection.
2026-06-25 19:53:29 +08:00
Hinotobi dafdb036fa fix(api): reject cross-site unsafe browser requests before loopback auth (#293)
Run the existing cross-site guard for unsafe methods (non GET/HEAD/OPTIONS) before honoring loopback dev-mode trust, so a malicious page cannot drive local POST/PUT/DELETE routes via blind cross-origin requests. Adds upload-API regressions for cross-site rejection and the local non-browser path.
2026-06-23 18:49:41 +08:00
Matt Van Horn 974ad59a68 feat(scheduled-research): add executor that fires due jobs on schedule (#278)
Adds the background executor that polls the scheduled-research store and dispatches due jobs (interval-ms + cron) through the existing session runtime. Gated behind VIBE_TRADING_ENABLE_SCHEDULER (default off), so existing deployments are unchanged. Resets stale RUNNING jobs on startup, re-reads each record before completion writes to survive delete/replace races, rejects impossible cron schedules without blocking the loop, and dispatches with a config copy so saved jobs are never mutated.

Completes the scheduled-research feature begun in #272 (data model + store + CRUD).

Closes #254
2026-06-21 19:06:46 +08:00
Matt Van HornandMatt Van Horn f3bdc3b9ad feat: add scheduled research job data model and CRUD API (#272)
* feat: add scheduled research job data model and CRUD API

Implements the first slice of issue #254 (scheduled execution of agent
prompts and backtests): a durable ScheduledResearchJob data model and
ScheduledResearchJobStore with crash-safe atomic persistence (write-temp
+ fsync + replace + fsync-dir), mirroring src/live/runtime/jobstore.py.
Wires three new API endpoints to api_server.py (POST /scheduled-runs,
GET /scheduled-runs, DELETE /scheduled-runs/{job_id}). Execution wiring
is intentionally deferred to a follow-up PR once the schedule types and
output channels are confirmed. 24 unit tests included.

Refs #254

* fix(scheduled-research): root job store under the user runtime dir

_default_store_path() wrote scheduled_research_jobs.json into the repo
working tree (agent/data/), which is not gitignored — running the API
would leave job state in the checkout. Root it under get_runtime_root()
(~/.vibe-trading/scheduled_research/) instead, the same root the live
runtime, swarm config, and persistent memory resolve. Also range-check
cron fields (minute 0-59 / hour 0-23 / dom 1-31 / month 1-12 / dow 0-6)
so an out-of-range expression like '99 * * * *' is rejected.

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-06-20 18:00:39 +08:00
Haozhe Wu 2a5557edb6 chore(release): 0.1.10 — version sync + wheel packaging + Docker weasyprint libs (#271)
* chore(release): 0.1.10 — version sync, wheel packaging, Docker weasyprint libs

Release-prep for 0.1.10 (bundles the global data layer + everything since 0.1.9):

- version 0.1.9 -> 0.1.10 synced across all surfaces: pyproject, frontend
  package.json/lock, sidebar footer + i18n, SKILL.md, Dockerfile LABEL. REST
  API + MCP server now derive the version from cli._version (were hardcoded
  "5.0.0" / unset).
- pyproject package-data ships skill example scripts (skills/**/*.py) so the
  wheel + sdist include them; fastmcp floor -> 2.14.0 (first release where the
  MCP version= kwarg applies).
- Dockerfile installs weasyprint native libs (Pango/HarfBuzz/Fontconfig/Cairo/
  gdk-pixbuf + DejaVu) so PDF reports render in the image; .dockerignore *.md
  -> /*.md (root-anchored, skill markdown still ships).
- README news (5 locales): 06-19 reframed as the v0.1.10 release; 06-19/06-18
  trimmed.

Verified: clean-room pip install imports all new loaders/tools; wheel + sdist
carry the eastmoney/sec-edgar skills incl. UTF-8 references + scripts; 4167
backend tests pass (weasyprint PDF path covered on CI).

* docs(release): credit v0.1.10 cycle contributors across READMEs

Refresh the Contributors section in all 5 READMEs from the v0.1.9 cycle to
the v0.1.10 cycle (PRs #162–#260): @Hinotoi-agent, @mvanhorn, @gyx09212214-prog,
@BillDin, @Robin1987China, @LemonCANDY42, @zwrong, @forge-builder, @skloxo,
@LeeCQiang, @KaiLuettmann, @ngoanpv, @ShahNewazKhan, @sambazhu, @bhlt, @octo-patch.
2026-06-19 20:54:20 +08:00
Haozhe Wu 0d0ef439bb chore: finish proposal_id hardening + document MCP initTimeout (#264)
Completes work the 2026-06-18 self-merged batch left half-applied:
- Tighten the mandate proposal_id relay/preview parsers in api_server.py
  and cli/_legacy.py to the strict mp_[0-9a-f]{32} format already enforced
  by commit.py (#256), so the relay and the commit gate agree on format.
- Document the MCP initTimeout config key (shipped in #263) in README and
  wire its base-default passthrough in config/loader.py.
- Add the registered pytest.mark.unit marker to test_mandate_commit_security.py.
2026-06-18 23:36:32 +08:00
Hinotobi 97c67c9bb5 [security] fix(api): require auth for settings writes (#245)
Require a valid bearer token (not just loopback peer IP) for settings WRITE endpoints (/settings/llm, /settings/data-sources) when API_AUTH_KEY is configured, closing a DNS-rebinding / loopback-trust bypass while keeping zero-config local dev writes.

Also reconciles the DNS-rebound security tests across the #241-#245 sprint: now that #242's rebound-host middleware 403s loopback requests with an attacker-controlled Host before they reach the route, the end-to-end rebound tests for /swarm/runs and /sessions/messages (#243) and /settings/llm (#245) assert the request is rejected at the host-gate layer (403) and never reaches the shell-tool / settings-write decision. Full suite: 3217 passed.
2026-06-16 00:51:58 +08:00
Hinotobi 0568527cd6 [security] fix(api): require explicit opt-in for agent shell tools (#243)
* fix(api): require explicit opt-in for swarm shell tools

* test: cover session shell tool opt-in boundary
2026-06-16 00:37:50 +08:00
Hinotobi e5ee704e2e fix(api): reject untrusted loopback hosts (#242) 2026-06-16 00:37:18 +08:00
Hinotobi 73d3e1153b fix: require explicit auth for local shutdown (#241)
Signed-off-by: hinotoi-agent <paperlantern.agent@gmail.com>
2026-06-16 00:36:27 +08:00
LemonCANDY42 88dd54c7c3 perf(run-detail): add opt-in chart payloads (#225)
Add opt-in chart payload modes for the Run Detail endpoint and UI. Default /runs/{id} stays byte-for-byte unchanged; ?chart_payload=summary returns metadata + chart_symbols (no bars/markers); ?chart_symbol=SYM returns one symbol's bars+markers. Run Detail UI renders summary first, then progressively loads selected symbols with loading/progress + cancel. New copy localized en + zh-CN.

Refs #215.
2026-06-14 22:14:50 +08:00
LemonCANDY42 8678c289ce feat(agent): persist AgentLoop usage artifacts (#223)
Persist provider-reported AgentLoop usage as a run-scoped artifact (<run_dir>/llm_usage.json) and surface it additively on /runs/{id}. Provider-reported tokens only — no prompt/content capture, no price estimation. Behind the existing usage guard so providers without usage_metadata write nothing. Live llm_usage SSE event keys unchanged.

Refs #214.
2026-06-14 21:52:11 +08:00
sambazhu d17faacefc test: add frontend test suite + backend security/coverage tests
Cherry-picked the test-infra commit from #175 (sambazhu): vitest setup + 19 frontend test files (197 tests), backend auth/path-traversal/CORS tests, yfinance crypto fallback (BTC-USDT->BTC-USD), and CI coverage + frontend-test steps. Dropped the PR's separate i18n commit to stay consistent with #163.

Fix: align @vitest/coverage-v8 to ^3.2.6 (was ^4.1.8, incompatible with vitest ^3.2.6 - blocked npm install and the new npm ci CI step).
2026-06-05 20:41:14 +08:00
Haozhe Wu b5efee66ab docs: remove dead docs/live-trading/SPEC.md references from source comments
The live-trading source files referenced docs/live-trading/SPEC.md in
docstrings, comments, and tests, but docs/ is gitignored (internal planning),
so external contributors hit a dead path when they grep / ls-tree for it.
Genericize the references to "the live-trading SPEC"; docs/ stays internal.

Closes #166
2026-06-03 22:59:21 +08:00
Haozhe Wuandai7eam-dev d2f853233f feat(swarm): retry failed/stale/cancelled runs (HTTP + MCP)
Completes the swarm-retry capability extracted from #159 and makes it
usable end-to-end instead of dead API surface.

- api_server: POST /swarm/runs/{id}/retry — reconciles a stale "running"
  run first, refuses a genuinely active run (409), else re-launches a new
  run with the original preset + user_vars
- mcp_server: retry_run(run_id) tool so the list_runs -> spot-failure ->
  retry loop works from OpenClaw/Claude Desktop (the frontend has no swarm
  dashboard; MCP + HTTP are the real consumers)
- api.ts: retrySwarmRun client method (parity with cancelSwarmRun)
- tests: missing-run / running-refused / happy-path relaunch, MCP well-known
  tool name, and HTTP traversal rejection for the new endpoint
- docs: bump current MCP tool count 35 -> 36 across the 5 READMEs (ar/ko
  prose still carries a stale 22-tool list — tracked separately)

Co-authored-by: ai7eam-dev <ai.7eam@gmail.com>
2026-06-01 22:39:57 +08:00
a8144e9acf feat(frontend): make SSE idle timeout configurable via VIBE_TRADING_SSE_TIMEOUT (#157)
CI / test (push) Waiting to run
Wiki / validate (push) Waiting to run
Deploy Wiki / Deploy to Cloudflare Pages (push) Canceled after 0s
The frontend safety timeout was hardcoded at 90 s, causing false
"Execution timed out" toasts for users running slow local models
(e.g. Ollama on limited VRAM or CPU).

- Backend: expose `sse_timeout_seconds` in `LLMSettingsResponse`,
  reading from `VIBE_TRADING_SSE_TIMEOUT` env var (default 90 s)
- Frontend: fetch the value from `/settings/llm` on mount and use it
  instead of the hardcoded 90 000 ms constant
- `.env.example`: document the new variable in the Agent Tuning section

Co-authored-by: Sky <985369746@qq.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 22:13:15 +08:00
Haozhe Wu 1e3bd7a8c0 chore(trading): clean connector docs and on-ramp mapping
Refresh multilingual MCP tool counts and centralize broker-to-connector on-ramp profile resolution so the frontend no longer duplicates broker profile fallbacks.
2026-06-01 00:27:38 +08:00
Haozhe Wu 52f5059159 feat(trading): add connector-first broker profiles
Add unified trading connector profiles and tools for IBKR and Robinhood. Gate live runner behavior by connector capability, preserve IBKR local read-only config, and update CLI, MCP, web UI, tests, skill docs, and multilingual README news.
2026-06-01 00:17:28 +08:00
Haozhe Wu 108bfae960 feat(live): bounded-autonomy live trading channel (Robinhood Agentic Trading)
Add an opt-in, read-only-by-default live execution channel via Robinhood
Agentic Trading (remote MCP, OAuth). The agent trades autonomously only inside
a user-committed mandate (symbol allowlist, order size, exposure, leverage,
instrument, daily cap):

- Mandate model + read-only protected store; commit is the ONLY writer
  (no set_mandate tool reachable from the agent loop)
- Pre-trade enforcement gate (fail-closed) + order-intent extractor + quote pricing
- 3-tier read/write tool classification (default-deny) + OAuth token cache
- Filesystem kill switch (LLM-independent) + preemptive flatten on trip
- Mandate auto-expiry, checked proactively every runtime tick
- Persistent autonomous runtime: scheduler, durable job store, liveness,
  market/interval triggers, crash-recovery reconciliation
- Consent UX (propose/commit/adjust) across CLI and Web UI
- Compliance-grade audit ledger with credential/PII redaction

Read-only/fail-closed by default; protected agent core (src/agent, src/session)
untouched. Paper/mock-tested only; live verification is the community's
(experimental, use at your own risk). Updates all 5 README languages with the
bounded-autonomy disclaimer.
2026-05-29 18:00:08 +08:00
shadowinlife 7acaf74e10 feat(swarm): operator-configured external MCP tools in workers (#142)
Lets swarm workers call tools from operator-approved external MCP
servers in addition to the 31 local Vibe-Trading tools. Useful for
internal knowledge bases, compliance services, or any extra MCP server
the operator wants to attach.

Trust model is preserved at the schema level: MCP server URLs, commands,
env, and allowlists are resolved from the operator's config file
(VIBE_TRADING_SWARM_AGENT_CONFIG / ~/.vibe-trading/swarm-agent.json /
~/.vibe-trading/agent.json), never from `variables` or any other
caller-supplied input. The `run_swarm` MCP entry point cannot inject
server config.

Per-worker registries are built by intersecting each agent's `tools:`
whitelist with the resolved local + remote tool pool. Whitelist entries
the operator hasn't surfaced are dropped with an operator-facing
warning rather than failing the worker. Discovery is narrowed to the
servers actually referenced by the whitelist, so local-only workers
incur no MCP spawn cost.

MCP server-name collisions (e.g. `foo-bar` / `foo_bar`) keep their hash
suffixes after pruning — `_prune_agent_config_for_swarm_tools` resolves
segments against the full config first, then passes the preserved
mapping into `build_registry` so the worker whitelist still matches.

Adds `server` + `remote_tool` metadata to `tool_call` / `tool_result`
events for audit clarity, with nested redaction of sensitive argument
and result values.

Wired into MCP server, API server, CLI live runner, and in-process
SwarmTool. 27 new tests across M1-M5 (config plumbing, registry
assembly, boot wiring, e2e, trust model); 288 broader swarm/mcp/tool
tests pass.
2026-05-28 16:21:32 +08:00
Haozhe Wu acab70c556 fix(goal): close research goal lifecycle 2026-05-26 00:43:28 +08:00
Haozhe Wu 2a18d33c23 feat(goal): add research goal runtime
Add the session-scoped Research Goal layer across backend, CLI, API/MCP,
SSE, and Web UI. Goals now persist claims, acceptance criteria, evidence,
budgets, and completion policy; agent tools and /goal can create goals and
attach evidence; REST/MCP expose snapshots and evidence writes; SSE keeps
chat clients fresh.

Also carry the 2026-05-24 transplant cleanup: replay-all/session-id/upload
wiring, report-worthy Full Report gating, English-only Web UI copy, and audit
fixes for verified evidence, live-trading risk tiers, CLI session linkage,
goal ledger cleanup, replay-all hookup, and frontend snapshot races.
2026-05-24 23:55:00 +08:00
Haozhe Wu cac3f0b5ed fix(swarm): unified reconcile + MCP keepalive + heartbeat coverage (#132)
Symptoms reported in #132 (WorkBuddy + DeepSeek MCP):
- MCP run_swarm blocked 30 min then errored, losing run_id
- get_swarm_status / get_run_result showed stale snapshot while tasks/*.json
  had real progress
- Host crash left runs "running" forever with no recovery path
- list_swarm_runs / SSE rendered the same stale snapshot

Architecture:
- store.reconcile_run(write=True): single read-side entry point. Hydrates
  live task files, recovers terminal-but-not-finalized state (host crashed
  between last layer sync and finalize), and reaps stale running runs whose
  events.jsonl has gone silent past compute_stale_threshold.
- Threshold is per-run: max(60, min(heartbeat_interval*10, retry_ceiling))
  — fast detection when heartbeats work, retry-budget-clamped when not.
- HeartbeatTimer wraps registry.execute, llm.stream_chat, AND grounding
  fetch so no normal execution phase can produce >heartbeat_interval of
  silence. Slow first-token / reasoning-mode / pure tool-call responses
  no longer trip the reaper.
- run_swarm emits ctx.report_progress every poll with elapsed seconds, so
  MCP transport stays alive via progress notifications; first frame is
  fixed-format ``swarm_started run_id=<id>`` so transport-drop clients can
  still recover the handle.

Endpoints updated to use reconcile_run:
- MCP: get_swarm_status, get_run_result, list_runs, run_swarm polling
- API: /swarm/runs, /swarm/runs/{id}, /swarm/runs/{id}/events SSE
- SwarmTool: polling + budget-out path (no longer cancels on timeout)

Other fixes:
- SWARM_HEARTBEAT_INTERVAL_S parses with ValueError fallback in worker
  (was crashing import on bad config)
- reaper derives run terminal status from task statuses (no more
  hardcoded "failed" on a run whose tasks all completed)
- serialize_task surfaces started_at / completed_at / depends_on / blocked_by
- reap_stale_runs() MCP tool for explicit user-triggered cleanup

Tests: 22 new regressions in tests/test_swarm_status_hydration.py covering
hydrate, reconcile, terminal recovery, stale reap, MCP keepalive cadence,
auto-recovery on read, threshold math, env var robustness, heartbeat
wiring around LLM + tool execution.

Verification:
- targeted suite: 22 passed
- full swarm/mcp suite: 169 passed, 4 skipped, 0 failed
- compileall + import smoke clean
2026-05-22 11:56:29 +08:00
Haozhe Wu b5a44a1e56 refactor(cli): split agent/cli.py into agent/cli/ package
Restructures the 3216-line agent/cli.py into a focused package
while preserving every existing surface verbatim.

Legacy compatibility:
- _legacy.py shim keeps every subcommand (serve, run, hypothesis,
  alpha, memory, provider, swarm, sessions, ...) reachable through
  the same CLI flags and console-script entry.
- Public symbols (cmd_*, _INIT_ENV_PATH, Confirm, AGENT_DIR, ...)
  re-exported through cli.<name>; `from cli import *` exposes 76
  symbols (was 1).
- Package-level cli.RUNS_DIR / cli.SESSIONS_DIR monkeypatches now
  propagate into _legacy before any cmd_* runs.

New scaffolding:
- agent/cli/main.py interactive REPL front door
- agent/cli/commands/ slash router + handlers (15 commands)
- agent/cli/components/ reusable Rich UI building blocks
- agent/cli/{theme,intro,onboard,input,completer,stream}.py
- agent/cli/__main__.py restores `python -m cli`
- agent/cli/_version.py reads importlib.metadata.version() so
  --version output and the banner stay aligned with pyproject.toml

Production wiring:
- New FastAPI middleware in api_server.py serves
  frontend/dist/index.html on browser navigation to /runs/{id}
  and /correlation, regex-narrowed so /runs/{id}/code and
  /runs/{id}/pine API routes stay reachable.
- frontend/vite.config.ts dev proxy mirrors the same narrowing.
- scripts/dev backend starts via package-safe
  `python -c 'import cli; cli.main(...)'`.

Chat-gate narrowed: chat --help / chat -h / chat --max-iter <bad> /
chat extra correctly reach legacy argparse instead of being
swallowed by the new REPL.

Tests: 2271 passed, 43 skipped (focused CLI/SPA test files:
test_cli_interactive.py 67 + test_spa_deep_link.py 13 + existing
CLI memory/init/hypothesis 48 = 128).
2026-05-22 00:00:47 +08:00
Haozhe Wu d77c64e2ce feat(alpha-zoo): bench runner + CLI + Web UI + 4 REST routes
End-to-end product surfaces over the factor framework: a CLI for
power users, an agent-tool layer for natural-language workflows,
a REST + SSE API for browser clients, and the Web UI itself.

CLI (vibe-trading alpha <subcommand>)
- list / show / bench / compare / export-manifest with security
  guards (path-traversal, alpha_id allowlist before any FS read)
- agent/cli.py wired (7-line glue), all logic in cli_handlers.py
- alpha bench: requires --zoo (or --yes); drives bench_runner with
  an on_progress callback feeding a Rich Progress bar; prints ETA
  banner; emits stderr summary "✓ Bench complete. N tested, M
  skipped. Report: <path>"; returns exit 1 on status != ok
- alpha list: --limit N / --json flags; TTY next-step hints
- alpha show: --brief; Syntax(word_wrap=True) so source survives
  narrow terminals
- TUSHARE_TOKEN errors append a 3-step fix banner
- ConstantInputWarning silenced at module level

Agent tools (auto-discovered via BaseTool.__subclasses__)
- AlphaZooTool: list_alphas / get_alpha / health
- AlphaBenchTool: orchestrator with Jinja2 autoescape HTML report +
  strict CSP meta. Module-level run_alpha_bench() reused by CLI

Universe loader (agent/src/tools/alpha_bench_tool.py)
- csi300 → Tushare index_weight + pro.daily, in-house panel build
  because the bundled tushare loader drops `amount`. Parallel fetch
  via ThreadPoolExecutor(max_workers=4); cache at ~/.vibe-trading/
  cache/<universe>_<start>_<end>.pkl with sha256 sidecar integrity
  guard
- sp500 → Wikipedia constituent list (UA-spoofed; bare pd.read_html
  returns 403) → yfinance loader; surfaces survivorship_bias=True
  in panel._meta because the constituent set is point-in-NOW
- btc-usdt → bundled okx loader; fails fast (ValueError) on single-
  asset cross-sectional IC degeneracy

REST API (agent/src/api/alpha_routes.py + agent/api_server.py +6 lines)
- GET /alpha/list?zoo=&theme=&universe=&limit= — paginated catalogue
- GET /alpha/{alpha_id} — meta + source code via Registry.get_source
- POST /alpha/bench — kicks off asyncio.create_task running the
  bench in asyncio.to_thread; in-memory job state with threading.Lock
  + 1-hour TTL + asyncio.Semaphore(2) concurrency cap (429 on
  saturation)
- GET /alpha/bench/{job_id}/stream — Server-Sent Events emitting
  progress / result / done / error events. Heartbeat ": ping\n\n"
  every 15s so reverse proxies don't close idle streams. Unexpected
  exceptions are sanitised to "internal error; see server logs"

Web UI (frontend/src/pages/AlphaZoo.tsx ~950 LOC, 3 sub-views)
- Browse: 4 gradient zoo cards (qlib158 / Kakushadze 101 / gtja191 /
  academic) + filter bar (zoo, theme, universe, id substring) +
  paginated table (50 rows + Load more)
- Detail: formula_latex in <code> block (no MathJax under strict
  CSP); metadata table; collapsible <details> source code; "Run
  bench" CTA prefilled
- Bench: form → SSE-streamed progress bar + currently-computing
  alpha id → Alive/Reversed/Dead/Skipped stat cards + Top-5-by-IR +
  Most-Reversed tables + by-theme echarts bar chart
- New /alpha-zoo route triplet wired in router.tsx; Layout.tsx
  nav entry with the Layers icon
- Raw EventSource pattern (useSSE hard-codes agent-stream event
  types and would drop our progress/result/done/error)
- a11y: htmlFor/id pairs on every label, aria-hidden on decorative
  lucide icons, sr-only table caption, CategoryBadge component
- BTC universe fail-fast surfaces as inline form error with hint
  to try sp500/csi300

Registry singleton via get_default_registry() so API requests don't
each pay the 452-module AST scan. compute_ic_series vectorised via
pandas corrwith(method="spearman"); ~5-10x speedup, numerically
identical to the prior scipy loop within 1.1e-16.

VWAP 千元 fix: empirical Tushare probe against 000001.SZ confirmed
daily.amount is in 千元 (not raw CNY). base.vwap(EQUITY_CN) now does
safe_div(amount * 1000.0, volume * 100.0 + 1.0) — previously
~1/1000th of true vwap. Affects factors mixing vwap with price
additively (alpha101_093 etc.).

969 tests pass; registry health 452 loaded / 0 failed; CI grep
gates green; TypeScript clean.
2026-05-17 20:04:02 +08:00
Haozhe Wu db21715cf9 feat(run-card): surface trust layer card in web UI 2026-05-15 11:51:18 +08:00