From 9b4a372c2a4535340514031d2763435f3e3cf08d Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 29 Sep 2026 10:53:10 -0500 Subject: [PATCH] fix(ai): classify Z.ai prompt length, sensitive content, and fair-use errors --- packages/ai/src/provider-error.ts | 9 +++--- packages/ai/test/provider-error.test.ts | 37 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/ai/src/provider-error.ts b/packages/ai/src/provider-error.ts index 57643aab62c..08fd5697a2e 100644 --- a/packages/ai/src/provider-error.ts +++ b/packages/ai/src/provider-error.ts @@ -33,7 +33,8 @@ const patterns = [ /context[_ ]length[_ ]exceeded/i, /context length is only \d+ tokens/i, /input length.*exceeds.*context length/i, - /prompt too long; exceeded (?:max )?context length/i, + // Z.ai code 1261 arrives as `Prompt too long` or `Prompt 超长`. + /prompt (?:too long|超长)/i, /too large for model with \d+ maximum context length/i, /prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i, /model_context_window_exceeded/i, @@ -145,15 +146,15 @@ const CONTENT_POLICY_CODES = new Set([ const GATEWAY_CODE_LABEL = /^[^:\n]+: \[([A-Za-z0-9_.-]+)\]/ const RATE_LIMIT_TEXT = /rate increased too quickly|rate[-_\s]?limit|too[_\s]?many[_\s]?requests/i // Only consulted on 429, where throttles and account caps share a status. -// Z.ai reports balance, plan expiry, plan limits, and plan model access on 429. +// Z.ai reports balance, plan expiry, plan limits, plan model access, and fair-use restrictions on 429. const QUOTA_TEXT = - /insufficient[-_\s]?(?:quota|balance)|quota[-_\s]?exceeded|budget exceeded|usage limit|limit exhausted|package has expired|plan does not yet include/i + /insufficient[-_\s]?(?:quota|balance)|quota[-_\s]?exceeded|budget exceeded|usage limit|limit exhausted|package has expired|plan does not yet include|fair usage policy/i // Policy rejections without a dedicated code, matched against the provider's own // explanation only. OpenAI reuses `invalid_prompt` for usage-policy rejections while // Bedrock Mantle reuses it for schema validation; Anthropic reports blocked output // under `invalid_request_error`. const CONTENT_POLICY_TEXT = - /violating our usage policy|blocked by content filtering policy|content[-_\s]?policy|rejected as a result of our safety system/i + /violating our usage policy|blocked by content filtering policy|content[-_\s]?policy|rejected as a result of our safety system|detected potentially unsafe or sensitive content/i const SERVER_ERROR_TEXT = /\b(?:try again|(?:please |you can )?retry (?:the |this |your )?request|try (?:the |this |your )?request again|(?:currently |temporarily )?at capacity|overloaded|temporarily unavailable|service[-_\s]?unavailable|(?:server|internal)[-_\s]?error|server (?:is )?busy|provider returned (?:an )?error|resource[-_\s]?exhausted|upstream (?:connect|connection|request)|request buffer limit while retrying upstream)\b/i diff --git a/packages/ai/test/provider-error.test.ts b/packages/ai/test/provider-error.test.ts index 7992cbc6c39..966b2ee1609 100644 --- a/packages/ai/test/provider-error.test.ts +++ b/packages/ai/test/provider-error.test.ts @@ -294,6 +294,10 @@ describe("provider error classification", () => { zai("1310", "Weekly/Monthly Limit Exhausted. Your limit will reset at 2026-10-01 00:00:00"), zai("1311", "Your current subscription plan does not yet include access to glm-5"), zai("1314", "Your enterprise package has expired. Please contact your enterprise administrator."), + zai( + "1313", + "Your account's current usage pattern does not comply with the Fair Usage Policy, and your request frequency has been limited. For details, please refer to the Subscription Service Agreement. To restore access, please submit a request.", + ), // Z.ai's Anthropic-compatible endpoint wraps the code and request ID into the message. { type: "error", @@ -313,6 +317,39 @@ describe("provider error classification", () => { ).toEqual(Array(cases.length).fill("QuotaExceeded")) }) + test("classifies Z.ai prompt length rejections as context overflow", () => { + const cases = [ + { error: { code: "1261", message: "Prompt 超长" } }, + { error: { code: "1261", message: "Prompt too long" } }, + { + type: "error", + error: { type: "invalid_request_error", code: "1261", message: "[1261][Prompt too long][2026092913]" }, + }, + ] + expect( + cases.map((body) => { + const reason = classifyProviderFailure({ + message: body.error.message, + status: 400, + rawBody: JSON.stringify(body), + }) + return reason._tag === "InvalidRequest" ? reason.classification : reason._tag + }), + ).toEqual(["context-overflow", "context-overflow", "context-overflow"]) + }) + + test("classifies Z.ai sensitive content rejections as content policy", () => { + const message = + "System detected potentially unsafe or sensitive content in input or generation. Please avoid using prompts that may generate sensitive content. Thank you for your cooperation." + expect( + classifyProviderFailure({ + message, + status: 400, + rawBody: JSON.stringify({ error: { code: "1301", message } }), + })._tag, + ).toBe("ContentPolicy") + }) + test("keeps Z.ai throttling and overload retryable", () => { expect( [