From 4fce944fba87572d2e67d2bbf266203058083405 Mon Sep 17 00:00:00 2001 From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:09:05 -0800 Subject: [PATCH] fix(cerebras): trigger auto-compaction when context window exceeded Previously, Cerebras/GLM models would fail with repeated "rate limit exceeded" errors instead of auto-compacting when context was too large. This happened because: 1. GLM models weren't in the "next-gen" family, so pre-flight compaction checks were skipped 2. HTTP 400 errors were wrapped in new Error objects, losing the status code needed for context window detection 3. HTTP 429 errors (which Cerebras returns for oversized context due to token-based rate limiting) were retried instead of triggering compaction 4. Context error detection used fragile exact string matching Fixes: - Add GLM to isNextGenModelFamily for pre-flight compaction checks - Update isGLMModelFamily to match Cerebras patterns (zai-glm, glm-4.7) - Preserve original errors for HTTP 400 responses - Detect context-related 429 errors and reclassify as 400 for compaction - Use robust regex patterns for Cerebras context error detection --- src/core/api/providers/cerebras.ts | 18 +++++++++++++++--- .../context-error-handling.ts | 16 +++++++++++++++- src/utils/model-utils.ts | 5 ++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/core/api/providers/cerebras.ts b/src/core/api/providers/cerebras.ts index 23881f7525..921371e1d4 100644 --- a/src/core/api/providers/cerebras.ts +++ b/src/core/api/providers/cerebras.ts @@ -192,7 +192,18 @@ export class CerebrasHandler implements ApiHandler { } catch (error: any) { // Enhanced error handling for Cerebras API if (error?.status === 429 || error?.code === "rate_limit_exceeded") { - // Rate limit error - will be handled by retry decorator with patient backoff + // Check if this is actually a context window error disguised as rate limit + // Cerebras rate limiter counts input tokens, so oversized context can trigger 429 + const errorMessage = String(error?.message || "") + const isContextRelated = /reduce.*length|context.*length|too.*many.*tokens|tokens.*exceed|input.*too.*long/i.test( + errorMessage, + ) + if (isContextRelated) { + // Preserve original error so context window detection can catch it + error.status = 400 // Treat as bad request for context window detection + throw error + } + // Regular rate limit error - will be handled by retry decorator with patient backoff const _limits = this.getRateLimits() throw new Error(`Cerebras API rate limit exceeded.`) } else if (error?.status === 401) { @@ -203,8 +214,9 @@ export class CerebrasHandler implements ApiHandler { // Server errors - retryable throw new Error(`Cerebras API server error (${error.status}): ${error.message || "Unknown server error"}`) } else if (error?.status === 400) { - // Client errors - not retryable - throw new Error(`Cerebras API bad request: ${error.message || "Invalid request parameters"}`) + // Client errors (including context window exceeded) - preserve original error + // so checkIsCerebrasContextWindowError can detect it and trigger compaction + throw error } // Re-throw original error for other cases diff --git a/src/core/context/context-management/context-error-handling.ts b/src/core/context/context-management/context-error-handling.ts index f51919652f..5b5c05fb58 100644 --- a/src/core/context/context-management/context-error-handling.ts +++ b/src/core/context/context-management/context-error-handling.ts @@ -67,7 +67,21 @@ function checkIsCerebrasContextWindowError(response: any): boolean { const status = response?.status ?? response?.code ?? response?.error?.status ?? response?.response?.status const message: string = String(response?.message || response?.error?.message || "") - return String(status) === "400" && message.includes("Please reduce the length of the messages or completion") + if (String(status) !== "400") { + return false + } + + // Known Cerebras context window error patterns + const CEREBRAS_CONTEXT_PATTERNS = [ + /reduce.*length.*messages.*completion/i, + /\bcontext\s*(?:length|window)\b/i, + /\bmaximum\s*context\b/i, + /\b(?:input\s*)?tokens?\s*exceed/i, + /\btoo\s*many\s*tokens?\b/i, + /input is too long/i, + ] as const + + return CEREBRAS_CONTEXT_PATTERNS.some((pattern) => pattern.test(message)) } catch { return false } diff --git a/src/utils/model-utils.ts b/src/utils/model-utils.ts index 9e94dcc606..f3034c0529 100644 --- a/src/utils/model-utils.ts +++ b/src/utils/model-utils.ts @@ -97,6 +97,8 @@ export function isGLMModelFamily(id: string): boolean { return ( modelId.includes("glm-4.6") || modelId.includes("glm-4.5") || + modelId.includes("glm-4.7") || + modelId.includes("zai-glm") || // Cerebras pattern (e.g., zai-glm-4.7) modelId.includes("z-ai/glm") || modelId.includes("zai-org/glm") ) @@ -163,7 +165,8 @@ export function isNextGenModelFamily(id: string): boolean { isGemini3ModelFamily(modelId) || isNextGenOpenSourceModelFamily(modelId) || isDeepSeek32ModelFamily(modelId) || - isDeepSeekNativeModelFamily(modelId) + isDeepSeekNativeModelFamily(modelId) || + isGLMModelFamily(modelId) ) }