fix(ai): improved reasoning fallback logic for equidistant tiers
- Update fallback selection to prefer higher effort tiers when distance is equal. - Add test case verifying fallback from unsupported "medium" effort to "high".
This commit is contained in:
@@ -230,14 +230,16 @@ function nearestEnabledReasoningFallback(currentEffort: string, allowed: Set<str
|
||||
if (currentRank === undefined) return undefined;
|
||||
let best: string | undefined;
|
||||
let bestDistance = Number.POSITIVE_INFINITY;
|
||||
let bestRank = Number.NEGATIVE_INFINITY;
|
||||
for (const candidate of allowedEnabled) {
|
||||
if (candidate === current) continue;
|
||||
const candidateRank = REASONING_VALUE_RANK[candidate];
|
||||
if (candidateRank === undefined) continue;
|
||||
const distance = Math.abs(candidateRank - currentRank);
|
||||
if (distance < bestDistance) {
|
||||
if (distance < bestDistance || (distance === bestDistance && candidateRank > bestRank)) {
|
||||
best = candidate;
|
||||
bestDistance = distance;
|
||||
bestRank = candidateRank;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
|
||||
@@ -71,6 +71,19 @@ function invalidReasoningResponse(param: "reasoning_effort" | "reasoning.effort"
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
function invalidMediumReasoningResponse(): Response {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
error: {
|
||||
message: 'reasoning.effort: Invalid option: expected one of "high"|"low"|"minimal"|"none"',
|
||||
type: "invalid_request_error",
|
||||
param: "reasoning.effort",
|
||||
},
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
|
||||
function pipeDelimitedReasoningEffortResponse(): Response {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
@@ -271,6 +284,30 @@ describe("OpenAI reasoning effort fallback retry", () => {
|
||||
expect(bodies.map(body => (body.reasoning as { effort?: string } | undefined)?.effort)).toEqual(["max", "xhigh"]);
|
||||
});
|
||||
|
||||
it("retries medium as high when medium is missing and high is the closest upper tier", async () => {
|
||||
const bodies: Record<string, unknown>[] = [];
|
||||
const fetchMock: FetchImpl = Object.assign(
|
||||
async (_input: string | URL | Request, init?: RequestInit): Promise<Response> => {
|
||||
const body = parseJsonBody(init);
|
||||
bodies.push(body);
|
||||
return bodies.length === 1 ? invalidMediumReasoningResponse() : createResponsesSseResponse();
|
||||
},
|
||||
{ preconnect: fetch.preconnect },
|
||||
);
|
||||
|
||||
const result = await streamOpenAIResponses(createResponsesModel(), testContext, {
|
||||
apiKey: "test-key",
|
||||
fetch: fetchMock,
|
||||
reasoning: "medium",
|
||||
}).result();
|
||||
|
||||
expect(result.stopReason).toBe("stop");
|
||||
expect(bodies.map(body => (body.reasoning as { effort?: string } | undefined)?.effort)).toEqual([
|
||||
"medium",
|
||||
"high",
|
||||
]);
|
||||
});
|
||||
|
||||
it("retries Azure Responses xhigh as provider max", async () => {
|
||||
const bodies: Record<string, unknown>[] = [];
|
||||
const fetchMock: FetchImpl = Object.assign(
|
||||
|
||||
Reference in New Issue
Block a user