ModelPanel gateway 0.3.0 — explicit fusion, and the M2 road to it
Aliases, combos, presets — removed. One way to fuse: a named panel. The breaking change that says what the gateway is, after the release that made it complete.
Every project reaches the release where you delete options, not add them. For the ModelPanel gateway, that’s 0.3.0: fusion is now explicit — panel{} recipes and nothing else. Aliases, combos, presets: gone. Discovery from your keys. Why would we take away configuration? Because ambiguity is a runtime bug that reads like a feature:
modelpanel/fusion used to mean whatever the current roster resolves to — fine in a demo, terrifying in a cron job, and undebuggable when the roster changed and nobody updated the calling code. A fused model should be a config artifact you can diff — {members: [...], method: "synthesize", judge: ...} — not a promise the registry happens to keep today. So 0.3.0 forces the question: which panel do you mean? The breaking change is the answer.
The M2 road to it (gateway-v0.2.0)
You don’t get to make a statement like that without the release that made the gateway a complete product first. 0.2.0 (M2) was that release:
- Streaming everywhere — chat-completions, Responses typed events, Anthropic SSE. Fallback happens before the first token, so a dead model never breaks your stream; mid-stream failures surface as an error chunk, because pretending otherwise is how agents hang.
- The Anthropic dialect — full ingress + dialect writer +
/v1/messages, E2E-verified against Claude Code. PointingANTHROPIC_BASE_URLat a local gateway and watching Claude Code stream off your own keys is the demo this product exists for. - The adapters — OpenRouter, Mistral, Gemini, LLM7, joining Groq, NIM, and Cerebras: seven providers behind one endpoint, plus
store:falserespect and honestinternal_errormapping. - Opportunity notices — a NoticeEngine that tells you, once per (model, provider-pair) per 24h, when your pinned model is also served somewhere healthier. It never switches your model. It informs you. You decide.
- The fusion sidecar — a Python-stdlib engine, OpenAI-compatible on the wire, running panel recipes with a streaming judge alongside the TS gateway.
And the benchmark that made fusion an opinion rather than a hope was already on the wall: 95.0% vs 90.0% best-single vs 82.5% self-consistency on matched GSM1K — panel members and judge at temperature 0.0, greedy, on clean post-cutoff data (see the benchmark post).
Why this ordering matters
We shipped M2 first, then made fusion explicit. If we’d done it the other way, every breaking change would have shipped alongside the features that justify it — and the release notes would have been a wall of “we changed everything.”
This way the story is readable: here’s everything the gateway can do → here’s the one way its centerpiece is defined. Breaking changes with an argument beat breaking changes with a migration guide. The quickstart and API reference now document exactly one fusion path.