fix(ai): keep JSON mode when an endpoint rejects only reasoning_effort

An endpoint that does not know reasoning_effort answers with an unknown
parameter error, which the JSON-mode probe read as a refusal of
response_format and switched that base URL to plain prompts.
This commit is contained in:
Marc-André Bombeck committed 2026-10-04 10:48:35 +02:00
1 parent 39a5862d54
commit a0fa4783c0
2 files changed
+46 -1

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
import { describe, expect, it } from "vitest";
import { isResponseFormatRejection } from "../json-dialect";
describe("isResponseFormatRejection", () => {
it("reads a complaint about response_format as a JSON-mode rejection", () => {
expect(
isResponseFormatRejection(400, "Unsupported value: 'response_format'"),
).toBe(true);
expect(isResponseFormatRejection(422, "unknown parameter")).toBe(true);
});
it("does not read a complaint about reasoning_effort as one", () => {
expect(
isResponseFormatRejection(
400,
"Unrecognized request argument supplied: reasoning_effort",
),
).toBe(false);
expect(
isResponseFormatRejection(400, "unknown field `reasoning effort`"),
).toBe(false);
});
it("still flips when both fields are named", () => {
expect(
isResponseFormatRejection(
400,
"unknown parameters: response_format, reasoning_effort",
),
).toBe(true);
});
it("ignores server errors", () => {
expect(isResponseFormatRejection(500, "response_format")).toBe(false);
});
});
+9 -1
View File
@@ -56,13 +56,21 @@ export function resetJsonModeDialectCache(): void {
/**
* True when a 4xx error body reads as "this endpoint rejects the
* `response_format` field" — either it names the field outright or it
* complains about an unknown/unexpected parameter.
* complains about an unknown/unexpected parameter. A complaint that names
* `reasoning_effort` and not `response_format` is about the reasoning field,
* so it must not switch the endpoint's JSON mode off.
*/
export function isResponseFormatRejection(
status: number,
bodyExcerpt: string,
): boolean {
if (status < 400 || status >= 500) return false;
if (
/reasoning[\s_-]*effort/i.test(bodyExcerpt) &&
!/response_format/i.test(bodyExcerpt)
) {
return false;
}
return (
/response_format/i.test(bodyExcerpt) ||
/(unknown|unexpected|unrecognized|unsupported|extra)[\s_-]*(parameter|field|argument|property|key)/i.test(