✨ New Features
- chipotle: add Chipotle Pepper AI — a free provider implemented via the reverse-engineered Amelia protocol, with its executor error body routed through
sanitizeErrorMessage()(Hard Rule #12) (#3250 — thanks @oyi77) - web-cookie: add tool-call translation to 8 web-cookie executors via shared
webToolshelpers, so cookie-backed providers can participate in tool/function calling through a single serialize/parse path (#3259 — thanks @oyi77) - free-tiers: per-model free-token budget catalog + a Monthly Budget dashboard card surfacing each provider's monthly free allowance (joins the honest free-token catalog/API/headline work from #3257) (#3263, #3257 — thanks @diegosouzapw)
- dashboard: bulk activate / deactivate / retest for selected provider connections — multi-select with batch lifecycle actions on the providers page (#3271 — thanks @leninejunior)
- models: register MiniMax-M3 (frontier coding/agentic model, 1M context, Anthropic-compatible) across 8 provider tiers —
minimax,minimax-cn,opencode(free),opencode-go,opencode-zen,trae,ollama-cloud,nvidia(#3287, #3110 — thanks @wilsonicdev)
🔧 Bug Fixes
- api/responses: combo names without a slash (e.g.
paid-premium,n8n-text) are no longer force-rewritten tocodex/<combo>on/v1/responses—resolveResponsesApiModelnow returns the request unchanged when the model resolves to a combo (regression from the v3.8.9 Codex WS→HTTP fallback) (#3268, fixes #3227 / #3233 — thanks @wilsonicdev; supersedes the earlier closed #3242) - sse: strip every
<omniModel>tag before forwarding to the provider, not just the first — a global-regex variant prevents stray routing tags from leaking into the upstream prompt (#3248, fixes #454 — thanks @MikeTuev) - grok-web: add TLS fingerprint impersonation to bypass Cloudflare anti-bot on the Grok web endpoint, with the executor's error bodies routed through
sanitizeErrorMessage()(Hard Rule #12) (#3249, fixes #3180 — thanks @wilsonicdev) - providers: improve provider refresh/validation and the model-catalog UI — including the OpenRouter catalog and the proxy UI, plus the NVIDIA NIM
/models-suffix probe path (real-VPS validated) (#3261 — thanks @strangersp) - embeddings: block cross-dimension failover inside embedding combos so a fallback target with a different vector dimension can no longer corrupt results (#3256 — thanks @diegosouzapw)
- sse/web-tools: web-cookie providers (e.g.
ds-web/deepseek-v4-pro) that wrap tool calls as<tool_call name="...">{json}</tool_call>are now parsed correctly — the real tool name is read from the JSON body instead of the tag attribute, and the call is no longer silently dropped whenargumentsis absent (#3275, fixes #3260 — thanks @diegosouzapw) - sse/groq: non-reasoning Groq models (
llama-3.3-70b-versatile,llama-4-scout) are now flaggedsupportsReasoning: false, soreasoning_effort/output_config.effort/thinkingare stripped before dispatch instead of being forwarded and rejected with HTTP 400 — fixes the Claude Code → Groq regression of #764 (#3277, fixes #3258 — thanks @diegosouzapw) - api/images:
POST /v1/images/editsto a custom OpenAI-compatible provider no longer forwards an emptymodel. The multipart body is now built as aBufferwith an explicit boundary instead of a globalFormData— the patched undicifetchserialized a nativeFormDataas the literal string[object FormData](text/plain), dropping every field includingmodel(#3278, fixes #3273 — thanks @diegosouzapw) - db: detect SQLite driver-unavailable errors to avoid a destructive DB rename + an optional FTS5 migration guard, so a transient driver-load failure no longer triggers the backup-and-recreate path on a healthy database (split from #3073) (#3274 — thanks @zhiru)
- quota: repair the Quota Sharing Engine —
poolUsageWithDimensions()promoted onto theQuotaStoreinterface (kills the dynamic type-narrowing hack), single-snapshot burn rate viacomputeBurnRateFromWindow()(the dashboard previously always showed 0), zero-weight allocations normalized to equal distribution, Anthropicanthropic-ratelimit-*saturation signals, aquota.exceededwebhook fired on block, and quota enforcement extended to the embeddings handler (#3280 — thanks @oyi77) - plugins:
emitHookBlockingnow chains the payload between handlers — each blocking handler receives the body/metadata as mutated by previous handlers, so a later plugin can observe an earlier plugin's changes (previously every handler got the original static payload) (#3286 — thanks @oyi77) - api/webhooks: webhook URLs may now target a private/internal address (e.g.
192.168.x, a docker-internal host) whenOMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS=true— the webhook guard reuses the same explicit opt-in as private provider URLs (default OFF; protocol and embedded-credential checks stay unconditional). Cloud-metadata / link-local endpoints (169.254.169.254,metadata.google.internal,100.100.100.200,169.254.0.0/16) are blocked unconditionally even with the opt-in on, and the webhook test endpoint redacts the upstream response body for private targets (no SSRF→IAM-credential pivot, no content exfiltration) (#3279, #3281, fixes #3269 — thanks @diegosouzapw) - sse/qoder: a valid Qoder Personal Access Token is no longer wrongly reported as "expired" when the Cosy validation endpoint returns a generic
Internal Server Error(HTTP 500). A Cosy 500 only marks the PAT invalid when its body carries an explicit auth signal; a generic server fault now falls back to the #1391 valid-bypass rule (#3283, fixes #3247 — thanks @wilsonicdev, who independently diagnosed the same root cause and filed #3282; refined here to keep rejecting on an explicit-auth-signal 500)
📝 Maintenance
- ci:
deploy-vpsrecreates the PM2 process via theomniroutebin (instead of a barepm2 restartpinned to the removedapp/server-ws.mjspath) and gates the deploy on/api/monitoring/healthreporting"status":"healthy", failing the job (with recent PM2 logs) when the box never becomes healthy — supersedes #3262 (#3270 — thanks @diegosouzapw) - security: harden the Chipotle executor against CodeQL findings —
Math.random()→crypto.randomInt()/crypto.randomUUID()(imported fromnode:crypto) for session/server IDs, and a strictnew URL().hostnamecheck (replacing a substring match) in its test (#3285 — thanks @oyi77) - governance: raise the coverage gate from 40% to 60% (statements/lines/functions/branches) now that real coverage sits at ~80% — brings the threshold in line with Hard Rule #9 (thanks @diegosouzapw)
- docs: consolidate the community links (Discord + Telegram + WhatsApp) at the top of the README and promote the Free-Token Budget section (#3289 — thanks @diegosouzapw)
- docs: richer free-tier budget-card image (28 models + first-month strip) and softer ToS framing (caution rather than warning) (#3284 — thanks @diegosouzapw)
🙌 Contributors
Thanks to everyone whose work landed in v3.8.12:
| Contributor | PRs / Issues |
|---|---|
| @oyi77 | #3250, #3259, #3280, #3285, #3286 |
| @wilsonicdev | #3249, #3268, #3282 / #3283 (co-author, #3247 diagnosis), #3287 |
| @strangersp | #3261 |
| @MikeTuev | #3248 |
| @leninejunior | #3271 |
| @zhiru | #3274 |
| @diegosouzapw | maintainer — #3256, #3263, #3270, #3275, #3277, #3278, #3279, #3281, #3284, #3289 |
What's Changed
- fix(sse): strip all tags before forwarding to provider by @MikeTuev in #3248
- fix(grok-web): add TLS fingerprint impersonation to bypass Cloudflare anti-bot (#3180) by @wilsonicdev in #3249
- feat(web-cookie): add tool-call translation to 8 executors via shared webTools helpers by @oyi77 in #3259
- Fix provider refresh, validation, OpenRouter catalog and proxy UI by @strangersp in #3261
- feat(provider): add Chipotle Pepper AI — free provider via reverse-engineered Amelia protocol by @oyi77 in #3250
- fix(v1/responses): skip codex rewrite for combo names (#3233, #3227) by @wilsonicdev in #3268
- fix(embeddings): block cross-dimension failover in embedding combos by @diegosouzapw in #3256
- fix(ci): deploy-vps recreates PM2 via bin + gates on /login 200 by @diegosouzapw in #3270
- fix(db): detect SQLite driver-unavailable errors to avoid destructive rename by @zhiru in #3274
- feat(dashboard): bulk activate/deactivate/retest for selected provider connections by @leninejunior in #3271
- feat(free-tiers): per-model free-token budget + Monthly Budget dashboard card by @diegosouzapw in #3263
- fix(sse): parse <tool_call name=...> wrapper from web-cookie providers (#3260) by @diegosouzapw in #3275
- fix(sse): strip reasoning_effort for non-reasoning Groq models (#3258) by @diegosouzapw in #3277
- fix(api): build /v1/images/edits multipart as Buffer, not global FormData (#3273) by @diegosouzapw in #3278
- fix(api): allow private webhook targets behind explicit opt-in (#3269) by @diegosouzapw in #3279
- fix(api): harden private webhook opt-in against cloud-metadata SSRF (#3269) by @diegosouzapw in #3281
- fix(sse): don't mark a valid Qoder PAT expired on a generic Cosy 500 (#3247) by @diegosouzapw in #3283
- docs(free-tiers): richer budget-card image + soften ToS framing to caution by @diegosouzapw in #3284
- fix(quota): resolve poolUsage dead code, burn rate, saturation signals, webhooks, and embeddings enforcement by @oyi77 in #3280
- fix(security): use crypto.randomInt/randomUUID in chipotle + URL parser in test by @oyi77 in #3285
- feat(models): add MiniMax M3 across all provider tiers (#3110) by @wilsonicdev in #3287
- docs(readme): community block (Discord+Telegram+WhatsApp) at top + promote Free-Token Budget section by @diegosouzapw in #3289
- fix(plugins): chain payload in emitHookBlocking + capture runOnResponse stream return by @oyi77 in #3286
- Release v3.8.12 by @diegosouzapw in #3264
New Contributors
- @MikeTuev made their first contribution in #3248
- @strangersp made their first contribution in #3261
Full Changelog: v3.8.11...v3.8.12