copilot-api-plus 1.2.50 → 1.2.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -2184,9 +2184,12 @@ async function createWithSingleAccount(payload) {
2184
2184
  }
2185
2185
  if (!response.ok) {
2186
2186
  const errorBody = await response.text();
2187
- if (response.status === 400) if (errorBody.includes("reasoning_effort") || errorBody.includes("invalid_reasoning_effort") || errorBody.includes("does not support reasoning")) consola.debug(`400 (auto-handled): ${errorBody}`);
2188
- else consola.warn(`400: ${errorBody}`);
2189
- else consola.error("Failed to create chat completions", {
2187
+ if (response.status === 400) {
2188
+ const isExpectedReasoningError = errorBody.includes("reasoning_effort") || errorBody.includes("invalid_reasoning_effort") || errorBody.includes("does not support reasoning");
2189
+ const isModelNotSupported = errorBody.includes("model_not_supported");
2190
+ if (isExpectedReasoningError || isModelNotSupported) consola.debug(`400 (auto-handled): ${errorBody}`);
2191
+ else consola.warn(`400: ${errorBody}`);
2192
+ } else consola.error("Failed to create chat completions", {
2190
2193
  status: response.status,
2191
2194
  statusText: response.statusText,
2192
2195
  body: errorBody
@@ -2266,6 +2269,7 @@ async function handleMultiAccountHttpError(error, account, retryContext) {
2266
2269
  default:
2267
2270
  if (error.response.status >= 500) {
2268
2271
  accountManager.markAccountStatus(account.id, "error", `HTTP ${error.response.status}`);
2272
+ recordBreakerFailure(`HTTP ${error.response.status}`);
2269
2273
  return null;
2270
2274
  }
2271
2275
  if (error.response.status === 400) {
@@ -2280,7 +2284,42 @@ async function handleMultiAccountHttpError(error, account, retryContext) {
2280
2284
  return null;
2281
2285
  }
2282
2286
  }
2287
+ const CB_THRESHOLD = 3;
2288
+ const CB_OPEN_MS = 3e4;
2289
+ const breaker = {
2290
+ failures: 0,
2291
+ openedAt: 0
2292
+ };
2293
+ function breakerOpenRemainingMs() {
2294
+ if (breaker.openedAt === 0) return 0;
2295
+ const elapsed = Date.now() - breaker.openedAt;
2296
+ return elapsed >= CB_OPEN_MS ? 0 : CB_OPEN_MS - elapsed;
2297
+ }
2298
+ function recordBreakerSuccess() {
2299
+ if (breaker.failures !== 0 || breaker.openedAt !== 0) consola.info("Circuit breaker: closing (request succeeded)");
2300
+ breaker.failures = 0;
2301
+ breaker.openedAt = 0;
2302
+ }
2303
+ function recordBreakerFailure(reason) {
2304
+ breaker.failures += 1;
2305
+ if (breaker.failures >= CB_THRESHOLD && breaker.openedAt === 0) {
2306
+ breaker.openedAt = Date.now();
2307
+ consola.warn(`Circuit breaker OPEN for ${CB_OPEN_MS / 1e3}s after ${breaker.failures} consecutive failures (last: ${reason})`);
2308
+ }
2309
+ }
2283
2310
  async function createWithMultiAccount(payload) {
2311
+ const remaining = breakerOpenRemainingMs();
2312
+ if (remaining > 0) throw new HTTPError("Upstream temporarily unavailable", new Response(JSON.stringify({ error: {
2313
+ type: "service_unavailable",
2314
+ message: `Upstream (or proxy) is failing repeatedly. Circuit breaker open; will retry probe in ${Math.ceil(remaining / 1e3)}s.`
2315
+ } }), {
2316
+ status: 503,
2317
+ statusText: "Service Unavailable",
2318
+ headers: {
2319
+ "content-type": "application/json",
2320
+ "retry-after": String(Math.ceil(remaining / 1e3))
2321
+ }
2322
+ }));
2284
2323
  const triedAccountIds = /* @__PURE__ */ new Set();
2285
2324
  let lastError;
2286
2325
  let networkRetried = false;
@@ -2321,6 +2360,7 @@ async function createWithMultiAccount(payload) {
2321
2360
  const result = await doFetch(payload, tokenSource, account.id);
2322
2361
  account.lastRequestAt = Date.now();
2323
2362
  accountManager.markAccountSuccess(account.id);
2363
+ recordBreakerSuccess();
2324
2364
  if (Symbol.asyncIterator in result) result.__accountInfo = {
2325
2365
  accountId: account.id,
2326
2366
  accountProxy: account.proxy,
@@ -2346,6 +2386,7 @@ async function createWithMultiAccount(payload) {
2346
2386
  continue;
2347
2387
  }
2348
2388
  consola.warn(`Account ${account.label}: network error after retry (giving up): ${errMsg}`);
2389
+ recordBreakerFailure(`network: ${errMsg.slice(0, 80)}`);
2349
2390
  throw error;
2350
2391
  }
2351
2392
  consola.warn(`Account ${account.label} failed (attempt ${attempt + 1}), trying next...`);
@@ -2388,9 +2429,12 @@ async function doFetch(payload, source, accountId) {
2388
2429
  });
2389
2430
  if (!response.ok) {
2390
2431
  const errorBody = await response.text();
2391
- if (response.status === 400) if (errorBody.includes("reasoning_effort") || errorBody.includes("invalid_reasoning_effort") || errorBody.includes("does not support reasoning")) consola.debug(`400 (auto-handled): ${errorBody}`);
2392
- else consola.warn(`400: ${errorBody}`);
2393
- else consola.error("Failed to create chat completions", {
2432
+ if (response.status === 400) {
2433
+ const isExpectedReasoningError = errorBody.includes("reasoning_effort") || errorBody.includes("invalid_reasoning_effort") || errorBody.includes("does not support reasoning");
2434
+ const isModelNotSupported = errorBody.includes("model_not_supported");
2435
+ if (isExpectedReasoningError || isModelNotSupported) consola.debug(`400 (auto-handled): ${errorBody}`);
2436
+ else consola.warn(`400: ${errorBody}`);
2437
+ } else consola.error("Failed to create chat completions", {
2394
2438
  status: response.status,
2395
2439
  statusText: response.statusText,
2396
2440
  body: errorBody
@@ -2737,11 +2781,20 @@ function translateModelName(model) {
2737
2781
  const supportedModels = state.models?.data.map((m) => m.id) ?? [];
2738
2782
  if (supportedModels.includes(model)) return model;
2739
2783
  const modelBase = model.replace(/-\d{8}$/, "");
2740
- if (supportedModels.includes(modelBase)) return modelBase;
2784
+ if (supportedModels.includes(modelBase)) {
2785
+ consola.debug(`Model name: "${model}" → "${modelBase}" (stripped date suffix)`);
2786
+ return modelBase;
2787
+ }
2741
2788
  const modelWithDot = modelBase.replace(/-(\d+)-(\d+)$/, "-$1.$2");
2742
- if (supportedModels.includes(modelWithDot)) return modelWithDot;
2789
+ if (supportedModels.includes(modelWithDot)) {
2790
+ consola.debug(`Model name: "${model}" → "${modelWithDot}" (dash→dot)`);
2791
+ return modelWithDot;
2792
+ }
2743
2793
  const modelWithDash = model.replace(/(\d+)\.(\d+)/, "$1-$2");
2744
- if (supportedModels.includes(modelWithDash)) return modelWithDash;
2794
+ if (supportedModels.includes(modelWithDash)) {
2795
+ consola.debug(`Model name: "${model}" → "${modelWithDash}" (dot→dash)`);
2796
+ return modelWithDash;
2797
+ }
2745
2798
  for (const [oldFormat, newFormat] of Object.entries({
2746
2799
  "claude-3-5-sonnet": "claude-sonnet-4.5",
2747
2800
  "claude-3-sonnet": "claude-sonnet-4",
@@ -2749,7 +2802,11 @@ function translateModelName(model) {
2749
2802
  "claude-3-opus": "claude-opus-4.5",
2750
2803
  "claude-3-5-haiku": "claude-haiku-4.5",
2751
2804
  "claude-3-haiku": "claude-haiku-4.5"
2752
- })) if (modelBase.startsWith(oldFormat) && supportedModels.includes(newFormat)) return newFormat;
2805
+ })) if (modelBase.startsWith(oldFormat) && supportedModels.includes(newFormat)) {
2806
+ consola.debug(`Model name: "${model}" → "${newFormat}" (legacy mapping)`);
2807
+ return newFormat;
2808
+ }
2809
+ consola.warn(`Model name: "${model}" not found in supported models list, passing as-is`);
2753
2810
  return model;
2754
2811
  }
2755
2812
  function translateAnthropicMessagesToOpenAI(anthropicMessages, system) {