diff --git a/CHANGELOG.md b/CHANGELOG.md index a6400e3eb6..ae6e0d53b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - **AGENTS.md rewrite:** Condensed from 297→153 lines. Added build/lint/test commands (including single-test execution), code style guidelines (Prettier, TypeScript, ESLint, naming, imports, error handling, security), and trimmed verbose architecture tables for AI agent consumption. -## [3.4.2] - 2026-04-01 +## [3.4.3] - 2026-04-01 ### ✨ New Features diff --git a/docs/openapi.yaml b/docs/openapi.yaml index f003be54a4..4f1fbee775 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: OmniRoute API - version: 3.4.2 + version: 3.4.3 description: | OmniRoute is a local-first AI API proxy router. It provides an OpenAI-compatible endpoint that routes requests to multiple AI providers with load balancing, diff --git a/open-sse/handlers/responseTranslator.ts b/open-sse/handlers/responseTranslator.ts index daa687b90a..1622653c69 100644 --- a/open-sse/handlers/responseTranslator.ts +++ b/open-sse/handlers/responseTranslator.ts @@ -429,15 +429,15 @@ function convertOpenAINonStreamingToClaude(openaiResponse: JsonRecord): JsonReco if (messageObj.content !== undefined && messageObj.content !== null) { hasTextOrReasoning = true; + const resolvedText = toString(messageObj.content); content.push({ type: "text", - text: toString(messageObj.content), + text: resolvedText === "" ? "(empty response)" : resolvedText, }); } else if (!hasTextOrReasoning) { - // Claude format expects a text block even before tool calls (or if empty) content.push({ type: "text", - text: "", + text: "(empty response)", }); } diff --git a/open-sse/services/tokenRefresh.ts b/open-sse/services/tokenRefresh.ts index c661326cb4..cb2f020e14 100644 --- a/open-sse/services/tokenRefresh.ts +++ b/open-sse/services/tokenRefresh.ts @@ -324,7 +324,7 @@ export async function refreshQwenToken(refreshToken, log) { }); return { - accessToken: tokens.id_token || tokens.access_token, + accessToken: tokens.access_token, refreshToken: tokens.refresh_token || refreshToken, expiresIn: tokens.expires_in, }; diff --git a/package-lock.json b/package-lock.json index 313ad45ec6..8e0e86e1d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "3.4.2", + "version": "3.4.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "3.4.2", + "version": "3.4.3", "hasInstallScript": true, "license": "MIT", "workspaces": [ @@ -3013,19 +3013,6 @@ "node": ">= 10" } }, - "node_modules/@noble/hashes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", - "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/package.json b/package.json index bc9963049e..a7296f56b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "3.4.2", + "version": "3.4.3", "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.", "type": "module", "bin": { @@ -116,7 +116,6 @@ "uuid": "^13.0.0", "wreq-js": "^2.0.1", "yazl": "^3.3.1", - "js-yaml": "^4.1.0", "zod": "^4.3.6", "zustand": "^5.0.10" }, diff --git a/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx b/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx index 8bf11c95d4..995d1e4493 100644 --- a/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx +++ b/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx @@ -203,6 +203,9 @@ export function parseQuotaData(provider, data) { case "antigravity": if (data.quotas) { Object.entries(data.quotas).forEach(([modelKey, quota]: [string, any]) => { + if (quota?.unlimited && (!quota?.total || quota.total <= 0)) { + return; + } normalizedQuotas.push( normalizeQuotaEntry(modelKey, quota, { modelKey: modelKey, diff --git a/src/lib/oauth/providers/qwen.ts b/src/lib/oauth/providers/qwen.ts index a400bdb2cb..0a31c09212 100644 --- a/src/lib/oauth/providers/qwen.ts +++ b/src/lib/oauth/providers/qwen.ts @@ -60,7 +60,7 @@ export const qwen = { } return { - accessToken: tokens.id_token || tokens.access_token, + accessToken: tokens.access_token, refreshToken: tokens.refresh_token, expiresIn: tokens.expires_in, idToken: tokens.id_token,