mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:20:43 +00:00
fix(agents): surface OpenAI model capacity errors
This commit is contained in:
@@ -64,6 +64,12 @@ describe("formatAssistantErrorText", () => {
|
||||
"The AI service is temporarily overloaded. Please try again in a moment.",
|
||||
);
|
||||
});
|
||||
it("returns a model-switch hint for OpenAI model capacity errors", () => {
|
||||
const msg = makeAssistantError("Selected model is at capacity. Please try a different model.");
|
||||
expect(formatAssistantErrorText(msg)).toBe(
|
||||
"⚠️ Selected model is at capacity. Try a different model, or wait and retry.",
|
||||
);
|
||||
});
|
||||
it("returns a recovery hint when tool call input is missing", () => {
|
||||
const msg = makeAssistantError("tool_use.input: Field required");
|
||||
const result = formatAssistantErrorText(msg);
|
||||
|
||||
@@ -141,6 +141,17 @@ describe("sanitizeUserFacingText", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("returns a model-switch hint for OpenAI model capacity errors", () => {
|
||||
expect(
|
||||
sanitizeUserFacingText(
|
||||
"OpenAI error: Selected model is at capacity. Please try a different model.",
|
||||
{
|
||||
errorContext: true,
|
||||
},
|
||||
),
|
||||
).toBe("⚠️ Selected model is at capacity. Try a different model, or wait and retry.");
|
||||
});
|
||||
|
||||
it("returns a transport-specific message for prefixed ECONNREFUSED errors", () => {
|
||||
expect(
|
||||
sanitizeUserFacingText("Error: connect ECONNREFUSED 127.0.0.1:443", {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
isAuthErrorMessage,
|
||||
isBillingErrorMessage,
|
||||
isOverloadedErrorMessage,
|
||||
isRateLimitErrorMessage,
|
||||
} from "./failover-matches.js";
|
||||
|
||||
@@ -68,6 +69,12 @@ describe("Z.ai vendor error codes (#48988)", () => {
|
||||
expect(isRateLimitErrorMessage("rate limit exceeded")).toBe(true);
|
||||
});
|
||||
|
||||
it("OpenAI model-capacity text is classified as overloaded", () => {
|
||||
expect(
|
||||
isOverloadedErrorMessage("Selected model is at capacity. Please try a different model."),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("billing still classified correctly", () => {
|
||||
expect(isBillingErrorMessage("insufficient credits")).toBe(true);
|
||||
});
|
||||
|
||||
@@ -73,6 +73,7 @@ const ERROR_PATTERNS = {
|
||||
overloaded: [
|
||||
/overloaded_error|"type"\s*:\s*"overloaded_error"/i,
|
||||
"overloaded",
|
||||
/\b(?:selected\s+)?model\s+(?:is\s+)?at capacity\b/i,
|
||||
// Match "service unavailable" only when combined with an explicit overload
|
||||
// indicator — a generic 503 from a proxy/CDN should not be classified as
|
||||
// provider-overload (#32828).
|
||||
|
||||
@@ -34,6 +34,8 @@ export function formatBillingErrorMessage(provider?: string, model?: string): st
|
||||
export const BILLING_ERROR_USER_MESSAGE = formatBillingErrorMessage();
|
||||
|
||||
const RATE_LIMIT_ERROR_USER_MESSAGE = "⚠️ API rate limit reached. Please try again later.";
|
||||
const MODEL_CAPACITY_ERROR_USER_MESSAGE =
|
||||
"⚠️ Selected model is at capacity. Try a different model, or wait and retry.";
|
||||
const OVERLOADED_ERROR_USER_MESSAGE =
|
||||
"The AI service is temporarily overloaded. Please try again in a moment.";
|
||||
const FINAL_TAG_RE = /<\s*\/?\s*final\s*>/gi;
|
||||
@@ -60,6 +62,7 @@ const HTTP_ERROR_HINTS = [
|
||||
];
|
||||
const RATE_LIMIT_SPECIFIC_HINT_RE =
|
||||
/\bmin(ute)?s?\b|\bhours?\b|\bseconds?\b|\btry again in\b|\breset\b|\bplan\b|\bquota\b/i;
|
||||
const MODEL_CAPACITY_ERROR_RE = /\b(?:selected\s+)?model\s+(?:is\s+)?at capacity\b/i;
|
||||
const NON_ERROR_PROVIDER_PAYLOAD_MAX_LENGTH = 16_384;
|
||||
const NON_ERROR_PROVIDER_PAYLOAD_PREFIX_RE = /^codex\s*error(?:\s+\d{3})?[:\s-]+/i;
|
||||
|
||||
@@ -93,6 +96,9 @@ export function formatRateLimitOrOverloadedErrorCopy(raw: string): string | unde
|
||||
if (isRateLimitErrorMessage(raw)) {
|
||||
return extractProviderRateLimitMessage(raw) ?? RATE_LIMIT_ERROR_USER_MESSAGE;
|
||||
}
|
||||
if (MODEL_CAPACITY_ERROR_RE.test(raw)) {
|
||||
return MODEL_CAPACITY_ERROR_USER_MESSAGE;
|
||||
}
|
||||
if (isOverloadedErrorMessage(raw)) {
|
||||
return OVERLOADED_ERROR_USER_MESSAGE;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,20 @@ describe("buildEmbeddedRunPayloads", () => {
|
||||
expect(payloads.some((payload) => payload.text?.includes("request_id"))).toBe(false);
|
||||
});
|
||||
|
||||
it("surfaces OpenAI model capacity errors instead of generic empty-response copy", () => {
|
||||
const payloads = buildPayloads({
|
||||
lastAssistant: makeAssistant({
|
||||
errorMessage: "Selected model is at capacity. Please try a different model.",
|
||||
content: [],
|
||||
}),
|
||||
});
|
||||
|
||||
expectSinglePayloadSummary(payloads, {
|
||||
text: "⚠️ Selected model is at capacity. Try a different model, or wait and retry.",
|
||||
isError: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("includes provider and model context for billing errors", () => {
|
||||
const payloads = buildPayloads({
|
||||
lastAssistant: makeAssistant({
|
||||
|
||||
Reference in New Issue
Block a user