fix(agents): avoid classifying reasoning-required errors as context overflow (#24593)
* Agents: exclude reasoning-required errors from overflow detection * Tests: cover reasoning-required overflow classification guard * Tests: format reasoning-required endpoint errors
This commit is contained in:
@@ -35,6 +35,15 @@ describe("formatAssistantErrorText", () => {
|
||||
);
|
||||
expect(formatAssistantErrorText(msg)).toContain("Context overflow");
|
||||
});
|
||||
it("returns a reasoning-required message for mandatory reasoning endpoint errors", () => {
|
||||
const msg = makeAssistantError(
|
||||
"400 Reasoning is mandatory for this endpoint and cannot be disabled.",
|
||||
);
|
||||
const result = formatAssistantErrorText(msg);
|
||||
expect(result).toContain("Reasoning is required");
|
||||
expect(result).toContain("/think minimal");
|
||||
expect(result).not.toContain("Context overflow");
|
||||
});
|
||||
it("returns a friendly message for Anthropic role ordering", () => {
|
||||
const msg = makeAssistantError('messages: roles must alternate between "user" and "assistant"');
|
||||
expect(formatAssistantErrorText(msg)).toContain("Message ordering conflict");
|
||||
|
||||
@@ -208,6 +208,17 @@ describe("isContextOverflowError", () => {
|
||||
expect(isContextOverflowError("We're debugging context overflow issues")).toBe(false);
|
||||
expect(isContextOverflowError("Something is causing context overflow messages")).toBe(false);
|
||||
});
|
||||
|
||||
it("excludes reasoning-required invalid-request errors", () => {
|
||||
const samples = [
|
||||
"400 Reasoning is mandatory for this endpoint and cannot be disabled.",
|
||||
'{"type":"error","error":{"type":"invalid_request_error","message":"Reasoning is mandatory for this endpoint and cannot be disabled."}}',
|
||||
"This model requires reasoning to be enabled",
|
||||
];
|
||||
for (const sample of samples) {
|
||||
expect(isContextOverflowError(sample)).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("error classifiers", () => {
|
||||
@@ -286,6 +297,17 @@ describe("isLikelyContextOverflowError", () => {
|
||||
expect(isLikelyContextOverflowError(sample)).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it("excludes reasoning-required invalid-request errors", () => {
|
||||
const samples = [
|
||||
"400 Reasoning is mandatory for this endpoint and cannot be disabled.",
|
||||
'{"type":"error","error":{"type":"invalid_request_error","message":"Reasoning is mandatory for this endpoint and cannot be disabled."}}',
|
||||
"This endpoint requires reasoning",
|
||||
];
|
||||
for (const sample of samples) {
|
||||
expect(isLikelyContextOverflowError(sample)).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("isTransientHttpError", () => {
|
||||
|
||||
@@ -34,6 +34,19 @@ function formatRateLimitOrOverloadedErrorCopy(raw: string): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isReasoningConstraintErrorMessage(raw: string): boolean {
|
||||
if (!raw) {
|
||||
return false;
|
||||
}
|
||||
const lower = raw.toLowerCase();
|
||||
return (
|
||||
lower.includes("reasoning is mandatory") ||
|
||||
lower.includes("reasoning is required") ||
|
||||
lower.includes("requires reasoning") ||
|
||||
(lower.includes("reasoning") && lower.includes("cannot be disabled"))
|
||||
);
|
||||
}
|
||||
|
||||
export function isContextOverflowError(errorMessage?: string): boolean {
|
||||
if (!errorMessage) {
|
||||
return false;
|
||||
@@ -45,6 +58,10 @@ export function isContextOverflowError(errorMessage?: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isReasoningConstraintErrorMessage(errorMessage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hasRequestSizeExceeds = lower.includes("request size exceeds");
|
||||
const hasContextWindow =
|
||||
lower.includes("context window") ||
|
||||
@@ -85,6 +102,10 @@ export function isLikelyContextOverflowError(errorMessage?: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isReasoningConstraintErrorMessage(errorMessage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CONTEXT_WINDOW_TOO_SMALL_RE.test(errorMessage)) {
|
||||
return false;
|
||||
}
|
||||
@@ -464,6 +485,13 @@ export function formatAssistantErrorText(
|
||||
);
|
||||
}
|
||||
|
||||
if (isReasoningConstraintErrorMessage(raw)) {
|
||||
return (
|
||||
"Reasoning is required for this model endpoint. " +
|
||||
"Use /think minimal (or any non-off level) and try again."
|
||||
);
|
||||
}
|
||||
|
||||
// Catch role ordering errors - including JSON-wrapped and "400" prefix variants
|
||||
if (
|
||||
/incorrect role information|roles must alternate|400.*role|"message".*role.*information/i.test(
|
||||
|
||||
Reference in New Issue
Block a user