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.
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.
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.
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.
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
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>
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.
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
* 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>
* 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.
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.
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.
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.
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.
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).
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
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>
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>
Refresh multilingual MCP tool counts and centralize broker-to-connector on-ramp profile resolution so the frontend no longer duplicates broker profile fallbacks.
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.
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.
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.
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.
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
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).
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.