Requesty (added in #474) is an OpenAI-compatible gateway whose capabilities
were a copy of OpenRouter's: same provider/model naming, same
extra_body.reasoning opt-in, no adapter code of its own. Built-in slots are
kept for providers with their own behaviour; a gateway that speaks an
existing wire format is configured through that provider, and #1532 (API
Route) is being closed on the same grounds.
Migration, identical request shape: LANGCHAIN_PROVIDER=openrouter,
OPENROUTER_BASE_URL=https://router.requesty.ai/v1, OPENROUTER_API_KEY=<the
Requesty key>. Past news and contributor credits in the READMEs are left
as history; the supported-provider lists drop it.
The PR's CI failed on its own changes: the seven README loader tree lines
still said 27 sources without gildata, and two tests pinned a seven-source
A-share order that stops validating once gildata joins the chain.
README_id.md, which landed after the PR's base, also gets the source-table
row, the count and the chain. The loader docstring and CHANGELOG still said
the token rides the URL query string; since the review it is sent in the
Authorization header.
One sentence per README in the existing "Configure from the Web UI"
paragraph: register a bot on the QQ Open Platform (q.qq.com), copy
AppID/AppSecret into the form, verify with Test connection before
saving, then enable - no public callback URL needed (WebSocket via the
official botpy SDK). The DingTalk "first fully-guided channel"
sentence stays; news entries are historical and untouched.
Part of #1519.
Signed-off-by: shadowinlife <shadowinlife@gmail.com>
User-facing features of this size land a dated News bullet per repo
convention; the branch only carried the "Configure from the Web UI"
subsection. Add the 2026-09-20 entry (validate-before-save, masked
secrets, connection test, per-channel hot apply, DingTalk guided
setup) to all six READMEs, and note in the subsection that only
built-in adapters are listed — entry-points plugin channels remain
file-configured. Dated news bullets are excluded from the
test_readme_counts anchors, which stay green.
Part of #1519.
Signed-off-by: shadowinlife <shadowinlife@gmail.com>
Add a 'Configure from the Web UI' subsection to the IM channels section of
all six READMEs: expandable per-channel panel, DingTalk Stream Mode setup
guide, credential probing before save, immediate hot-apply enable/disable,
masked secrets, and the JSON-only editing constraint.
Part of #1519.
Signed-off-by: shadowinlife <shadowinlife@gmail.com>
One Robinhood login reaches several accounts, and every account-scoped tool
takes account_number. Nothing sent one, and every consumer read the reply one
level too shallow (data.positions where Robinhood nests data.data.positions),
so the portfolio could not use Robinhood and the live runner and pre-trade gate
failed closed on every read.
Shapes: one module, connectors/robinhood/mcp.py, reads every Robinhood reply,
built only from the shapes posted on #1428 (observed get_accounts and
get_portfolio, advertised get_equity_positions outputSchema). A non-empty
data.next, a null list or item, or an unmapped data key is an error, never a
shorter account.
Portfolio (#1428): robinhood-live-mcp-readonly shares the MCP server and
OAuth grant. A connection instance carries account_ref, chosen from
get_accounts through the API, the CLI (connector select-account, setup
--account) or the connection center, with nothing preselected. A source with
no account errors before any call. Positions stay unpriced, because the profile
declares no quotes.read. A non-zero or unreported options, crypto, futures,
event-contract, mutual-fund or fixed-income value fails the source.
Live (#1442): /mandate/commit requires an account for such a broker and checks
it against get_accounts (listed, not deactivated, agentic_allowed). The Web
confirm dialog and the CLI REPL ask the user to pick from GET /live/accounts,
and never take the account from the agent-written proposal. Runner reads and
submits, the ceiling fetch and the gate's reads resolve the mandate's account
on each call and unwrap through the same module. The gate refuses an unbound
mandate or an order naming another account, and prices held positions through
the order-notional quote path, failing closed per row.
Existing gate and runner tests encoded replies Robinhood never sends. They now
use tests/robinhood_mcp_helpers.py.
Scalable Capital's Agentic Investing MCP endpoint is registered read-only.
They publish no paper environment, so the tier is bounded-live behind the
mandate gate, and no built-in profile places orders.
- 29-name catalog pinned in connectors/scalable/classification.py (18 READ /
11 WRITE; preview_* is WRITE on purpose, since its confirmation feeds
submit_*), seeded allowlist = the READ names only, wildcard refused. A
hand-enabled WRITE tool assembles gate-wrapped and is refused at the intent
step, because no extractor is registered for this broker.
- The profile exposes quotes.read only. account.read / positions.read are
withheld together with the portfolio compatibility tier: those two are
exactly what is_portfolio_connection_profile requires, and nothing maps
Scalable's holdings reply into the shared positions shape, so a refresh
would store a complete snapshot holding zero positions. Add the pair back
with the normalisation once a live tools/list settles the reply shape.
- The READ/WRITE name sets in the tests are pinned literally rather than
derived from the map, so a tool cannot be moved between classes (or seeded)
without a test diff naming it.
Refs #1367.
Signed-off-by: cgycorey <cgycorey@users.noreply.github.com>
Adds a new broker_sdk connector for Toss Securities KR/US equities via the
Toss Invest Open API (developers.tossinvest.com, launched 2026-05), OAuth2
client-credentials + requests only, no third-party SDK.
Per the tracker (HKUDS/Vibe-Trading#1367): no documented sandbox and no
account-response field distinguishing test from live were found in the
public docs (flagged there as lower-confidence than the Upbit/KIS reads,
since the docs render client-side and I could not get a maintainer-grade
read on every endpoint). Applying for API access itself requires a real
Toss Securities brokerage account, which points the same direction.
Following the Trading 212 precedent, this connector is therefore fully
read-only: place_order/cancel_order hard-refuse for every profile, paper
included, with the environment check as the first statement in each
function (same guard shape Trading 212 uses, verified by
test_paper_capped_connectors_refuse_live.py).
Also updates the anti-drift guards: toss added to _PAPER_CAPPED, portfolio
compatibility tier (experimental), broker count/table across all six locale
READMEs (14 -> 15 brokers), and the "brokers without paper trading" exceptions
paragraph now names Toss Securities alongside IBKR/Robinhood/Trading 212.
New agent/tests/test_sdk_connectors_toss.py covers profile registration, the
always-refuse guard (including the declared-paper case, since there is no
verified sandbox to simulate against), secret redaction, and service
dispatch.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYruJS2jFvSoi7DdWWuMvW
Signed-off-by: heonjinjeong <hj.jeong@okestro.com>
Adds a new broker_sdk connector for Upbit, Korea's largest KRW crypto
exchange, via its public JWT-signed REST API (requests + PyJWT only, no
third-party SDK).
Per the tracker (HKUDS/Vibe-Trading#1367): Upbit has no sandbox and no
runtime paper/live discriminator -- one access/secret key pair reads the
same account regardless of the declared profile. Following the
Longbridge/Dhan/Zerodha precedent, this ships paper (order placement
simulated locally against a live quote) + read-only live only; place_order
and cancel_order hard-refuse any non-paper config as the first statement in
each function, structurally -- not a flag checked later -- before any
network call, matching the pattern test_paper_capped_connectors_refuse_live.py
enforces for every capped broker.
Also updates the anti-drift guards: upbit added to _PAPER_CAPPED, portfolio
compatibility tier (experimental), broker count/table across all six locale
READMEs (14 -> 15 brokers).
New agent/tests/test_sdk_connectors_upbit.py covers profile registration,
the structural paper-only guard, a bug a code review caught before this PR
(a notional order returning a fabricated "ok" result with a null price/
quantity when the live-quote lookup failed -- now fails closed), secret
redaction, and service dispatch.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYruJS2jFvSoi7DdWWuMvW
Signed-off-by: heonjinjeong <hj.jeong@okestro.com>
Adds a new broker_sdk connector for Korea Investment & Securities (KIS)
KOSPI/KOSDAQ equities via the official KIS Developers REST API.
Per the tracker (HKUDS/Vibe-Trading#1367): KIS has a genuine structural
paper/live discriminator confirmed against the docs — 모의투자 (paper) and
실전투자 (live) are reached through entirely separate hosts and ports
(openapivts.koreainvestment.com:29443 vs openapi.koreainvestment.com:9443),
each issuing its own OAuth2 client-credentials token. This ships paper (which
places real orders against KIS's own paper-trading server, not a local
simulation) + read-only live. It deliberately does not wire a mandate-gated
live-trade profile yet -- that would need a new AssetClass.KR_EQUITY in the
mandate model -- mirroring how Zerodha/Dhan/Shoonya shipped conservatively
for a first connector into a new market.
TR_ID transaction codes and response field names were sourced from the
official example repo (koreainvestment/open-trading-api) and public docs,
not verified against a live KIS account -- flagged in the tracker thread.
Also updates the anti-drift guards: kis added to _LIVE_CAPABLE (genuine
discriminator, unlike the paper-capped brokers), portfolio compatibility
tier (experimental), broker count/table across all six locale READMEs
(14 -> 15 brokers).
New agent/tests/test_sdk_connectors_kis.py covers profile registration, the
host-separation guard, order validation (including two bugs a code review
caught before this PR: a fractional cancel-quantity truncating into a
full-quantity cancel, and get_historical_bars(limit=0) returning the full
history instead of nothing), secret redaction, and service dispatch.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYruJS2jFvSoi7DdWWuMvW
Signed-off-by: heonjinjeong <hj.jeong@okestro.com>
`test_readme_loader_tree_line_matches_the_registry` guarded the loaders line
of the repo tree and only that line, so the tree line was right while the
prose two hundred lines above it and the table directly beneath it were not:
* the intro claimed "23 free market-data sources" against a registry of 27
— contradicting the tree line in the same file
* nobitex and wallex never reached the table in any language, so two
sources that shipped this cycle were listed nowhere a reader looks
* tickerall was in the English table only; the five translations never got
a row when it landed as the 25th source
* the engines tree line said 8 where the code ships 9 plus the composite,
while the feature badge — which is checked — said 10
Three guards now cover those spots, anchored on code literals (`source:
"auto"`, `engines/`, a backticked source name) so they survive translation,
per this file's founding constraint. The table check runs against the
registry rather than across READMEs, so all six being uniformly wrong still
fails; that is how tickerall stayed missing from five of them.
Mutation-tested: reverting the count to 23, deleting the nobitex row,
reverting the engines line to 8, and deleting tickerall from one translation
each fail exactly one test.
The release entry and the day's sweep entry carried the same date, so the
timeline showed 2026-09-09 twice in all six languages.
They are not redundant, though — the two bullets shared no references at all
(release: #1317, #1376, #1377, #1395; sweep: #1392, #1393, #1394, #1396,
#1397, #1398, #1399, #1400), so deleting either would have dropped eight
pull requests from the README. The sweep's substance is spliced into the
release entry ahead of its "new this cycle" segment instead, where it reads
as what it was: the last batch to land before the tag, and a miniature of
the same three themes the release is about — a contract classified into the
wrong market, a fill default inventing a return, and a default value that
must not read as a looked-up one.
Verified per language that the merged bullet carries all 12 references and
that the whole file's reference set is unchanged, and the collapsed list
gives back one entry so three stay visible.
Rolls up 551 commits / 162 merged pull requests since 0.1.14, from 35
contributors.
Served price frames now stamp the adjustment caliber they carry, and a
source whose caliber was never measured against a live payload reports
`unknown` rather than guessing one. The Alpha Zoo's NaN contract moved out
of the individual alphas and into the registry: an alpha branching on an
`np.where` comparison never sees a NaN, so blanking every declared input on
one bar left 84 of 462 alphas returning a number anyway, each consumed as a
real signal because `dropna()` is what keeps a gap out of an IC. The same
sweep afterwards finds none. The futures loader chain was the last instance
of that class and closes in this release.
New markets and surfaces: UK equities (LSE .L/.IL, SDRT modelled as a
purchase-side-only duty), Zerodha Kite Connect as the fourteenth broker
(paper plus read-only, since Kite exposes no runtime live discriminator), a
read-only multi-broker portfolio across Web / REST / CLI / agent tool,
fifteen Quant Library additions, Brazilian Portuguese as the eighth locale,
read-only Nobitex and Wallex, and an offline evals harness that emits
NOT_EVALUABLE rather than passing when instrumentation is absent.
`test_release_version_consistency.py` caught a fourteenth declaration site
the eleven it was written for did not cover: the `app.version` mock in
`frontend/src/components/layout/__tests__/Layout.test.tsx`. The comment in
`test_cli_update.py` that named the current version is de-versioned here —
a version in a comment has no guard and goes stale at the next bump.
Reader-facing counts were re-measured rather than incremented: 74 MCP tools,
107 registry tools, 10 engines, 90 skills, 462 alphas, 27 data sources, 30
swarm presets, 14 broker connectors. None had drifted.
Today's landings: the composite engine's shared sub-engine dropping a
50 oz gold order to zero and charging an index future's fee schedule,
the futures product codes that fell through to the default multiplier of
50, the four Alpha Zoo factors that fabricated a signal through a halt,
the per-regime position sizing, and the no-progress budget with its
second-failure retry rule.
Same shape as the existing entries: three visible, 2026-09-04 demoted
into the collapsed block, one date set and one link set across all six
files. Every figure quoted was measured on this tree rather than taken
from a PR description; the ~35-iteration figure is the reporter's and is
attributed as such.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The news entry leads with the day's two guard failures — the MCP order gate
sizing a quantity order from the live quote alone, so a buy limit at twice the
market could fill at twice the authorized notional, and the report auditor
returning PASS after skipping every unverifiable point — then the grounding,
trade-journal, compaction and Windows fixes, then Zerodha, the two Iranian
sources, and Anthropic prompt caching. Three visible entries as always;
2026-09-03 moves into the collapsed block.
Writing it surfaced a real drift. Each README's repo-tree line both counts and
NAMES the loaders, and it read '24 sources' while the registry held 27 —
nobitex and wallex from #1263 were never added, and tickerall had been missing
for longer. All six were wrong in exactly the same way, so the existing count
tests, which only prove the READMEs agree with each other, stayed green. Same
failure mode the broker pin was added for after eToro shipped as the 13th
connector against a pin of 12.
The line is fixed in all six and now guarded against the live LOADER_REGISTRY
by name, not just by count, so omitting a source fails even when the number is
edited to match. Both mutations are killed: reverting the count to 24 fails,
and dropping a single name while keeping the count correct also fails.
Leads on the grounding gate matching `close` but not `closed`, so a
fabricated USD price passed in English while the identical Chinese claim was
caught, and on the compaction/dedup deadlock that left a run answering
"fundamental data not retrieved" for data it had already fetched.
2026-09-02 folds into <details> so three entries stay visible. All six files
carry the same 16 PR/issue links and the same 11 acknowledgements, checked
by set comparison rather than by eye.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two dated entries, one per day of merges, matching the commit dates on main.
2026-09-03 — a data source that never answers, and dated figures that could not
be proved: stooq's proof-of-work page read as "no data" so the second link of
the US-equity chain was dead weight with nothing in the log (#1342), and a
generic tool result lost the date it carried alongside its price, so a dated
claim had no evidence that could match it (#1333). Plus the MCP goal wrappers
demanding an id the registered tools call optional (#1331), the Codex adapter
dropping provider token counts (#1334), and real subprocess coverage for the
swarm's MCP stdio path (#1335).
2026-09-04 — every Claude 5 run failing at the first request (#1330), a halted
position re-marked at entry cost and printing a drawdown with no market event
behind it (#1332), three commit-time mandate-widening paths closed with cash-only
restored as the floor of the leverage axis (#1285), the elapsed clock surviving
navigation and reload (#1340), and the seven npm advisories patched.
Both entries are visible; 09-01 and 08-31 move into the folded block, keeping
three on screen per the news convention. Cross-checked by script: the PR/issue
references and the acknowledged handles are identical in all six files. Every
closes-reference verified against the PR's own closingIssuesReferences, and
every acknowledgement against the PR author.
The forward-fill limit is described without a bar count: it is 5 within one
market and 10 across markets, so naming "5-bar" would have been wrong for any
cross-market run.
Yahoo dividend adjustment, requested-vs-executed rebalance counts, the
calendar rebalance mask and the survivorship disclosure, plus the batch
of fixes. Notes that sina and longbridge still serve unadjusted prices
and points at #1301 rather than claiming the chain now speaks one
caliber. 2026-08-28 rolls into the folded section.