feat(video): expose Seedance reference media and output controls - #70
Closed
KillerQueen-Z wants to merge 254 commits into
Closed
KillerQueen-Z wants to merge 254 commits into
KillerQueen-Z wants to merge 254 commits into
Conversation
- Document that private keys NEVER leave the machine - Key is only used for LOCAL EIP-712 signing - Only signatures are transmitted, not keys - Same security model as MetaMask transactions
- Update docstring to use correct provider/model format (e.g., openai/gpt-4o instead of gpt-4o) - Add examples/arbitrage_analyzer.py showing integration with crypto arbitrage bots 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
x402 has $0.001 minimum payment requirement
More descriptive name for Base chain wallet
- Update all code and docs to use BASE_CHAIN_WALLET_KEY - Clearer naming since we're using Base chain wallet 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change primary env var from BASE_CHAIN_WALLET_KEY to BLOCKRUN_WALLET_KEY - Keep BASE_CHAIN_WALLET_KEY as fallback for backward compatibility - Update README and docstrings to reflect new naming
Add DeepSeek, Qwen, xAI Grok, OpenAI OSS models Add Nano Banana image generation models Remove unavailable models from list
* add ci/cd * add manual dispatch * clean up ci workflow * style: format code with black * fix: remove unused imports and fix lint errors * fix: include sanitized error response in list_models * test: fix unit tests to match implementation * chore: remove coverage reporting --------- Co-authored-by: Arthur Chiu <achiurizo@users.noreply.github.com>
- Add wallet.py for wallet lifecycle management - Auto-load wallet from ~/.blockrun/.session (privacy-friendly name) - Generate MetaMask-compatible EIP-681 QR codes for USDC on Base - Add Base logo to QR codes for brand recognition - Auto-open QR in image viewer when wallet needs funding - Update LLMClient, AsyncLLMClient, ImageClient to auto-load from .session - Export wallet utilities: get_eip681_uri, save_wallet_qr, open_wallet_qr
- New functions don't require wallet initialization - list_models() fetches from /api/pricing for full model details with pricing - list_image_models() returns empty list if endpoint unavailable (404)
…_wallet - LLMClient() now auto-creates wallet if none exists (no more ValueError) - Add get_balance() method to check on-chain USDC balance - Export generate_wallet function for explicit wallet creation - Auto-normalize private keys (add 0x prefix if missing) - Add qrcode[pil] as dependency - Update tests to reflect new auto-create behavior
- Add status() to wallet.py - prints wallet address and balance - Export status in __init__.py - Bump version to 0.3.6
- Format wallet.py with black - Add TYPE_CHECKING import for LLMClient type hint - Update test to match current behavior (require explicit wallet setup)
- get_balance() now tries 3 RPCs before failing - Order: publicnode.com, mainnet.base.org, meowrpc.com - Fixes false $0 balance issue with unreliable RPCs
- Default timeout: 60s -> 120s - Add search_timeout param (default 300s = 5 min) - Auto-detect search requests and use longer timeout - Update README with timeout documentation
- Add Claude Opus 4.5 (latest Anthropic flagship) - Add Flux 1.1 Pro (Black Forest Labs image model) - Remove Qwen models (not currently supported)
- Add testnet_client() convenience function - Add TESTNET_API_URL class constant - Add is_testnet() method to check if using testnet - Update get_balance() to use correct USDC contract per network - Update README with testnet usage examples and setup instructions
- Add BASE_SEPOLIA_CHAIN_ID and USDC_BASE_SEPOLIA constants - Add get_chain_config() to dynamically select chain based on network - Add asset parameter to create_payment_payload() - Update EIP-712 domain to use dynamic chain_id and usdc_address - Pass asset from server payment requirements in both sync/async clients
- Add get_usdc_domain_name() function - Mainnet USDC uses 'USD Coin', testnet uses 'USDC' - Use correct domain name based on network for signing
Use is_testnet() to determine correct network identifier (eip155:84532 for Base Sepolia) instead of always defaulting to mainnet (eip155:8453).
API no longer returns breakdown in 402 response.
…er from probed ids (BlockRunAI#55) Router Core was two commits behind upstream. V3.5 rebuilds every tier chain around ids the public catalog actually lists, so the withheld kimi-k2.5/k2.6/ k2.7, both grok-4-fast pairs, grok-4-0709, claude-opus-4.6 and gemini-3-pro-preview leave every rung including the fallbacks. Measured against the live catalog, each profile carried 3-4 off-catalog rungs per decision before this; now every profile carries none. The newer generation the catalog already sells enters as fallback rungs (GPT-5.6 Luna/Terra, Gemini 3.6 Flash, GLM-5.3, Grok 4.3/4.5, Kimi K3, Qwen 3.7 Plus, MiniMax M3); primaries moved only where portfolio.py already holds calibration evidence for the successor. Priors come with it: 66 model profiles (was 30) and a 71-model capability snapshot. Two stale capability values had been reaching the hard filter, Haiku 4.5 at 8K max output (64K) and Sonnet 4.6 at 200K context (1M). config.py was not hand-transcribed. A TS->Python converter was validated by running it over config.ts at the OLD pin and checking it reproduced the current config.py tier chains line for line (223/223) before it was pointed at HEAD. Separately, routing_profile="free" had collapsed to one model with no fallbacks. Four of the five ids in the SDK-only FREE_TIERS table were retired by NVIDIA and they were every primary plus all but one fallback. Nothing looked broken because the gateway server-redirects a retired free id: the dead rung returns 200 and answers normally while serving a different model, which is the shape that defeats unavailable_models. The table is rebuilt from ids verified by a two-pass probe that reads back the response's own model field, since a 200 proves nothing. nemotron-3-ultra-550b and nemotron-3-nano-omni-30b-a3b-reasoning are excluded despite listing at $0 -- both answer as nemotron-3-nano-30b. Every tier is back to four candidates and the free tier is no longer NVIDIA-only. The new depth test asserts fallback depth per tier rather than membership: the table stayed internally consistent all through the rot, so a membership check could never have caught it. 669 unit tests pass, the 88 cross-language parity decisions included. mypy reports the same 198 baseline errors before and after. Co-authored-by: 1bcMax <viewitter@gmail.com>
Vendored copy update. blockrun/ci.yml's brand-script-sync fails on any drift from brand/sync-brand-numbers.mjs, so this must land before BlockRunAI/blockrun#469. Fixes in this build: markers inside fenced blocks can opt in with @LiVe and any that silently drift are now reported; fence offsets are recomputed per marker (a badge expands 2 chars to ~150 and shifted every later fence test); an unterminated fence now runs to EOF instead of un-fencing the tail; and the walk is filtered through git ls-files, which the header always claimed but never did. Co-authored-by: 1bcMax <viewitter@gmail.com>
…lockRunAI#57) The gateway repriced six Grok SKUs to xAI's list price on 2026-09-04, removing a resale spread of up to +140% on output. This repo quoted the old numbers. xai/grok-4.3 $1.50/$4.00 -> $1.25/$2.50 xai/grok-4.5 $2.50/$9.00 -> $2.00/$6.00 xai/grok-build-0.1 $1.50/$3.00 -> $1.00/$2.00 No price guard reaches this repo — the gateway's drift sweep covers its own sheets only, and brand/consumers.json lists 15 repos it cannot see. Found by grep. CHANGELOG entries left alone on purpose: a dated entry records what the price was that day. Claude-Session: https://claude.ai/code/session_01ChUparsmmkz1GJrvzqmuvL Co-authored-by: 1bcMax <viewitter@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lockRunAI#59) Every paid path assumed x402 — a 402 challenge, a local signature, a retry — which made holding a wallet the price of admission. A key from user.blockrun.ai now works in the same place, across all fourteen client classes, with no new client type and no signature change: the private_key parameter accepts a brk_ key, and BLOCKRUN_API_KEY is read when it is empty. Four things beyond the header, each a silent failure rather than an import error: - api.blockrun.ai serves /v1 at the root and answers /api/v1 with wrong_host, so the account rail needs its own base URL. - poll_url is minted relative to the x402 gateway's host, so it arrives as /api/v1/... — resolved unchanged, every async job polls a 404 to timeout. - The async submit answers 202 on the FIRST post here. ImageClient raised "API error: 202" and VideoClient raised "Expected 402 on first POST", so both were broken for keys before they began. - setup_agent_wallet() minted a keyfile unconditionally. With a key configured there is nothing to sign with, so it writes nothing. SolanaLLMClient and AsyncSolanaLLMClient take the key too, and no longer need the optional x402 SDK when one is present: on the account rail there is no transfer to sign, so the chain stops being a question. blockrun_llm.apikey holds the rail in one module — precedence, auth_headers, poll-URL resolution, the two refusals — rather than fourteen copies that drift. Each client's httpx.Client carries the key as a default header, so the sixteen request sites did not have to be edited one by one. Wallet users are untouched: precedence is explicit argument, then BLOCKRUN_API_KEY, then the wallet variables. BLOCKRUN_API_KEY_URL is deliberately separate from BLOCKRUN_API_URL — the latter names an x402 gateway, and following it would send the key to a host configured for another rail. Wallet-only helpers refuse rather than answer wrongly. get_balance() returning 0 is indistinguishable from an empty wallet, and an agent gating on it would stop calling a funded account. tests/conftest.py clears BLOCKRUN_API_KEY for every test: without it, the "no credential" tests fail on the machine of anyone who has a key exported. Claude-Session: https://claude.ai/code/session_01T5RKUETYjxwNRqkURLnatJ Co-authored-by: 1bcMax <viewitter@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…BlockRunAI#60) * fix: complete account clients and preserve payment selection * fix: constrain Anthropic to the supported HTTP transport major * fix: skip Solana signer initialization for API accounts * fix(apikey): blank env is unset, and close the account rail's last gaps Review follow-ups on this branch, in descending order of blast radius. `resolve_api_key` checked `ENV_API_KEY not in os.environ`, which is presence rather than value. `BLOCKRUN_API_KEY=` in a .env file, a bare `docker -e BLOCKRUN_API_KEY`, and an unpopulated `${{ secrets.X }}` all arrive as the empty string, so every client constructor in the package started raising for wallet users who never opted into the account rail — `setup_agent_wallet()` included, which the comment there says an agent may call unconditionally on either rail. Blank is now unset again; a non-blank value that is not a `brk_` key still refuses, because silently spending USDC instead of credit is the wrong way to report a typo. `max_retries=0` was set only on the account rail. The wallet rail kept the Anthropic SDK's default of 2, and `_BlockRunX402Transport` signs a fresh payment for every 402 it sees — so a 5xx retried after the gateway settled signs and settles again. Measured at three on-chain transfers for one `messages.create()`. The setdefault now applies to both rails, and an explicit `max_retries=` still wins. The account rail's remaining wallet assumptions: - `list_portraits` was the only sibling of `list_realfaces` without the 402 guard, so an out-of-credit account got `HTTP 402` instead of the credit refusal with the top-up link. - Both listings are keyed by wallet address and did `wallet_address or self.account.address`, which is `AttributeError` on None. They now raise `wallet_only()`, naming the method like every other wallet-only helper. - The Solana media probe had no 402 guard, so an out-of-credit account fell into the x402 branch — which has no signer to reach for on this rail and, without the optional SDK installed, no decoder either. - `SolanaLLMClient._absolute_url` never went through `resolve_poll_url`, so account-rail slow-path polls went to `api.blockrun.ai/api/v1/...`, which the gateway answers with `wrong_host`. Every slow image and video job on account credit polled a dead URL until its budget ran out. Routing it through the shared helper also pins the Authorization header to the gateway's origin, which is what the Base clients already do. Dead line: the fourth `raise_for_api_key_402` in `_post_with_payment` sits where the status can no longer be 402, since the branch above always raises or returns. `payment_mode` used string literals where apikey.py exports the constants for exactly this reason. CLAUDE.md still said "No API keys — wallet signature is authentication"; AGENTS.md was updated in this branch and it was not. 21 new cases. Each new guard was mutation-tested: reverting any one of the seven fixes individually turns its test red. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMLNFbR6Jg2HBFpRUGBjyh --------- Co-authored-by: 1bcMax <vicky.fuyu@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: type reasoning token usage * fix(types): read a flat reasoning_tokens extra, and pin the guard with tests Two gaps in the new property, both verified against the live gateway. ChatUsage sets `extra = "allow"` so an upstream shape change still reaches callers. A property named `reasoning_tokens` takes precedence over an extra of the same name, so a payload carrying it at the top level of `usage` answered None while `model_dump()` still held the number. The nested OpenAI shape stays authoritative; the flat value is the fallback. The `isinstance(value, int) and value >= 0` filter had no test — gutting it to `return value` left both existing tests green. Five mutants now die: gutting the guard, dropping the bool check, dropping the negative check, removing the flat fallback, and turning the None test into a falsy test (which would collapse a real `reasoning_tokens: 0` into None). `bool` is excluded explicitly. It is an int subclass, so `True` would otherwise arrive as a token count of 1. Probed openai/gpt-5.4-nano for $0.002: the gateway forwards the nested OpenAI shape (`completion_tokens_details.reasoning_tokens`, and `prompt_tokens_details` alongside it) and sends no flat extra today, so the fallback is insurance rather than a live fix. `reasoning_tokens: 0` on a non-reasoning turn is real and now pinned as a measurement rather than an absence. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMLNFbR6Jg2HBFpRUGBjyh --------- Co-authored-by: x <x@y> Co-authored-by: 1bcMax <vicky.fuyu@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
`--check` was green because it only validates the keys a marker actually renders, and those five were current. The rest of the snapshot had drifted: withFallback 48 → 34, withFallbackAllEntries 89 → 73, aliases 229 → 259, plus three mcp context keys the artifact now carries. No rendered number changes, so this is not a docs fix — it stops the next marker added for one of those keys from rendering a stale value on day one. Produced by `scripts/sync-brand-numbers.mjs --refresh`, no hand-edited digits. Supersedes BlockRunAI#51, which proposed the same refresh against a 26 Aug main. Its five rendered numbers have since landed independently, so the branch had nothing left to deliver and conflicted with the API-key documentation merged in BlockRunAI#59/BlockRunAI#60. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMLNFbR6Jg2HBFpRUGBjyh
… client The rule: an API key goes to api.blockrun.ai, a Solana key to sol.blockrun.ai, a Base key to blockrun.ai. Sending one to the wrong front door is not a 404 — a key handed to an x402 host is a key disclosed to a host that never needed it. Every client already followed it except one. The Solana constructors default api_url to the SVM gateway rather than None, so the account-rail branch passed a hard-coded None to avoid sending the key to sol.blockrun.ai — which also threw away an api_url the caller had typed. Every other client honours it. The branch now tells "the caller typed this" apart from "nobody passed anything", and validates the resolved host like the rest do. 87 cases across all 17 exported clients: the three credential-to-host pairings, that BLOCKRUN_API_URL (an x402 host) never captures an API-key client, that BLOCKRUN_API_KEY_URL does, that an explicit api_url wins everywhere, and that passing the Solana default explicitly still resolves to the account rail. Both mutants die: reverting to None, and letting the SVM default through. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMLNFbR6Jg2HBFpRUGBjyh
Closes BlockRunAI#61. api.blockrun.ai answers a rate limit with Retry-After and the gateway sets it deliberately: it is what turns a refused request into a caller that waits instead of one that spins against the limit the header exists to prevent. It never survived the SDK boundary — APIError carried message, status_code and response, and `grep -rn retry_after blockrun_llm/` returned nothing. Every consumer on the account rail had to guess or spin. APIError gains `retry_after`, kept as the raw header string. The HTTP spec allows both a delay in seconds and an HTTP-date, and inventing a number for the date form would be worse than handing back what arrived; `retry_after_seconds` parses the delay form and answers None for everything else, including a negative value. `retry_after_of()` is the single reader. It tolerates a response with no headers attribute, because it runs inside an error path and raising there would replace the real failure with an AttributeError about the failure. Migrated all 75 raise sites that hold a response, across 14 files. The remaining 15 have no response to read — poll-budget timeouts, a missing poll_url, stream probes that exhausted retries — so they carry None because there is nothing to carry, not because they were skipped. The issue warns that a partial migration is worse than none; this one is complete. portrait.py, realface.py and video.py each carried a byte-identical private `_raise_api_error`. They now delegate to one `raise_api_error` in validation.py, so the next change to how failures are reported lands in three places at once rather than two out of three. 45 new cases, including the 30 client x method table from BlockRunAI#58 that this issue asked to salvage. Mutants that die: the reader always returning None, the shared helper dropping the header, a negative delay passing through, the seconds parser inventing a number for an unparseable value, and stripping every retry_after kwarg from any one client file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QMLNFbR6Jg2HBFpRUGBjyh
Raise sites build their message from the status code and stash the sanitized
body on `.response`, so the one line worth reading never reached the string a
caller actually prints or logs.
Read against the live gateway with a real account key, a free-tier stream 429
surfaced as:
API error: 429
while the body said:
Free tier rate limit reached (30 requests/minute per IP).
Retry after 10s, or use a paid model
That gap is not cosmetic. Working from the first string I misread the limit as
throttling on the customer's key and started looking for a routing bug; the
second says plainly that it is the free tier, metered per IP, and what to do
instead. The same 429 now reads:
API error: 429: Free model capacity exhausted — retry shortly, or use a
paid model (from $0.002/request).
Folded into APIError.__init__ rather than the 90 raise sites, so it holds for
every one of them and for any added later. Sanitizer placeholders
("API request failed" and friends) are not appended — they restate the status
code and push the real prefix off the end of the line. A message that already
contains the upstream text is left alone, `.response` is untouched, and a
bodyless error is unchanged.
11 cases. Confirmed against the live gateway: the free-tier 429 now arrives
with both the explanation and Retry-After: 30.
For the record, since the number prompted this: an account key is not rate
limited. 25 sequential non-streaming calls returned 200 with no rate-limit
headers at all, and a paid model streamed 5 of 5 on the same key. Only the free
NVIDIA tier is capped, per IP.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QMLNFbR6Jg2HBFpRUGBjyh
…RunAI#63) Music is never fast: MiniMax takes one to three minutes and the gateway answers 202 + poll_url — since 2026-09-08, at once. MusicClient treated every non-200 as an error, so a music request could not succeed on either rail; the enterprise ledger showed 11 of 11 creates in 30 days answered 202, and this client raised "API error: 202" for each. The image client already polls. Its loop moves to jobs.py and both clients use it: the wallet rail replays the create's PAYMENT-SIGNATURE on each poll (the job is bound to that wallet, and settles on the completed poll); the account rail sees its 202 on the first post and polls with the key. A poll budget that runs out has cost nothing. Co-authored-by: 1bcMax <viewitter@gmail.com>
Co-authored-by: 1bcMax <viewitter@gmail.com>
…ks (BlockRunAI#65) Co-authored-by: 1bcMax <viewitter@gmail.com>
…le catalog (BlockRunAI#62) Opened by brand/fanout-brand-numbers.mjs. brand-numbers.json here was behind the published artifact, so every br: marker in this repo rendered a number that is no longer true. The markers did their job — they rendered the input they were given. --check is offline on purpose so PR CI stays deterministic, which means it validates against this repo's own snapshot, and only --refresh updates that snapshot. This job is what runs it. Produced by --refresh, not by hand. Co-authored-by: 1bcMax <viewitter@gmail.com>
…le catalog (BlockRunAI#66) Opened by brand/fanout-brand-numbers.mjs. brand-numbers.json here was behind the published artifact, so every br: marker in this repo rendered a number that is no longer true. The markers did their job — they rendered the input they were given. --check is offline on purpose so PR CI stays deterministic, which means it validates against this repo's own snapshot, and only --refresh updates that snapshot. This job is what runs it. Produced by --refresh, not by hand. Co-authored-by: 1bcMax <viewitter@gmail.com>
…rable/escAttr) (BlockRunAI#68) Verbatim from blockrun-mcp f9480ad2. A brand value fetched from the mirror is now refused, and attribute-escaped, before the unattended brand-sync bot writes it into this repo's markdown. --check output unchanged here. Co-authored-by: 1bcMax <viewitter@gmail.com>
…Base Sepolia (BlockRunAI#69) The chain table knew Base and Base Sepolia and fell back to Base for any other network, while `asset` and `extra` were taken from the 402 as given. Against arc.blockrun.ai (eip155:5042, USDC at 0x3600…, domain name "USDC") that signed chainId 8453 against Arc's contract — an invalid signature, a 401 from the facilitator, after the SDK had reported a payment. EVM_NETWORKS maps a 402's `network` to the SDK's OWN chain id, USDC address and EIP-712 domain; create_payment_payload signs those. The 402 SELECTS the network and supplies nothing else: its `extra` no longer reaches the domain (a hostile 402 cannot steer a signature onto another contract), an unknown network raises naming what is supported, and an `asset` that is not that network's USDC raises before signing. The twelve EVM clients that did not pass the 402's asset now do, so the check protects every route. get_chain_config / get_usdc_domain_name read the same table; the `base-sepolia` alias still resolves. Verified against arc.blockrun.ai with an unfunded throwaway key: Circle's /verify answers insufficient_funds and recovers the throwaway's own address as payer — the signature verifies on Arc's domain, only the balance is missing. Six new tests recover the signer against each domain (Arc passes, Base fails for an Arc payment), pin the refusals, and that a 402's `extra` is ignored. 983 unit tests, ruff and black clean. 1.17.0, mirroring @blockrun/llm 3.16.0. Co-authored-by: 1bcMax <viewitter@gmail.com>
This was referenced Sep 23, 2026
Merged
Contributor
|
Landing via #80, with your commit and authorship kept. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Expose reference_videos/reference_audios and supported output controls on VideoClient and synchronous/asynchronous Solana video clients. Permit up to 30 reference images on Seedance 2.5, retain frame/reference exclusivity, and preserve last_frame_url plus backup status in parsed results.
Validation
66 video/Solana media unit tests passed with mocked transport and no funded wallet. Black 24.10.0 and Ruff 0.16.0 checks passed on changed files; Python compilation and git diff checks passed.
Rollout and limits
This PR does not deploy or change
R2V_ENABLED. Existing production 503s caused by an explicit off switch require a separate controlled enablement. Publish client changes after the gateway changes are deployed.No new paid upstream renders were performed. New request/response behavior is validated against the captured public upstream parameter schema and mocked contract/payment tests; perform a small paid render smoke test before production enablement. Automatic duration, editing/extension, 2.5 reference video/audio and 1080p, callbacks and draft/flex remain held pending cost/output or lifecycle validation.
See
SEEDANCE_CAPABILITIES.mdfor input examples and capability limits. No authentication, signed-quote format or settlement formula changes.Related PRs