omniroute 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/.next/BUILD_ID +1 -1
- package/app/.next/build-manifest.json +2 -2
- package/app/.next/prerender-manifest.json +3 -3
- package/app/.next/server/app/(dashboard)/dashboard/a2a/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/agents/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/analytics/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/api-manager/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/audit-log/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/auto-combo/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/costs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/health/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/limits/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/logs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/mcp/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/media/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/onboarding/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/search-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/settings/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/400/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/401/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/403/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/408/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/429/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/500/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/502/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/503/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error.html +2 -2
- package/app/.next/server/app/_global-error.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/forbidden/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/forgot-password/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/maintenance/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/status/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/terms/page_client-reference-manifest.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__051203a6._.js +2 -2
- package/app/.next/server/chunks/[root-of-the-server]__0891af92._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__1f2b0d89._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__61d78f9d._.js +2 -2
- package/app/.next/server/chunks/[root-of-the-server]__6e52619e._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__afddb4ce._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__e27a89bd._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__fd2fbc93._.js +1 -1
- package/app/.next/server/chunks/_05c48915._.js +1 -1
- package/app/.next/server/chunks/_06515a8a._.js +1 -1
- package/app/.next/server/chunks/_2115d8de._.js +1 -1
- package/app/.next/server/chunks/_3ac953eb._.js +1 -1
- package/app/.next/server/chunks/_4b8fd853._.js +1 -1
- package/app/.next/server/chunks/_68683848._.js +1 -1
- package/app/.next/server/chunks/_6f1b3c3f._.js +1 -1
- package/app/.next/server/chunks/_ee9b677b._.js +1 -1
- package/app/.next/server/chunks/_efd5ede2._.js +2 -2
- package/app/.next/server/chunks/_ffda39da._.js +1 -1
- package/app/.next/server/chunks/open-sse_translator_index_ts_f5fd0821._.js +1 -1
- package/app/.next/server/chunks/src_6320c728._.js +1 -1
- package/app/.next/server/chunks/ssr/[root-of-the-server]__9ef96d20._.js +1 -1
- package/app/.next/server/chunks/ssr/[root-of-the-server]__a6942102._.js +1 -1
- package/app/.next/server/chunks/ssr/_f3674909._.js +1 -1
- package/app/.next/server/chunks/ssr/src_a82a42f9._.js +1 -1
- package/app/.next/server/chunks/ssr/src_app_(dashboard)_dashboard_936a9ee0._.js +1 -1
- package/app/.next/server/chunks/ssr/src_app_(dashboard)_dashboard_settings_9e20fb8d._.js +1 -1
- package/app/.next/server/pages/500.html +2 -2
- package/app/.next/server/server-reference-manifest.js +1 -1
- package/app/.next/server/server-reference-manifest.json +1 -1
- package/app/.next/static/chunks/26aeb12cf79339b1.js +1 -0
- package/app/.next/static/chunks/{80658e0c2b2c7004.js → 633a312ddcf9fa11.js} +1 -1
- package/app/.next/static/chunks/7df0b3c357097db5.js +1 -0
- package/app/.next/static/chunks/a051245b46459ad2.css +1 -0
- package/app/.next/static/chunks/d188e358e1ec0a7d.js +1 -0
- package/app/.next/static/chunks/{4e3fe685e3218d24.js → fa9e2a946d2cdbc7.js} +1 -1
- package/app/CHANGELOG.md +122 -68
- package/app/docs/i18n/ru/README.md +3 -3
- package/app/docs/openapi.yaml +1 -1
- package/app/open-sse/handlers/chatCore.ts +9 -2
- package/app/open-sse/handlers/responseTranslator.ts +13 -3
- package/app/open-sse/services/usage.ts +22 -9
- package/app/open-sse/translator/request/openai-to-claude.ts +10 -2
- package/app/package-lock.json +2 -2
- package/app/package.json +1 -1
- package/app/src/app/(dashboard)/dashboard/providers/[id]/page.tsx +198 -63
- package/app/src/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager.tsx +123 -19
- package/app/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx +22 -24
- package/app/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx +5 -0
- package/app/src/lib/providers/validation.ts +21 -0
- package/app/src/shared/components/ProxyConfigModal.tsx +42 -13
- package/package.json +1 -1
- package/app/.next/static/chunks/594bdf69c19b5310.js +0 -1
- package/app/.next/static/chunks/643428fcd3f9bb51.js +0 -1
- package/app/.next/static/chunks/8efe14530c87d9f6.css +0 -1
- package/app/.next/static/chunks/d0cff7a6c3a66c7d.js +0 -1
- /package/app/.next/static/{cQZnxkFFvb8O7T4x7OSsG → bF7pUIj1e9VsHgSW5x9WX}/_buildManifest.js +0 -0
- /package/app/.next/static/{cQZnxkFFvb8O7T4x7OSsG → bF7pUIj1e9VsHgSW5x9WX}/_clientMiddlewareManifest.json +0 -0
- /package/app/.next/static/{cQZnxkFFvb8O7T4x7OSsG → bF7pUIj1e9VsHgSW5x9WX}/_ssgManifest.js +0 -0
package/app/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,53 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [3.0.1] — 2026-03-25
|
|
8
|
+
|
|
9
|
+
### 🔧 Hotfix Patch — Critical Bug Fixes
|
|
10
|
+
|
|
11
|
+
Three critical regressions reported by users after the v3.0.0 launch have been resolved.
|
|
12
|
+
|
|
13
|
+
#### fix(translator): strip `proxy_` prefix in non-streaming Claude responses (#605)
|
|
14
|
+
|
|
15
|
+
The `proxy_` prefix added by Claude OAuth was only stripped from **streaming** responses. In **non-streaming** mode, `translateNonStreamingResponse` had no access to the `toolNameMap`, causing clients to receive mangled tool names like `proxy_read_file` instead of `read_file`.
|
|
16
|
+
|
|
17
|
+
**Fix:** Added optional `toolNameMap` parameter to `translateNonStreamingResponse` and applied prefix stripping in the Claude `tool_use` block handler. `chatCore.ts` now passes the map through.
|
|
18
|
+
|
|
19
|
+
#### fix(validation): add LongCat specialty validator to skip /models probe (#592)
|
|
20
|
+
|
|
21
|
+
LongCat AI does not expose `GET /v1/models`. The generic `validateOpenAICompatibleProvider` validator fell through to a chat-completions fallback only if `validationModelId` was set, which LongCat doesn't configure. This caused provider validation to fail with a misleading error on add/save.
|
|
22
|
+
|
|
23
|
+
**Fix:** Added `longcat` to the specialty validators map, probing `/chat/completions` directly and treating any non-auth response as a pass.
|
|
24
|
+
|
|
25
|
+
#### fix(translator): normalize object tool schemas for Anthropic (#595)
|
|
26
|
+
|
|
27
|
+
MCP tools (e.g. `pencil`, `computer_use`) forward tool definitions with `{type:"object"}` but without a `properties` field. Anthropic's API rejects these with: `object schema missing properties`.
|
|
28
|
+
|
|
29
|
+
**Fix:** In `openai-to-claude.ts`, inject `properties: {}` as a safe default when `type` is `"object"` and `properties` is absent.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
### 🔀 Community PRs Merged (2)
|
|
34
|
+
|
|
35
|
+
| PR | Author | Summary |
|
|
36
|
+
| -------- | ------- | -------------------------------------------------------------------------- |
|
|
37
|
+
| **#589** | @flobo3 | docs(i18n): fix Russian translation for Playground and Testbed |
|
|
38
|
+
| **#591** | @rdself | fix(ui): improve Provider Limits light mode contrast and plan tier display |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
### ✅ Issues Resolved
|
|
43
|
+
|
|
44
|
+
`#592` `#595` `#605`
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### 🧪 Tests
|
|
49
|
+
|
|
50
|
+
- **926 tests, 0 failures** (unchanged from v3.0.0)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
7
54
|
## [3.0.0] — 2026-03-24
|
|
8
55
|
|
|
9
56
|
### 🎉 OmniRoute v3.0.0 — The Free AI Gateway, Now with 67+ Providers
|
|
@@ -16,39 +63,39 @@
|
|
|
16
63
|
|
|
17
64
|
### 🆕 New Providers (+31 since v2.9.5)
|
|
18
65
|
|
|
19
|
-
| Provider
|
|
20
|
-
|
|
21
|
-
| **OpenCode Zen**
|
|
22
|
-
| **OpenCode Go**
|
|
23
|
-
| **LongCat AI**
|
|
24
|
-
| **Pollinations AI**
|
|
25
|
-
| **Cloudflare Workers AI**
|
|
26
|
-
| **Scaleway AI**
|
|
27
|
-
| **AI/ML API**
|
|
28
|
-
| **Puter AI**
|
|
29
|
-
| **Alibaba Cloud (DashScope)** | `ali`
|
|
30
|
-
| **Alibaba Coding Plan**
|
|
31
|
-
| **Kimi Coding (API Key)**
|
|
32
|
-
| **MiniMax Coding**
|
|
33
|
-
| **MiniMax (China)**
|
|
34
|
-
| **Z.AI (GLM-5)**
|
|
35
|
-
| **Vertex AI**
|
|
36
|
-
| **Ollama Cloud**
|
|
37
|
-
| **Synthetic**
|
|
38
|
-
| **Kilo Gateway**
|
|
39
|
-
| **Perplexity Search**
|
|
40
|
-
| **Serper Search**
|
|
41
|
-
| **Brave Search**
|
|
42
|
-
| **Exa Search**
|
|
43
|
-
| **Tavily Search**
|
|
44
|
-
| **NanoBanana**
|
|
45
|
-
| **ElevenLabs**
|
|
46
|
-
| **Cartesia**
|
|
47
|
-
| **PlayHT**
|
|
48
|
-
| **Inworld**
|
|
49
|
-
| **SD WebUI**
|
|
50
|
-
| **ComfyUI**
|
|
51
|
-
| **GLM Coding**
|
|
66
|
+
| Provider | Alias | Tier | Notes |
|
|
67
|
+
| ----------------------------- | --------------- | ----------- | --------------------------------------------------------------------------- |
|
|
68
|
+
| **OpenCode Zen** | `opencode-zen` | Free | 3 models via `opencode.ai/zen/v1` (PR #530 by @kang-heewon) |
|
|
69
|
+
| **OpenCode Go** | `opencode-go` | Paid | 4 models via `opencode.ai/zen/go/v1` (PR #530 by @kang-heewon) |
|
|
70
|
+
| **LongCat AI** | `lc` | Free | 50M tokens/day (Flash-Lite) + 500K/day (Chat/Thinking) during public beta |
|
|
71
|
+
| **Pollinations AI** | `pol` | Free | No API key needed — GPT-5, Claude, Gemini, DeepSeek V3, Llama 4 (1 req/15s) |
|
|
72
|
+
| **Cloudflare Workers AI** | `cf` | Free | 10K Neurons/day — ~150 LLM responses or 500s Whisper audio, edge inference |
|
|
73
|
+
| **Scaleway AI** | `scw` | Free | 1M free tokens for new accounts — EU/GDPR compliant (Paris) |
|
|
74
|
+
| **AI/ML API** | `aiml` | Free | $0.025/day free credits — 200+ models via single endpoint |
|
|
75
|
+
| **Puter AI** | `pu` | Free | 500+ models (GPT-5, Claude Opus 4, Gemini 3 Pro, Grok 4, DeepSeek V3) |
|
|
76
|
+
| **Alibaba Cloud (DashScope)** | `ali` | Paid | International + China endpoints via `alicode`/`alicode-intl` |
|
|
77
|
+
| **Alibaba Coding Plan** | `bcp` | Paid | Alibaba Model Studio with Anthropic-compatible API |
|
|
78
|
+
| **Kimi Coding (API Key)** | `kmca` | Paid | Dedicated API-key-based Kimi access (separate from OAuth) |
|
|
79
|
+
| **MiniMax Coding** | `minimax` | Paid | International endpoint |
|
|
80
|
+
| **MiniMax (China)** | `minimax-cn` | Paid | China-specific endpoint |
|
|
81
|
+
| **Z.AI (GLM-5)** | `zai` | Paid | Zhipu AI next-gen GLM models |
|
|
82
|
+
| **Vertex AI** | `vertex` | Paid | Google Cloud — Service Account JSON or OAuth access_token |
|
|
83
|
+
| **Ollama Cloud** | `ollamacloud` | Paid | Ollama's hosted API service |
|
|
84
|
+
| **Synthetic** | `synthetic` | Paid | Passthrough models gateway |
|
|
85
|
+
| **Kilo Gateway** | `kg` | Paid | Passthrough models gateway |
|
|
86
|
+
| **Perplexity Search** | `pplx-search` | Paid | Dedicated search-grounded endpoint |
|
|
87
|
+
| **Serper Search** | `serper-search` | Paid | Web search API integration |
|
|
88
|
+
| **Brave Search** | `brave-search` | Paid | Brave Search API integration |
|
|
89
|
+
| **Exa Search** | `exa-search` | Paid | Neural search API integration |
|
|
90
|
+
| **Tavily Search** | `tavily-search` | Paid | AI search API integration |
|
|
91
|
+
| **NanoBanana** | `nb` | Paid | Image generation API |
|
|
92
|
+
| **ElevenLabs** | `el` | Paid | Text-to-speech voice synthesis |
|
|
93
|
+
| **Cartesia** | `cartesia` | Paid | Ultra-fast TTS voice synthesis |
|
|
94
|
+
| **PlayHT** | `playht` | Paid | Voice cloning and TTS |
|
|
95
|
+
| **Inworld** | `inworld` | Paid | AI character voice chat |
|
|
96
|
+
| **SD WebUI** | `sdwebui` | Self-hosted | Stable Diffusion local image generation |
|
|
97
|
+
| **ComfyUI** | `comfyui` | Self-hosted | ComfyUI local workflow node-based generation |
|
|
98
|
+
| **GLM Coding** | `glm` | Paid | BigModel/Zhipu coding-specific endpoint |
|
|
52
99
|
|
|
53
100
|
**Total: 67+ providers** (4 Free, 8 OAuth, 55 API Key) + unlimited OpenAI/Anthropic-Compatible custom providers.
|
|
54
101
|
|
|
@@ -60,15 +107,15 @@
|
|
|
60
107
|
|
|
61
108
|
Auto-generate and issue OmniRoute API keys programmatically with per-provider and per-account quota enforcement.
|
|
62
109
|
|
|
63
|
-
| Endpoint
|
|
64
|
-
|
|
65
|
-
| `/api/v1/registered-keys`
|
|
66
|
-
| `/api/v1/registered-keys`
|
|
67
|
-
| `/api/v1/registered-keys/{id}`
|
|
68
|
-
| `/api/v1/quotas/check`
|
|
69
|
-
| `/api/v1/providers/{id}/limits` | `GET/PUT`
|
|
70
|
-
| `/api/v1/accounts/{id}/limits`
|
|
71
|
-
| `/api/v1/issues/report`
|
|
110
|
+
| Endpoint | Method | Description |
|
|
111
|
+
| ------------------------------- | ------------ | ------------------------------------------------ |
|
|
112
|
+
| `/api/v1/registered-keys` | `POST` | Issue a new key — raw key returned **once only** |
|
|
113
|
+
| `/api/v1/registered-keys` | `GET` | List registered keys (masked) |
|
|
114
|
+
| `/api/v1/registered-keys/{id}` | `GET/DELETE` | Get metadata / Revoke |
|
|
115
|
+
| `/api/v1/quotas/check` | `GET` | Pre-validate quota before issuing |
|
|
116
|
+
| `/api/v1/providers/{id}/limits` | `GET/PUT` | Configure per-provider issuance limits |
|
|
117
|
+
| `/api/v1/accounts/{id}/limits` | `GET/PUT` | Configure per-account issuance limits |
|
|
118
|
+
| `/api/v1/issues/report` | `POST` | Report quota events to GitHub Issues |
|
|
72
119
|
|
|
73
120
|
**Security:** Keys stored as SHA-256 hashes. Raw key shown once on creation, never retrievable again.
|
|
74
121
|
|
|
@@ -83,6 +130,7 @@ Auto-refreshes model lists for connected providers every **24 hours**. Runs on s
|
|
|
83
130
|
#### 🔀 Per-Model Combo Routing (#563)
|
|
84
131
|
|
|
85
132
|
Map model name patterns (glob) to specific combos for automatic routing:
|
|
133
|
+
|
|
86
134
|
- `claude-sonnet*` → code-combo, `gpt-4o*` → openai-combo, `gemini-*` → google-combo
|
|
87
135
|
- New `model_combo_mappings` table with glob-to-regex matching
|
|
88
136
|
- Dashboard UI section: "Model Routing Rules" with inline add/edit/toggle/delete
|
|
@@ -122,12 +170,14 @@ Full media generation playground at `/dashboard/media`: Image Generation, Video,
|
|
|
122
170
|
### 🐛 Bug Fixes (40+)
|
|
123
171
|
|
|
124
172
|
#### OAuth & Auth
|
|
173
|
+
|
|
125
174
|
- **#537** — Gemini CLI OAuth: clear actionable error when `GEMINI_OAUTH_CLIENT_SECRET` missing in Docker
|
|
126
175
|
- **#549** — CLI settings routes now resolve real API key from `keyId` (not masked strings)
|
|
127
176
|
- **#574** — Login no longer freezes after skipping wizard password setup
|
|
128
177
|
- **#506** — Cross-platform `machineId` rewritten (Windows REG.exe → macOS ioreg → Linux → hostname fallback)
|
|
129
178
|
|
|
130
179
|
#### Providers & Routing
|
|
180
|
+
|
|
131
181
|
- **#536** — LongCat AI: fixed `baseUrl` and `authHeader`
|
|
132
182
|
- **#535** — Pinned model override: `body.model` correctly set to `pinnedModel`
|
|
133
183
|
- **#570** — Unprefixed Claude models now resolve to Anthropic provider
|
|
@@ -137,6 +187,7 @@ Full media generation playground at `/dashboard/media`: Image Generation, Video,
|
|
|
137
187
|
- **#511** — `<omniModel>` tag injected into first content chunk (not after `[DONE]`)
|
|
138
188
|
|
|
139
189
|
#### CLI & Tools
|
|
190
|
+
|
|
140
191
|
- **#527** — Claude Code + Codex loop: `tool_result` blocks now converted to text
|
|
141
192
|
- **#524** — OpenCode config saved correctly (XDG_CONFIG_HOME, TOML format)
|
|
142
193
|
- **#522** — API Manager: removed misleading "Copy masked key" button
|
|
@@ -146,12 +197,14 @@ Full media generation playground at `/dashboard/media`: Image Generation, Video,
|
|
|
146
197
|
- **#492** — CLI detects `mise`/`nvm`-managed Node when `app/server.js` missing
|
|
147
198
|
|
|
148
199
|
#### Streaming & SSE
|
|
200
|
+
|
|
149
201
|
- **PR #587** — Revert `resolveDataDir` import in responsesTransformer for Cloudflare Workers compat (@k0valik)
|
|
150
202
|
- **PR #495** — Bottleneck 429 infinite wait: drop waiting jobs on rate limit (@xandr0s)
|
|
151
203
|
- **#483** — Stop trailing `data: null` after `[DONE]` signal
|
|
152
204
|
- **#473** — Zombie SSE streams: timeout reduced 300s → 120s for faster fallback
|
|
153
205
|
|
|
154
206
|
#### Media & Transcription
|
|
207
|
+
|
|
155
208
|
- **Transcription** — Deepgram `video/mp4` → `audio/mp4` MIME mapping, auto language detection, punctuation
|
|
156
209
|
- **TTS** — `[object Object]` error display fixed for ElevenLabs-style nested errors
|
|
157
210
|
- **Upload limits** — Media transcription increased to 2GB (nginx `client_max_body_size 2g` + `maxDuration=300`)
|
|
@@ -214,27 +267,27 @@ Full media generation playground at `/dashboard/media`: Image Generation, Video,
|
|
|
214
267
|
|
|
215
268
|
### 🔀 Community PRs Merged (10)
|
|
216
269
|
|
|
217
|
-
| PR
|
|
218
|
-
|
|
219
|
-
| **#587** | @k0valik
|
|
220
|
-
| **#582** | @jay77721
|
|
221
|
-
| **#581** | @jay77721
|
|
222
|
-
| **#578** | @hijak
|
|
223
|
-
| **#575** | @zhangqiang8vip | feat: per-model upstream headers, compat PATCH, chat alignment
|
|
224
|
-
| **#562** | @coobabm
|
|
225
|
-
| **#561** | @zen0bit
|
|
226
|
-
| **#555** | @k0valik
|
|
227
|
-
| **#546** | @k0valik
|
|
228
|
-
| **#544** | @k0valik
|
|
229
|
-
| **#542** | @rdself
|
|
230
|
-
| **#530** | @kang-heewon
|
|
231
|
-
| **#512** | @zhangqiang8vip | feat: per-protocol model compatibility (`compatByProtocol`)
|
|
232
|
-
| **#497** | @zhangqiang8vip | fix: dev-mode HMR resource leaks (ZWS v5)
|
|
233
|
-
| **#495** | @xandr0s
|
|
234
|
-
| **#494** | @zhangqiang8vip | feat: MiniMax developer→system role fix
|
|
235
|
-
| **#480** | @prakersh
|
|
236
|
-
| **#479** | @prakersh
|
|
237
|
-
| **#475** | @only4copilot
|
|
270
|
+
| PR | Author | Summary |
|
|
271
|
+
| -------- | --------------- | -------------------------------------------------------------------- |
|
|
272
|
+
| **#587** | @k0valik | fix(sse): revert resolveDataDir import for Cloudflare Workers compat |
|
|
273
|
+
| **#582** | @jay77721 | feat(proxy): model name prefix stripping option |
|
|
274
|
+
| **#581** | @jay77721 | fix(npm): link electron-release to npm-publish workflow |
|
|
275
|
+
| **#578** | @hijak | feat: configurable context length in model metadata |
|
|
276
|
+
| **#575** | @zhangqiang8vip | feat: per-model upstream headers, compat PATCH, chat alignment |
|
|
277
|
+
| **#562** | @coobabm | fix: MCP session management, Claude passthrough, detectFormat |
|
|
278
|
+
| **#561** | @zen0bit | fix(i18n): Czech translation corrections |
|
|
279
|
+
| **#555** | @k0valik | fix(sse): centralized `resolveDataDir()` for path resolution |
|
|
280
|
+
| **#546** | @k0valik | fix(cli): `--version` returning `unknown` on Windows |
|
|
281
|
+
| **#544** | @k0valik | fix(cli): secure CLI tool detection via installation paths |
|
|
282
|
+
| **#542** | @rdself | fix(ui): light mode contrast CSS theme variables |
|
|
283
|
+
| **#530** | @kang-heewon | feat: OpenCode Zen + Go providers with `OpencodeExecutor` |
|
|
284
|
+
| **#512** | @zhangqiang8vip | feat: per-protocol model compatibility (`compatByProtocol`) |
|
|
285
|
+
| **#497** | @zhangqiang8vip | fix: dev-mode HMR resource leaks (ZWS v5) |
|
|
286
|
+
| **#495** | @xandr0s | fix: Bottleneck 429 infinite wait (drop waiting jobs) |
|
|
287
|
+
| **#494** | @zhangqiang8vip | feat: MiniMax developer→system role fix |
|
|
288
|
+
| **#480** | @prakersh | fix: stream flush usage extraction |
|
|
289
|
+
| **#479** | @prakersh | feat: Codex 5.3/5.4 and Anthropic pricing entries |
|
|
290
|
+
| **#475** | @only4copilot | feat(i18n): improved Chinese translation |
|
|
238
291
|
|
|
239
292
|
**Thank you to all contributors!** 🙏
|
|
240
293
|
|
|
@@ -255,11 +308,11 @@ Full media generation playground at `/dashboard/media`: Image Generation, Video,
|
|
|
255
308
|
|
|
256
309
|
### 📦 Database Migrations
|
|
257
310
|
|
|
258
|
-
| Migration | Description
|
|
259
|
-
|
|
260
|
-
| **008**
|
|
261
|
-
| **009**
|
|
262
|
-
| **010**
|
|
311
|
+
| Migration | Description |
|
|
312
|
+
| --------- | --------------------------------------------------------------------- |
|
|
313
|
+
| **008** | `registered_keys`, `provider_key_limits`, `account_key_limits` tables |
|
|
314
|
+
| **009** | `requested_model` column in `call_logs` |
|
|
315
|
+
| **010** | `model_combo_mappings` table for per-model combo routing |
|
|
263
316
|
|
|
264
317
|
---
|
|
265
318
|
|
|
@@ -310,6 +363,7 @@ docker pull diegosouzapw/omniroute:3.0.0
|
|
|
310
363
|
## [3.0.0-rc.16] — 2026-03-24
|
|
311
364
|
|
|
312
365
|
### ✨ New Features
|
|
366
|
+
|
|
313
367
|
- Increased media transcription limits
|
|
314
368
|
- Added Model Context Length to registry metadata
|
|
315
369
|
- Added per-model upstream custom headers via configuration UI
|
|
@@ -386,7 +386,7 @@ Claude Code, Codex, Gemini CLI, Copilot — все используют OAuth 2.
|
|
|
386
386
|
- **Панель управления унифицированными журналами** — 4 вкладки: журналы запросов, журналы прокси, журналы аудита, консоль.
|
|
387
387
|
- **Консольный просмотр журнала** — просмотрщик в режиме терминала в режиме реального времени с уровнями с цветовой кодировкой, автоматической прокруткой, поиском и фильтрацией.
|
|
388
388
|
- **Журналы прокси-сервера SQLite** — постоянные журналы, сохраняющиеся после перезапуска сервера.
|
|
389
|
-
- **Площадка
|
|
389
|
+
- **Площадка транслятора (Translator Playground)** — 4 режима отладки: Площадка (перевод формата), Тестер чата (туда и обратно), Тестовый стенд (пакетный), Мониторинг в реальном времени (в режиме реального времени).
|
|
390
390
|
- **Запрос телеметрии** — задержка p50/p95/p99 + отслеживание X-Request-Id
|
|
391
391
|
- **Журналирование на основе файлов с ротацией** — перехватчик консоли записывает все в журнал JSON с ротацией на основе размера.
|
|
392
392
|
|
|
@@ -451,7 +451,7 @@ Claude Code, Codex, Gemini CLI, Copilot — все используют OAuth 2.
|
|
|
451
451
|
|
|
452
452
|
- **Оценки LLM** — тестирование золотого набора с 10 предварительно загруженными вариантами, охватывающими приветствия, математику, географию, генерацию кода, соответствие JSON, перевод, уценку, отказ от безопасности.
|
|
453
453
|
- **4 стратегии сопоставления** — `exact`, `contains`, `regex`, `custom` (функция JS)
|
|
454
|
-
- **Тестовый стенд
|
|
454
|
+
- **Тестовый стенд (Testbed)** — пакетное тестирование с несколькими входными данными и ожидаемыми результатами, сравнение между поставщиками.
|
|
455
455
|
- **Тестер чата** — полный цикл с визуальным отображением ответов.
|
|
456
456
|
- **Живой монитор** — поток всех запросов, проходящих через прокси, в реальном времени.
|
|
457
457
|
|
|
@@ -1016,7 +1016,7 @@ OmniRoute включает встроенный фреймворк оценки
|
|
|
1016
1016
|
|
|
1017
1017
|
- Приветствия, математика, география, генерация кода
|
|
1018
1018
|
- Соответствие формату JSON, перевод, markdown
|
|
1019
|
-
- Отказ от небезопасного
|
|
1019
|
+
- Отказ от небезопасного контента (Safety refusal), подсчёт, булева логика
|
|
1020
1020
|
|
|
1021
1021
|
### Стратегии оценки
|
|
1022
1022
|
|
package/app/docs/openapi.yaml
CHANGED
|
@@ -223,7 +223,8 @@ export async function handleChatCore({
|
|
|
223
223
|
|
|
224
224
|
const endpointPath = String(clientRawRequest?.endpoint || "");
|
|
225
225
|
const sourceFormat = detectFormatFromEndpoint(body, endpointPath);
|
|
226
|
-
const isResponsesEndpoint =
|
|
226
|
+
const isResponsesEndpoint =
|
|
227
|
+
/\/responses(?=\/|$)/i.test(endpointPath) || /^responses(?=\/|$)/i.test(endpointPath);
|
|
227
228
|
const nativeCodexPassthrough = shouldUseNativeCodexPassthrough({
|
|
228
229
|
provider,
|
|
229
230
|
sourceFormat,
|
|
@@ -1067,8 +1068,14 @@ export async function handleChatCore({
|
|
|
1067
1068
|
}
|
|
1068
1069
|
|
|
1069
1070
|
// Translate response to client's expected format (usually OpenAI)
|
|
1071
|
+
// Pass toolNameMap so Claude OAuth proxy_ prefix is stripped in tool_use blocks (#605)
|
|
1070
1072
|
let translatedResponse = needsTranslation(targetFormat, sourceFormat)
|
|
1071
|
-
? translateNonStreamingResponse(
|
|
1073
|
+
? translateNonStreamingResponse(
|
|
1074
|
+
responseBody,
|
|
1075
|
+
targetFormat,
|
|
1076
|
+
sourceFormat,
|
|
1077
|
+
toolNameMap as Map<string, string> | null
|
|
1078
|
+
)
|
|
1072
1079
|
: responseBody;
|
|
1073
1080
|
|
|
1074
1081
|
// T26: Strip markdown code blocks if provider format is Claude
|
|
@@ -68,11 +68,14 @@ function findBestMessageText(output: unknown[]): {
|
|
|
68
68
|
/**
|
|
69
69
|
* Translate non-streaming response to OpenAI format
|
|
70
70
|
* Handles different provider response formats (Gemini, Claude, etc.)
|
|
71
|
+
*
|
|
72
|
+
* @param toolNameMap - Optional Map<prefixedName, originalName> for Claude OAuth tool name stripping
|
|
71
73
|
*/
|
|
72
74
|
export function translateNonStreamingResponse(
|
|
73
75
|
responseBody: unknown,
|
|
74
76
|
targetFormat: string,
|
|
75
|
-
sourceFormat: string
|
|
77
|
+
sourceFormat: string,
|
|
78
|
+
toolNameMap?: Map<string, string> | null
|
|
76
79
|
): unknown {
|
|
77
80
|
// If already in source format (usually OpenAI), return as-is
|
|
78
81
|
if (targetFormat === sourceFormat || targetFormat === FORMATS.OPENAI) {
|
|
@@ -122,11 +125,14 @@ export function translateNonStreamingResponse(
|
|
|
122
125
|
typeof itemObj.arguments === "string"
|
|
123
126
|
? itemObj.arguments
|
|
124
127
|
: JSON.stringify(itemObj.arguments || {});
|
|
128
|
+
const rawName = toString(itemObj.name);
|
|
129
|
+
// Strip Claude OAuth proxy_ prefix using toolNameMap (mirrors tool_use fix for #605)
|
|
130
|
+
const resolvedName = toolNameMap?.get(rawName) ?? rawName;
|
|
125
131
|
toolCalls.push({
|
|
126
132
|
id: callId,
|
|
127
133
|
type: "function",
|
|
128
134
|
function: {
|
|
129
|
-
name:
|
|
135
|
+
name: resolvedName,
|
|
130
136
|
arguments: fnArgs,
|
|
131
137
|
},
|
|
132
138
|
});
|
|
@@ -334,11 +340,15 @@ export function translateNonStreamingResponse(
|
|
|
334
340
|
} else if (blockObj.type === "thinking") {
|
|
335
341
|
thinkingContent += toString(blockObj.thinking);
|
|
336
342
|
} else if (blockObj.type === "tool_use") {
|
|
343
|
+
// Strip Claude OAuth tool name prefix (proxy_) using the map from request translation.
|
|
344
|
+
// Fallback to raw name if block wasn't prefixed (disableToolPrefix path).
|
|
345
|
+
const rawName = toString(blockObj.name);
|
|
346
|
+
const strippedName = toolNameMap?.get(rawName) ?? rawName;
|
|
337
347
|
toolCalls.push({
|
|
338
348
|
id: toString(blockObj.id, `call_${Date.now()}_${toolCalls.length}`),
|
|
339
349
|
type: "function",
|
|
340
350
|
function: {
|
|
341
|
-
name:
|
|
351
|
+
name: strippedName,
|
|
342
352
|
arguments: JSON.stringify(blockObj.input || {}),
|
|
343
353
|
},
|
|
344
354
|
});
|
|
@@ -86,7 +86,8 @@ function toDisplayLabel(value: string): string {
|
|
|
86
86
|
.filter(Boolean)
|
|
87
87
|
.map((part) => {
|
|
88
88
|
if (/^pro\+$/i.test(part)) return "Pro+";
|
|
89
|
-
if (/^[a-z]{2,}$/.test(part))
|
|
89
|
+
if (/^[a-z]{2,}$/.test(part))
|
|
90
|
+
return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
|
|
90
91
|
return part;
|
|
91
92
|
})
|
|
92
93
|
.join(" ")
|
|
@@ -200,7 +201,9 @@ async function getGitHubUsage(accessToken, providerSpecificData) {
|
|
|
200
201
|
if (dataRecord.quota_snapshots) {
|
|
201
202
|
// Paid plan format
|
|
202
203
|
const snapshots = toRecord(dataRecord.quota_snapshots);
|
|
203
|
-
const resetAt = parseResetTime(
|
|
204
|
+
const resetAt = parseResetTime(
|
|
205
|
+
getFieldValue(dataRecord, "quota_reset_date", "quotaResetDate")
|
|
206
|
+
);
|
|
204
207
|
const premiumQuota = formatGitHubQuotaSnapshot(snapshots.premium_interactions, resetAt);
|
|
205
208
|
const chatQuota = formatGitHubQuotaSnapshot(snapshots.chat, resetAt);
|
|
206
209
|
const completionsQuota = formatGitHubQuotaSnapshot(snapshots.completions, resetAt);
|
|
@@ -225,7 +228,11 @@ async function getGitHubUsage(accessToken, providerSpecificData) {
|
|
|
225
228
|
// Free/limited plan format
|
|
226
229
|
const monthlyQuotas = toRecord(dataRecord.monthly_quotas);
|
|
227
230
|
const usedQuotas = toRecord(dataRecord.limited_user_quotas);
|
|
228
|
-
const resetDate = getFieldValue(
|
|
231
|
+
const resetDate = getFieldValue(
|
|
232
|
+
dataRecord,
|
|
233
|
+
"limited_user_reset_date",
|
|
234
|
+
"limitedUserResetDate"
|
|
235
|
+
);
|
|
229
236
|
const resetAt = parseResetTime(resetDate);
|
|
230
237
|
const quotas: Record<string, UsageQuota> = {};
|
|
231
238
|
|
|
@@ -327,11 +334,7 @@ function inferGitHubPlanName(data: JsonRecord, premiumQuota: UsageQuota | null):
|
|
|
327
334
|
toNumber(getFieldValue(monthlyQuotas, "premium_interactions", "premiumInteractions"), 0);
|
|
328
335
|
const chatTotal = toNumber(getFieldValue(monthlyQuotas, "chat", "chat"), 0);
|
|
329
336
|
|
|
330
|
-
if (
|
|
331
|
-
combined.includes("PRO+") ||
|
|
332
|
-
combined.includes("PRO_PLUS") ||
|
|
333
|
-
combined.includes("PROPLUS")
|
|
334
|
-
) {
|
|
337
|
+
if (combined.includes("PRO+") || combined.includes("PRO_PLUS") || combined.includes("PROPLUS")) {
|
|
335
338
|
return "Copilot Pro+";
|
|
336
339
|
}
|
|
337
340
|
if (combined.includes("ENTERPRISE")) return "Copilot Enterprise";
|
|
@@ -655,8 +658,18 @@ async function getClaudeUsage(accessToken) {
|
|
|
655
658
|
}
|
|
656
659
|
}
|
|
657
660
|
|
|
661
|
+
// Try to extract plan tier from the OAuth response
|
|
662
|
+
const planRaw =
|
|
663
|
+
typeof data.tier === "string"
|
|
664
|
+
? data.tier
|
|
665
|
+
: typeof data.plan === "string"
|
|
666
|
+
? data.plan
|
|
667
|
+
: typeof data.subscription_type === "string"
|
|
668
|
+
? data.subscription_type
|
|
669
|
+
: null;
|
|
670
|
+
|
|
658
671
|
return {
|
|
659
|
-
plan: "Claude Code",
|
|
672
|
+
plan: planRaw || "Claude Code",
|
|
660
673
|
quotas,
|
|
661
674
|
extraUsage: data.extra_usage ?? null,
|
|
662
675
|
};
|
|
@@ -259,11 +259,19 @@ export function openaiToClaudeRequest(model, body, stream) {
|
|
|
259
259
|
toolNameMap.set(toolName, originalName);
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
// Normalize input_schema: Anthropic requires `properties` when type is "object" (#595).
|
|
263
|
+
// MCP tools (e.g. pencil, computer_use) may omit properties on object-type schemas.
|
|
264
|
+
const rawSchema: Record<string, unknown> =
|
|
265
|
+
toolData.parameters || toolData.input_schema || { type: "object", properties: {}, required: [] };
|
|
266
|
+
const normalizedSchema =
|
|
267
|
+
rawSchema.type === "object" && !rawSchema.properties
|
|
268
|
+
? { ...rawSchema, properties: {} }
|
|
269
|
+
: rawSchema;
|
|
270
|
+
|
|
262
271
|
return {
|
|
263
272
|
name: toolName,
|
|
264
273
|
description: toolData.description || "",
|
|
265
|
-
input_schema:
|
|
266
|
-
toolData.input_schema || { type: "object", properties: {}, required: [] },
|
|
274
|
+
input_schema: normalizedSchema,
|
|
267
275
|
};
|
|
268
276
|
});
|
|
269
277
|
|
package/app/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omniroute",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omniroute",
|
|
9
|
-
"version": "3.0.
|
|
9
|
+
"version": "3.0.1",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"workspaces": [
|
package/app/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omniroute",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|