mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 20:32:20 +03:00
* fix(sse): sanitize empty-signature thinking blocks + hoist strict-provider system messages (#6953, #7293) #6953: prepareClaudeRequest's "preserve latest-assistant thinking verbatim" guard (claudeHelper.ts, anti-400 for legitimate Anthropic replay) did not distinguish a genuine Claude signature from an empty one fabricated by a non-Anthropic leg (e.g. codex reasoning_content). It forwarded signature:"" verbatim to Anthropic, which always 400s ("Invalid signature in thinking block"), permanently locking combo routing onto the non-Anthropic leg. The response-side half of this bug (openai-to-claude.ts synthesizing the empty signature in the first place) was already fixed by #6982/PR#6982; this PR closes the remaining request-side half. Fix: the verbatim-preserve guard now requires every thinking-ish block on the latest assistant message to carry a non-empty signature/data; otherwise it falls through to the existing sanitization path (redacted_thinking + DEFAULT_THINKING_CLAUDE_SIGNATURE) already applied to older turns. #7293: translateRequest() is the single outbound choke point every chat request passes through, including same-format (OpenAI→OpenAI) passthrough where none of the format-specific translators run. systemMessageMustBeFirst() / PROVIDERS_SYSTEM_MUST_BE_FIRST (src/lib/memory/injection.ts, #6135/PR#6225) was only consulted by the memory injector, so a client-injected system message landing mid-array (OpenCode/Kilo Code style clients, Discussion #6129) reached strict providers (xiaomi-mimo) untouched and 400'd. Fix: a new helper (open-sse/translator/helpers/strictSystemHoist.ts) hoists every system message onto index 0 for strict providers, reusing systemMessageMustBeFirst() as the single source of truth, merging (never dropping) multiple offenders in original order, and no-op'ing (same array reference) for non-strict providers and already-compliant requests to preserve prompt-cache prefix stability. Both defects live in the same file cluster (openai-to-claude request-path translator + its helpers), hence one PR for both issues per triage guidance. Regression tests: - tests/unit/repro-6953.test.ts — RED (actual signature:'' forwarded) → GREEN - tests/unit/probe-7293-strict-system-hoist.test.ts — RED (system message left at index 10 of 70) → GREEN, plus multi-offender merge, existing-leading merge, non-strict-provider no-op, and already-compliant no-op cases. Gates run: file-size, complexity, cognitive-complexity (both at/under baseline), typecheck:core (clean), eslint on changed files (clean), test:vitest (254/254 green), plus all directly relevant existing suites (translator-claude-helper-thinking, translator-xiaomi-mimo-reasoning-replay, memory-system-first-6135, dashscope-cache-control-openai-2069, xiaomi-mimo-provider, role-normalizer, translation.golden, translators.property, translator-helper-branches, translator-claude-to-openai, translator-same-format-null-flush — all green). Closes #6953 Closes #7293 * chore(quality): prune the now-stale claudeHelper no-explicit-any suppression (#6953) The #6953 fix removed the single `any` that config/quality/eslint-suppressions.json still had frozen for open-sse/translator/helpers/claudeHelper.ts, so the entry became stale and ESLint's stale-suppression enforcement failed the 'No new ESLint warnings' gate — the gate went red because the code got better. Pruned that one entry only (never a global --prune-suppressions: other entries are other sessions' frozen debt).