omniroute 3.3.10 → 3.3.11

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 (115) 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/page_client-reference-manifest.js +1 -1
  9. package/app/.next/server/app/(dashboard)/dashboard/audit-log/page_client-reference-manifest.js +1 -1
  10. package/app/.next/server/app/(dashboard)/dashboard/auto-combo/page_client-reference-manifest.js +1 -1
  11. package/app/.next/server/app/(dashboard)/dashboard/cache/page_client-reference-manifest.js +1 -1
  12. package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  13. package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  14. package/app/.next/server/app/(dashboard)/dashboard/costs/page_client-reference-manifest.js +1 -1
  15. package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  16. package/app/.next/server/app/(dashboard)/dashboard/health/page_client-reference-manifest.js +1 -1
  17. package/app/.next/server/app/(dashboard)/dashboard/limits/page_client-reference-manifest.js +1 -1
  18. package/app/.next/server/app/(dashboard)/dashboard/logs/page_client-reference-manifest.js +1 -1
  19. package/app/.next/server/app/(dashboard)/dashboard/mcp/page_client-reference-manifest.js +1 -1
  20. package/app/.next/server/app/(dashboard)/dashboard/media/page_client-reference-manifest.js +1 -1
  21. package/app/.next/server/app/(dashboard)/dashboard/onboarding/page_client-reference-manifest.js +1 -1
  22. package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  23. package/app/.next/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
  24. package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  25. package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  26. package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  27. package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  28. package/app/.next/server/app/(dashboard)/dashboard/search-tools/page_client-reference-manifest.js +1 -1
  29. package/app/.next/server/app/(dashboard)/dashboard/settings/page_client-reference-manifest.js +1 -1
  30. package/app/.next/server/app/(dashboard)/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  31. package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  32. package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  33. package/app/.next/server/app/400/page_client-reference-manifest.js +1 -1
  34. package/app/.next/server/app/401/page_client-reference-manifest.js +1 -1
  35. package/app/.next/server/app/403/page_client-reference-manifest.js +1 -1
  36. package/app/.next/server/app/408/page_client-reference-manifest.js +1 -1
  37. package/app/.next/server/app/429/page_client-reference-manifest.js +1 -1
  38. package/app/.next/server/app/500/page_client-reference-manifest.js +1 -1
  39. package/app/.next/server/app/502/page_client-reference-manifest.js +1 -1
  40. package/app/.next/server/app/503/page_client-reference-manifest.js +1 -1
  41. package/app/.next/server/app/_global-error.html +2 -2
  42. package/app/.next/server/app/_global-error.rsc +1 -1
  43. package/app/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  44. package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  45. package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  46. package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  47. package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  48. package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  49. package/app/.next/server/app/api/system/version/route.js.nft.json +1 -1
  50. package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
  51. package/app/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  52. package/app/.next/server/app/forbidden/page_client-reference-manifest.js +1 -1
  53. package/app/.next/server/app/forgot-password/page_client-reference-manifest.js +1 -1
  54. package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  55. package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
  56. package/app/.next/server/app/maintenance/page_client-reference-manifest.js +1 -1
  57. package/app/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  58. package/app/.next/server/app/page_client-reference-manifest.js +1 -1
  59. package/app/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
  60. package/app/.next/server/app/status/page_client-reference-manifest.js +1 -1
  61. package/app/.next/server/app/terms/page_client-reference-manifest.js +1 -1
  62. package/app/.next/server/chunks/[root-of-the-server]__112a90be._.js +2 -2
  63. package/app/.next/server/chunks/[root-of-the-server]__46e00e59._.js +2 -2
  64. package/app/.next/server/chunks/[root-of-the-server]__5c021c68._.js +1 -1
  65. package/app/.next/server/chunks/[root-of-the-server]__6fba99f4._.js +1 -1
  66. package/app/.next/server/chunks/[root-of-the-server]__745fa111._.js +1 -1
  67. package/app/.next/server/chunks/[root-of-the-server]__78f7009e._.js +1 -1
  68. package/app/.next/server/chunks/[root-of-the-server]__7ace0fcd._.js +1 -1
  69. package/app/.next/server/chunks/[root-of-the-server]__7d4ffdb3._.js +1 -1
  70. package/app/.next/server/chunks/[root-of-the-server]__8c57851d._.js +1 -1
  71. package/app/.next/server/chunks/[root-of-the-server]__9096d2fa._.js +1 -1
  72. package/app/.next/server/chunks/[root-of-the-server]__a1f12196._.js +1 -1
  73. package/app/.next/server/chunks/[root-of-the-server]__a32d3818._.js +1 -1
  74. package/app/.next/server/chunks/[root-of-the-server]__b39d0020._.js +2 -2
  75. package/app/.next/server/chunks/[root-of-the-server]__bc251fbe._.js +1 -1
  76. package/app/.next/server/chunks/_05c48915._.js +1 -1
  77. package/app/.next/server/chunks/_06515a8a._.js +1 -1
  78. package/app/.next/server/chunks/_2115d8de._.js +1 -1
  79. package/app/.next/server/chunks/_3ac953eb._.js +1 -1
  80. package/app/.next/server/chunks/_4b8fd853._.js +1 -1
  81. package/app/.next/server/chunks/_68683848._.js +1 -1
  82. package/app/.next/server/chunks/_7badaddf._.js +2 -2
  83. package/app/.next/server/chunks/_ee9b677b._.js +1 -1
  84. package/app/.next/server/chunks/open-sse_config_providerModels_ts_04541468._.js +1 -1
  85. package/app/.next/server/chunks/open-sse_config_providerRegistry_ts_2f74ec2a._.js +1 -1
  86. package/app/.next/server/chunks/open-sse_config_providerRegistry_ts_dec0f840._.js +1 -1
  87. package/app/.next/server/chunks/open-sse_executors_01c3e95e._.js +1 -1
  88. package/app/.next/server/chunks/open-sse_executors_codex_ts_6d18ec4b._.js +1 -1
  89. package/app/.next/server/chunks/ssr/[root-of-the-server]__9ef96d20._.js +1 -1
  90. package/app/.next/server/chunks/ssr/[root-of-the-server]__a6942102._.js +1 -1
  91. package/app/.next/server/chunks/ssr/_19b3d5b1._.js +1 -1
  92. package/app/.next/server/chunks/ssr/_31f623fe._.js +1 -1
  93. package/app/.next/server/chunks/ssr/open-sse_config_providerModels_ts_4cac55e2._.js +1 -1
  94. package/app/.next/server/pages/500.html +2 -2
  95. package/app/.next/server/server-reference-manifest.js +1 -1
  96. package/app/.next/server/server-reference-manifest.json +1 -1
  97. package/app/.next/static/chunks/{c7acff0f25f46281.js → 7c68da7fb645b441.js} +1 -1
  98. package/app/.next/static/chunks/{aa0bfbc0b2eb7658.js → 93854a469fd935c2.js} +1 -1
  99. package/app/.next/static/chunks/{5a0cb6640589f4fa.js → af07e5bb4e2fd5ef.js} +1 -1
  100. package/app/CHANGELOG.md +24 -0
  101. package/app/docs/openapi.yaml +1 -1
  102. package/app/open-sse/config/providerRegistry.ts +2 -1
  103. package/app/open-sse/executors/codex.ts +5 -0
  104. package/app/open-sse/handlers/chatCore.ts +35 -13
  105. package/app/open-sse/package.json +1 -1
  106. package/app/package-lock.json +3 -3
  107. package/app/package.json +1 -1
  108. package/app/src/shared/components/OAuthModal.tsx +6 -1
  109. package/app/src/shared/services/cliRuntime.ts +7 -3
  110. package/app/tests/unit/cli-runtime-detection.test.mjs +15 -6
  111. package/app/tests/unit/t28-model-catalog-updates.test.mjs +2 -2
  112. package/package.json +1 -1
  113. /package/app/.next/static/{JHXiVG41z1UrA7MsRLXGd → wq1Ii1uhsKllCHQoeqLBt}/_buildManifest.js +0 -0
  114. /package/app/.next/static/{JHXiVG41z1UrA7MsRLXGd → wq1Ii1uhsKllCHQoeqLBt}/_clientMiddlewareManifest.json +0 -0
  115. /package/app/.next/static/{JHXiVG41z1UrA7MsRLXGd → wq1Ii1uhsKllCHQoeqLBt}/_ssgManifest.js +0 -0
package/app/CHANGELOG.md CHANGED
@@ -4,6 +4,30 @@
4
4
 
5
5
  ---
6
6
 
7
+ ## [3.3.11] - 2026-03-31
8
+
9
+ ### 🚀 Features
10
+
11
+ - **Subscription Utilization Analytics:** Added quota snapshot time-series tracking, Provider Utilization and Combo Health tabs with recharts visualizations, and corresponding API endpoints (#847)
12
+ - **SQLite Backup Control:** New `OMNIROUTE_DISABLE_AUTO_BACKUP` env flag to disable automatic SQLite backups (#846)
13
+ - **Model Registry Update:** Injected `gpt-5.4-mini` into the Codex provider's array of models (#756)
14
+ - **Provider Limit Tracking:** Track and display when provider rate limits were last refreshed per account (#843)
15
+
16
+ ### 🐛 Bug Fixes
17
+
18
+ - **Qwen Auth Routing:** Re-routed Qwen OAuth completions from the DashScope API to the Web Inference API (`chat.qwen.ai`), resolving authorization failures (#844, #807, #832)
19
+ - **Qwen Auto-Retry Loop:** Added targeted 429 Quota Exceeded backoff handling inside `chatCore` protecting burst requests
20
+ - **Codex OAuth Fallback:** Modern browser popup blocking no longer traps the user; it automatically falls back to manual URL entry (#808)
21
+ - **Claude Token Refresh:** Anthropic's strict `application/json` boundaries are now respected during token generation instead of encoded URLs (#836)
22
+ - **Codex Messages Schema:** Stripped purist `messages` injects from native passthrough requests to avoid structural rejections from the ChatGPT upstream (#806)
23
+ - **CLI Detection Size Limit:** Safely bumped the Node binary scanning upper bound from 100MB to 350MB, allowing heavy standalone tools like Claude Code (229MB) and OpenCode (153MB) to be correctly detected by the VPS runtime (#809)
24
+ - **CLI Runtime Environment:** Restored ability for CLI configurations to respect user override paths (`CLI_{PROVIDER}_BIN`) bypassing strict path-bound discovery rules
25
+ - **Nvidia Header Conflicts:** Removed `prompt_cache_key` properties from upstream headers when calling non-Anthropic providers (#848)
26
+ - **Codex Fast Tier Toggle:** Restored Codex service tier toggle contrast in light mode (#842)
27
+ - **Test Infrastructure:** Updated `t28-model-catalog-updates` test that incorrectly expected the outdated DashScope endpoint for the Qwen native registry
28
+
29
+ ---
30
+
7
31
  ## [3.3.9] - 2026-03-31
8
32
 
9
33
  ### 🐛 Bug Fixes
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: OmniRoute API
4
- version: 3.3.10
4
+ version: 3.3.11
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,
@@ -264,6 +264,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
264
264
  },
265
265
  models: [
266
266
  { id: "gpt-5.4", name: "GPT 5.4" },
267
+ { id: "gpt-5.4-mini", name: "GPT 5.4 Mini" },
267
268
  { id: "gpt-5.3-codex", name: "GPT 5.3 Codex" },
268
269
  { id: "gpt-5.3-codex-xhigh", name: "GPT 5.3 Codex (xHigh)" },
269
270
  { id: "gpt-5.3-codex-high", name: "GPT 5.3 Codex (High)" },
@@ -286,7 +287,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
286
287
  alias: "qw",
287
288
  format: "openai",
288
289
  executor: "default",
289
- baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions",
290
+ baseUrl: "https://chat.qwen.ai/api/v1/services/aigc/text-generation/generation",
290
291
  authType: "oauth",
291
292
  authHeader: "bearer",
292
293
  headers: {
@@ -270,6 +270,11 @@ export class CodexExecutor extends BaseExecutor {
270
270
  // Ensure store is false (Codex requirement)
271
271
  body.store = false;
272
272
 
273
+ // Issue #806: Even for native passthrough, some clients (purist completions) might indiscriminately inject
274
+ // a `messages` or `prompt` array which the strict Codex Responses schema rejects.
275
+ delete body.messages;
276
+ delete body.prompt;
277
+
273
278
  if (nativeCodexPassthrough) {
274
279
  return body;
275
280
  }
@@ -959,7 +959,8 @@ export async function handleChatCore({
959
959
  if (
960
960
  targetFormat === FORMATS.OPENAI &&
961
961
  !bodyToSend.prompt_cache_key &&
962
- Array.isArray(bodyToSend.messages)
962
+ Array.isArray(bodyToSend.messages) &&
963
+ !["nvidia", "codex", "xai"].includes(provider)
963
964
  ) {
964
965
  const { generatePromptCacheKey } = await import("@/lib/promptCache");
965
966
  const cacheKey = generatePromptCacheKey(bodyToSend.messages);
@@ -968,18 +969,39 @@ export async function handleChatCore({
968
969
  }
969
970
  }
970
971
 
971
- const rawResult = await withRateLimit(provider, connectionId, modelToCall, () =>
972
- executor.execute({
973
- model: modelToCall,
974
- body: bodyToSend,
975
- stream,
976
- credentials: getExecutionCredentials(),
977
- signal: streamController.signal,
978
- log,
979
- extendedContext,
980
- upstreamExtraHeaders: buildUpstreamHeadersForExecute(modelToCall),
981
- })
982
- );
972
+ const rawResult = await withRateLimit(provider, connectionId, modelToCall, async () => {
973
+ let attempts = 0;
974
+ const maxAttempts = provider === "qwen" ? 3 : 1;
975
+
976
+ while (attempts < maxAttempts) {
977
+ const res = await executor.execute({
978
+ model: modelToCall,
979
+ body: bodyToSend,
980
+ stream,
981
+ credentials: getExecutionCredentials(),
982
+ signal: streamController.signal,
983
+ log,
984
+ extendedContext,
985
+ upstreamExtraHeaders: buildUpstreamHeadersForExecute(modelToCall),
986
+ });
987
+
988
+ // Qwen 429 strict quota backoff (wait 1.5s, 3s and retry)
989
+ if (provider === "qwen" && res.response.status === 429 && attempts < maxAttempts - 1) {
990
+ const bodyPeek = await res.response
991
+ .clone()
992
+ .text()
993
+ .catch(() => "");
994
+ if (bodyPeek.toLowerCase().includes("exceeded your current quota")) {
995
+ const delay = 1500 * (attempts + 1);
996
+ log?.warn?.("QWEN_RETRY", `Quota 429 hit. Retrying in ${delay}ms...`);
997
+ await new Promise((r) => setTimeout(r, delay));
998
+ attempts++;
999
+ continue;
1000
+ }
1001
+ }
1002
+ return res;
1003
+ }
1004
+ });
983
1005
 
984
1006
  if (stream) return rawResult;
985
1007
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omniroute/open-sse",
3
- "version": "3.3.9",
3
+ "version": "3.3.11",
4
4
  "description": "Express SSE sidecar for OmniRoute — handles streaming, protocol translation, and provider orchestration",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omniroute",
3
- "version": "3.3.10",
3
+ "version": "3.3.11",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omniroute",
9
- "version": "3.3.10",
9
+ "version": "3.3.11",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "workspaces": [
@@ -20325,7 +20325,7 @@
20325
20325
  },
20326
20326
  "open-sse": {
20327
20327
  "name": "@omniroute/open-sse",
20328
- "version": "3.3.9"
20328
+ "version": "3.3.11"
20329
20329
  }
20330
20330
  }
20331
20331
  }
package/app/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omniroute",
3
- "version": "3.3.10",
3
+ "version": "3.3.11",
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": {
@@ -225,7 +225,12 @@ export default function OAuthModal({
225
225
 
226
226
  setAuthData({ ...serverData, redirectUri: serverData.redirectUri });
227
227
  setStep("waiting");
228
- window.open(serverData.authUrl, "oauth_auth");
228
+ popupRef.current = window.open(serverData.authUrl, "oauth_auth");
229
+
230
+ // If browser blocked the popup, switch to manual input step immediately
231
+ if (!popupRef.current) {
232
+ setStep("input");
233
+ }
229
234
 
230
235
  setPolling(true);
231
236
  const maxAttempts = 150;
@@ -591,10 +591,11 @@ const checkKnownPath = async (commandPath: string) => {
591
591
  return { installed: false, commandPath: null, reason: "not_file" };
592
592
  }
593
593
 
594
- // CLI binaries should be > 30 bytes and < 100MB
594
+ // CLI binaries should be > 30 bytes and < 350MB
595
595
  // npm .cmd wrappers on Windows are ~300-500 bytes, JS wrappers on Linux can be ~44 bytes
596
596
  // Minimum catches empty/suspicious files while allowing legitimate thin wrappers
597
- if (stat.size < 30 || stat.size > 100 * 1024 * 1024) {
597
+ // Many modern CLIs (like Claude Code and OpenCode) build as single ~150-250MB binaries
598
+ if (stat.size < 30 || stat.size > 350 * 1024 * 1024) {
598
599
  return { installed: false, commandPath: null, reason: "suspicious_size" };
599
600
  }
600
601
  } catch (error) {
@@ -787,7 +788,10 @@ export const getCliRuntimeStatus = async (toolId: string) => {
787
788
  };
788
789
  }
789
790
 
790
- const located = await locateCommandCandidate(commands, env, toolId);
791
+ const envCommand = String(process.env[tool.envBinKey] || "").trim();
792
+ const hasEnvOverride = !!envCommand;
793
+
794
+ const located = await locateCommandCandidate(commands, env, hasEnvOverride ? undefined : toolId);
791
795
  const command = located.command;
792
796
 
793
797
  if (!located.installed) {
@@ -15,7 +15,11 @@ const { getCliRuntimeStatus, CLI_TOOL_IDS } =
15
15
  // ─── Helpers ──────────────────────────────────────────────────
16
16
 
17
17
  function createTempDir() {
18
- return fs.mkdtempSync(path.join(os.tmpdir(), "cli-test-"));
18
+ const testRoot = path.join(os.homedir(), ".omniroute-test-tmp");
19
+ if (!fs.existsSync(testRoot)) {
20
+ fs.mkdirSync(testRoot, { recursive: true });
21
+ }
22
+ return fs.mkdtempSync(path.join(testRoot, "cli-test-"));
19
23
  }
20
24
 
21
25
  function createFile(dir, name, content) {
@@ -64,11 +68,11 @@ describe("Size threshold — checkKnownPath", () => {
64
68
 
65
69
  it("should detect files >= 30 bytes via env var", async () => {
66
70
  const prev = process.env.CLI_DROID_BIN;
67
- // Create a valid 30-byte+ script
71
+ // Create a valid 30-byte+ script (using spaces/comments for padding, NO \r on linux)
68
72
  const content =
69
73
  process.platform === "win32"
70
- ? "@echo off\r\necho 1.0.0\r\nexit 0\r\n"
71
- : "#!/bin/sh\r\necho 1.0.0\r\nexit 0\r\n";
74
+ ? "@echo off\r\necho 1.0.0\r\nREM PADDING_PADDIN\r\nexit 0\r\n"
75
+ : "#!/bin/sh\necho 1.0.0\n# PADDING_PADDING_PAD\nexit 0\n";
72
76
  const script = createFile(tmpDir, "droid-valid", content);
73
77
  // Verify it's at least 30 bytes
74
78
  const stat = fs.statSync(script);
@@ -87,10 +91,15 @@ describe("Size threshold — checkKnownPath", () => {
87
91
 
88
92
  it("should detect a valid CLI script (>= 30 bytes) via env var", async () => {
89
93
  const prev = process.env.CLI_DROID_BIN;
94
+ // Ensure the size stays > 30 bytes without \r\n on bash
95
+ const content =
96
+ process.platform === "win32"
97
+ ? "@echo off\r\necho 1.0.0\r\nREM PADDING_PAD\r\n"
98
+ : "#!/bin/sh\necho 1.0.0\n# PADDING_PADDING_PAD\n";
90
99
  const script =
91
100
  process.platform === "win32"
92
- ? createFile(tmpDir, "droid.cmd", "@echo off\necho 1.0.0\n")
93
- : createFile(tmpDir, "droid", "#!/bin/sh\necho 1.0.0\n");
101
+ ? createFile(tmpDir, "droid.cmd", content)
102
+ : createFile(tmpDir, "droid", content);
94
103
 
95
104
  process.env.CLI_DROID_BIN = script;
96
105
  try {
@@ -22,10 +22,10 @@ test("T28: antigravity static catalog includes Gemini 3.1 preview fallbacks", ()
22
22
  assert.ok(staticIds.includes("gemini-3.1-flash-lite-preview"));
23
23
  });
24
24
 
25
- test("T28: qwen registry uses DashScope-compatible base URL", () => {
25
+ test("T28: qwen registry uses native chat.qwen.ai base URL", () => {
26
26
  assert.equal(
27
27
  REGISTRY.qwen.baseUrl,
28
- "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions"
28
+ "https://chat.qwen.ai/api/v1/services/aigc/text-generation/generation"
29
29
  );
30
30
  });
31
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omniroute",
3
- "version": "3.3.10",
3
+ "version": "3.3.11",
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": {