feat(provider): add free providers and enhance error handling

This commit is contained in:
decolua
2026-02-07 11:17:06 +07:00
parent 53a5f43993
commit bdbe8162e7
16 changed files with 285 additions and 120 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
import crypto from "crypto";
import { BaseExecutor } from "./base.js";
import { PROVIDERS, OAUTH_ENDPOINTS } from "../config/constants.js";
import { PROVIDERS, OAUTH_ENDPOINTS, HTTP_STATUS } from "../config/constants.js";
const MAX_RETRY_AFTER_MS = 10000;
@@ -162,7 +162,7 @@ export class AntigravityExecutor extends BaseExecutor {
signal
});
if (response.status === 429 || response.status === 503) {
if (response.status === HTTP_STATUS.RATE_LIMITED || response.status === HTTP_STATUS.SERVICE_UNAVAILABLE) {
// Try to get retry time from headers first
let retryMs = this.parseRetryHeaders(response.headers);
@@ -186,7 +186,7 @@ export class AntigravityExecutor extends BaseExecutor {
}
// Auto retry only for 429 when retryMs is 0 or undefined
if (response.status === 429 && (!retryMs || retryMs === 0) && retryAttemptsByUrl[urlIndex] < MAX_AUTO_RETRIES) {
if (response.status === HTTP_STATUS.RATE_LIMITED && (!retryMs || retryMs === 0) && retryAttemptsByUrl[urlIndex] < MAX_AUTO_RETRIES) {
retryAttemptsByUrl[urlIndex]++;
// Exponential backoff: 2s, 4s, 8s...
const backoffMs = Math.min(1000 * (2 ** retryAttemptsByUrl[urlIndex]), MAX_RETRY_AFTER_MS);
+3 -1
View File
@@ -1,3 +1,5 @@
import { HTTP_STATUS } from "../config/constants.js";
/**
* BaseExecutor - Base class for provider executors
*/
@@ -55,7 +57,7 @@ export class BaseExecutor {
}
shouldRetry(status, urlIndex) {
return status === 429 && urlIndex + 1 < this.getFallbackCount();
return status === HTTP_STATUS.RATE_LIMITED && urlIndex + 1 < this.getFallbackCount();
}
// Override in subclass for provider-specific refresh
+5 -5
View File
@@ -1,5 +1,5 @@
import { BaseExecutor } from "./base.js";
import { PROVIDERS } from "../config/constants.js";
import { PROVIDERS, HTTP_STATUS } from "../config/constants.js";
import {
generateCursorBody,
parseConnectRPCFrame,
@@ -77,7 +77,7 @@ function createErrorResponse(jsonError) {
code: jsonError?.error?.details?.[0]?.debug?.error || "unknown"
}
}), {
status: isRateLimit ? 429 : 400,
status: isRateLimit ? HTTP_STATUS.RATE_LIMITED : HTTP_STATUS.BAD_REQUEST,
headers: { "Content-Type": "application/json" }
});
}
@@ -275,7 +275,7 @@ export class CursorExecutor extends BaseExecutor {
code: ""
}
}), {
status: 500,
status: HTTP_STATUS.SERVER_ERROR,
headers: { "Content-Type": "application/json" }
});
return { response: errorResponse, url, headers, transformedBody: body };
@@ -338,7 +338,7 @@ export class CursorExecutor extends BaseExecutor {
code: "rate_limited"
}
}), {
status: 429,
status: HTTP_STATUS.RATE_LIMITED,
headers: { "Content-Type": "application/json" }
});
}
@@ -480,7 +480,7 @@ export class CursorExecutor extends BaseExecutor {
code: "rate_limited"
}
}), {
status: 429,
status: HTTP_STATUS.RATE_LIMITED,
headers: { "Content-Type": "application/json" }
});
}