copilot-api-plus 1.4.8 → 1.4.9
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 +60 -27
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2763,9 +2763,19 @@ async function handleMultiAccountHttpError(error, account, retryContext) {
|
|
|
2763
2763
|
consola.warn(`Account ${account.label}: 401, refreshing token...`);
|
|
2764
2764
|
return tryRefreshAndRetry(account, retryContext.payload, retryContext.tokenSource);
|
|
2765
2765
|
case 403:
|
|
2766
|
+
if (!retryContext.hasOtherAccount) {
|
|
2767
|
+
consola.warn(`Account ${account.label}: 403 — only account, propagating to client without marking`);
|
|
2768
|
+
error.__nonAccountError = true;
|
|
2769
|
+
return null;
|
|
2770
|
+
}
|
|
2766
2771
|
accountManager.markAccountStatus(account.id, "banned", "403 Forbidden");
|
|
2767
2772
|
return null;
|
|
2768
2773
|
case 429:
|
|
2774
|
+
if (!retryContext.hasOtherAccount) {
|
|
2775
|
+
consola.warn(`Account ${account.label}: 429 — only account, propagating to client without marking`);
|
|
2776
|
+
error.__nonAccountError = true;
|
|
2777
|
+
return null;
|
|
2778
|
+
}
|
|
2769
2779
|
accountManager.markAccountStatus(account.id, "rate_limited", "429 Rate limited");
|
|
2770
2780
|
return null;
|
|
2771
2781
|
case 408:
|
|
@@ -2880,7 +2890,8 @@ async function createWithMultiAccount$1(payload) {
|
|
|
2880
2890
|
if (error instanceof HTTPError) {
|
|
2881
2891
|
const retryResult = await handleMultiAccountHttpError(error, account, {
|
|
2882
2892
|
payload,
|
|
2883
|
-
tokenSource
|
|
2893
|
+
tokenSource,
|
|
2894
|
+
hasOtherAccount: hasAnotherAccountToTry(triedAccountIds)
|
|
2884
2895
|
});
|
|
2885
2896
|
if (retryResult) return retryResult;
|
|
2886
2897
|
if (error.__nonAccountError) throw error;
|
|
@@ -3779,9 +3790,9 @@ async function createWithMultiAccount(payload, options$1) {
|
|
|
3779
3790
|
} catch (error) {
|
|
3780
3791
|
lastError = error;
|
|
3781
3792
|
if (error instanceof HTTPError) {
|
|
3782
|
-
|
|
3783
|
-
if (
|
|
3784
|
-
|
|
3793
|
+
const action = handleAnthropicHttpError(error, account, triedAccountIds);
|
|
3794
|
+
if (action === "refresh401") return handleMultiAccount401(ctx, account);
|
|
3795
|
+
if (action === "throw") throw error;
|
|
3785
3796
|
continue;
|
|
3786
3797
|
}
|
|
3787
3798
|
const errMsg = error.message || String(error);
|
|
@@ -3800,6 +3811,35 @@ async function createWithMultiAccount(payload, options$1) {
|
|
|
3800
3811
|
throw new Error("No available accounts");
|
|
3801
3812
|
}
|
|
3802
3813
|
/**
|
|
3814
|
+
* Decide what to do for an HTTP error from a multi-account request attempt.
|
|
3815
|
+
*
|
|
3816
|
+
* Returns:
|
|
3817
|
+
* - "refresh401" — caller should run the 401-refresh-and-retry flow
|
|
3818
|
+
* - "throw" — caller should rethrow the error to the client
|
|
3819
|
+
* - "continue" — caller should try the next account
|
|
3820
|
+
*
|
|
3821
|
+
* Single-account guard: marking the only account as rate_limited / banned
|
|
3822
|
+
* would disable the proxy entirely, so 429 / 403 are propagated unchanged
|
|
3823
|
+
* to the client when no other account is available.
|
|
3824
|
+
*/
|
|
3825
|
+
function handleAnthropicHttpError(error, account, triedAccountIds) {
|
|
3826
|
+
const status = error.response.status;
|
|
3827
|
+
if (status === 401) return "refresh401";
|
|
3828
|
+
if (status === 429 || status === 403) {
|
|
3829
|
+
const isRateLimit = status === 429;
|
|
3830
|
+
if (hasAnotherAnthropicAccountToTry(triedAccountIds)) {
|
|
3831
|
+
accountManager.markAccountStatus(account.id, isRateLimit ? "rate_limited" : "banned", isRateLimit ? "429 Rate limited" : "403 Forbidden");
|
|
3832
|
+
consola.warn(`Account ${account.label}: ${status} on /v1/messages, trying next account`);
|
|
3833
|
+
return "continue";
|
|
3834
|
+
}
|
|
3835
|
+
consola.warn(`Account ${account.label}: ${status} on /v1/messages — only account, propagating to client without marking`);
|
|
3836
|
+
return "throw";
|
|
3837
|
+
}
|
|
3838
|
+
if (status >= 400 && status < 500) return "throw";
|
|
3839
|
+
consola.warn(`Account ${account.label}: 5xx from /v1/messages${hasAnotherAnthropicAccountToTry(triedAccountIds) ? ", trying next account" : " — no other accounts available, propagating error"}`);
|
|
3840
|
+
return "continue";
|
|
3841
|
+
}
|
|
3842
|
+
/**
|
|
3803
3843
|
* Peek at whether `getActiveAccount()` would return an untried account on the
|
|
3804
3844
|
* next iteration. Used purely for honest log messaging — doesn't affect
|
|
3805
3845
|
* routing.
|
|
@@ -4133,37 +4173,30 @@ async function handleCompletion(c) {
|
|
|
4133
4173
|
if (state.manualApprove) await awaitApproval();
|
|
4134
4174
|
const route = resolveAnthropicRoute(anthropicPayload.model);
|
|
4135
4175
|
consola.debug(`Anthropic route resolved: ${route}`);
|
|
4136
|
-
if (route === "native-anthropic"
|
|
4176
|
+
if (route === "native-anthropic") return handleNativePassthrough(c, anthropicPayload);
|
|
4137
4177
|
return handleTranslatedCompletion(c, anthropicPayload);
|
|
4138
4178
|
}
|
|
4139
|
-
/**
|
|
4140
|
-
* Models whose native /v1/messages path returned an unrecoverable upstream
|
|
4141
|
-
* policy error (e.g. Vertex AI's `structured_outputs` GCP org policy).
|
|
4142
|
-
* Once added, future requests for that model skip the native path and go
|
|
4143
|
-
* straight to the translated /chat/completions path.
|
|
4144
|
-
*
|
|
4145
|
-
* Cleared on process restart — so a fixed Copilot routing self-heals.
|
|
4146
|
-
*/
|
|
4147
|
-
const nativeBlockedModels = /* @__PURE__ */ new Set();
|
|
4148
|
-
const VERTEX_STRUCTURED_OUTPUTS_PATTERN = /vertexai\.allowedPartnerModelFeatures.*?structured_outputs/i;
|
|
4149
|
-
function isVertexStructuredOutputsBlock(error) {
|
|
4150
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
4151
|
-
return VERTEX_STRUCTURED_OUTPUTS_PATTERN.test(message);
|
|
4152
|
-
}
|
|
4153
4179
|
async function handleNativePassthrough(c, anthropicPayload) {
|
|
4154
4180
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
4181
|
+
const sanitized = injectIntoAnthropicPayload(stripSystemReminders(anthropicPayload));
|
|
4155
4182
|
let result;
|
|
4156
4183
|
try {
|
|
4157
|
-
result = await createAnthropicMessages(
|
|
4184
|
+
result = await createAnthropicMessages(sanitized, { anthropicBeta });
|
|
4158
4185
|
} catch (error) {
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4186
|
+
const message = error.message || String(error);
|
|
4187
|
+
if (/vertexai\.allowedPartnerModelFeatures.*?structured_outputs/i.test(message)) {
|
|
4188
|
+
consola.debug(`Native /v1/messages: Vertex GCP policy 400, retrying once (Copilot will likely route to Anthropic-direct)`);
|
|
4189
|
+
try {
|
|
4190
|
+
result = await createAnthropicMessages(sanitized, { anthropicBeta });
|
|
4191
|
+
} catch (retryError) {
|
|
4192
|
+
const retryMessage = retryError.message || String(retryError);
|
|
4193
|
+
consola.warn(`Native /v1/messages: Vertex GCP policy 400 on both attempts, propagating to client: ${retryMessage}`);
|
|
4194
|
+
throw retryError;
|
|
4195
|
+
}
|
|
4196
|
+
} else {
|
|
4197
|
+
consola.warn(`Native /v1/messages failed: ${message}`);
|
|
4198
|
+
throw error;
|
|
4164
4199
|
}
|
|
4165
|
-
consola.warn(`Native /v1/messages failed: ${error.message || String(error)}`);
|
|
4166
|
-
throw error;
|
|
4167
4200
|
}
|
|
4168
4201
|
if (!anthropicPayload.stream) return c.json(overrideAnthropicResponseModel(result, anthropicPayload.model));
|
|
4169
4202
|
const stream = result;
|