Releases: BlockRunAI/Franklin
Release list
Franklin Agent 3.35.5 — the last three OpenAI ceilings, measured
| model | was | now |
|---|---|---|
openai/gpt-5.5 |
32,768 | 128,000 |
openai/gpt-5.4 |
32,768 | 128,000 |
openai/gpt-5-mini |
16,384 | 65,536 |
These took three attempts, and the story is worth keeping because a token table is where a wrong belief gets frozen.
First attempt set gpt-5.5 and gpt-5.4 to 100,000, citing "upstream's stated maximum". There was no upstream response — both BlockRun SDKs rejected max_tokens > 100000 client-side, so 19 probes at 128,000 never reached a provider. A uniform limit across three unrelated vendors should have been the tell. That PR was closed.
Second attempt put them back at 32,768 and recorded the catalog's 128,000 as unrefuted but unverified. Honest, but still not measured.
Third re-probed with the SDK guard bypassed: every model advertising a ceiling above 100,000 accepts it, including zai/glm-5.2 at 262,144. The catalog was right the whole time; the measurement was broken.
Fixed at the root in blockrun-llm 1.8.1 and @blockrun/llm 3.8.1, which raise that guard to a 1,000,000 typo bound and reword the message so it no longer reads like a provider response.
Franklin never ran that guard — both request paths use raw fetch and import only payment helpers from the SDK — so these values don't depend on the SDK release.
Effect is on the escalation path. A normal turn still sends min(16384, ceiling); after a max_tokens stop the ceiling for gpt-5.5 and gpt-5.4 goes from 32,768 to 65,536 (ESCALATED_MAX_TOKENS), so recovery doubles instead of clamping back below where it started.
Local suite 636 pass.
Franklin Agent 3.35.4 — Haiku and Sonnet 4.6 get their real output ceilings
| model | was | now |
|---|---|---|
anthropic/claude-haiku-4.5 |
16,384 | 64,000 |
anthropic/claude-sonnet-4.6 |
64,000 | 128,000 |
Both are Anthropic's documented limits.
They were held low deliberately. The gateway clamped Haiku to 8,192 and Sonnet 4.6 to 64,000, and asking past a clamp is not free — the upfront price quote scales with the ceiling you request, so a bigger ask inflated what you were quoted while the reply stayed capped. Raising these before the gateway was corrected would have cost money and bought nothing. The gateway now honors the real ceilings (BlockRunAI/blockrun#266 + #268, deployed and verified against the live catalog), so this catches Franklin up.
Where it takes effect: the escalation path. A normal turn still sends min(16384, ceiling); the higher ceiling is reached after a max_tokens stop escalates. That path was previously a no-op for Haiku — it escalated to 65,536 and got clamped straight back to 16,384.
Three OpenAI entries deliberately left alone, even though the gateway catalog now reads higher: gpt-5.5 and gpt-5.4 stay at 32,768 (catalog claims 128,000), gpt-5-mini stays at 16,384 (catalog claims 65,536). The catalog is the only evidence for those three, and it was 8× wrong about Haiku. A test pins all three, so syncing them requires arguing with a failing assertion rather than a quiet edit.
One existing test had to be repointed: it asserted Haiku stays 16,384 to prove the static table beats the catalog. Valid when the catalog said 8,192 — but once both sides read 64,000 it proved nothing while still passing green. It now tests gpt-5.5, where the disagreement is real and deliberate.
Local suite 636 pass. E2E 14 pass, 0 fail.
Franklin Agent 3.35.3 — docs only
No runtime change. Ships a corrected comment in src/gateway-models.ts.
The note added in 3.35.2 said the gateway's max_output values are "not enforced: Franklin sends max_tokens 16384 to haiku today and the gateway accepts it." Accepting a request and honoring it are different things.
Both gateway handlers clamp with Math.min(request.max_tokens, model.maxOutput) and derive the price quote from the clamped ceiling. An over-cap request is accepted rather than rejected — the handler logs capping to <limit> server-side, where the caller never sees it, and continues. The clamp only becomes visible when a reply is long enough to hit it, which is why the short smoke test behind that claim returned a clean 200 while the model was capped at an eighth of its real ceiling.
The rule the comment supports is unchanged and still correct: static tables stay authoritative. Only the stated reason was wrong, and a wrong reason is how a right rule gets reverted by the next person who checks it.
Underlying gateway-side fix for the wrong values: BlockRunAI/blockrun#266.
Local suite 634 pass.
Franklin Agent 3.35.2 — one token-limit table
The proxy stops capping every model at 16K. src/proxy/server.ts carried its own hardcoded ladder — deepseek|haiku|gpt-oss → 8192, everything else → 16384 — that never consulted MODEL_MAX_OUTPUT. Anyone driving Franklin through the payment proxy was losing 4-8× of output headroom on models the CLI already knew better: Kimi K3 can emit 65,536 tokens and GPT-5.6 Sol 128,000. Both paths read getMaxOutputTokens() now.
Uncatalogued models stop falling through to blind defaults. Context window and max output now consult the live gateway catalog — but only for model ids with no static entry. That is the qwen/qwen3.7-max case from 3.35.1: a real paid model that compacted at 128k and truncated at 16k until someone hand-added it to three tables.
The catalog is a gap-filler, deliberately not a source of truth — the opposite of what gateway-models.ts claims in its own header. Two reasons, both verified against the live catalog:
| model | Anthropic | gateway | Franklin |
|---|---|---|---|
claude-haiku-4.5 |
64,000 | 8,192 | 16,384 |
claude-sonnet-4.6 |
128,000 | 64,000 | 64,000 |
- Its numbers are wrong for models we already know, and unenforced — Franklin sends
max_tokens: 16384to haiku today, above the advertised 8192, and the gateway accepts it. - Where it is right, we deliberately disagree. Every Anthropic model is pinned to a 200k context window against the advertised 1M, because the gateway's 1M beta header is not enabled and anything larger 413s.
Static entries win; the catalog answers only for ids we have never heard of. Access is a synchronous cache-only peek that never fetches, with a fire-and-forget warm on the first miss — no startup latency, and a cold or unreachable gateway degrades to the previous behavior exactly.
Left alone on purpose: haiku-4.5 max output is 16,384 here vs Anthropic's documented 64,000, and sonnet-4.6 is 64,000 vs 128,000. Both are under-estimates, not errors — raising them needs a real long-output run against a gateway whose metadata this release just established is unreliable.
Local suite 634 pass. E2E 14 pass, 0 fail — run against zai/glm-5.1, which has no static token entry, so the whole run exercised the new gap-filler path.
Franklin Agent 3.35.1 — Qwen3.7 Max
Qwen3.7 Max joins the picker. Alibaba's flagship Max tier — $1.475/$4.425 per million tokens, 1M context, 65K max output — is now a /model row and answers to qwen-max. Community contribution from @Fsocietyhhh (#107).
The shortcut is qwen-max, not bare qwen. qwen has long been an alias for the free nvidia/qwen3-next-80b-a3b-instruct default, and a free alias must never quietly start spending your USDC.
The tables a new model has to land in. Adding a model id touches five lookups, four of which default silently when you miss one. Qwen3.7 Max now has explicit entries for context window (1M — the generic qwen fallback returns 128k and would compact ~8x too early), max output (65K — the default is 16K, which truncates long answers and burns USDC on continuation calls that can never succeed), model guidance (a bare qwen substring written back when every qwen id was a free NVIDIA SKU was routing a premium flagship into the mid-tier prompt), and provider grouping in the expanded picker.
tool_choice compatibility. Qwen3.7 Max returns an opaque 400 Invalid request on any request carrying tool_choice, which killed the grounding-retry path that forces tool use after an ungrounded answer. It's now stripped for that model up front. The runtime retry that recovers this class also got broader: it used to fire only when the upstream error text named tool_choice, so an opaque 400 slipped past it. It now retries on any 400 that carried a tool_choice.
The e2e suite stops swallowing schema failures. skipIfRateLimited() was classifying that hard failure as a free-tier rate limit and skipping, so the suite reported green with the bash and grep tool tests silently dead. A [Schema] error is no longer skippable.
Local suite 630 pass. E2E against qwen/qwen3.7-max: 13 pass, 0 fail.
v3.35.0 — expandable model picker + hook stdin fix
Two community contributions from @0xCheetah1.
Ctrl+A expands the model picker (#106). /model stays curated by default; Ctrl+A toggles the full live gateway chat catalog, grouped by provider and ranked newest/strongest first. The "+N more" hint now points at Ctrl+A. Also: Esc no longer quits an idle session (it aborts work / closes dialogs — Ctrl+C and /exit are the exits), and the bare claude shortcut now resolves to Opus.
Hook stdin EPIPE fix (#105). A hook that exits before reading stdin caused an async EPIPE the old synchronous try/catch couldn't catch (latent crash risk). Stdin errors now flow through the stream error event — EPIPE ignored (fail-open), other failures logged.
625 tests pass.
v3.34.3 — concurrent trade-plan fix
A self-review of the 3.34.x work caught one real money-path bug.
Concurrent hosted agents proposed trade plans under the wrong session. In a franklin serve process hosting multiple agents (AgentHost, 3.34.0), the TradePlan tool took its session id from a process-global slot the last-started session overwrote — so agent A could "approve" a plan that landed under agent B, then have its own swap denied by the gate (which correctly used A). Trading blocked, plan orphaned. Single-agent CLI use was never affected.
Fix: the executing session id now rides on the tool execution scope; the TradePlan tool binds to its own agent's session. Gate + budget drawdown already threaded the id — this closes the gap. Regression test added.
Also memoized the git-origin lookup behind memory search. 622 tests pass.
v3.34.2 — Kimi K3
The gateway retired the Kimi K2.x line and shipped moonshot/kimi-k3 — Moonshot's 2.8T open MoE: 1M context, multimodal (image + text), returns reasoning content, $3/$15 per M. Franklin's model tables are synced:
kimi/k3and every retiredk2.7/k2.6/k2.5pin now resolve to K3. Pricing, context window (1M), max-output (65K) updated.- Picker moves Kimi from Budget to Premium frontier ($3/$15).
- K3 is vision-capable (gateway
visioncategory) → replaces K2.7/K2.6 in the vision allowlist. - K3 is deliberately kept out of the cost-saving fallback chains (a $3/$15 flagship doesn't belong where a cheap fallback is wanted); the dead K2.7 was removed from them.
621 tests pass.
v3.34.1 — desktop trade-plan approvals
The desktop app's serve session can now surface trade-plan approvals: serve emits agent.permissionAsk over the in-flight turn stream and resolves the parked plan on the client's agent.permissionResponse (askId + y/n/always — the wire contract the desktop declared from day one). Unanswered asks fail closed at the plan TTL; no connected client = immediate deny.
Pairs with franklin-desktop #5, which adds the approval card UI. Older desktop builds stay safe against this CLI (asks time out, plans reject); this CLI stays byte-compatible with clients that predate the contract.
v3.34.0 — the economic agent grows up
Highlights
- Trade-plan approval gate — no real-money trade (Jupiter / 0x / Polymarket orders) executes without a user-approved plan: venue, asset, size, slippage, stop, rationale, total spend. Budgets draw down per trade, plans expire in 15 min, and the gate holds in every permission mode including
--trust. Headless runs fail closed (--approve-tradesopts in, still bounded by--max-spend). One audit book:~/.blockrun/approvals.jsonl. - Lifecycle hooks — 8 events incl. blocking PreSpend (estimated USD on stdin, veto before funds move). Fail-open on crash/timeout; only explicit deny blocks. Examples: daily spend cap, token blacklist, spend ledger.
/goal— verified autonomy — plans the objective, works it across turns, and completion claims are audited by a 3-reviewer adversarial panel (majority-refute, default-refute, anti-ratchet). Bounded by turn cap, round cap, budget; Esc always pauses. Plus/loopdurable scheduler and aMonitortool.- Wallet-keyed memory — trades auto-journal (thesis on open, P&L on close) into
trading-<chain>-<addr>/memory that follows the wallet across directories; workspace memory keyed by git origin;/remember/flush/dream; 7-day decay on session logs only. - Mission control —
franklin servehosts many concurrent agents (default permission mode, approvals over the wire); thefranklin panelAgents tab dispatches, streams, replies, and answers approvals from the browser.
Tests: 621 passing. Kill switches: FRANKLIN_HOOKS=0, FRANKLIN_MEMORY=0.
Full narrative in CHANGELOG.md.