* 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.
Three bare except: clauses in api_server.py silently caught BaseException
(KeyboardInterrupt, SystemExit, GeneratorExit) in addition to ordinary
errors. That makes the API server unresponsive to Ctrl+C inside these
blocks and hides real bugs (NameError, AttributeError) as silent passes.
The blocks themselves are best-effort metadata extraction from per-run
artifact files, where falling through with the default values is the
right behavior — but only for the specific I/O / parse failures these
blocks can actually produce. The new clauses spell those out:
- lines 1015, 1022 (req.json / planner_output.json prompt extraction):
except (json.JSONDecodeError, OSError)
- line 1042 (metrics.csv numeric parse):
except (OSError, ValueError)
Behavior is unchanged for the failures the blocks are designed to swallow;
KeyboardInterrupt, SystemExit, and programming errors now propagate as
they should.
Endpoints under /runs/{run_id}, /swarm/runs/{run_id} and /sessions/{session_id}
constructed filesystem paths as `RUNS_DIR / run_id / ...` without validating
the path-parameter value. An authenticated caller could submit values like
`..` or `foo/../bar` and reach paths outside the intended directory.
The same file already validates `{shadow_id}` with `_SHADOW_ID_RE`. This
change applies the same hardening to `run_id` and `session_id` via a shared
`_validate_path_param()` helper that enforces a safe character class
(`^[A-Za-z0-9_-]{1,128}$`). The class accepts every ID format produced by the
codebase today (regular run_id from `state.create_run_dir`, swarm
`swarm-{ts}-{short_uuid}`, session_id from `uuid.uuid4().hex[:12]`) and
rejects path separators, dots, NUL, whitespace, and oversize input.
13 endpoints are guarded:
- GET /runs/{run_id}/code, /pine, /
- GET|DELETE|PATCH /sessions/{session_id}
- POST /sessions/{session_id}/messages, /cancel
- GET /sessions/{session_id}/messages, /events
- GET /swarm/runs/{run_id}, /events
- POST /swarm/runs/{run_id}/cancel
Tests added in `test_security_auth_api.py`:
- parametrized validator unit tests (5 valid IDs / 9 invalid inputs)
- per-endpoint integration tests using FastAPI TestClient
read_document now dispatches by extension across PDF, Word, Excel,
PowerPoint, images (OCR), and 30+ plain-text formats (config, markup,
source code). Unified JSON envelope across formats so downstream
agent prompts don't need to branch on file type.
/upload flips from allowlist to blocklist — rejects only executables
and archives. Frontend accept attr widened to the same surface.
Show connectivity status on startup (CLI + API server) so users
immediately see which services are reachable and which are not,
instead of getting cryptic errors mid-run.
Add full-stack Pine Script export: backtest strategies can now be
converted to TradingView Pine Script v6 via natural language, CLI,
API, or the web UI.
- New `pine-script` skill with Python-to-Pine mapping table and v6 syntax guide
- CLI: `/pine <run_id>` slash command and `--pine` flag
- API: `GET /runs/{run_id}/pine` endpoint
- Frontend: Pine Script button on RunCompleteCard + modal code viewer with copy
- README: updated news, capabilities, skill count (65), CLI/API docs