diff --git a/CHANGELOG.md b/CHANGELOG.md index 47612e09bb..fdd82d2ee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,30 @@ --- +## [2.8.5] — 2026-03-19 + +> Sprint: Fix zombie SSE streams, context cache first-turn, KIRO MITM, and triage 5 external issues. + +### Bug Fixes + +- **Zombie SSE Streams** (#473): Reduce `STREAM_IDLE_TIMEOUT_MS` from 300s → 120s for faster combo fallback when providers hang mid-stream. Configurable via env var. +- **Context Cache Tag** (#474): Fix `injectModelTag()` to handle first-turn requests (no assistant messages) — context cache protection now works from the very first response. +- **KIRO MITM** (#481): Change KIRO `configType` from `guide` → `mitm` so the dashboard renders MITM Start/Stop controls. +- **E2E Test** (CI): Fix `providers-bailian-coding-plan.spec.ts` — dismiss pre-existing modal overlay before clicking Add API Key button. + +### Closed Issues + +- #473 — Zombie SSE streams bypass combo fallback +- #474 — Context cache `` tag missing on first turn +- #481 — MITM for KIRO not activatable from dashboard +- #468 — Gemini CLI remote server (superseded by #462 deprecation) +- #438 — Claude unable to write files (external CLI issue) +- #439 — AppImage doesn't work (documented libfuse2 workaround) +- #402 — ARM64 DMG "damaged" (documented xattr -cr workaround) +- #460 — CLI not runnable on Windows (documented PATH fix) + +--- + ## [2.8.4] — 2026-03-19 > Sprint: Gemini CLI deprecation, VM guide i18n fix, dependabot security fix, provider schema expansion. diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 3f313ef4f7..70094e1f5e 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: OmniRoute API - version: 2.8.4 + version: 2.8.5 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/config/constants.ts b/open-sse/config/constants.ts index 9b4aeaf720..bd63f5ca3e 100644 --- a/open-sse/config/constants.ts +++ b/open-sse/config/constants.ts @@ -4,9 +4,9 @@ import { loadProviderCredentials } from "./credentialLoader.ts"; export const FETCH_TIMEOUT_MS = parseInt(process.env.FETCH_TIMEOUT_MS || "120000", 10); // Idle timeout for SSE streams (ms). Closes stream if no data for this duration. -// Default: 300s to support extended-thinking models (claude-opus-4-6, o3, etc.) -// that may pause for >60s during deep reasoning phases. Override with STREAM_IDLE_TIMEOUT_MS env var. -export const STREAM_IDLE_TIMEOUT_MS = parseInt(process.env.STREAM_IDLE_TIMEOUT_MS || "300000", 10); +// Default: 120s balances deep-reasoning pauses with fast zombie stream detection (#473). +// Extended-thinking models rarely pause >90s between chunks. Override with STREAM_IDLE_TIMEOUT_MS env var. +export const STREAM_IDLE_TIMEOUT_MS = parseInt(process.env.STREAM_IDLE_TIMEOUT_MS || "120000", 10); // Provider configurations // OAuth credentials read from env vars with hardcoded fallbacks for backward compatibility. diff --git a/open-sse/services/comboAgentMiddleware.ts b/open-sse/services/comboAgentMiddleware.ts index 7017599528..02333cb145 100644 --- a/open-sse/services/comboAgentMiddleware.ts +++ b/open-sse/services/comboAgentMiddleware.ts @@ -52,7 +52,15 @@ export function injectModelTag(messages: Message[], providerModel: string): Mess // Find last assistant message with string content const lastAssistantIdx = cleaned.map((m) => m.role).lastIndexOf("assistant"); - if (lastAssistantIdx === -1) return cleaned; + + // #474: If no assistant message exists yet (first turn), append a synthetic one + // so the tag is present when the client sends the next request with the response. + if (lastAssistantIdx === -1) { + return [ + ...cleaned, + { role: "assistant", content: `\n${providerModel}` }, + ]; + } const msg = cleaned[lastAssistantIdx]; if (typeof msg.content !== "string") return cleaned; diff --git a/package-lock.json b/package-lock.json index 2e8c06229c..21e1b69a02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "2.8.4", + "version": "2.8.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "2.8.4", + "version": "2.8.5", "hasInstallScript": true, "license": "MIT", "workspaces": [ diff --git a/package.json b/package.json index 9e04019aca..2ce552b6ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "2.8.4", + "version": "2.8.5", "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/shared/constants/cliTools.ts b/src/shared/constants/cliTools.ts index f66d7ea8bd..026b5692bb 100644 --- a/src/shared/constants/cliTools.ts +++ b/src/shared/constants/cliTools.ts @@ -193,8 +193,8 @@ export const CLI_TOOLS = { image: "/providers/kiro.png", icon: "psychology_alt", color: "#FF6B35", - description: "Amazon Kiro — AI-powered IDE", - configType: "guide", + description: "Amazon Kiro — AI-powered IDE with MITM", + configType: "mitm", guideSteps: [ { step: 1, title: "Open Kiro Settings", desc: "Go to Settings → AI Provider" }, { step: 2, title: "Base URL", value: "{{baseUrl}}", copyable: true },