From c900bbb67a3b875052dfa465c1559b63ee42f9cf Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Sat, 4 Jul 2026 00:37:10 -0300 Subject: [PATCH] fix(providers): strip thinking param for minimax-m2.7 on NVIDIA NIM (#6102) Strip unsupported thinking param for minimax-m2.7 on NVIDIA NIM. Integrated into release/v3.8.44. --- CHANGELOG.md | 2 + open-sse/translator/paramSupport.ts | 4 ++ .../nvidia-minimax-thinking-strip.test.ts | 52 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 tests/unit/nvidia-minimax-thinking-strip.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 88471b5b6d..20339a8a0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ ### 🔧 Bug Fixes +- **fix(providers):** disable the unsupported `thinking` param for `minimax-m2.7` on NVIDIA NIM (the upstream rejects it). Regression guard: `tests/unit/nvidia-minimax-thinking-strip.test.ts`. (thanks @anki1kr) + - **fix(mitm):** add an in-process guard so concurrent MITM server starts no longer race — a second start while one is already in flight is short-circuited instead of double-binding the listener. Regression guard: `tests/unit/mitm-start-guard.test.ts`. (thanks @anki1kr) - **translator (Responses → Chat Completions):** strip the Responses-API-only `truncation` field before forwarding a `/v1/responses` request to a non-OpenAI Chat Completions upstream. Strict upstreams (e.g. NVIDIA NIM) rejected it with HTTP 400 `Unsupported parameter(s): truncation`, breaking Codex-style clients routed to those providers. `client_metadata`, `background`, and `safety_identifier` were already stripped — `truncation` was the remaining gap. Regression guard: `tests/unit/responses-strip-truncation-2311.test.ts`. (thanks @TuanNguyen0708) diff --git a/open-sse/translator/paramSupport.ts b/open-sse/translator/paramSupport.ts index 142f5528bb..08e0e807a4 100644 --- a/open-sse/translator/paramSupport.ts +++ b/open-sse/translator/paramSupport.ts @@ -29,6 +29,10 @@ const STRIP_RULES: StripRule[] = [ /claude/i.test(m) && !/claude.*(opus|sonnet).*4\.6/i.test(m), drop: ["thinking", "reasoning_effort"], }, + // NVIDIA NIM minimaxai/minimax-m2.7: NVIDIA's OpenAI-compatible wrapper + // (format:"openai") does not accept the Claude-style `thinking` body field + // and returns 400 "Unsupported parameter(s): thinking". Upstream #2268. + { provider: "nvidia", match: /minimax-m2\.7/i, drop: ["thinking"] }, ]; function matches(rule: StripRule, model: string): boolean { diff --git a/tests/unit/nvidia-minimax-thinking-strip.test.ts b/tests/unit/nvidia-minimax-thinking-strip.test.ts new file mode 100644 index 0000000000..4c67616f39 --- /dev/null +++ b/tests/unit/nvidia-minimax-thinking-strip.test.ts @@ -0,0 +1,52 @@ +// Regression guard: NVIDIA NIM's OpenAI-compatible wrapper (format:"openai") +// does not accept the Claude-style `thinking` body field for +// minimaxai/minimax-m2.7 and returns 400 "Unsupported parameter(s): thinking". +// Upstream #2268 / 9router#2323. +// +// Fix: paramSupport.ts STRIP_RULES drops `thinking` for provider "nvidia" + +// model matching /minimax-m2\.7/i before the request reaches the executor. + +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { stripUnsupportedParams } from "../../open-sse/translator/paramSupport.ts"; + +test("stripUnsupportedParams: nvidia + minimaxai/minimax-m2.7 drops thinking", () => { + const body: Record = { + model: "minimaxai/minimax-m2.7", + thinking: { type: "adaptive" }, + max_tokens: 512, + temperature: 0.7, + }; + stripUnsupportedParams("nvidia", "minimaxai/minimax-m2.7", body); + assert.equal(body.thinking, undefined, "thinking must be stripped for NVIDIA minimax-m2.7"); + assert.equal(body.max_tokens, 512, "other params must survive"); + assert.equal(body.temperature, 0.7, "other params must survive"); + assert.equal(body.model, "minimaxai/minimax-m2.7", "model must not be touched"); +}); + +test("stripUnsupportedParams: nvidia + other model KEEPS thinking (regression guard)", () => { + const body: Record = { thinking: { type: "adaptive" } }; + stripUnsupportedParams("nvidia", "some-other-model", body); + assert.deepEqual( + body.thinking, + { type: "adaptive" }, + "unrelated NVIDIA-hosted models must not be affected" + ); +}); + +test("stripUnsupportedParams: non-nvidia provider KEEPS thinking for minimax-m2.7", () => { + const body: Record = { thinking: { type: "adaptive" } }; + stripUnsupportedParams("minimax", "minimax-m2.7", body); + assert.deepEqual( + body.thinking, + { type: "adaptive" }, + "direct MiniMax API still supports the native thinking field" + ); +}); + +test("stripUnsupportedParams: nvidia + minimax-m2.7 without thinking present is a no-op", () => { + const body: Record = { max_tokens: 100 }; + stripUnsupportedParams("nvidia", "minimaxai/minimax-m2.7", body); + assert.equal(body.max_tokens, 100); + assert.equal("thinking" in body, false); +});