diff --git a/CHANGELOG.md b/CHANGELOG.md index b0dc2e2a35..6440883715 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ --- +## [3.0.8] — 2026-03-25 + +### 🐛 Bug Fixes + +- **Translation Failures for OpenAI-format Providers in Claude CLI (#632):** + - Handle `reasoning_details[]` array format from StepFun/OpenRouter — converts to `reasoning_content` + - Handle `reasoning` field alias from some providers → normalized to `reasoning_content` + - Cross-map usage field names: `input_tokens`↔`prompt_tokens`, `output_tokens`↔`completion_tokens` in `filterUsageForFormat` + - Fix `extractUsage` to accept both `input_tokens`/`output_tokens` and `prompt_tokens`/`completion_tokens` as valid usage fields + - Applied to both streaming (`sanitizeStreamingChunk`, `openai-to-claude.ts` translator) and non-streaming (`sanitizeMessage`) paths + +--- + ## [3.0.7] — 2026-03-25 ### 🐛 Bug Fixes diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 0e1b017f15..99a56165a2 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: OmniRoute API - version: 3.0.7 + version: 3.0.8 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/package-lock.json b/package-lock.json index 11bef9cfb6..228bbd53fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "3.0.7", + "version": "3.0.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "3.0.7", + "version": "3.0.8", "hasInstallScript": true, "license": "MIT", "workspaces": [ diff --git a/package.json b/package.json index 279dc83ece..6336177c42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "3.0.7", + "version": "3.0.8", "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": { diff --git a/src/lib/db/combos.ts b/src/lib/db/combos.ts index d477568076..fb2ca528fb 100644 --- a/src/lib/db/combos.ts +++ b/src/lib/db/combos.ts @@ -27,21 +27,21 @@ export async function getCombos() { .map((row) => JSON.parse(row)); } -export async function getComboById(id) { +export async function getComboById(id: string) { const db = getDbInstance(); const row = db.prepare("SELECT data FROM combos WHERE id = ?").get(id); const payload = getSerializedData(row); return payload ? JSON.parse(payload) : null; } -export async function getComboByName(name) { +export async function getComboByName(name: string) { const db = getDbInstance(); const row = db.prepare("SELECT data FROM combos WHERE name = ?").get(name); const payload = getSerializedData(row); return payload ? JSON.parse(payload) : null; } -export async function createCombo(data) { +export async function createCombo(data: JsonRecord) { const db = getDbInstance(); const now = new Date().toISOString(); @@ -63,7 +63,7 @@ export async function createCombo(data) { return combo; } -export async function updateCombo(id, data) { +export async function updateCombo(id: string, data: JsonRecord) { const db = getDbInstance(); const existing = db.prepare("SELECT data FROM combos WHERE id = ?").get(id); if (!existing) return null; @@ -84,7 +84,7 @@ export async function updateCombo(id, data) { return merged; } -export async function deleteCombo(id) { +export async function deleteCombo(id: string) { const db = getDbInstance(); const result = db.prepare("DELETE FROM combos WHERE id = ?").run(id); if (result.changes === 0) return false; diff --git a/src/lib/db/models.ts b/src/lib/db/models.ts index 8f8874760e..1f3650cbf3 100644 --- a/src/lib/db/models.ts +++ b/src/lib/db/models.ts @@ -247,7 +247,7 @@ export async function getModelAliases() { return result; } -export async function setModelAlias(alias, model) { +export async function setModelAlias(alias: string, model: unknown) { const db = getDbInstance(); db.prepare( "INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('modelAliases', ?, ?)" @@ -255,7 +255,7 @@ export async function setModelAlias(alias, model) { backupDbFile("pre-write"); } -export async function deleteModelAlias(alias) { +export async function deleteModelAlias(alias: string) { const db = getDbInstance(); db.prepare("DELETE FROM key_value WHERE namespace = 'modelAliases' AND key = ?").run(alias); backupDbFile("pre-write"); @@ -263,7 +263,7 @@ export async function deleteModelAlias(alias) { // ──────────────── MITM Alias ──────────────── -export async function getMitmAlias(toolName) { +export async function getMitmAlias(toolName?: string) { const db = getDbInstance(); if (toolName) { const row = db @@ -282,7 +282,7 @@ export async function getMitmAlias(toolName) { return result; } -export async function setMitmAliasAll(toolName, mappings) { +export async function setMitmAliasAll(toolName: string, mappings: unknown) { const db = getDbInstance(); db.prepare( "INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('mitmAlias', ?, ?)" @@ -292,7 +292,7 @@ export async function setMitmAliasAll(toolName, mappings) { // ──────────────── Custom Models ──────────────── -export async function getCustomModels(providerId) { +export async function getCustomModels(providerId?: string) { const db = getDbInstance(); if (providerId) { const row = db @@ -342,7 +342,7 @@ export async function addCustomModel( const value = getKeyValue(row).value; const models = value ? JSON.parse(value) : []; - const exists = models.find((m) => m.id === modelId); + const exists = models.find((m: JsonRecord) => m.id === modelId); if (exists) return exists; const model = { @@ -430,7 +430,7 @@ export async function replaceCustomModels( return merged; } -export async function removeCustomModel(providerId, modelId) { +export async function removeCustomModel(providerId: string, modelId: string) { const db = getDbInstance(); const row = db .prepare("SELECT value FROM key_value WHERE namespace = 'customModels' AND key = ?") @@ -441,7 +441,7 @@ export async function removeCustomModel(providerId, modelId) { if (!value) return false; const models = JSON.parse(value); const before = models.length; - const filtered = models.filter((m) => m.id !== modelId); + const filtered = models.filter((m: JsonRecord) => m.id !== modelId); if (filtered.length === before) return false; @@ -476,7 +476,7 @@ export async function updateCustomModel( if (!value) return null; const models = JSON.parse(value); - const index = models.findIndex((m) => m.id === modelId); + const index = models.findIndex((m: JsonRecord) => m.id === modelId); if (index === -1) return null; const current = models[index];