- fix(translator): preserve prompt_cache_key in Responses API translation (#517)
- fix(combo): escape \n in tagContent for valid JSON injection (#515)
- fix(usage): sync expired token status back to DB on live auth failure (#491)
- chore: bump version to 2.9.4 in package.json + docs/openapi.yaml
- docs: update CHANGELOG.md with v2.9.4 release notes
fix(translator): preserve prompt_cache_key when translating Responses API requests
(#517) — prompt_cache_key is an account-affinity signal used by Codex for
prompt cache routing. Deleting it from the translated request prevented full
cache effectiveness. Removed delete from openai-responses.ts and
responsesApiHelper.ts cleanup blocks.
fix(combo): escape \n in tagContent so injected JSON string is valid (#515)
— omniModel tag content used template literal newlines (U+000A) which produce
unescaped newline chars inside a JSON string value. Replaced with literal \n
escape sequences for valid JSON injection in streaming SSE content chunks.
- Version bumped from 2.9.2 → 2.9.3 in package.json + docs/openapi.yaml
- CHANGELOG.md updated with full release notes for 2.9.3
(5 new free providers, 2 metadata updates, 2 custom executors, docs)
upstreamErrorResponse() now guards against parsed.error being an
object (e.g. ElevenLabs { error: { message, status_code } }) instead
of blindly using it as the error message string.
Both audioSpeech.ts and audioTranscription.ts fixed.
- Add resolveAudioContentType() to map video/* MIME to audio/* (fixes .mp4 uploads returning 'no speech detected')
- Add detect_language=true for Deepgram auto-language detection (fixes non-English audio)
- Add punctuate=true for better output quality
- Forward language form param to Deepgram when provided
- Apply same Content-Type fix to HuggingFace handler
The truthy check treated false as falsy and deleted the property, preventing users from explicitly disabling normalization for a specific protocol when the top-level flag was true. Now stores both true and false values, consistent with preserveOpenAIDeveloperRole handling.
Made-with: Cursor
The word 'any' in a JSDoc comment was matched by the regex-based t11 checker. Reworded to 'prefixes' to eliminate the false positive.
Made-with: Cursor
Rewrite getMachineIdRaw() to use a try/catch waterfall instead of
process.platform conditionals. Next.js SWC bundler evaluates
process.platform at BUILD time, so when built on Linux, the win32
branch was dead-code-eliminated — causing 'head is not recognized'
errors on Windows.
New approach:
1. Try Windows REG.exe (existsSync check, not platform check)
2. Try macOS ioreg command
3. Try reading /etc/machine-id directly (no head/pipe)
4. Try hostname command
5. Fallback to os.hostname()
Also eliminates the patch-machine-id.cjs post-install workaround.
- #493: Fix custom provider model naming — removed incorrect prefix
stripping in DefaultExecutor.transformRequest() that broke org-scoped
model IDs like 'zai-org/GLM-5-FP8'
- #490: Enable context cache protection for streaming responses using
TransformStream to inject omniModel tag as final SSE content delta
before [DONE] marker
- #452: Add per-API-key request-count limits (max_requests_per_day,
max_requests_per_minute) with in-memory sliding window counter,
schema auto-migration, and Check 5 in enforceApiKeyPolicy()
- Replace execSync template string with execFileSync + args array on Windows
to prevent command injection via SystemRoot/windir environment variables
- Add optional chaining (?.) and nullish coalescing (?? "") on Windows
REG_SZ output parsing to prevent crash if REG.exe output is unexpected
- Add optional chaining on macOS IOPlatformUUID parsing for the same reason
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace 'any other path' with 'all other paths' in translator comment to avoid false match by the \bany\b regex in check-t11-any-budget
- Scope e2e error locator to dialog and use .first() to prevent Playwright strict-mode violations from broad page-level selectors
- Fix fallback logic: treat dialog-still-open as validation success signal
Made-with: Cursor
- Use globalThis singleton guards for DB connection, HealthCheck timers, console interceptor, and graceful shutdown to survive Webpack HMR re-evaluation (fixes 485+ leaked DB connections per session)
- Split instrumentation.ts into instrumentation-node.ts with computed import path to prevent Turbopack Edge bundler from tracing Node.js modules (eliminates 10+ spurious warnings per hot compile)
- Parallelize startup imports in instrumentation-node.ts (3 batch Promise.all instead of 9 serial awaits)
- Add OMNIROUTE_USE_TURBOPACK=1 env switch in run-next.mjs (default behavior unchanged)
- Replace node:crypto with crypto in proxies.ts and errorResponse.ts to fix UnhandledSchemeError
- Add unlinkFileWithRetry with EBUSY/EPERM retry for Windows file handle timing in backup restore
- Fix pre-restore backup to await completion before closing DB
- Fix bootstrap-env, domain-persistence, and fixes-p1 test stability on Windows
Made-with: Cursor
Problem:
node-machine-id constructs the REG.exe command path at module load time
using process.platform. When Next.js bundles this module, process.platform
is "" (not "win32") in the webpack/build context, so the lookup returns
undefined and bakes "undefined\REG.exe ..." permanently into the compiled
chunk. At runtime on Windows this causes:
Error: Command failed: undefined\REG.exe QUERY HKEY_LOCAL_MACHINE\...
The system cannot find the path specified.
Fix:
Remove the node-machine-id dependency from machineId.ts and replace it
with a direct execSync implementation that resolves process.env.SystemRoot
at call time (not load time), so the correct Windows path is always used
regardless of when or how the module was bundled.
Platform support is preserved for Windows, macOS, and Linux/FreeBSD using
the same underlying OS queries that node-machine-id used internally.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>