The shipped 0.1.8 wheel reported 0.1.7 because a hardcoded constant was
not bumped on release. The metadata path already fixed installed packages;
this removes the remaining hardcoded fallback so an un-installed checkout
reads the version straight from pyproject.toml — making pyproject the one
and only place the version is written, with no constant left to drift.
- _version: tomllib-based pyproject fallback (>=3.11 guaranteed), "unknown"
sentinel only if the tree is moved away from its pyproject.toml
- tests: pyproject fallback matches declared version, resolved-not-unknown,
and a guard against reintroducing any hardcoded version literal
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>
Scoped extraction of the UI running-status indicator from #159 (the
remaining commits there overlapped with #157/#158 or touched the
protected providers/ module).
- useSSE: add attempt.created/started, message.received, session.created,
tool_heartbeat, llm_usage to knownTypes so a mid-stream reconnect/replay
still surfaces the working state
- agent store: track streamingSessionId, preserved across switchSession so
the sidebar spinner persists when navigating away from a running session
- Agent.tsx: handle attempt.created/started (re-affirm streaming on reconnect
and page reload), keep streaming alive on tool_heartbeat, add a persistent
pulse bar, reword "Thinking…" to "Agent is working…"
- Layout: replace the dead-code (status === "failed") dot with a spinning
Loader2 for the actively streaming session
- index.css: pulse-slide keyframe for the running bar
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>
Cross-market correlation (e.g. BTC-USDT vs MSTR) failed with
'No overlapping return data between assets' because different loaders
produce DatetimeIndex values at different UTC offsets:
- OKX/CCXT (crypto): timestamps at UTC midnight (00:00:00)
- yfinance (US equity): timestamps at EDT midnight (04:00:00 UTC)
After tz_localize(None) the time component is preserved,
so 04:00 != 00:00 and the inner join produces zero rows.
Fix: call .index.normalize() on each close series before computing
returns, collapsing all timestamps to midnight regardless of source.
Also improve the error message to show actual date ranges per asset
when no overlap is found, making future debugging easier.
* fix(ui): always show Full Report link when runId exists in session history
Previously, when loading a session from history (e.g. in a new browser),
the run_complete card was silently dropped if api.getRun() failed or
returned non-report-worthy data. This caused the "Full Report" link to
disappear for remote/cross-browser users while remaining visible in the
original browser's in-memory cache.
Now the card always renders when runId is present in message metadata,
with metrics and equity curve as optional enrichments. Also improves the
RunDetail error page with diagnostic hints and a back button.
* fix(ui): cast equity to number to satisfy TypeScript strict typing
* fix(ui): distinguish non-report runs from fetch failures in run card logic
Address PR review: not every run_id is a backtest — plain chat turns also
get a run_id. Now only show the Full Report card when getRun() confirms
report-worthiness OR when the fetch fails (auth/network). Plain chat turns
where getRun() succeeds but isReportWorthyRun is false correctly skip the
card, avoiding spurious links.
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.
Follow-up to #149. Source-level AST validation (circular self-import,
unsafe imports, decorators, top-level statements) raises ValueError from
_load_module_from_file, but the call site was unguarded so it surfaced
as a raw Python traceback -- contradicting #149's stated goal of
actionable JSON errors for the circular-import case. Wrap the call and
emit a clean JSON envelope, unifying all source-validation errors with
the runner's JSON error contract.
Follow-up to #148. The wrap-up nudge fired at iteration == wrap_up_at
unconditionally, which on tiny budgets (max_iter<=2 -> wrap_up_at==1)
injected a '[SYSTEM] wrap up' user message on the very first iteration,
displacing the active research-goal context as the most recent user
message and breaking test_agent_goal_context. It also conflicted with
goal-continuation by telling the agent to stop early.
Now the nudge only fires for 1 < iteration < max_iterations: never on
the first iteration, and never on the last (the forced text-only path
already guarantees a final answer there).
AgentLoop could exhaust all 50 iterations when the LLM kept calling tools,
resulting in status="failed" with no useful output. Mirror the swarm worker's
proven approach: inject a wrap-up nudge at 80% of iteration budget and drop
tool definitions on the last iteration to force a text response.
Truncated writes (from process crash mid-append) produce invalid JSON
lines that crash the GET /sessions/{id}/messages endpoint with a 500.
Write-side: flush + fsync after each append so the full line is
durable before the request continues — prevents data loss for
expensive AI API responses.
Read-side: catch JSONDecodeError per line, log the first 200 chars
for manual recovery, and continue loading the remaining messages
instead of failing the entire endpoint.
Add interface checks before instantiation to catch common LLM mistakes
early with actionable JSON errors instead of raw tracebacks:
- Circular self-import detection (from signal_engine import SignalEngine)
- Required __init__ args check (all params must have defaults)
- Missing generate() method check
- Return-type validation (must be Dict[str, pd.Series], not list)
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.
bench_runner.run_bench() labels an alpha "alive" when its raw IC mean
beats 0.02, IC-positive ratio beats 0.55, and the IC self-t-stat clears
2. That gate accepts factors whose IC is driven by shared cross-sectional
beta (market/size/sector leakage) — the test is benchmarked against zero,
not against a same-universe random control, so a row-shuffled version of
the same factor typically clears the gate too.
Adds an opt-in `run_bench_strict()` companion (existing `run_bench()`
untouched and back-compat) that:
1. Builds N same-universe random controls per alpha by row-shuffling the
factor values within each row — preserves the per-date cross-sectional
distribution (mean, std, fat tails) while destroying the
signal-to-instrument mapping. Fairer null than Gaussian noise for IC.
2. Computes a per-date paired alpha series = signal_IC - random_IC and
evaluates its t-stat instead of the IC self-t-stat.
3. Optionally splits train/test on a user-supplied date and requires the
test-period alpha_t to also clear the threshold before labelling an
alpha `confirmed_alive` (otherwise `train_only` for benign decay,
`reversed_strict` for OOS sign-flip).
4. Makes `random_control: bool` keyword-only with no default — passing
nothing raises TypeError. Mirrors the rail from Soli22de/Bili_Stock's
foundation Backtest constructor, which was hardened after a 9-month
audit found every accidental no-random-control run inflated alpha by
3-8 pp.
Categories:
confirmed_alive alpha_t_full >= thr AND (no OOS OR alpha_t_test >= thr)
train_only alpha_t_full >= thr AND alpha_t_test in noise band
reversed_strict alpha_t_full <= -thr OR OOS sign-flip
noise alpha_t_full in (-thr, thr) OR ic_count < min_ic_count
Default threshold 2.0 stays numerically comparable with the existing
`categorise()` gate. Pass `StrictThresholds(alpha_t_threshold=3.5)` to
apply the Harvey-Liu-Zhu (2016) multiple-testing correction when running
the full 455-alpha zoo (the Vibe-Trading default zoo size).
Legacy bucket aliases (`alive` / `reversed` / `dead` / `by_theme`) are
preserved on the wire payload so existing dashboards keep rendering
without code changes:
alive = confirmed_alive
reversed = reversed_strict
dead = noise + train_only
Tests: 33 in test_bench_strict.py (helpers, categorisation rules,
keyword-only rail, OOS boundary semantics, inf-as-NaN, legacy aliases,
schema-complete error envelope, exception-safe on_progress, planted-
signal integration for both confirmed_alive and reversed_strict).
Full agent/tests/factors/ suite: 1002 passed, 1 skipped — zero
regression in the existing factor tests.
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.
Follow-up to #145. The new task_blocked event was emitted without
agent_id, so the CLI live panel (cli/_legacy.py) could not attach it
to the per-agent row — blocked agents stayed visually "pending" until
the run finalized. Three small fixes:
- runtime.py: pass agent_id=task.agent_id on the task_blocked emit
- cli/_legacy.py: handle task_blocked in the live event loop
- models.py: extend SwarmEvent docstring to mention task_blocked
- test_swarm_dag_gating.py: assert agent_id is present on the event
Bug
---
A failed task in layer N did NOT prevent layer N+1 tasks that declare it
as a dependency from being dispatched. The orchestration loop in
_execute_run set all_succeeded=False on failure but never gated the next
layer. The downstream worker's upstream-summary loop in _execute_layer
silently skipped the missing key (the `if source_task_id in task_summaries`
check), so the worker ran with no upstream context.
This is most visible in the investment_committee preset, where
portfolio_manager depends_on=["task-risk"]: a failed risk_officer
let PM produce a "decision" with no risk input. Reproducer attached as
tests/test_swarm_dag_gating.py shows the same pattern in 3 tasks.
The layer-boundary _sync_run_tasks_snapshot added in #132 surfaces the
failure to polling clients sooner, but it does not gate dispatch — PM
still runs the moment the layer with the failed risk task finishes.
Fix
---
_execute_layer: before dispatch, walk task.depends_on and load each
upstream from TaskStore. If any upstream has status != completed
(failed / blocked / cancelled / missing), mark this task
TaskStatus.blocked, record blocked_by + reason, emit task_blocked,
and skip executor.submit. Same-layer peers with no shared upstream
are unaffected (the loop continues).
_execute_run: tasks blocked in _execute_layer are absent from
layer_results. After the result loop, any layer_task_id missing from
layer_results was blocked -> set all_succeeded = False so the run is
marked RunStatus.failed at finalization.
Tests
-----
3 new regression tests in tests/test_swarm_dag_gating.py (TDD red-green
verified before-and-after on this PR's diff):
- test_failed_upstream_blocks_downstream
- test_blocked_downstream_emits_task_blocked_event
- test_run_marked_failed_when_downstream_blocked
Full swarm test suite: 115/115 pass (112 existing + 3 new).
- 5 READMEs had "75 skills" / "75 个 skills" / similar wording stale
in 7+ places each; actual `agent/src/skills/` count is 77 after
today's mootdx skill. Bumped every mention to 77.
- The "no-API-key" tip recommended AKShare as the free A-share
fallback, but mootdx is now the more reliable option (TCP-direct,
no IP throttle). Reworded the tip in all 5 languages: mootdx
preferred, AKShare as broader-coverage backup.
Add the 2026-05-27 entry to all 5 READMEs and rotate the
2026-05-24 Research Goal runtime entry into Earlier news so the
top-3 stays at 5-27 / 5-26 / 5-25 per the news convention.
User report (#139): example output shows ugly full-width horizontal
lines instead of clean tables. Root cause is the LLM emitting `---`
between sections, which Rich (CLI) and react-markdown (web) both
render as a full-width separator. Fixed at three layers:
1. System prompt (context.py): explicit rule to use markdown pipe
tables for multi-row data and `##` headings instead of `---`
horizontal rules. Also corrected stale "5 data sources" -> "7"
to reflect mootdx + futu.
2. CLI render_answer (transcript.py): strip standalone `---` /
`***` / `___` lines as defense-in-depth so historical answers
and the occasional rule-breaking output render cleanly.
3. Frontend MessageBubble.tsx: add `prose-hr:hidden` so any `<hr>`
that slips through doesn't draw a line.
Also fixed backtest_tool valid_sources whitelist: `source="mootdx"`
and `source="futu"` were rejected by the validator even though both
loaders were registered. Added both to the allowed set.
Tests: +1 transcript regression covering the HR strip; existing
2385 tests stay green.
Mootdx talks the native 通达信 binary protocol over TCP, bypassing
akshare's East Money HTTP scrape that periodically throttles. No API
token, no per-IP rate limit.
Scope: A-share OHLCV.
- Daily 1D/1W/1M via get_k_data (native date range).
- Intraday 1m/5m/15m/30m/1H via bars() with 25-page walk-back
pagination (~10y daily, ~5y 1H, ~3mo 1m of lookback).
- SH / SZ supported. 北交所 (BJ) returns empty upstream, so the
loader detects BJ symbols and skips with a clear warning rather
than swallowing the failure.
- Mootdx extended market (futures/options) is upstream-broken in
v0.11.7 — falls through to tushare/akshare for those markets.
Fallback chain becomes a_share: [tushare, mootdx, akshare] so
mootdx serves as the no-token, no-scrape middle tier between
tushare (auth-gated) and akshare (HTTP scrape).
Optional dependency: pip install mootdx && pip install 'httpx>=0.28.1'.
Mootdx pins httpx<0.26 in setup.py but only uses forward-compatible
httpx APIs; the second install restores the modern httpx that the
rest of the project (MCP server, fastmcp) needs.
Closes#107.
Read HTTP_PROXY/HTTPS_PROXY/ALL_PROXY (and lowercase variants) and pass them to the CCXT exchange constructor so Binance/OKX public data works from restricted networks. Additive only; no behavior change when no proxy env is set.
Normalize csi300/sp500/btc-usdt to canonical names before validation
in GET /alpha/list, matching the behavior of the bench form endpoint.
Signed-off-by: liucaiwen <liucaiwenseven@163.com>
Move Research Goal entry into the chat composer: the + menu now switches the
normal input into goal mode, sends create the session goal directly, and the
active goal stays above the input as an inline chip with expandable criteria
and evidence details.
Stabilize the local dev launcher used for browser smoke tests by wiring custom
backend ports into VITE_API_URL, launching long-lived process groups, cleaning
up child processes reliably, and reporting actual frontend/backend status.
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.
Refresh the interactive terminal transcript, activity rail, and prompt visuals. Document the 2026-05-23 CLI update in README and keep generated CLI screenshots out of git.
Co-authored-by: ykykj <140159248+ykykj@users.noreply.github.com>
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
The CLI was split into a package in b5a44a1; the workflow still
ran ``python -m py_compile cli.py`` against the now-renamed file
and failed with "No such file or directory: 'cli.py'".
Use ``python -m compileall -q cli`` so every module under the
package (``main.py``, ``_legacy.py``, ``commands/``, ``components/``,
``utils/``, ``_version.py``, ``__main__.py``) is checked together.
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).
Adds a 2026-05-20 entry to all 5 READMEs (EN/ZH/JA/KO/AR) covering the
`vibe-trading hypothesis {list,show,invalidate}` subcommands shipped in
dda06ae. Pushes the 2026-05-17 Alpha Zoo v1 entry into the collapsed
"Earlier news" block to preserve the 3-latest-visible convention.
Adds `vibe-trading hypothesis {list,show,invalidate}` subcommands that wrap
the existing HypothesisRegistry storage. List prints a Rich table (or JSON
with --json), supports --status filter and --limit. Show prints a Rich
detail panel including linked run cards. Invalidate flips status to
rejected and optionally records an invalidation_notes message; existing
notes are preserved when --note is omitted.
Closes the roadmap P2 backlog item "Add CLI workflows for listing,
editing, and reviewing hypotheses" on the CLI side; Web workflow waits
on the v0.2.0 IA landing.
22 new tests cover wiring, list/show/invalidate paths, JSON output,
status filter, limit, missing-id errors, and note persistence.
Tool calls now emit a 3s heartbeat plus structured per-stage progress
via emit_progress(). run_backtest, read_document, read_url opted in;
all other tools get heartbeat-only feedback automatically.
CLI Rich Live dashboard: Unicode spinner, ASCII progress bar, ETA,
per-tool rows (up to 3 parallel) keyed by tool name. Color discipline
restored (yellow reserved for cancelled/warning; running stays cyan).
0.25s throttle on tool_progress; no-rich path coalesces dots and
progress lines with per-tool gating.
Frontend: new ToolProgressIndicator with rAF coalescing, ARIA
role=status + hidden <progress>, ProgressRing SVG when determinate,
parallel-tool stacking with overflow + truncation. Extracted reusable
primitives ProgressBar.tsx and lib/tools.ts (shared tool-name i18n).
CLI Ctrl+C: first press calls agent.cancel() for graceful exit
(current step finishes, trace closes cleanly); second within 2s
force-quits. Backend POST /sessions/{id}/cancel was already wired.
Also fixes 2 pre-existing baseline test failures:
test_fundamental_filter_example (path resolved via __file__) and
test_openai_codex (pytest.importorskip for optional dep).
Tests: 2174 -> 2176 pass.
Append /v1 automatically when LANGCHAIN_PROVIDER=ollama so remote hosts
like http://host:11434 work with ChatOpenAI without manual path suffixes.
Co-authored-by: Cursor <cursoragent@cursor.com>
Help text and docstring promised ~/.vibe-trading/.env but the
implementation wrote to <AGENT_DIR>/.env, which lives inside
site-packages for pip-installed users and gets wiped on upgrade.
Align the implementation with the documented behavior, mkdir -p
the parent, and chmod 600 the file since it holds API keys.
Closes#127
Before this change, the live streaming area in Agent.tsx only rendered
when streamingText was non-empty or toolCalls had at least one entry.
The gap between handleSubmit setting status="streaming" and the first
SSE event arriving left the chat area visually blank, making the UI
look unresponsive on slow networks or long agent "thinking" time.
Add a Thinking… placeholder that renders exactly during that gap
(status === "streaming" && !streamingText && toolCalls.length === 0)
and is implicitly hidden once the first SSE event populates either
streaming state.
Bug fixes
- CompositeEngine no longer misroutes bare Chinese-futures codes like
RB2410 to GlobalFuturesEngine. _is_china_futures moved into a shared
_market_hooks module with a case-normalized product table and a
non-CN exchange guard. 9 new regression cases (RB2410 / rb2410 /
RB2410.SHFE / CL.NYMEX / M2412.CBOT / CF2412.ICE / AU2412.COMEX /
FG2412.EUREX / bare CN-collision still routes Chinese).
- Session FTS5 indexes now persist timestamps so cross-session search
can sort by date. Same path also fixes a re-upsert that was
wall-clocking every session's started_at on title-rename.
- Vite dev-mode proxy gained the missing /alpha entry; AlphaZoo page
resolves on npm run dev.
Cleanup
- Deleted swarm/api_models.py + swarm/mailbox.py + SwarmDashboard.tsx
(dead modules / orphaned UI after swarm-via-agent flow).
- Deleted SessionService.resume_attempt + get_attempts + get_attempt
+ SessionStore.list_attempts + Attempt.mark_waiting_user chain
(half-baked human-in-the-loop from initial commit).
- Deleted ChatLLM.achat (async sibling never called) and
_extract_balanced_json (only-tested helper).
- Deleted american_exercise_value in options_portfolio.py
(driver inlines bs_price logic).
- Deleted _compute_ic_series_reference in factor_analysis_core.py
(kept-as-reference, no callers).
- Collapsed MEMORY_TYPES duplication between cli.py and
memory.persistent; restored set-equality invariant assert.
- Deleted runSwarm (~197 LOC), swarmDash state, swarmCancelRef
write-only ref (orphaned by new agent-driven swarm flow).
- Dropped 76 unused 'vw = vwap(...)' boilerplate lines across
gtja191 alphas + their now-unused vwap imports.
- Cleared 11 F401 unused-import sites in tools/, agent/, providers/.
Test infrastructure
- test_e2e_harness_v2.py (real-LLM e2e) gated behind
VIBE_TRADING_RUN_LIVE_E2E so CI no longer flips shape based on
env-key presence. CI workflow now has explicit --ignore.
- test_auto_compact_with_long_history: monkeypatch TOKEN_THRESHOLD so
the test deterministically triggers compact instead of relying on
unrelated LLM behaviour.
- test_compact_tool_explicit: assertion corrected — compact tool is
special-cased in loop._process_tool_calls and does NOT emit
tool_call events. Assert on the 'compact' event instead.
- TestSwarmE2E: per-test @pytest.mark.timeout overrides matching the
internal 300s poll deadlines; cancel test now polls for terminal
state instead of fixed sleep(3).
Tooling
- ruff per-file-ignores for factors/zoo/** (3783 → 0 F401 noise);
F841 stays active in zoo to catch real formula bugs.
- frontend tsconfig: noUnusedLocals + noUnusedParameters as
regression guards.
- highlight.js hoisted to direct dependency (was transitive via
rehype-highlight).
- Vite proxy: dropped unused /run, /skills, /health, /api, /system;
added /alpha.
Annotations
- direction parameter renamed to _direction in 6 calc_commission
signatures (reserved for future borrow-fee asymmetry).
- _MARGIN_PER_CONTRACT in global_futures.py annotated as reference
data.
- Backtest engines' _calc_pct_change variants cross-reference each
other in docstrings.
Docs
- 2026-05-18 news entry added to README.md / README_zh.md /
README_ja.md / README_ko.md / README_ar.md; 2026-05-15 entry
rolled into the Earlier news <details>.
- Contributors heading: v0.1.7 cycle → v0.1.8 cycle in all 5
READMEs.
126 files changed, +363 / -1276.