diff --git a/open-sse/translator/concerns/paramSupport.js b/open-sse/translator/concerns/paramSupport.js index dc030194..e165c949 100644 --- a/open-sse/translator/concerns/paramSupport.js +++ b/open-sse/translator/concerns/paramSupport.js @@ -1,3 +1,5 @@ +import { getCapabilitiesForModel } from "../../providers/capabilities.js"; + // Strip request params a given provider/model rejects upstream (e.g. HTTP 400). // Config-driven: add a rule instead of scattering `delete body.x` across executors. @@ -12,6 +14,7 @@ const STRIP_RULES = [ { provider: "github", match: (m) => /claude/i.test(m) && !/claude.*(opus|sonnet).*4\.6/i.test(m), drop: ["thinking", "reasoning_effort"] }, // Cloudflare Workers AI: content must be plain string, rejects OpenAI content-part array (#1926) { provider: "cloudflare-ai", flattenContent: true }, + { provider: "volcengine-ark", match: /glm-5/i, clampToModelMaxOutput: true }, ]; // Test a rule's match (regex or predicate) against the model id. @@ -20,6 +23,12 @@ function matches(rule, model) { return typeof rule.match === "function" ? rule.match(model) : rule.match.test(model); } +function clampNumber(body, key, ceiling) { + if (typeof body[key] === "number" && Number.isFinite(body[key]) && body[key] > ceiling) { + body[key] = ceiling; + } +} + // Remove unsupported params from body in place; returns body. export function stripUnsupportedParams(provider, model, body) { if (!model || !body || typeof body !== "object") return body; @@ -39,6 +48,14 @@ export function stripUnsupportedParams(provider, model, body) { } } } + if (rule.clampToModelMaxOutput) { + const ceiling = getCapabilitiesForModel(provider, model).maxOutput; + if (Number.isFinite(ceiling) && ceiling > 0) { + clampNumber(body, "max_tokens", ceiling); + clampNumber(body, "max_completion_tokens", ceiling); + clampNumber(body, "max_output_tokens", ceiling); + } + } } return body; } diff --git a/tests/unit/param-support.test.js b/tests/unit/param-support.test.js index 205a5fe2..c54d132b 100644 --- a/tests/unit/param-support.test.js +++ b/tests/unit/param-support.test.js @@ -28,4 +28,28 @@ describe("stripUnsupportedParams", () => { expect(body).toEqual({ top_p: 1 }); }); + + it("clamps VolcEngine Ark GLM max token fields to the model output ceiling", () => { + const body = { + max_tokens: 131072, + max_completion_tokens: 131072, + max_output_tokens: 131072, + }; + + stripUnsupportedParams("volcengine-ark", "GLM-5.2", body); + + expect(body).toEqual({ + max_tokens: 128000, + max_completion_tokens: 128000, + max_output_tokens: 128000, + }); + }); + + it("keeps VolcEngine Ark GLM max tokens when already under the ceiling", () => { + const body = { max_tokens: 64000 }; + + stripUnsupportedParams("volcengine-ark", "GLM-5.2", body); + + expect(body.max_tokens).toBe(64000); + }); });