diff --git a/open-sse/executors/antigravity.ts b/open-sse/executors/antigravity.ts index 1623b598f7..545a73ae70 100644 --- a/open-sse/executors/antigravity.ts +++ b/open-sse/executors/antigravity.ts @@ -224,6 +224,7 @@ export class AntigravityExecutor extends BaseExecutor { const collect = async () => { const chunks: string[] = []; + let timedOut = false; const timeout = AbortSignal.timeout(SSE_COLLECT_TIMEOUT_MS); try { // eslint-disable-next-line no-constant-condition @@ -239,7 +240,9 @@ export class AntigravityExecutor extends BaseExecutor { chunks.push(decoder.decode(value, { stream: true })); } } catch (err) { - log?.warn?.("SSE_COLLECT", `Error collecting SSE stream: ${err?.message || err}`); + const msg = err?.message || String(err); + timedOut = msg.includes("timed out"); + log?.warn?.("SSE_COLLECT", `Error collecting SSE stream: ${msg}`); // Fall through — return whatever was collected so far } const rawSSE = chunks.join(""); @@ -289,15 +292,16 @@ export class AntigravityExecutor extends BaseExecutor { { index: 0, message: { role: "assistant", content: textContent }, - finish_reason: finishReason, + finish_reason: timedOut ? "length" : finishReason, }, ], ...(usage && { usage }), }; + const syntheticStatus = timedOut ? 504 : response.status; const syntheticResponse = new Response(JSON.stringify(result), { - status: response.status, - statusText: response.statusText, + status: syntheticStatus, + statusText: timedOut ? "Gateway Timeout" : response.statusText, headers: [["Content-Type", "application/json"]], }); diff --git a/open-sse/handlers/chatCore.ts b/open-sse/handlers/chatCore.ts index c9612edd85..8b7176a91a 100644 --- a/open-sse/handlers/chatCore.ts +++ b/open-sse/handlers/chatCore.ts @@ -1217,7 +1217,7 @@ export async function handleChatCore({ const isPassthrough = provider && getPassthroughProviders().has(provider); if (isPassthrough) { const { lockModel } = await import("../services/accountFallback.ts"); - const cooldown = retryAfterMs || 60_000; + const cooldown = retryAfterMs || 120_000; // 2 min default, same as COOLDOWN_MS.rateLimit lockModel(provider, connectionId, model, "rate_limited", cooldown); console.warn( `[provider] Node ${connectionId} model-only rate limited (${statusCode}) for ${model} - ${Math.ceil(cooldown / 1000)}s (connection stays active)` diff --git a/src/sse/services/auth.ts b/src/sse/services/auth.ts index 7b24eaf19a..e465a7fd49 100644 --- a/src/sse/services/auth.ts +++ b/src/sse/services/auth.ts @@ -809,7 +809,7 @@ export async function markAccountUnavailable( // may still have quota available. Use lockModel() instead of connection-wide // rateLimitedUntil, same pattern as the 404 model-only lockout above. if (isPassthroughProvider && status === 429 && provider && model) { - const modelCooldown = cooldownMs || COOLDOWN_MS.rateLimited; + const modelCooldown = cooldownMs || COOLDOWN_MS.rateLimit; lockModel(provider, connectionId, model, reason || "rate_limited", modelCooldown); log.info( "AUTH",