Commit Graph
100 Commits
Author SHA1 Message Date
Haozhe Wu 3ed96c32ba feat: LLM auto session titles + live reasoning whisper
- POST /sessions/{id}/title/auto — summarize the first exchange into a short
  title in the user's language; never clobbers a manual rename
- Frontend fires it after the first completed exchange and refreshes the sidebar
- reasoning_delta now carries a bounded 600-char rolling tail on the existing
  throttled emit; ActivityLine whispers the live thought (serif italic, 3-line
  clamp) while the attempt is active
2026-07-30 11:58:19 +08:00
Haozhe Wu 8f40de5a5c feat: FW-3 live-test fix wave — connector resume + i18n, hero tabs, activity chain, pro validation charts
- ConnectionBanner: surface only during an active reconnect loop (boot-state false alarm fix)
- Trading-monitor wording replaces literal 'runtime' jargon across zh/ja/ko/ar
- Hero: vertical centering + category-tab example library; About relocated to sidebar footer
- Brand: ascending-candles mark in BrandMark/favicon/logo.svg (replaces VT lettermark + stale FIN-ANYTHING wordmark)
- Dark theme: surface separation and border/muted-foreground contrast lift
- Connector panel: /live/resume wired with a resume button; RunnerStatus internals fully i18n'd
- Activity chain: coalesced xN steps with argument summaries, chronological order, sub-second durations
- RunDetail: trades side-normalization fix + pnl/return/holding columns + filters/pagination/totals; code copy button; run-card validation rendered via ValidationPanel
- Validation: Monte Carlo fan chart + Sharpe distribution histograms + walk-forward bars; validation.py emits sharpe samples and path envelopes
- Compare: centered layout, rebase-to-100 overlay toggle, in-cell metric bars, swap button
2026-07-30 11:44:31 +08:00
Haozhe Wu d8c2a600c7 feat: FW-2 wave 2 — durable activity object, Agent decomposition, full ja/ko/ar parity, serif reading voice
One durable activity object per turn rendered by a single ActivityLine
(verb + newest step + 1s tabular timer; userOpen ?? auto disclosure with
900ms dwell; cancel/timeout/failure leave terminal rows with Continue and
re-attach; scattered spinners and the pulse bar removed). Escape-to-stop
and full + menu keyboard contract; follow-up placeholder after runs;
hidden-tab completion title marker. Agent.tsx decomposed 2353→1686 via
memoized Composer (byte-faithful IME guard + render-isolation test),
GoalPanel, LiveRuntimePanel. ja/ko/ar translated to full 929-key parity.
Assistant narrative paragraphs read in a CJK-safe serif at 15.5px; tables,
metrics, and code stay sans/mono. Remaining page-level hardcoded strings
localized.
2026-07-30 00:50:35 +08:00
Haozhe Wu 4b69f49809 feat: FW-2 wave 1 — end-to-end tool call_id, tool-trail persistence, 84-tool i18n, copy polish, a11y/robustness sweep
Backend (surgical, additive): call_id on tool_call/result/progress/heartbeat
(loop.py, swarm worker); tool_trail serialized onto assistant messages at
attempt completion and exposed through session history. Frontend: exact
call_id matching with FIFO replay fallback, trail rebuild on reload via the
same helper as the live path, 84 localized tool labels, MetricsCard plain-
language glosses, focus-trap dialogs, overlay connection banner with
terminal reload state, cross-tab prefs sync, idle echarts prefetch, mandate
zh glossing (交易授权), swarm vocabulary unification, '/' product-first
routing with /about.
2026-07-30 00:13:17 +08:00
Haozhe Wu 71933ecf31 feat(frontend): guided-minimalism WebUI overhaul — 12-way audit + fix fleet
Land the pre-talk WebUI campaign: first-frame stability (pre-paint theme
boot via CSP-safe public/theme-boot.js, self-hosted fonts + OFL license),
streaming performance (rAF token batching, throttled flush, streaming
markdown with deferred highlight, 160-row windowing, swarm state in its
own store slice with per-run coalescing), correctness (FIFO tool matching,
retry preserves request semantics, display/request separation, cache-hit
session refresh, multi-tab message.received), guided-minimalism welcome
(time-aware greeting + brand lockup + 4 quick actions + collapsible
library, fill-first affordance), SwarmDashboard rebuild with honest
indeterminate progress, five-locale copy de-jargoning with lazy locale
chunks, accessibility Level-A fixes (color-blind metric glyphs, aria-live
streaming, skip link, focus-visible affordances), robustness (markdown
link/table/KaTeX overflow, safe localStorage, portal modal), and '/' now
opens the product with marketing moved to /about.
2026-07-29 23:07:35 +08:00
Haozhe Wu c8741e34bf docs(readme): add 2026-07-29 news 2026-07-29 16:04:30 +08:00
Haozhe Wu 749c37b09f chore(frontend): declare the Node 22 requirement
React Router 8 requires Node >=22.22.0, so `npm install` now fails for anyone
still on Node 20 with an error that does not name the cause. Declare it in
package.json engines, and say it on the Quick Start line that tells people to
run it, in all five READMEs.
2026-07-28 15:59:33 +08:00
Haozhe Wu bd9a9b70b8 docs(readme): add 2026-07-28 news 2026-07-28 15:58:42 +08:00
Haozhe Wu 1e5b79dac6 chore(frontend): move to Node 22 and React Router 8
React Router 7.12.0 through 8.2.x carry a high-severity RSC-mode CSRF bypass
(GHSA-qwww-vcr4-c8h2). We were on 7.18.1, inside that range. The advisory is not
reachable here — the app is a client-side SPA on createBrowserRouter with no
@react-router/server and no RSC entry point, and the frontend ships as static
Vite output — but 7.18.1 is the final 7.x release, no backport exists, and 8.3.0
is the only patched version, so staying put means staying on an EOL line with a
permanent open alert.

react-router-dom has no 8.x at all; the DOM exports moved into react-router
itself. So the dependency is swapped and every import rewritten. All ten APIs in
use here are unchanged in 8.3.0, and none of the data-layer surface that changed
most between majors is used.

react-router 8 requires Node >=22.22.0, which is the same wall that had jsdom 30
and @testing-library/jest-dom 7 sitting in the Dependabot ignore list. Node 20
reached EOL on 2026-04-30, so the toolchain moves to Node 22 across CI, the wiki
workflow, the Dockerfile and docker-compose. That unblocks all three at once:
jsdom and jest-dom are taken here too, and their ignores are removed rather than
left carrying a rationale that no longer holds.

Verified on the frontend suite: tsc -b and vite build clean, 310 tests across 35
files pass before and after the jsdom/jest-dom bumps.
2026-07-28 14:39:59 +08:00
Haozhe Wu c63713c587 chore(deps): ignore the transitive versions ccxt exact-pins
ccxt does not use ranges — it exact-pins its entire transitive closure. All 23
of those packages that appear in our lock sit at precisely ccxt's pin, with no
mismatches, so none can move until ccxt itself releases, and ccxt 4.5.68 is
already the latest. Any Dependabot PR touching one is unmergeable by
construction: the pip group PR proposed five of them and died with
ResolutionImpossible on certifi against the ccxt line in the lock.

Re-running the resolver confirms this is the ceiling rather than a stale lock —
pip-compile --upgrade under python:3.11-slim, matching CI, reproduces every one
of those versions, so there is no lock change to make. pydantic-core is in the
same position via pydantic's own == pin, and was the sixth package in that PR.

Ignore the set. ccxt itself is deliberately not ignored: it is the package whose
bump legitimately carries all of them. This suppresses only the automated PRs —
Dependabot alerts come from the dependency graph and are unaffected by this
file, so a CVE in cryptography, urllib3, requests or certifi still surfaces in
the Security tab, where the remedy is a ccxt bump.
2026-07-28 12:57:46 +08:00
Haozhe Wu 452653c81c fix(backtest): make the buy-and-hold return path sign-safe
close.pct_change() silently assumes price[t-1] > 0. That holds for equities but
not for instruments that can print zero or negative prices, such as European
day-ahead power. As the divisor approaches zero an ordinary absolute move reads
as an enormous percentage move, so the compounded benchmark explodes — a
reported +39,560% where the honest figure was -42.7%. At exactly zero the next
bar is inf, which fillna(0.0) does not neutralise because it fills NaN, and
(1 + r).prod() then collapses to nan.

Adopt an explicit contract. A return is defined only when the previous price is
finite and strictly positive; otherwise it is 0.0, never inf or nan. Buy-and-
hold total return becomes the price relative P_end / P_start - 1 rather than the
compounded product, and is omitted entirely when the entry price is not
positive, because no honest percentage exists. Undefined bars are logged rather
than silently swallowed: a wrong return is a wrong reported number, not a crash.

bar_returns keeps the exact `close / prev - 1` expression pct_change uses, so
results for strictly positive series are bit-identical and ordinary equity and
crypto runs are unchanged.

The loader still rejects an exact-zero close, but the reason has narrowed to the
one that survives: sizing is target_notional / abs(price), undefined at zero.

Closes #872
2026-07-28 12:57:37 +08:00
Haozhe Wu 6a859902e9 fix(cli): inject a host session id into non-interactive runs
The research-goal tools are registered unconditionally and resolve their
session from the host runtime, so an entry point that calls _run_agent without
an id makes every goal call fail validation with "session_id is required" while
the run still reports SUCCESS. Reported for `vibe-trading run`; six of the seven
_run_agent call sites had the same omission, including cmd_session_chat, which
already received the session id as a parameter and simply never forwarded it.

Add _ensure_session_id, which builds a Session (whose id is populated at
construction) and persists it best effort, so a store or index failure still
yields a usable id rather than the empty string that caused the bug.
cmd_continue reuses one session across continuations so goals accumulate: a
session-backed run_id already is a session id, since sessions and their traces
share SESSIONS_DIR, so it is used directly; a plain run gets a derived id.
Re-registering an existing id is idempotent. The interactive REPL had the same
latent hole whenever _new_session returned None, and now falls back to an
unpersisted id.

Also align the MCP contract. All four MCP goal tools declared session_id
required while the in-process registry injects it and leaves it optional — the
opposite contract, which asked the model to invent an internal identifier it
has no way to know. session_id is now optional there too, defaulting to one
stable id per server process.

Closes #885
2026-07-28 12:57:28 +08:00
Haozhe Wu d528066646 docs(readme): fix Windows install steps in all five READMEs (#888)
CMD has no `cp`, so `cp agent/.env.example agent/.env` fails there; add the
`copy` form and note that PowerShell's `cp` alias already works. Also add the
CMD activation line and the execution-policy hint that blocks Activate.ps1.

Reported by @brady-cec in discussion #29.
2026-07-28 01:54:41 +08:00
Haozhe Wu db3ed92cef chore(deps): ignore jsdom majors until the Node 22 migration
jsdom 30.x requires Node ^22.22.2 || ^24.15.0 || >=26 while CI and Docker are
on Node 20. On Node 20 the incompatibility surfaces indirectly as vitest
failing to start its pool workers rather than as a clean engine error, so #877
reads like a flaky frontend failure. Same wall as @testing-library/jest-dom 7.
2026-07-27 18:03:57 +08:00
Haozhe Wu 58363fc01f chore(deps): unblock the ccxt/setuptools lock deadlock and cut dependabot churn
Dependabot could not land either half of a mutually-blocking pair: the
minor/patch group wanted ccxt 4.5.68 (which pins setuptools==83.0.0) while
keeping setuptools at 82.0.1, and the separate setuptools 83.0.0 PR conflicted
with the ccxt 4.5.67 already in the lock. Neither can go green alone because
setuptools is a major bump and is excluded from the minor/patch group by
design, so it cannot ride along.

Regenerate the lock so both move together. Verified with pip-compile under
Python 3.11 on Linux (matching CI) and checked with CI's own gate,
pip install --dry-run --require-hashes. Note the lock is platform-sensitive:
regenerating on macOS drops jeepney/secretstorage and swaps py-mini-racer for
mini-racer, so it must be produced on Linux.

Also ignore websockets, capped at <16 by langgraph-sdk 0.4.2, and move all
three ecosystems to monthly with 2 concurrent PRs. Security updates are a
separate channel and are unaffected.
2026-07-27 18:03:14 +08:00
Haozhe Wu 218d453859 build(deps): ignore bumps blocked by upstream or infra constraints
caio: aiofile 3.11.1 (latest) requires caio~=0.9.0, so bumping caio to 0.10.x
makes pip unresolvable and the grouped PR fails CI. Ignore only caio, not the
whole minor/patch group.

@vitejs/plugin-react 6.x peers vite@^8 (we are on 6.x) and
@testing-library/jest-dom 7.x requires Node >=22 (CI/Docker use 20). Both are
migrations, not dependency bumps.
2026-07-27 17:31:41 +08:00
Haozhe Wu 612004243c fix(loaders): keep a stubbed config from writing cache into the working tree
loader_cache_enabled() returned the raw config value, so a MagicMock config
read truthy and switched the opt-in cache on. loader_cache_root() then passed
that MagicMock to Path(), which resolves via __fspath__ to a *relative* path
and put real market-data parquet under agent/MagicMock/ inside the repo.

Validate both at the boundary: require a genuine True to enable the cache, and
honor the root override only when it is a real non-blank str.
2026-07-27 17:31:41 +08:00
Haozhe Wu a69c55944b docs(readme): add 2026-07-27 news 2026-07-27 17:15:06 +08:00
Haozhe Wu 5c690c7211 Merge branch 'main' into fix/journal-to-float-strip-currency
Resolves the import-list conflict in agent/tests/test_trade_journal.py
introduced when #862 landed on main: keep both _to_float (this branch)
and load_dataframe (#862).
2026-07-27 15:41:42 +08:00
Haozhe Wu f56a3d398f fix(background): prevent Windows host self-termination
Add task-scoped cancellation, reject broad Python process-name kills, expose timeout context, and cover the lifecycle on Windows 11 and Windows x64 with Python 3.14.

Signed-off-by: Haozhe Wu <haozhe_wu@connect.hku.hk>
2026-07-27 02:20:50 +08:00
Haozhe Wu d5ea0ec519 docs(readme): add 2026-07-26 news and ignore workbuddy 2026-07-26 19:13:36 +08:00
Haozhe Wu 2c1ccd7678 fix(alpha): disclose benchmark universe degradation 2026-07-26 13:03:57 +08:00
Haozhe Wu 8aa7a13bfe fix(deps): repair cold hash-locked installs 2026-07-26 12:53:22 +08:00
Haozhe Wu 93d666c5e6 docs(readme): add 2026-07-25 news across all 5 READMEs, keep 3 visible entries 2026-07-25 23:01:23 +08:00
Haozhe Wu 65bab10f32 docs(readme): add 2026-07-24 news across all 5 READMEs 2026-07-24 22:46:19 +08:00
Haozhe Wu 43c444292c docs(readme): add 2026-07-23 news across all 5 READMEs 2026-07-23 13:44:46 +08:00
Haozhe Wu 329b054128 docs(readme): backfill longbridge data-source parity in ja/ar
ja/ar were missing the longbridge Data Sources table row and its place in
the US/HK fallback chains (a pre-0.1.12 drift; en/ko/zh already had them).
Now all 5 locales agree on the 23-source table + chains. (The en-only
'Using Longbridge explicitly' config subsection remains en-only.)
2026-07-22 23:19:10 +08:00
Haozhe Wu 761d52155c docs(readme): sync all 5 READMEs to v0.1.12 features + counts
News: 🚀 v0.1.12 entry (3-visible, demote 07-19). Counts synced to code:
462 alphas (academic 12), 88 skills, 23 data sources, 12 broker connectors.
Data Sources: add binance + mt5 rows + forex/metals fallback chain. New
Broker Connectors (12) and Backtest Engines (8) capability tables. Providers
list + native Anthropic / SiliconFlow / NVIDIA. Roadmap: SDM + Correlation
Regime rows. en/ja/ko English descriptions; zh/ar translated.
2026-07-22 22:47:39 +08:00
Haozhe Wu 43331c3221 docs(readme): v0.1.12 contributor credits across all 5 READMEs
Add the v0.1.12 cycle cohort (28 contributors) and demote the v0.1.11 list
into a collapsible block, in en/ja/ko/zh/ar. en/ja/ko keep English
descriptions; zh/ar translated.
2026-07-22 21:13:25 +08:00
Haozhe Wu 8cb536fa61 chore(release): 0.1.12 — version bump + CHANGELOG
Bump version 0.1.11 → 0.1.12 across pyproject, frontend package(+lock),
i18n app.version, SKILL.md, and Dockerfile OCI label. CHANGELOG [0.1.12]
covers the 0.1.11→0.1.12 window (correlation regime timeline, 3 new LLM
providers, MT5 connector, SDM skill, USD-M perps, ~90 correctness fixes,
and the #758 zai streaming/base_url fix).
2026-07-22 13:14:11 +08:00
Haozhe Wu a066e5545e fix(providers): resolve zai streaming + base_url resolution (#758)
Three fixes for the native zai provider on glm-5.1:

- get_llm_credentials now falls back to the provider catalog's
  default_base_url when no *_BASE_URL is set, so CLI/manual-.env users
  reach the canonical endpoint (Z.ai /api/coding/paas/v4) instead of
  silently defaulting to api.openai.com. Web Settings already did this;
  the backend credential path did not. Benefits all 22 providers.
- stream_chat falls back to a non-streaming invoke when a provider
  streams zero chunks ('No generation chunks were returned'), instead of
  raising ProviderStreamError. Scoped to the empty-stream case; genuine
  provider errors still raise.
- ProviderStreamError appends a base-URL hint when the endpoint returns
  an HTML error page (a common misconfiguration signal).

Fixes #758.
2026-07-22 12:59:07 +08:00
Haozhe Wu f2c7256d56 Merge PR #756: feat(correlation): regime timeline endpoint and UI (edge density + hysteresis) 2026-07-22 12:51:20 +08:00
Haozhe Wu 93fa241fc8 Merge PR #757: feat(data): decouple maintenance-bracket acquisition from the historical fetch path 2026-07-22 12:51:19 +08:00
Haozhe Wu f06d399388 Merge PR #770: fix(journal): normalize Excel float-stringified A-share codes 2026-07-22 12:51:08 +08:00
Haozhe Wu 5eb45502c7 Merge PR #769: fix(tools): accept unicode dashes in PDF page ranges 2026-07-22 12:51:07 +08:00
Haozhe Wu d538bfa369 Merge PR #768: fix(api): treat export KEY= as KEY in dotenv settings helpers 2026-07-22 12:51:04 +08:00
Haozhe Wu 3f0e6b8c94 Merge PR #767: fix(factors): keep single-day IC std finite in factor analysis JSON 2026-07-22 12:51:03 +08:00
Haozhe Wu f1697117c1 Merge PR #766: fix(backtest): print scalar metrics as strict JSON 2026-07-22 12:51:02 +08:00
Haozhe Wu 566eb86ba3 Merge PR #765: fix(metrics): keep Sharpe/Sortino finite when equity hits zero mid-path 2026-07-22 12:51:02 +08:00
Haozhe Wu be0d0a7c2c Merge PR #764: fix(pattern): emit strict JSON when trend_slope mean is undefined 2026-07-22 12:51:01 +08:00
Haozhe Wu 6fffd52541 Merge PR #763: fix(session): skip schema-bad messages.jsonl lines when reading 2026-07-22 12:50:59 +08:00
Haozhe Wu e8241034e9 Merge PR #762: fix(session): skip corrupt session.json when listing sessions 2026-07-22 12:50:58 +08:00
Haozhe Wu c350cddf8c Merge PR #761: fix(loaders): keep yahoo 1m as minute bars, not monthly 2026-07-22 12:50:57 +08:00
Haozhe Wu a44e1be357 docs: add 2026-07-21 news across all 5 READMEs 2026-07-21 14:58:18 +08:00
Haozhe Wu 251e7e0987 Merge PR #689: complete partial market-data results through fallback
Rebased onto main and deduped — reuse the existing _restore_original_codes helper instead of the PR's parallel _map_result_to_requested; apply the same missing-symbol completion to both _fetch_auto and the explicit-source path. Fixes #681.
2026-07-21 13:42:04 +08:00
Haozhe Wu 585b8f69cd fix(frontend): render LaTeX math in chat via remark-math + KaTeX
LLM answers with \(...\)/\[...\] or $$ formulas rendered as plain text --
the markdown pipeline had no math plugin. Normalize LLM delimiters to $$
outside code segments (streaming-safe for unclosed fences), parse with
remark-math (single-$ disabled so dollar amounts like "$150 to $120"
never become formulas), render with rehype-katex.
2026-07-20 20:56:55 +08:00
Haozhe Wu 7abc2a8a03 docs: add 2026-07-20 news across all 5 READMEs
Providers (Anthropic native/SiliconFlow/iFlytek), MetaTrader 5 connector + mt5
source, llm-vision OCR, 80x signal vectorization, USD-M funding data, reliability
consolidation (#584, 13 issues), options partial-close fix, and more. Keeps 3
entries visible; 2026-07-17 moved into the earlier-news details.
2026-07-20 19:07:11 +08:00
Haozhe Wu aaa1061b78 fix(options): honor partial-close quantity instead of flattening the lot
The options engine close branch computed cash/PnL from the full matched lot and
removed the whole position, ignoring the leg's requested qty — any partial close
wiped the entire lot with full PnL. Now an explicit leg qty closes only that many
contracts (clamped to the open size), cash/PnL scale to the closed fraction, and
the remainder stays open as a reduced-qty position; a close leg with no qty still
closes the whole lot (legacy). Closes #577.
2026-07-20 19:00:53 +08:00
Haozhe Wu c1f9f96a60 Merge PR #548: feat(ocr): pluggable engine architecture + LLM vision OCR + configurable threshold
Self-fix on merge: the qwen-vl → llm-vision deprecation warning now calls out the
credential-source change (DASHSCOPE_API_KEY → configured LANGCHAIN_PROVIDER) so
existing DashScope users aren't surprised. Generalizes the shipped qwen-vl engine
into a provider-agnostic llm-vision engine + entry-point plugin discovery + OCR
threshold + quality metrics. Closes #547.
2026-07-20 18:56:15 +08:00
Haozhe Wu 2400bbcbaa Merge PR #695: feat(providers): add native Anthropic Messages API support
Self-fix on merge: moved langchain-anthropic from core dependencies to an
[anthropic] optional extra (like [deepseek]) — _build_anthropic lazy-imports it
and raises an actionable install hint, so the base install stays lean. Resolved
llm.py conflicts against #563's centralized get_llm_credentials + the anthropic
native adapter-mode branch. Closes #694.
2026-07-20 18:55:21 +08:00
Haozhe Wu 0c86356a77 docs(skill): market-data source count 22 → 23 (mt5 loader, #481) 2026-07-20 18:51:50 +08:00
Haozhe Wu 11b4f62340 Merge PR #481: feat: MetaTrader 5 (Exness) broker connector + mt5 market-data source
Red-lines verified PASS (mandate gate, structural trade_mode discriminator, no MCP
order exposure, sandbox-barred loader). Resolved additive conflicts: registry (mt5
loader alongside longbridge), pyproject (mt5 extra), CHANGELOG (kept both entries);
README/SKILL counts reconciled in the news pass. market_data =F/=X (yahoo) and mt5
forex routing coexist.
2026-07-20 18:48:32 +08:00
Haozhe Wu 5278469d0d Merge PR #584: Fix reliability across packaging, web, scheduler, swarm, and CLI
Consolidation resolving #603 #605 #611 #613 #617 #639 (named) + folded #583 #585 #587 #589 #591 #595 #599.
Kept both dev-extra and slack-version packaging tests at merge.
2026-07-20 18:45:20 +08:00
Haozhe Wu 949ccad594 Merge PR #726: fix: Robinhood connector account_number wiring + remote-MCP display shape
Reconciled the connector renderers with #735 (Longbridge schema-tolerant balances):
_print_connector_account now handles balances (broker_sdk) → remote-MCP nested
(Robinhood) → IBKR summary; positions use both remote-MCP shape and _first_present aliasing.
2026-07-20 18:44:45 +08:00
Haozhe Wu b7c62c68a1 Merge PR #716: feat(data): add historical USD-M funding settlements + maintenance brackets
Stray docs/superpowers/pr-drafts/pr1b-funding-brackets.md dropped at merge (repo never carries docs/ from contributor PRs).
2026-07-20 18:42:41 +08:00
Haozhe Wu c2151a2269 fix(backtest): make vectorized _align writable (follow-up #698)
The vectorized _align did in-place np.nan_to_num/clip on arrays taken from
pandas via .values/astype(copy=False), which are read-only views under pandas
copy-on-write, raising 'ValueError: assignment destination is read-only' on
current main. Force a writable copy for the per-symbol signal array and use the
copy-returning nan_to_num for the position matrix. Vectorization stays numerically
equivalent to the scalar path (assert_frame_equal tests pass).
2026-07-20 18:39:21 +08:00
Haozhe Wu 099948ec01 Merge PR #698: perf: Signal alignment vectorization — 80x speedup 2026-07-20 18:37:45 +08:00
Haozhe Wu 8c627b00f7 test(cli): update provider-menu indices after SiliconFlow(#565)+Spark(#537) inserts
Both PRs insert providers ahead of ollama/openai-codex in the init menu; the
combined order puts ollama at 17 and openai-codex at 18.
2026-07-20 18:33:20 +08:00
Haozhe Wu add7b3f364 Merge PR #563: refactor(providers): centralize credentials + fix gateway misroute (closes #549, #553)
# Conflicts:
#	agent/src/providers/capabilities.py
#	agent/tests/test_llm.py
2026-07-20 18:32:08 +08:00
Haozhe Wu 7ba3bf2f5d Merge PR #537: feat(providers): add iFlytek Spark as an OpenAI-compatible provider 2026-07-20 18:31:33 +08:00
Haozhe Wu 3b9dba55eb Merge PR #565: feat: add SiliconFlow CN and Global providers 2026-07-20 18:31:33 +08:00
Haozhe Wu e796a34dd6 Merge PR #663: fix(codex): classify stream HTTP failures 2026-07-20 18:31:33 +08:00
Haozhe Wu 0802a535a6 Merge PR #641: Honor cancellation before the first AgentLoop iteration (closes #638) 2026-07-20 18:31:33 +08:00
Haozhe Wu 205c940c99 Merge PR #704: perf(swarm): cache MCP tool discovery specs to avoid redundant RPC calls 2026-07-20 18:31:33 +08:00
Haozhe Wu 015e1f7e3e Merge PR #717: fix(frontend): prevent insertBefore DOM race during streaming output 2026-07-20 18:31:33 +08:00
Haozhe Wu 7eff24ddf0 test(api): preserve #738 commented-key upsert coverage after folding into #742 2026-07-20 17:49:20 +08:00
Haozhe Wu 8b4dcaf313 fix(data): resolve Yahoo futures (=F) and forex (=X) suffix tickers
get_market_data could not resolve tickers like GC=F or EURUSD=X: detect_source
matched no pattern and fell to the 'tushare' default, routing them to
China-market loaders that cannot serve them; and the yahoo direct loader's
_is_supported guard rejected any non-.US/.HK/.NS/.BO symbol even though Yahoo's
public chart endpoint serves =F/=X verbatim.

Add =F/=X source patterns (route to yahoo) and accept =F/=X in the yahoo loader.

Closes #718
2026-07-20 17:46:14 +08:00
Haozhe Wu 2b31effe13 fix(cli): make connector positions/account renderers schema-tolerant
The shared 'connector positions'/'connector account' CLI renderers assumed the
IBKR result shape (position/avg_cost/sec_type/summary). broker_sdk connectors
such as Longbridge emit quantity/cost_price/market/balances, so every
non-matching key rendered as an empty cell.

Read key aliases (position|quantity, avg_cost|cost_price, sec_type|market) via a
None-aware _first_present helper (keeps a real zero qty), and render a balances
table when a connector returns 'balances' instead of IBKR 'summary' rows.

Closes #735
2026-07-20 17:46:14 +08:00
Haozhe Wu 57034a0fbc Merge PR #743: fix(api): keep hash characters inside quoted dotenv values
# Conflicts:
#	agent/tests/test_api_infrastructure.py
2026-07-20 17:36:16 +08:00
Haozhe Wu 7558b8b86a Merge PR #742: fix(api): upsert last duplicate active dotenv key (also skips commented keys, folding in #738) 2026-07-20 17:35:24 +08:00
Haozhe Wu 707ceb1c2b Merge PR #744: fix(options): treat non-positive spot/strike as intrinsic in BS helpers 2026-07-20 17:35:16 +08:00
Haozhe Wu 45b21ff516 Merge PR #741: fix(pattern): reject window=1 for trend_line_slope 2026-07-20 17:35:16 +08:00
Haozhe Wu 2c679b2a23 Merge PR #740: fix(options): catch OverflowError in options metrics annualization 2026-07-20 17:35:16 +08:00
Haozhe Wu dd5494f92c Merge PR #739: fix(metrics): avoid OverflowError annualizing explosive equity paths 2026-07-20 17:35:16 +08:00
Haozhe Wu f72f3ff822 Merge PR #737: fix(ui): skip non-positive MA periods in indicator overlays 2026-07-20 17:35:16 +08:00
Haozhe Wu 2d35e8000a Merge PR #736: fix(channels): avoid hang splitting telegram fenced markdown chunks 2026-07-20 17:35:16 +08:00
Haozhe Wu 3bd64c3b1f Merge PR #734: fix(composite): fall back to first available sub-engine for unknown symbols 2026-07-20 17:35:16 +08:00
Haozhe Wu 97e762e51c docs: add 2026-07-19 news across all 5 READMEs
Real US/HK Yahoo Finance news articles (#730), MCP factor_analysis contract
fix (#715/#635), Kimi K-series temperature=1 forcing (#701), and inverted/
degenerate-input fail-fast across split_message/PDF pages/journal filters
(#727-#729). Keeps 3 entries visible; 07-16 moves into the details block.
2026-07-19 19:50:02 +08:00
Haozhe Wu cf51bc322b ci: correct setup-node pin comment to v7.0.0 (follow-up #720)
Dependabot bumped the setup-node SHA to v7.0.0 (820762786...) but left the
pin comment reading # v6. Align the comment with the actual pinned version.
2026-07-19 19:41:57 +08:00
Haozhe Wu 668389bdea fix(tools): surface inverted journal date filter as error envelope (follow-up #729)
#729 made _apply_filter raise on inverted/degenerate date ranges (fail-fast
over silently returning an empty frame). But analyze_trade_journal called it
unwrapped, so the ValueError escaped as a raw traceback instead of the
{status: error} envelope the rest of the function uses; and the pre-existing
test_apply_filter_preserves_full_date_and_mixed_precision still asserted the
old silent-empty behavior. Wrap the call to return the error envelope and
update the stale assertion to expect the raise.
2026-07-19 19:41:57 +08:00
Haozhe Wu d55de48d42 fix(skills): use API-native decimal funding rate in perp-funding-basis
The annualized example used 0.01 with a '0.01%' comment, which reads as
1% (→1095% annualized), not the intended 0.01% (→10.95%). Standardize the
whole skill on the per-8h decimal convention OKX/Binance actually return
(0.0001 = 0.01%): fix the annualized example, funding_regime and
oi_funding_matrix thresholds, the cross-exchange dict, and the carry-trade
example; add an explicit units-convention note. Human-readable % tables
kept as-is.
2026-07-19 19:23:23 +08:00
Haozhe Wu b79e4c54bd docs: add July 18 news (Binance loader + parallel-exec / correctness fixes) 2026-07-18 22:39:31 +08:00
Haozhe Wu ec052ffab2 fix(backtest): block getattr indirection onto os in signal-engine sandbox (GHSA-jqmf F8)
The AST validator scanned os.<attr> but not getattr(os, "system")(...). Reject
getattr/setattr/delattr whose target is os or a forbidden module — keyed off the
target, not the attr string, so getattr(os, "sys"+"tem") is caught too.
Legit getattr(obj, name, default) on user objects (as the bundled harmonic
example uses) is unaffected.
2026-07-18 21:46:44 +08:00
Haozhe Wu a8f75628d6 fix(channels): operator-gate IM /pairing control plane (GHSA-fwpw)
IM /pairing ran with no authorization, so any allow-listed chat participant could
take over pairing across channels (+ Signal group members bypassed the sender
check, + code/sender_id leak). Add a config-driven operators allowlist (global +
per-channel, fail-closed when empty); gate every /pairing on operator identity in
runtime; scope store list/approve/revoke by channel; require per-sender auth for
control-plane slash-commands in Signal groups (ordinary /new /reset unchanged).
README documents the operator requirement.
2026-07-18 21:46:44 +08:00
Haozhe Wu a1ec1c0cb4 fix(security): neutralize chat-template control tokens in external content (GHSA-v8fm)
Untrusted web/doc/search content entered the LLM context with no special-token
filtering, letting it forge system/assistant role boundaries. Add
neutralize_special_tokens() (hooked into with_security_warnings, applied to the 3
untrusted ingestion tools) that ZWSP-defangs the ChatML <|...|> family, the
DeepSeek fullwidth-bar <|...|> family (the shipped default model), Llama
[INST]/<<SYS>>/<s>, and Gemma role tokens. Text stays visually identical.
2026-07-18 21:46:44 +08:00
Haozhe Wu e4498d403f fix(mcp): Host/Origin guard on network transports (GHSA-p3c9)
sse / streamable-http bound a TCP port with no Host/Origin validation (fastmcp
3.2.4 ships none), so a DNS-rebinding browser page could reach every MCP tool.
Wrap the network ASGI app (mcp.http_app) with TrustedHostMiddleware + an Origin
allow-list (VIBE_TRADING_MCP_ALLOWED_HOSTS, default loopback) and serve via
uvicorn. stdio (default) untouched.
2026-07-18 21:46:44 +08:00
Haozhe Wu 2f35bce832 fix(api): require the configured key on loopback too (GHSA-7wgj)
_validate_api_auth / require_event_stream_auth trusted the loopback peer BEFORE
checking API_AUTH_KEY, so a same-host reverse-proxy/sidecar reached key-protected
routes with no token. Invert to key-first (mirrors require_settings_write_auth):
when a key is set every peer incl. loopback must present a valid bearer/ticket;
only the no-key dev mode keeps loopback trust. No-key default UX unchanged; the
bundled frontend already sends the bearer/ticket when a key is stored. Updates
3 tests that codified the loopback-bypass behavior.
2026-07-18 21:46:44 +08:00
Haozhe Wu 106edbdb41 fix(mcp): stop stdio transport from force-enabling shell tools (GHSA-6wjh)
MCP stdio previously force-enabled bash/background_run with no opt-out and the
module-level default was fail-open. Default to fail-closed and gate every
transport behind explicit opt-in (--enable-shell-tools flag or
VIBE_TRADING_ENABLE_SHELL_TOOLS). Local CLI is unaffected (still opts in
explicitly). Also shrinks the network-reachable surface of the bash
OS-command-injection sink (GHSA-m768). Adds regression tests + doc alignment.
2026-07-18 21:46:43 +08:00
Haozhe Wu 7cd998da1f docs(skill): bump market-data source count to 22 for Binance loader (#643) 2026-07-18 19:28:33 +08:00
Haozhe Wu 4275b85fe6 Merge PR #643 2026-07-18 19:25:53 +08:00
Haozhe Wu 1ad07f316c Merge PR #645 2026-07-18 19:25:52 +08:00
Haozhe Wu eb518947aa Merge PR #636 2026-07-18 19:25:52 +08:00
Haozhe Wu 9cc7d273ab Merge PR #634 2026-07-18 19:25:52 +08:00
Haozhe Wu dbaefaa00e Merge PR #705 2026-07-18 19:25:52 +08:00
Haozhe Wu 0f88c50fbe Merge PR #707 2026-07-18 19:25:52 +08:00
Haozhe Wu 96f7a9174c Merge PR #714 2026-07-18 19:25:52 +08:00
Haozhe Wu 3aa7aebef7 Merge PR #713 2026-07-18 19:25:52 +08:00
Haozhe Wu 0bcc2d5937 Merge PR #712 2026-07-18 19:25:52 +08:00
Haozhe Wu b1964cdedb Merge PR #711 2026-07-18 19:25:52 +08:00
Haozhe Wu 7d69947327 Merge PR #710 2026-07-18 19:25:52 +08:00