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.
Files changed (116) hide show
  1. package/app/.next/BUILD_ID +1 -1
  2. package/app/.next/build-manifest.json +2 -2
  3. package/app/.next/prerender-manifest.json +3 -3
  4. package/app/.next/server/app/(dashboard)/dashboard/a2a/page_client-reference-manifest.js +1 -1
  5. package/app/.next/server/app/(dashboard)/dashboard/agents/page_client-reference-manifest.js +1 -1
  6. package/app/.next/server/app/(dashboard)/dashboard/analytics/page_client-reference-manifest.js +1 -1
  7. package/app/.next/server/app/(dashboard)/dashboard/api-manager/page_client-reference-manifest.js +1 -1
  8. package/app/.next/server/app/(dashboard)/dashboard/audit-log/page_client-reference-manifest.js +1 -1
  9. package/app/.next/server/app/(dashboard)/dashboard/auto-combo/page_client-reference-manifest.js +1 -1
  10. package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  11. package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  12. package/app/.next/server/app/(dashboard)/dashboard/costs/page_client-reference-manifest.js +1 -1
  13. package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  14. package/app/.next/server/app/(dashboard)/dashboard/health/page_client-reference-manifest.js +1 -1
  15. package/app/.next/server/app/(dashboard)/dashboard/limits/page_client-reference-manifest.js +1 -1
  16. package/app/.next/server/app/(dashboard)/dashboard/logs/page_client-reference-manifest.js +1 -1
  17. package/app/.next/server/app/(dashboard)/dashboard/mcp/page_client-reference-manifest.js +1 -1
  18. package/app/.next/server/app/(dashboard)/dashboard/media/page_client-reference-manifest.js +1 -1
  19. package/app/.next/server/app/(dashboard)/dashboard/onboarding/page_client-reference-manifest.js +1 -1
  20. package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  21. package/app/.next/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
  22. package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  23. package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  24. package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  25. package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  26. package/app/.next/server/app/(dashboard)/dashboard/search-tools/page_client-reference-manifest.js +1 -1
  27. package/app/.next/server/app/(dashboard)/dashboard/settings/page_client-reference-manifest.js +1 -1
  28. package/app/.next/server/app/(dashboard)/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  29. package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  30. package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  31. package/app/.next/server/app/400/page_client-reference-manifest.js +1 -1
  32. package/app/.next/server/app/401/page_client-reference-manifest.js +1 -1
  33. package/app/.next/server/app/403/page_client-reference-manifest.js +1 -1
  34. package/app/.next/server/app/408/page_client-reference-manifest.js +1 -1
  35. package/app/.next/server/app/429/page_client-reference-manifest.js +1 -1
  36. package/app/.next/server/app/500/page_client-reference-manifest.js +1 -1
  37. package/app/.next/server/app/502/page_client-reference-manifest.js +1 -1
  38. package/app/.next/server/app/503/page_client-reference-manifest.js +1 -1
  39. package/app/.next/server/app/_global-error.html +2 -2
  40. package/app/.next/server/app/_global-error.rsc +1 -1
  41. package/app/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  42. package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  43. package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  44. package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  45. package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  46. package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  47. package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
  48. package/app/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  49. package/app/.next/server/app/forbidden/page_client-reference-manifest.js +1 -1
  50. package/app/.next/server/app/forgot-password/page_client-reference-manifest.js +1 -1
  51. package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  52. package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
  53. package/app/.next/server/app/maintenance/page_client-reference-manifest.js +1 -1
  54. package/app/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  55. package/app/.next/server/app/page_client-reference-manifest.js +1 -1
  56. package/app/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
  57. package/app/.next/server/app/status/page_client-reference-manifest.js +1 -1
  58. package/app/.next/server/app/terms/page_client-reference-manifest.js +1 -1
  59. package/app/.next/server/chunks/[root-of-the-server]__051203a6._.js +2 -2
  60. package/app/.next/server/chunks/[root-of-the-server]__0891af92._.js +1 -1
  61. package/app/.next/server/chunks/[root-of-the-server]__1f2b0d89._.js +1 -1
  62. package/app/.next/server/chunks/[root-of-the-server]__61d78f9d._.js +2 -2
  63. package/app/.next/server/chunks/[root-of-the-server]__6e52619e._.js +1 -1
  64. package/app/.next/server/chunks/[root-of-the-server]__afddb4ce._.js +1 -1
  65. package/app/.next/server/chunks/[root-of-the-server]__e27a89bd._.js +1 -1
  66. package/app/.next/server/chunks/[root-of-the-server]__fd2fbc93._.js +1 -1
  67. package/app/.next/server/chunks/_05c48915._.js +1 -1
  68. package/app/.next/server/chunks/_06515a8a._.js +1 -1
  69. package/app/.next/server/chunks/_2115d8de._.js +1 -1
  70. package/app/.next/server/chunks/_3ac953eb._.js +1 -1
  71. package/app/.next/server/chunks/_4b8fd853._.js +1 -1
  72. package/app/.next/server/chunks/_68683848._.js +1 -1
  73. package/app/.next/server/chunks/_6f1b3c3f._.js +1 -1
  74. package/app/.next/server/chunks/_ee9b677b._.js +1 -1
  75. package/app/.next/server/chunks/_efd5ede2._.js +2 -2
  76. package/app/.next/server/chunks/_ffda39da._.js +1 -1
  77. package/app/.next/server/chunks/open-sse_translator_index_ts_f5fd0821._.js +1 -1
  78. package/app/.next/server/chunks/src_6320c728._.js +1 -1
  79. package/app/.next/server/chunks/ssr/[root-of-the-server]__9ef96d20._.js +1 -1
  80. package/app/.next/server/chunks/ssr/[root-of-the-server]__a6942102._.js +1 -1
  81. package/app/.next/server/chunks/ssr/_f3674909._.js +1 -1
  82. package/app/.next/server/chunks/ssr/src_a82a42f9._.js +1 -1
  83. package/app/.next/server/chunks/ssr/src_app_(dashboard)_dashboard_936a9ee0._.js +1 -1
  84. package/app/.next/server/chunks/ssr/src_app_(dashboard)_dashboard_settings_9e20fb8d._.js +1 -1
  85. package/app/.next/server/pages/500.html +2 -2
  86. package/app/.next/server/server-reference-manifest.js +1 -1
  87. package/app/.next/server/server-reference-manifest.json +1 -1
  88. package/app/.next/static/chunks/26aeb12cf79339b1.js +1 -0
  89. package/app/.next/static/chunks/{80658e0c2b2c7004.js → 633a312ddcf9fa11.js} +1 -1
  90. package/app/.next/static/chunks/7df0b3c357097db5.js +1 -0
  91. package/app/.next/static/chunks/a051245b46459ad2.css +1 -0
  92. package/app/.next/static/chunks/d188e358e1ec0a7d.js +1 -0
  93. package/app/.next/static/chunks/{4e3fe685e3218d24.js → fa9e2a946d2cdbc7.js} +1 -1
  94. package/app/CHANGELOG.md +122 -68
  95. package/app/docs/i18n/ru/README.md +3 -3
  96. package/app/docs/openapi.yaml +1 -1
  97. package/app/open-sse/handlers/chatCore.ts +9 -2
  98. package/app/open-sse/handlers/responseTranslator.ts +13 -3
  99. package/app/open-sse/services/usage.ts +22 -9
  100. package/app/open-sse/translator/request/openai-to-claude.ts +10 -2
  101. package/app/package-lock.json +2 -2
  102. package/app/package.json +1 -1
  103. package/app/src/app/(dashboard)/dashboard/providers/[id]/page.tsx +198 -63
  104. package/app/src/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager.tsx +123 -19
  105. package/app/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx +22 -24
  106. package/app/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx +5 -0
  107. package/app/src/lib/providers/validation.ts +21 -0
  108. package/app/src/shared/components/ProxyConfigModal.tsx +42 -13
  109. package/package.json +1 -1
  110. package/app/.next/static/chunks/594bdf69c19b5310.js +0 -1
  111. package/app/.next/static/chunks/643428fcd3f9bb51.js +0 -1
  112. package/app/.next/static/chunks/8efe14530c87d9f6.css +0 -1
  113. package/app/.next/static/chunks/d0cff7a6c3a66c7d.js +0 -1
  114. /package/app/.next/static/{cQZnxkFFvb8O7T4x7OSsG → bF7pUIj1e9VsHgSW5x9WX}/_buildManifest.js +0 -0
  115. /package/app/.next/static/{cQZnxkFFvb8O7T4x7OSsG → bF7pUIj1e9VsHgSW5x9WX}/_clientMiddlewareManifest.json +0 -0
  116. /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 | Alias | Tier | Notes |
20
- |----------|-------|------|-------|
21
- | **OpenCode Zen** | `opencode-zen` | Free | 3 models via `opencode.ai/zen/v1` (PR #530 by @kang-heewon) |
22
- | **OpenCode Go** | `opencode-go` | Paid | 4 models via `opencode.ai/zen/go/v1` (PR #530 by @kang-heewon) |
23
- | **LongCat AI** | `lc` | Free | 50M tokens/day (Flash-Lite) + 500K/day (Chat/Thinking) during public beta |
24
- | **Pollinations AI** | `pol` | Free | No API key needed — GPT-5, Claude, Gemini, DeepSeek V3, Llama 4 (1 req/15s) |
25
- | **Cloudflare Workers AI** | `cf` | Free | 10K Neurons/day — ~150 LLM responses or 500s Whisper audio, edge inference |
26
- | **Scaleway AI** | `scw` | Free | 1M free tokens for new accounts — EU/GDPR compliant (Paris) |
27
- | **AI/ML API** | `aiml` | Free | $0.025/day free credits — 200+ models via single endpoint |
28
- | **Puter AI** | `pu` | Free | 500+ models (GPT-5, Claude Opus 4, Gemini 3 Pro, Grok 4, DeepSeek V3) |
29
- | **Alibaba Cloud (DashScope)** | `ali` | Paid | International + China endpoints via `alicode`/`alicode-intl` |
30
- | **Alibaba Coding Plan** | `bcp` | Paid | Alibaba Model Studio with Anthropic-compatible API |
31
- | **Kimi Coding (API Key)** | `kmca` | Paid | Dedicated API-key-based Kimi access (separate from OAuth) |
32
- | **MiniMax Coding** | `minimax` | Paid | International endpoint |
33
- | **MiniMax (China)** | `minimax-cn` | Paid | China-specific endpoint |
34
- | **Z.AI (GLM-5)** | `zai` | Paid | Zhipu AI next-gen GLM models |
35
- | **Vertex AI** | `vertex` | Paid | Google Cloud — Service Account JSON or OAuth access_token |
36
- | **Ollama Cloud** | `ollamacloud` | Paid | Ollama's hosted API service |
37
- | **Synthetic** | `synthetic` | Paid | Passthrough models gateway |
38
- | **Kilo Gateway** | `kg` | Paid | Passthrough models gateway |
39
- | **Perplexity Search** | `pplx-search` | Paid | Dedicated search-grounded endpoint |
40
- | **Serper Search** | `serper-search` | Paid | Web search API integration |
41
- | **Brave Search** | `brave-search` | Paid | Brave Search API integration |
42
- | **Exa Search** | `exa-search` | Paid | Neural search API integration |
43
- | **Tavily Search** | `tavily-search` | Paid | AI search API integration |
44
- | **NanoBanana** | `nb` | Paid | Image generation API |
45
- | **ElevenLabs** | `el` | Paid | Text-to-speech voice synthesis |
46
- | **Cartesia** | `cartesia` | Paid | Ultra-fast TTS voice synthesis |
47
- | **PlayHT** | `playht` | Paid | Voice cloning and TTS |
48
- | **Inworld** | `inworld` | Paid | AI character voice chat |
49
- | **SD WebUI** | `sdwebui` | Self-hosted | Stable Diffusion local image generation |
50
- | **ComfyUI** | `comfyui` | Self-hosted | ComfyUI local workflow node-based generation |
51
- | **GLM Coding** | `glm` | Paid | BigModel/Zhipu coding-specific endpoint |
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 | Method | Description |
64
- |----------|--------|-------------|
65
- | `/api/v1/registered-keys` | `POST` | Issue a new key — raw key returned **once only** |
66
- | `/api/v1/registered-keys` | `GET` | List registered keys (masked) |
67
- | `/api/v1/registered-keys/{id}` | `GET/DELETE` | Get metadata / Revoke |
68
- | `/api/v1/quotas/check` | `GET` | Pre-validate quota before issuing |
69
- | `/api/v1/providers/{id}/limits` | `GET/PUT` | Configure per-provider issuance limits |
70
- | `/api/v1/accounts/{id}/limits` | `GET/PUT` | Configure per-account issuance limits |
71
- | `/api/v1/issues/report` | `POST` | Report quota events to GitHub Issues |
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 | Author | Summary |
218
- |----|--------|---------|
219
- | **#587** | @k0valik | fix(sse): revert resolveDataDir import for Cloudflare Workers compat |
220
- | **#582** | @jay77721 | feat(proxy): model name prefix stripping option |
221
- | **#581** | @jay77721 | fix(npm): link electron-release to npm-publish workflow |
222
- | **#578** | @hijak | feat: configurable context length in model metadata |
223
- | **#575** | @zhangqiang8vip | feat: per-model upstream headers, compat PATCH, chat alignment |
224
- | **#562** | @coobabm | fix: MCP session management, Claude passthrough, detectFormat |
225
- | **#561** | @zen0bit | fix(i18n): Czech translation corrections |
226
- | **#555** | @k0valik | fix(sse): centralized `resolveDataDir()` for path resolution |
227
- | **#546** | @k0valik | fix(cli): `--version` returning `unknown` on Windows |
228
- | **#544** | @k0valik | fix(cli): secure CLI tool detection via installation paths |
229
- | **#542** | @rdself | fix(ui): light mode contrast CSS theme variables |
230
- | **#530** | @kang-heewon | feat: OpenCode Zen + Go providers with `OpencodeExecutor` |
231
- | **#512** | @zhangqiang8vip | feat: per-protocol model compatibility (`compatByProtocol`) |
232
- | **#497** | @zhangqiang8vip | fix: dev-mode HMR resource leaks (ZWS v5) |
233
- | **#495** | @xandr0s | fix: Bottleneck 429 infinite wait (drop waiting jobs) |
234
- | **#494** | @zhangqiang8vip | feat: MiniMax developer→system role fix |
235
- | **#480** | @prakersh | fix: stream flush usage extraction |
236
- | **#479** | @prakersh | feat: Codex 5.3/5.4 and Anthropic pricing entries |
237
- | **#475** | @only4copilot | feat(i18n): improved Chinese translation |
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** | `registered_keys`, `provider_key_limits`, `account_key_limits` tables |
261
- | **009** | `requested_model` column in `call_logs` |
262
- | **010** | `model_combo_mappings` table for per-model combo routing |
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
- - **Площадка переводчика** — 4 режима отладки: Площадка (перевод формата), Тестер чата (туда и обратно), Тестовый стенд (пакетный), Мониторинг в реальном времени (в режиме реального времени).
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
- - **Тестовый стенд Translator Playground** — пакетное тестирование с несколькими входными данными и ожидаемыми результатами, сравнение между поставщиками.
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
 
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: OmniRoute API
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  description: |
6
6
  OmniRoute is a local-first AI API proxy router. It provides an OpenAI-compatible
7
7
  endpoint that routes requests to multiple AI providers with load balancing,
@@ -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 = /\/responses(?=\/|$)/i.test(endpointPath) || /^responses(?=\/|$)/i.test(endpointPath);
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(responseBody, targetFormat, sourceFormat)
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: toString(itemObj.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: toString(blockObj.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)) return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
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(getFieldValue(dataRecord, "quota_reset_date", "quotaResetDate"));
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(dataRecord, "limited_user_reset_date", "limitedUserResetDate");
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: toolData.parameters ||
266
- toolData.input_schema || { type: "object", properties: {}, required: [] },
274
+ input_schema: normalizedSchema,
267
275
  };
268
276
  });
269
277
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omniroute",
3
- "version": "3.0.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.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.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": {