@xiaoso/dsh-tool-plus 0.1.16 → 0.1.17-beta.0
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/lib/{abort-DZ54CaKU.mjs → abort-BTblp0Rt.mjs} +2 -2
- package/lib/{alibaba-coding-plan-DODpkcqi.mjs → alibaba-coding-plan-t3R4YKCB.mjs} +3 -3
- package/lib/{alibaba-token-plan-C6lpKCda.mjs → alibaba-token-plan-CO4djG1y.mjs} +4 -4
- package/lib/{alibaba-token-plan-CHGyWOfX.mjs → alibaba-token-plan-CUjYJX0-.mjs} +1 -1
- package/lib/{anthropic-Dv_GGX6g.mjs → anthropic-nf7w6so1.mjs} +48 -21
- package/lib/{api-key-validation-MnMf_ihX.mjs → api-key-validation-C_tZ7Y9a.mjs} +2 -2
- package/lib/behavior-BwvTUtag.mjs +111 -0
- package/lib/{browser-render-BZXt548F.mjs → browser-render-BQaEVK_n.mjs} +4 -4
- package/lib/{reference-CtvM4zLU.mjs → bundled-references-CrQ4dQcT.mjs} +57 -4
- package/lib/cascade-BWjRTD1q.mjs +30265 -0
- package/lib/{cline-pass-BT9CBEOj.mjs → cline-pass-Bjm-O8GG.mjs} +2 -2
- package/lib/cloudflare-CKXRJ0l9.mjs +37 -0
- package/lib/{cloudflare-ai-gateway-DReN6ohJ.mjs → cloudflare-ai-gateway-BpnBSjwV.mjs} +8 -4
- package/lib/cloudflare-workers-ai-odj9XswL.mjs +32 -0
- package/lib/collapse-_nkb2dn7.mjs +1945 -0
- package/lib/{coreweave-C82HrLpb.mjs → coreweave-CGDZOD8-.mjs} +1 -1
- package/lib/{coreweave-C68UgRQO.mjs → coreweave-DwffcgW5.mjs} +4 -4
- package/lib/cursor-BgOuV7Qf.mjs +794 -0
- package/lib/{cursor-_gHHq-Dq.mjs → cursor-CF1iHHbv.mjs} +68 -19
- package/lib/{cursor-proto-Cr_WEMuv.mjs → cursor-proto-BuNTjX3L.mjs} +823 -23
- package/lib/{devin-QpfTSl9H.mjs → devin-7OEeEb80.mjs} +112 -31
- package/lib/{devin-proto-DYhp4Ty6.mjs → devin-proto-C-QreeAv.mjs} +71 -5
- package/lib/{dom-DG3sPESc.mjs → dom-BmbZv4v9.mjs} +598 -182
- package/lib/{error-O63pC8zg.mjs → error-8LVo7tug.mjs} +725 -104
- package/lib/factory-droid-ChhmsGWb.mjs +71 -0
- package/lib/{fs-promises-shim-B2YFWkcd.mjs → fs-promises-shim-CANAxFWh.mjs} +10 -1
- package/lib/{github-copilot-BMEcw8N1.mjs → github-copilot-QwevdT30.mjs} +4 -4
- package/lib/{github-copilot-headers-DnjGEbko.mjs → github-copilot-headers-CAUZ0rUD.mjs} +138 -26
- package/lib/{gitlab-duo-DnHqJjFY.mjs → gitlab-duo-DigV7k_o.mjs} +2 -2
- package/lib/{google-antigravity-B1mSckrK.mjs → google-antigravity-D-oe0r8A.mjs} +6 -7
- package/lib/{google-gemini-cli-DJwThCCn.mjs → google-gemini-cli-CQBHgGJT.mjs} +5 -6
- package/lib/{google-oauth-shared-BctLpVUN.mjs → google-oauth-shared-CvgVIUwJ.mjs} +2 -2
- package/lib/google-validation-CdvRj4ec.mjs +126 -0
- package/lib/id-EJwVLDHE.mjs +2548 -0
- package/lib/index.mjs +248 -258
- package/lib/{kilo-BEgEwMJQ.mjs → kilo-5r6OffCa.mjs} +2 -2
- package/lib/{kimi-T9NldEIJ.mjs → kimi-DOOtbXmm.mjs} +9 -10
- package/lib/{launch-BIWNyrBB.mjs → launch-DkAjib7h.mjs} +1 -1
- package/lib/{markit-Dvp2JPdT.mjs → markit-CCcyeAds.mjs} +359 -140
- package/lib/{models-DnXMYGcJ.mjs → models-DCpDT_im.mjs} +199203 -112275
- package/lib/{muse-code-CNvqqAp6.mjs → muse-code-CYf8zj_B.mjs} +5 -5
- package/lib/{openai-codex-D5-CyTxa.mjs → openai-codex-Cj-TvSFh.mjs} +13 -10
- package/lib/{perplexity-A2PEoGaC.mjs → perplexity-Dh_Qgsmx.mjs} +68 -25
- package/lib/{pkce-BYjmugmw.mjs → pkce-DO-jBJLV.mjs} +1 -1
- package/lib/pricing-DusBEhwm.mjs +593 -0
- package/lib/{readability-uGhqb4GC.mjs → readability-XHK0o3bv.mjs} +287 -27
- package/lib/{scrapers-C1ujjV8k.mjs → scrapers-B6PADOVm.mjs} +13 -13
- package/lib/slugify-ynYWBIA5.mjs +11 -0
- package/lib/snowflake-B_jap6lz.mjs +666 -0
- package/lib/snowflake-Cu1ZyOp6.mjs +151 -0
- package/lib/{src-AELUUb5U.mjs → src-BhinCSpi.mjs} +1172 -458
- package/lib/{stream-AVOoe5Hj.mjs → stream-D2ivg3GH.mjs} +3740 -5311
- package/lib/{turndown-D6fof1OX.mjs → turndown-Vya8SavL.mjs} +82 -30
- package/lib/types/tools/hashline/native/index.d.ts +2 -2
- package/lib/types/tools/hashline/native/policy.d.ts +19 -21
- package/lib/types/tools/omp/session/agent-storage.d.ts +3 -3
- package/lib/types/tools/shared/bun-named-shim.d.ts +5 -0
- package/lib/{types-BLrLohwK.mjs → types-tH1v9uRm.mjs} +2 -2
- package/lib/{utils-cZX3f_Ls.mjs → utils-C_Ncya1r.mjs} +1737 -509
- package/lib/utils-D2tK38xq.mjs +34006 -0
- package/lib/{utils-I4I8azHN.mjs → utils-DrDwmNtu.mjs} +8 -3
- package/lib/{xai-oauth-CbeldUSV.mjs → xai-oauth-DLLzX6my.mjs} +4 -4
- package/lib/{xiaomi-Dl3VSs04.mjs → xiaomi-CqK-KivK.mjs} +2 -2
- package/lib/{zai-FyjGSypr.mjs → zai-DoJ2xPIH.mjs} +2 -2
- package/lib/{zip-DRrycScC.mjs → zip-DG1mUV6X.mjs} +1 -1
- package/package.json +8 -8
- package/lib/amazon-bedrock-Dx0rr9dY.mjs +0 -996
- package/lib/anthropic-ClCw0PV_.mjs +0 -3624
- package/lib/anthropic-wire-lbGAFzYb.mjs +0 -927
- package/lib/azure-openai-responses-WE_bgFWp.mjs +0 -285
- package/lib/bundled-references-DY3EJxZV.mjs +0 -56
- package/lib/cloudflare-ai-gateway-CrMa97Ap.mjs +0 -44
- package/lib/collapse-CkMNRNr7.mjs +0 -2304
- package/lib/cursor-C6jaIJDg.mjs +0 -283
- package/lib/cursor-D-XZYDf_.mjs +0 -4544
- package/lib/deterministic-id-CUEIMSqR.mjs +0 -17
- package/lib/devin-ExGIghmx.mjs +0 -69
- package/lib/devin-u0ljw5P6.mjs +0 -628
- package/lib/effort-BdtQMN-_.mjs +0 -23
- package/lib/event-stream-BKEtb45Y.mjs +0 -167
- package/lib/gemini-headers-Co9cVvex.mjs +0 -54
- package/lib/google-auth-qAN-6DMW.mjs +0 -232
- package/lib/google-gemini-cli-B2Aw1S5w.mjs +0 -844
- package/lib/google-lTxuq28n.mjs +0 -38
- package/lib/google-shared-Y01j9xOr.mjs +0 -856
- package/lib/google-validation-BEkNs-Bx.mjs +0 -18
- package/lib/google-vertex-DcM-FRC5.mjs +0 -99
- package/lib/hosts-00rjRzUD.mjs +0 -203
- package/lib/id-AL5obQzR.mjs +0 -71
- package/lib/idle-iterator-D0ZXEcUq.mjs +0 -366
- package/lib/ollama-6R0oXZks.mjs +0 -574
- package/lib/openai-codex-responses-C8bnBWOe.mjs +0 -3232
- package/lib/openai-completions-DNr3mUsn.mjs +0 -1430
- package/lib/openai-configuration-update-xMYUjaK_.mjs +0 -150
- package/lib/openai-reasoning-fallback-Ju-5pSR8.mjs +0 -380
- package/lib/openai-responses-CjpafAEr.mjs +0 -861
- package/lib/protobuf-BMgDYu_U.mjs +0 -717
- package/lib/provider-response-SqKSkkUc.mjs +0 -22
- package/lib/proxy-DxvCQOCA.mjs +0 -230
- package/lib/request-debug-BwPOqN_j.mjs +0 -183
- package/lib/sanitize-text-BCf5KmCf.mjs +0 -33
- package/lib/sse-debug-B-tkLCPW.mjs +0 -11
- package/lib/stream-markup-healing-CN3RsqG9.mjs +0 -267
- package/lib/strict-tool-validation-CBTz1dAA.mjs +0 -105
- package/lib/taxonomy-DSIM99rS.mjs +0 -15392
- package/lib/thinking-ngMwf_1Y.mjs +0 -336
- package/lib/type-guards-CttAANEx.mjs +0 -11
- package/lib/utils-CE3DSebh.mjs +0 -11763
- package/lib/vision-guard-BCpXWUj3.mjs +0 -77
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
2
|
__installBunShim();
|
|
3
|
-
import {
|
|
3
|
+
import { n as fs_promises_shim_exports } from "./fs-promises-shim-CANAxFWh.mjs";
|
|
4
|
+
import { at as getLogsDir, dt as isEnoent, k as warn, lt as isBunTestRuntime } from "./src-BhinCSpi.mjs";
|
|
5
|
+
import { h as isRecord } from "./cascade-BWjRTD1q.mjs";
|
|
6
|
+
import "./behavior-BwvTUtag.mjs";
|
|
4
7
|
import * as path$1 from "node:path";
|
|
5
8
|
import { scheduler } from "node:timers/promises";
|
|
6
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.
|
|
9
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.12.6/node_modules/@oh-my-pi/pi-utils/src/fetch-retry.ts
|
|
7
10
|
const QUOTA_RESET_PATTERN = /reset after (?:(\d+)h)?(?:(\d+)m)?(\d+(?:\.\d+)?)s/i;
|
|
8
11
|
const PLEASE_RETRY_PATTERN = /Please retry in ([0-9.]+)(ms|s)/i;
|
|
9
12
|
const RETRY_DELAY_FIELD_PATTERN = /"retryDelay":\s*"([0-9.]+)(ms|s)"/i;
|
|
10
13
|
const TRY_AGAIN_PATTERN = /try again in\s+~?\s*([0-9.]+)\s*(ms|sec|s|minutes?|mins?|m|hours?|hrs?|h)\b/i;
|
|
11
|
-
const WILL_RESET_IN_PATTERN = /(?:will\s+)?
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
+
const WILL_RESET_IN_PATTERN = /(?:will\s+)?resets?\s+in\s+~?\s*([0-9.]+)\s*(ms|sec|s|minutes?|mins?|m|hours?|hrs?|h|days?|d)\b/i;
|
|
15
|
+
const RESET_IN_HR_MIN_PATTERN = /resets?\s+in\s+~?\s*(\d+(?:\.\d+)?)\s*hr\s*(\d+(?:\.\d+)?)\s*min\b/i;
|
|
16
|
+
const RESET_AT_PATTERNS = [/(?:will\s+)?reset at\s+([0-9]{4}-[0-9]{2}-[0-9]{2}[ T][0-9]{2}:[0-9]{2}:[0-9]{2}(?:\.[0-9]+)?(?:Z|[+-][0-9]{2}:?[0-9]{2})?)/i, /将在\s*([0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]{2}:[0-9]{2}:[0-9]{2})\s*重置/];
|
|
14
17
|
const RETRY_AFTER_MS_BODY_PATTERN = /\bretry-after-ms\s*[:=]\s*([0-9]+)\b/i;
|
|
15
18
|
/**
|
|
16
19
|
* Server-suggested retry delay extraction. Merges the patterns historically used
|
|
17
|
-
* by the OpenAI Codex and Google Gemini retry helpers.
|
|
18
20
|
*
|
|
19
21
|
* Header sources (checked in order):
|
|
20
22
|
* - `retry-after-ms` (milliseconds)
|
|
@@ -30,12 +32,14 @@ const RETRY_AFTER_MS_BODY_PATTERN = /\bretry-after-ms\s*[:=]\s*([0-9]+)\b/i;
|
|
|
30
32
|
* - `try again in 250ms` / `try again in 12s` / `try again in 5 min` / `try again in ~158 min`
|
|
31
33
|
* - `retry-after-ms=98497000` / `retry-after-ms: 7200000` / `retry-after-ms = 7200000`
|
|
32
34
|
* - `Your limit will reset at 2026-09-01 09:44:51` / `将在 2026-09-01 09:44:51 重置`
|
|
35
|
+
* (a provider offset makes a naive wall clock authoritative; otherwise it
|
|
36
|
+
* resolves only when no relative signal is present)
|
|
33
37
|
*
|
|
34
38
|
* Returns `undefined` if no signal is found, or `0` when the provider
|
|
35
39
|
* explicitly asks for an immediate retry (`retry-after…=0`, or an absolute
|
|
36
40
|
* reset timestamp that has already elapsed).
|
|
37
41
|
*/
|
|
38
|
-
function extractRetryHint(source, body) {
|
|
42
|
+
function extractRetryHint(source, body, options) {
|
|
39
43
|
const headers = source instanceof Headers ? source : source?.headers ?? void 0;
|
|
40
44
|
if (headers) {
|
|
41
45
|
const retryAfterMs = headers.get("retry-after-ms");
|
|
@@ -77,6 +81,10 @@ function extractRetryHint(source, body) {
|
|
|
77
81
|
if (!body) return void 0;
|
|
78
82
|
let longestMs;
|
|
79
83
|
let retryNow = false;
|
|
84
|
+
let longestNaiveMs;
|
|
85
|
+
const considerNaive = (ms) => {
|
|
86
|
+
if (ms !== void 0 && ms > 0 && (longestNaiveMs === void 0 || ms > longestNaiveMs)) longestNaiveMs = ms;
|
|
87
|
+
};
|
|
80
88
|
const consider = (ms) => {
|
|
81
89
|
if (ms !== void 0 && ms > 0 && (longestMs === void 0 || ms > longestMs)) longestMs = ms;
|
|
82
90
|
};
|
|
@@ -95,15 +103,24 @@ function extractRetryHint(source, body) {
|
|
|
95
103
|
consider(totalMs > 0 ? totalMs : void 0);
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
|
-
for (const pattern of
|
|
106
|
+
for (const pattern of RESET_AT_PATTERNS) {
|
|
99
107
|
const match = pattern.exec(body);
|
|
100
|
-
if (match?.[1])
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
if (!match?.[1]) continue;
|
|
109
|
+
const normalized = match[1].replace(" ", "T");
|
|
110
|
+
const hasOffset = /(?:Z|[+-][0-9]{2}:?[0-9]{2})$/i.test(normalized);
|
|
111
|
+
const configuredOffset = options?.naiveResetTimezoneOffset;
|
|
112
|
+
const parsed = Date.parse(hasOffset ? normalized : `${normalized}${configuredOffset ?? "Z"}`);
|
|
113
|
+
if (!Number.isNaN(parsed) && parsed > Date.now()) {
|
|
114
|
+
if (hasOffset || configuredOffset !== void 0) consider(parsed - Date.now());
|
|
115
|
+
else considerNaive(parsed - Date.now());
|
|
105
116
|
}
|
|
106
117
|
}
|
|
118
|
+
const compoundResetMatch = RESET_IN_HR_MIN_PATTERN.exec(body);
|
|
119
|
+
if (compoundResetMatch?.[1] && compoundResetMatch[2]) {
|
|
120
|
+
const hours = Number.parseFloat(compoundResetMatch[1]);
|
|
121
|
+
const minutes = Number.parseFloat(compoundResetMatch[2]);
|
|
122
|
+
if (Number.isFinite(hours) && Number.isFinite(minutes) && hours >= 0 && minutes > 0) consider(hours * 60 * 6e4 + minutes * 6e4);
|
|
123
|
+
}
|
|
107
124
|
const accountResetMatch = WILL_RESET_IN_PATTERN.exec(body);
|
|
108
125
|
if (accountResetMatch?.[1]) {
|
|
109
126
|
const value = Number.parseFloat(accountResetMatch[1]);
|
|
@@ -151,7 +168,7 @@ function extractRetryHint(source, body) {
|
|
|
151
168
|
const resetSeconds = Number(resetMatch[1]);
|
|
152
169
|
if (!Number.isNaN(resetSeconds)) considerClamped(resetSeconds > 1e9 ? resetSeconds * 1e3 - Date.now() : resetSeconds * 1e3);
|
|
153
170
|
}
|
|
154
|
-
return longestMs ?? (retryNow ? 0 : void 0);
|
|
171
|
+
return longestMs ?? longestNaiveMs ?? (retryNow ? 0 : void 0);
|
|
155
172
|
}
|
|
156
173
|
function unitToMs(unit) {
|
|
157
174
|
switch (unit.toLowerCase()) {
|
|
@@ -168,6 +185,9 @@ function unitToMs(unit) {
|
|
|
168
185
|
case "hrs":
|
|
169
186
|
case "hour":
|
|
170
187
|
case "hours": return 36e5;
|
|
188
|
+
case "d":
|
|
189
|
+
case "day":
|
|
190
|
+
case "days": return 864e5;
|
|
171
191
|
default: return;
|
|
172
192
|
}
|
|
173
193
|
}
|
|
@@ -202,13 +222,15 @@ async function fetchWithRetry(url, options = {}) {
|
|
|
202
222
|
await waitForRetry(resolveDefaultDelay(defaultDelayMs, attempt, maxDelayMs), signal);
|
|
203
223
|
continue;
|
|
204
224
|
}
|
|
205
|
-
if (!isRetryableStatus(response.status)) return response;
|
|
225
|
+
if (!isRetryableStatus$1(response.status)) return response;
|
|
206
226
|
if (attempt + 1 >= maxAttempts) return response;
|
|
207
227
|
const retryBody = await response.clone().text();
|
|
208
228
|
if (shouldRetryResponse && !await shouldRetryResponse(response, retryBody, attempt)) return response;
|
|
209
229
|
const hint = extractRetryHint(response, retryBody);
|
|
210
230
|
if (hint !== void 0 && hint > maxDelayMs) return response;
|
|
211
|
-
|
|
231
|
+
const delayMs = Math.min(hint ?? resolveDefaultDelay(defaultDelayMs, attempt, maxDelayMs), maxDelayMs);
|
|
232
|
+
if (!response.bodyUsed) response.body?.cancel().catch(() => {});
|
|
233
|
+
await waitForRetry(delayMs, signal);
|
|
212
234
|
}
|
|
213
235
|
}
|
|
214
236
|
function mergeInit(base, overlay, timeout) {
|
|
@@ -237,7 +259,7 @@ async function waitForRetry(delayMs, signal) {
|
|
|
237
259
|
function wrapNetworkError(error) {
|
|
238
260
|
if (error instanceof Error) {
|
|
239
261
|
if (error.name === "AbortError" || error.message === "Request was aborted") return /* @__PURE__ */ new Error("Request was aborted");
|
|
240
|
-
if (error.message === "fetch failed" && error.cause instanceof Error) return
|
|
262
|
+
if (error.message === "fetch failed" && error.cause instanceof Error) return new Error(`Network error: ${error.cause.message}`, { cause: error });
|
|
241
263
|
return error;
|
|
242
264
|
}
|
|
243
265
|
return new Error(String(error));
|
|
@@ -293,7 +315,7 @@ function extractStatusFromMessage(message) {
|
|
|
293
315
|
* `true` if the given HTTP status code is one we treat as transient: 408
|
|
294
316
|
* (Request Timeout), 429 (Too Many Requests), or any 5xx (server error).
|
|
295
317
|
*/
|
|
296
|
-
function isRetryableStatus(status) {
|
|
318
|
+
function isRetryableStatus$1(status) {
|
|
297
319
|
return status >= 500 || status === 408 || status === 429;
|
|
298
320
|
}
|
|
299
321
|
/**
|
|
@@ -317,14 +339,14 @@ function isRetryableError(error) {
|
|
|
317
339
|
if ((info?.name ?? "") === "AbortError" || /timeout|timed out|aborted/i.test(message)) return true;
|
|
318
340
|
const status = extractHttpStatusFromError(error);
|
|
319
341
|
if (status !== void 0) {
|
|
320
|
-
if (isRetryableStatus(status)) return true;
|
|
342
|
+
if (isRetryableStatus$1(status)) return true;
|
|
321
343
|
if (status >= 400 && status < 500) return false;
|
|
322
344
|
}
|
|
323
345
|
if (VALIDATION_MESSAGE_PATTERN.test(message)) return false;
|
|
324
346
|
return isUnexpectedSocketCloseMessage(message) || TRANSIENT_MESSAGE_PATTERN.test(message);
|
|
325
347
|
}
|
|
326
348
|
//#endregion
|
|
327
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
349
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/aws.ts
|
|
328
350
|
/** A failure resolving AWS credentials for the Bedrock provider. */
|
|
329
351
|
var AwsCredentialsError = class extends Error {
|
|
330
352
|
kind;
|
|
@@ -342,7 +364,136 @@ var EventStreamFrameError = class extends Error {
|
|
|
342
364
|
}
|
|
343
365
|
};
|
|
344
366
|
//#endregion
|
|
345
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
367
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/network-cause.ts
|
|
368
|
+
const MAX_CAUSE_DEPTH = 8;
|
|
369
|
+
const MAX_AGGREGATE_BRANCH = 4;
|
|
370
|
+
const MAX_LINKS = 16;
|
|
371
|
+
const MAX_DETAIL_LENGTH = 120;
|
|
372
|
+
const UNKNOWN_HOST = "the API host";
|
|
373
|
+
const OFFLINE_CODE_PATTERN = /^(?:ETIMEOUT|EAI_AGAIN|ENETUNREACH|EHOSTUNREACH)$/i;
|
|
374
|
+
const OFFLINE_TEXT_PATTERN = /\b(?:ETIMEOUT|EAI_AGAIN|ENETUNREACH|EHOSTUNREACH)\b/i;
|
|
375
|
+
const UNREACHABLE_CODE_PATTERN = /^(?:ENOTFOUND|FailedToOpenSocket)$/i;
|
|
376
|
+
const UNREACHABLE_TEXT_PATTERN = /\b(?:ENOTFOUND|FailedToOpenSocket|getaddrinfo)\b/i;
|
|
377
|
+
const REFUSED_CODE_PATTERN = /^(?:ECONNREFUSED|ConnectionRefused)$/i;
|
|
378
|
+
const REFUSED_TEXT_PATTERN = /\bECONNREFUSED\b|\bConnectionRefused\b|\bUnable to connect\b/i;
|
|
379
|
+
const TLS_CODE_PATTERN = /^(?:CERT_|SELF_SIGNED|UNABLE_TO_GET_ISSUER_CERT|UNABLE_TO_VERIFY|DEPTH_ZERO_SELF_SIGNED_CERT|ERR_TLS_CERT)/i;
|
|
380
|
+
const TLS_TEXT_PATTERN = /unable to verify|certificate verif(?:y|ication)|self[- ]signed certificate|\bCERT_[A-Z_]+\b|\bSELF_SIGNED[A-Z_]*\b|\bUNABLE_TO_GET_ISSUER_CERT[A-Z_]*\b|\bUNABLE_TO_VERIFY_LEAF_SIGNATURE\b/i;
|
|
381
|
+
const GETADDRINFO_HOST_PATTERN = /\bgetaddrinfo\s+[A-Z_]+\s+([^\s,)]+)/i;
|
|
382
|
+
const CONNECT_HOST_PATTERN = /\b(?:connect|connection to)\s+[A-Z_]+\s+([^\s,)]+?)(?::\d+)?(?=[\s,)]|$)/i;
|
|
383
|
+
const BARE_HOST_PATTERN = /\b((?:[a-z0-9-]+\.)+[a-z]{2,})\b/i;
|
|
384
|
+
const GETADDRINFO_DETAIL_PATTERN = /\bgetaddrinfo\s+[A-Z_]+/i;
|
|
385
|
+
const ERRNO_DETAIL_PATTERN = /\b(?:ETIMEOUT|ENOTFOUND|EAI_AGAIN|ENETUNREACH|EHOSTUNREACH|FailedToOpenSocket)\b/i;
|
|
386
|
+
const HOST_PATTERNS = [
|
|
387
|
+
GETADDRINFO_HOST_PATTERN,
|
|
388
|
+
CONNECT_HOST_PATTERN,
|
|
389
|
+
BARE_HOST_PATTERN
|
|
390
|
+
];
|
|
391
|
+
function kindOf(code, message) {
|
|
392
|
+
if (code !== void 0 && TLS_CODE_PATTERN.test(code)) return "tls";
|
|
393
|
+
if (message !== void 0 && TLS_TEXT_PATTERN.test(message)) return "tls";
|
|
394
|
+
if (code !== void 0 && REFUSED_CODE_PATTERN.test(code)) return "refused";
|
|
395
|
+
if (message !== void 0 && REFUSED_TEXT_PATTERN.test(message)) return "refused";
|
|
396
|
+
if (code !== void 0 && OFFLINE_CODE_PATTERN.test(code)) return "offline";
|
|
397
|
+
if (message !== void 0 && OFFLINE_TEXT_PATTERN.test(message)) return "offline";
|
|
398
|
+
if (code !== void 0 && UNREACHABLE_CODE_PATTERN.test(code)) return "unreachable";
|
|
399
|
+
if (message !== void 0 && UNREACHABLE_TEXT_PATTERN.test(message)) return "unreachable";
|
|
400
|
+
}
|
|
401
|
+
/** First host named by any message seen so far, most specific pattern first. */
|
|
402
|
+
function hostFromTexts(texts) {
|
|
403
|
+
for (const pattern of HOST_PATTERNS) for (const text of texts) {
|
|
404
|
+
const host = pattern.exec(text)?.[1];
|
|
405
|
+
if (host) return host;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function detailOf(kind, code, message) {
|
|
409
|
+
if (kind === "refused") return void 0;
|
|
410
|
+
if (kind === "tls" && code !== void 0) return code;
|
|
411
|
+
const matched = message === void 0 ? void 0 : (kind === "tls" ? TLS_TEXT_PATTERN : GETADDRINFO_DETAIL_PATTERN).exec(message)?.[0];
|
|
412
|
+
if (matched !== void 0) return matched.replace(/\s+/g, " ").trim().slice(0, MAX_DETAIL_LENGTH);
|
|
413
|
+
if (kind === "tls") return void 0;
|
|
414
|
+
return code ?? (message === void 0 ? void 0 : ERRNO_DETAIL_PATTERN.exec(message)?.[0]);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Walk an error's `cause`/`errors` graph (bounded depth, cycle-safe) and report
|
|
418
|
+
* the outermost link that describes a local transport failure. Returns
|
|
419
|
+
* `undefined` for anything else, including HTTP-level provider errors.
|
|
420
|
+
*/
|
|
421
|
+
function classifyNetworkCause(err) {
|
|
422
|
+
const seen = /* @__PURE__ */ new Set();
|
|
423
|
+
const queue = [{
|
|
424
|
+
value: err,
|
|
425
|
+
depth: 0
|
|
426
|
+
}];
|
|
427
|
+
const texts = [];
|
|
428
|
+
let links = 0;
|
|
429
|
+
while (links < MAX_LINKS) {
|
|
430
|
+
const link = queue.shift();
|
|
431
|
+
if (link === void 0) break;
|
|
432
|
+
links++;
|
|
433
|
+
const { value, depth } = link;
|
|
434
|
+
let code;
|
|
435
|
+
let message;
|
|
436
|
+
const isObject = typeof value === "object" && value !== null;
|
|
437
|
+
if (typeof value === "string") message = value;
|
|
438
|
+
else if (isObject) {
|
|
439
|
+
if (seen.has(value)) continue;
|
|
440
|
+
seen.add(value);
|
|
441
|
+
if ("code" in value && typeof value.code === "string") code = value.code;
|
|
442
|
+
if ("message" in value && typeof value.message === "string") message = value.message;
|
|
443
|
+
} else continue;
|
|
444
|
+
if (message !== void 0) texts.push(message);
|
|
445
|
+
const kind = kindOf(code, message);
|
|
446
|
+
if (kind !== void 0) return {
|
|
447
|
+
kind,
|
|
448
|
+
code,
|
|
449
|
+
detail: detailOf(kind, code, message),
|
|
450
|
+
host: hostFromTexts(texts)
|
|
451
|
+
};
|
|
452
|
+
if (!isObject || depth >= MAX_CAUSE_DEPTH) continue;
|
|
453
|
+
if ("cause" in value) queue.push({
|
|
454
|
+
value: value.cause,
|
|
455
|
+
depth: depth + 1
|
|
456
|
+
});
|
|
457
|
+
if ("errors" in value && Array.isArray(value.errors)) for (const nested of value.errors.slice(0, MAX_AGGREGATE_BRANCH)) queue.push({
|
|
458
|
+
value: nested,
|
|
459
|
+
depth: depth + 1
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* User-visible sentence for a network failure, or `undefined` when the error is
|
|
465
|
+
* not one. `requestUrl` wins over any host parsed out of the error text.
|
|
466
|
+
*/
|
|
467
|
+
function networkFailureMessage(err, requestUrl) {
|
|
468
|
+
const failure = classifyNetworkCause(err);
|
|
469
|
+
if (failure === void 0) return void 0;
|
|
470
|
+
let urlHost;
|
|
471
|
+
if (typeof requestUrl === "string" && requestUrl.length > 0) try {
|
|
472
|
+
const { host } = new URL(requestUrl);
|
|
473
|
+
if (host.length > 0) urlHost = host;
|
|
474
|
+
} catch {
|
|
475
|
+
urlHost = void 0;
|
|
476
|
+
}
|
|
477
|
+
const host = urlHost ?? failure.host ?? UNKNOWN_HOST;
|
|
478
|
+
const detail = failure.detail === void 0 ? "" : ` (${failure.detail})`;
|
|
479
|
+
switch (failure.kind) {
|
|
480
|
+
case "offline": return `No internet connection: couldn't reach ${host}${detail}. Check your network or proxy and try again.`;
|
|
481
|
+
case "unreachable": return `Couldn't reach ${host}${detail}. Check the URL, your network, or proxy.`;
|
|
482
|
+
case "refused": return `Couldn't connect to ${host} (connection refused). Check that the server is running and reachable.`;
|
|
483
|
+
case "tls": return `TLS certificate verification failed for ${host}${detail}. If you're behind a TLS-inspecting proxy, its CA may need to be trusted.`;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Re-describe a rejected `fetch` with {@link networkFailureMessage}, keeping the
|
|
488
|
+
* original error as `cause`. Anything that is not a local transport failure is
|
|
489
|
+
* returned untouched, so provider/HTTP errors keep their identity.
|
|
490
|
+
*/
|
|
491
|
+
function networkFailureError(err, requestUrl) {
|
|
492
|
+
const message = networkFailureMessage(err, requestUrl);
|
|
493
|
+
return message === void 0 ? err : new Error(message, { cause: err });
|
|
494
|
+
}
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/classes.ts
|
|
346
497
|
/** Prefix on errors raised when an Anthropic SSE stream envelope is malformed. */
|
|
347
498
|
const STREAM_ENVELOPE_ERROR_PREFIX = "Anthropic stream envelope error:";
|
|
348
499
|
/** Non-2xx HTTP response from a provider. */
|
|
@@ -410,8 +561,12 @@ let anthropicErrorBodyReadTimeoutMs = DEFAULT_ANTHROPIC_ERROR_BODY_READ_TIMEOUT_
|
|
|
410
561
|
/** Non-2xx response from the Anthropic API. */
|
|
411
562
|
var AnthropicApiError = class AnthropicApiError extends ProviderHttpError {
|
|
412
563
|
requestId;
|
|
413
|
-
constructor(status, message, headers) {
|
|
414
|
-
super(message, status, {
|
|
564
|
+
constructor(status, message, headers, options) {
|
|
565
|
+
super(message, status, {
|
|
566
|
+
headers,
|
|
567
|
+
code: options?.code,
|
|
568
|
+
cause: options?.cause
|
|
569
|
+
});
|
|
415
570
|
this.name = "AnthropicApiError";
|
|
416
571
|
this.requestId = headers.get("request-id");
|
|
417
572
|
}
|
|
@@ -486,13 +641,24 @@ var AnthropicApiError = class AnthropicApiError extends ProviderHttpError {
|
|
|
486
641
|
reader.releaseLock();
|
|
487
642
|
}
|
|
488
643
|
const detail = bodyChunks.join("").trim() || "status code (no body)";
|
|
489
|
-
|
|
644
|
+
let code;
|
|
645
|
+
try {
|
|
646
|
+
const parsed = JSON.parse(detail);
|
|
647
|
+
if (parsed && typeof parsed === "object" && "error" in parsed) {
|
|
648
|
+
const err = parsed.error;
|
|
649
|
+
if (err && typeof err === "object") {
|
|
650
|
+
if ("details" in err && err.details && typeof err.details === "object" && "error_code" in err.details && typeof err.details.error_code === "string") code = err.details.error_code;
|
|
651
|
+
else if ("type" in err && typeof err.type === "string") code = err.type;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
} catch {}
|
|
655
|
+
return new AnthropicApiError(response.status, `${response.status} ${detail}`, response.headers, { code });
|
|
490
656
|
}
|
|
491
657
|
};
|
|
492
658
|
/** Network-level failure (DNS, TLS, socket reset) after retries were exhausted. */
|
|
493
659
|
var AnthropicConnectionError = class extends Error {
|
|
494
|
-
constructor(cause) {
|
|
495
|
-
super("Connection error.", { cause });
|
|
660
|
+
constructor(cause, requestUrl) {
|
|
661
|
+
super(networkFailureMessage(cause, requestUrl) ?? "Connection error.", { cause });
|
|
496
662
|
this.name = "AnthropicConnectionError";
|
|
497
663
|
}
|
|
498
664
|
};
|
|
@@ -532,11 +698,13 @@ var OllamaApiError = class extends ProviderHttpError {
|
|
|
532
698
|
name = "OllamaApiError";
|
|
533
699
|
};
|
|
534
700
|
//#endregion
|
|
535
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
701
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/rate-limit.ts
|
|
536
702
|
const ACCOUNT_RATE_LIMIT_PATTERN = /\baccount(?:'s)?\b[^\n]{0,80}\brate.?limit\b|\brate.?limit\b[^\n]{0,80}\baccount\b/i;
|
|
537
703
|
const INSUFFICIENT_BALANCE_PATTERN = /insufficient.?balance/i;
|
|
538
704
|
const CREDITS_EXHAUSTED_PATTERN = /\b(?:exceed\w*|insufficient|not enough)\b[^\n]{0,40}\bcredits?\b|\bcredits?\b[^\n]{0,40}\b(?:exhausted|depleted)\b/i;
|
|
539
|
-
const
|
|
705
|
+
const ANTHROPIC_CREDITS_REQUIRED_PATTERN = /\busage credits are required\b|\bcredits_required\b/i;
|
|
706
|
+
const PREPAID_BALANCE_EXHAUSTED_PATTERN = /\busage_pricing_required\b|\bprepaid balance\b[^\n]{0,40}\b(?:used up|exhausted|depleted)\b/i;
|
|
707
|
+
const SPEND_LIMIT_PATTERN = /spend(?:ing)?[\s_-]?(?:limit|cap)\b/i;
|
|
540
708
|
const SUBSCRIPTION_CAP_PATTERN = /\b(?:subscription|plan|membership)\b[^\n]{0,80}\b(?:rate.?limits?|quota|cap)\b|\b(?:rate.?limits?|quota|cap)\b[^\n]{0,80}\b(?:subscription|plan|membership)\b/i;
|
|
541
709
|
const TRANSIENT_INTERVAL_RATE_LIMIT_PATTERN = /\bper\s+(?:second|minute)\b/i;
|
|
542
710
|
function matchesSubscriptionCapText(errorMessage) {
|
|
@@ -547,7 +715,7 @@ const CLINE_PASS_QUOTA_PATTERN = /clinepass limit|free limit reached on model/i;
|
|
|
547
715
|
const RESOURCE_EXHAUSTED_PATTERN = /resource.?exhausted/gi;
|
|
548
716
|
const CONCURRENT_LIMIT_PATTERN = /\btoo many\s+concurren\w*\s+(?:requests?|invocations?)\b|\bconcurren\w*\b[^\n]{0,60}\b(?:limit|quota|exceed\w*|reach\w*)\b|\b(?:limit|quota|exceed\w*|reach\w*)\b[^\n]{0,60}\bconcurren\w*\b|\bconcurren[a-z]*[-_](?:[a-z]+[_-])*(?:limit|quota|exceed\w*|reach\w*)/i;
|
|
549
717
|
const ACCOUNT_SCOPED_403_PATTERN = /\b(?:overall|account|organization|team|workspace)\b[^\n]{0,40}\b(?:message |request )?rate.?limit\b|\byour\b[^\n]{0,30}\b(?:limit )?will reset\b/i;
|
|
550
|
-
const CN_QUOTA_EXHAUSTED_PATTERN =
|
|
718
|
+
const CN_QUOTA_EXHAUSTED_PATTERN = /(?:使用|用量).{0,30}?上限|(?:额度|配额)已?(?:用|耗)(?:完|尽)|限额.{0,30}重置|余额不足/;
|
|
551
719
|
const CN_TRANSIENT_CAP_PATTERN = /速率.{0,30}上限|频率.{0,30}上限|每分钟.{0,30}上限|并发.{0,30}上限|使用.{0,30}(?:速率|频率|每分钟|并发).{0,30}上限/;
|
|
552
720
|
const CN_THROTTLE_PATTERN = /速率(?:限制|过快)|频率(?:过高|过快)|过于频繁|稍后[重再]试/;
|
|
553
721
|
const DASHSCOPE_TOKEN_LIMIT_DOC_PATTERN = /error-code[^()\s]*#token-limit/i;
|
|
@@ -556,6 +724,7 @@ const DASHSCOPE_TOKEN_LIMIT_MESSAGE_PATTERN = /\byou exceeded your current quota
|
|
|
556
724
|
function isDashScopeTokenLimitText(errorMessage) {
|
|
557
725
|
return DASHSCOPE_TOKEN_LIMIT_DOC_PATTERN.test(errorMessage) && DASHSCOPE_TOKEN_LIMIT_MESSAGE_PATTERN.test(errorMessage);
|
|
558
726
|
}
|
|
727
|
+
const TPM_RPM_THROTTLE_PATTERN = /\b(?:tpm|rpm)\b[^\n]{0,40}\b(?:exhaust\w*|exceed\w*|limit\w*|throttl\w*|reach\w*)\b|\b(?:exhaust\w*|exceed\w*|limit\w*|throttl\w*|reach\w*)\b[^\n]{0,40}\b(?:tpm|rpm)\b|\bRateLimitExceeded\.(?:Endpoint)?(?:TPM|RPM)\w*/i;
|
|
559
728
|
const GOOGLE_RPC_ERROR_INFO_TYPE = "type.googleapis.com/google.rpc.ErrorInfo";
|
|
560
729
|
const ANTIGRAVITY_MODEL_QUOTA_PATTERN = /\bexhausted your capacity on this model\b/i;
|
|
561
730
|
const LONG_RATE_LIMIT_DELAY_MS = 3e5;
|
|
@@ -602,8 +771,9 @@ function isQuotaExhaustedReason(reason) {
|
|
|
602
771
|
* Classify a rate-limit error message into a reason category.
|
|
603
772
|
* Priority order: explicit details in a resource-exhausted error > QUOTA
|
|
604
773
|
* (Antigravity "quota will reset") > CN quota > DASHSCOPE_TOKEN_LIMIT (TPM/TPS
|
|
605
|
-
* throttle) > CONCURRENT_LIMIT > MODEL_CAPACITY > QUOTA (account) > RATE_LIMIT
|
|
606
|
-
* QUOTA (generic) > SERVER_ERROR > bare
|
|
774
|
+
* throttle) > CONCURRENT_LIMIT > MODEL_CAPACITY > QUOTA (account) > RATE_LIMIT
|
|
775
|
+
* (including TPM/RPM rolling windows) > QUOTA (generic) > SERVER_ERROR > bare
|
|
776
|
+
* resource-exhausted > UNKNOWN.
|
|
607
777
|
*
|
|
608
778
|
* Bare "resource exhausted" / "resource_exhausted" maps to MODEL_CAPACITY (transient, short wait).
|
|
609
779
|
* Explicit details such as "quota exceeded" retain their normal classification.
|
|
@@ -624,28 +794,31 @@ function parseRateLimitReason(errorMessage) {
|
|
|
624
794
|
if (matchesSubscriptionCapText(errorMessage)) return "QUOTA_EXHAUSTED";
|
|
625
795
|
if (OPENROUTER_DAILY_FREE_LIMIT_PATTERN.test(errorMessage)) return "QUOTA_EXHAUSTED";
|
|
626
796
|
if (CLINE_PASS_QUOTA_PATTERN.test(errorMessage)) return "QUOTA_EXHAUSTED";
|
|
627
|
-
if (
|
|
628
|
-
if (
|
|
797
|
+
if (ANTHROPIC_CREDITS_REQUIRED_PATTERN.test(errorMessage)) return "QUOTA_EXHAUSTED";
|
|
798
|
+
if (PREPAID_BALANCE_EXHAUSTED_PATTERN.test(errorMessage)) return "QUOTA_EXHAUSTED";
|
|
799
|
+
if (lower.includes("per minute") || lower.includes("rate limit") || lower.includes("too many requests") || lower.includes("presque") || TPM_RPM_THROTTLE_PATTERN.test(errorMessage)) return "RATE_LIMIT_EXCEEDED";
|
|
800
|
+
if (lower.includes("exhausted") || lower.includes("quota") || lower.includes("usage limit") || lower.includes("run out of credits") || lower.includes("out of credits") || lower.includes("spending-limit") || lower.includes("spending limit") || lower.includes("access_terminated_error") || INSUFFICIENT_BALANCE_PATTERN.test(errorMessage) || CREDITS_EXHAUSTED_PATTERN.test(errorMessage)) return "QUOTA_EXHAUSTED";
|
|
629
801
|
if (lower.includes("500") || lower.includes("internal error") || lower.includes("internal server error")) return "SERVER_ERROR";
|
|
630
802
|
if (hasResourceExhaustedStatus) return "MODEL_CAPACITY_EXHAUSTED";
|
|
631
803
|
return "UNKNOWN";
|
|
632
804
|
}
|
|
633
805
|
/** Detect usage/quota limit errors in error messages (persistent, requires credential switch). */
|
|
634
|
-
const USAGE_LIMIT_PATTERN = /usage.?limit|usage_limit_reached|usage_not_included|limit_reached|quota.?(?:exceeded|reached|insufficient)|额度不足|额度耗尽|resource.?exhausted|exhausted your capacity|quota will reset|insufficient.?(?:balance|quota)|balance.?exhausted|run out of credits|out of credits|spending[- _]?limit|personal-team-blocked|clinepass limit|free limit reached on model/i;
|
|
806
|
+
const USAGE_LIMIT_PATTERN = /usage.?limit|usage_limit_reached|usage_not_included|limit_reached|quota.?(?:exceeded|reached|insufficient)|额度不足|额度耗尽|resource.?exhausted|exhausted your capacity|quota will reset|insufficient.?(?:balance|quota)|balance.?exhausted|run out of credits|out of credits|out of (?:extra )?usage|spending[- _]?limit|personal-team-blocked|clinepass limit|free limit reached on model|access_terminated_error/i;
|
|
635
807
|
/**
|
|
636
808
|
* HTTP status codes that, absent richer body classification, represent an
|
|
637
809
|
* account-local usage cap rather than a bad credential or a transient blip.
|
|
638
810
|
* HTTP 402 Payment Required represents an account-billing cap (xAI
|
|
639
811
|
* Grok Build "usage balance exhausted", DeepSeek "Insufficient Balance",
|
|
640
|
-
* OpenRouter credit exhaustion)
|
|
641
|
-
*
|
|
812
|
+
* OpenCode Go "Insufficient account funds", OpenRouter credit exhaustion)
|
|
813
|
+
* when opaque, payment/deactivation/balance/funds-worded, or
|
|
814
|
+
* QUOTA_EXHAUSTED/CONCURRENT_LIMIT. Informative non-quota 402s (e.g.
|
|
642
815
|
* endpoint subscription requirements) remain non-usage-limits. Always combine
|
|
643
816
|
* with {@link isUsageLimitOutcome} when a message is available.
|
|
644
817
|
*/
|
|
645
818
|
function isUsageLimitStatus(status) {
|
|
646
819
|
return status === 429 || status === 402;
|
|
647
820
|
}
|
|
648
|
-
const STATUS_402_QUOTA_PATTERN = /\b(?:payment(?:\s+is)?[-_.\s]*required|deactivated_workspace|insufficient.?balance)\b/i;
|
|
821
|
+
const STATUS_402_QUOTA_PATTERN = /\b(?:payment(?:\s+is)?[-_.\s]*required|deactivated_workspace|insufficient.?(?:balance|account.?funds))\b/i;
|
|
649
822
|
function is402BillingCapBody(message) {
|
|
650
823
|
if (message === void 0 || isOpaqueStatusBody(message)) return true;
|
|
651
824
|
if (STATUS_402_QUOTA_PATTERN.test(message)) return true;
|
|
@@ -673,7 +846,8 @@ function matchesUsageLimitText(errorMessage) {
|
|
|
673
846
|
const structuredReason = parseGoogleRpcRateLimitReason(errorMessage);
|
|
674
847
|
if (structuredReason !== void 0) return isQuotaExhaustedReason(structuredReason);
|
|
675
848
|
if (isDashScopeTokenLimitText(errorMessage)) return false;
|
|
676
|
-
|
|
849
|
+
if (TPM_RPM_THROTTLE_PATTERN.test(errorMessage) && parseRateLimitReason(errorMessage) === "RATE_LIMIT_EXCEEDED") return false;
|
|
850
|
+
return USAGE_LIMIT_PATTERN.test(errorMessage) || ANTHROPIC_CREDITS_REQUIRED_PATTERN.test(errorMessage) || PREPAID_BALANCE_EXHAUSTED_PATTERN.test(errorMessage) || CREDITS_EXHAUSTED_PATTERN.test(errorMessage) || CN_QUOTA_EXHAUSTED_PATTERN.test(errorMessage) && !CN_TRANSIENT_CAP_PATTERN.test(errorMessage) || SPEND_LIMIT_PATTERN.test(errorMessage) || ACCOUNT_RATE_LIMIT_PATTERN.test(errorMessage) || matchesSubscriptionCapText(errorMessage) || OPENROUTER_DAILY_FREE_LIMIT_PATTERN.test(errorMessage);
|
|
677
851
|
}
|
|
678
852
|
/**
|
|
679
853
|
* Account-scoped cap phrasing delivered on a 403 (or a statusless Connect
|
|
@@ -686,7 +860,7 @@ function isAccountScopedCapText(message) {
|
|
|
686
860
|
return ACCOUNT_SCOPED_403_PATTERN.test(message);
|
|
687
861
|
}
|
|
688
862
|
//#endregion
|
|
689
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
863
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/flags.ts
|
|
690
864
|
const Flag = {
|
|
691
865
|
Class: 4096,
|
|
692
866
|
ThinkingLoop: 65536,
|
|
@@ -711,10 +885,20 @@ const Flag = {
|
|
|
711
885
|
FastModeUnsupported: 536870912,
|
|
712
886
|
/** OAuth refresh failed definitively — the stored grant is dead, re-login required. */
|
|
713
887
|
OAuthExpiry: 1073741824,
|
|
888
|
+
/**
|
|
889
|
+
* An Anthropic-compatible endpoint rejected the `cache_control` field with a
|
|
890
|
+
* 400, so prompt-cache breakpoints must be dropped for it.
|
|
891
|
+
*
|
|
892
|
+
* Every bit from {@link Flag.Class} up is already taken, so this claims a low
|
|
893
|
+
* bit instead. Those belong to the raw-status lane — an unclassified id is an
|
|
894
|
+
* HTTP status (100-599, see `statusFromId`) — and 0x800 is 2048, above every
|
|
895
|
+
* status value, so no raw status id can set it.
|
|
896
|
+
*/
|
|
897
|
+
CacheControlUnsupported: 2048,
|
|
714
898
|
/** HTTP 413 byte/media rejection — token compaction cannot shrink bytes or media budgets (#9235). */
|
|
715
899
|
PayloadRejected: 2147483648
|
|
716
900
|
};
|
|
717
|
-
const KIND_MASK = Flag.ThinkingLoop | Flag.Transient | Flag.Timeout | Flag.UsageLimit | Flag.StaleResponsesItem | Flag.MalformedFunctionCall | Flag.ProviderFinishError | Flag.EmptyResponse | Flag.ContentBlocked | Flag.AccountPolicy | Flag.ContextOverflow | Flag.AuthFailed | Flag.PayloadRejected | Flag.SilentAbort | Flag.UserInterrupt | Flag.Abort | Flag.Grammar | Flag.FastModeUnsupported | Flag.OAuthExpiry;
|
|
901
|
+
const KIND_MASK = Flag.ThinkingLoop | Flag.Transient | Flag.Timeout | Flag.UsageLimit | Flag.StaleResponsesItem | Flag.MalformedFunctionCall | Flag.ProviderFinishError | Flag.EmptyResponse | Flag.ContentBlocked | Flag.AccountPolicy | Flag.ContextOverflow | Flag.AuthFailed | Flag.PayloadRejected | Flag.SilentAbort | Flag.UserInterrupt | Flag.Abort | Flag.Grammar | Flag.FastModeUnsupported | Flag.CacheControlUnsupported | Flag.OAuthExpiry;
|
|
718
902
|
const RETRIABLE_KINDS = Flag.Transient | Flag.UsageLimit | Flag.ThinkingLoop | Flag.StaleResponsesItem | Flag.ProviderFinishError | Flag.EmptyResponse;
|
|
719
903
|
const CONTEXT_OVERFLOW_EVIDENCE_PATTERNS = [
|
|
720
904
|
/prompt is too long/i,
|
|
@@ -725,6 +909,8 @@ const CONTEXT_OVERFLOW_EVIDENCE_PATTERNS = [
|
|
|
725
909
|
/reduce the length of the messages/i,
|
|
726
910
|
/maximum context length is \d+ tokens/i,
|
|
727
911
|
/exceeds the available context size/i,
|
|
912
|
+
/\bprompt\s*\(\s*\d+\s+tokens\s*\)\s*\+\s*max\s+tokens\s*\(\s*\d+\s*\)\s+exceeds\s+the\s+context\s*\(\s*\d+\s*\)/i,
|
|
913
|
+
/\bprompt\s*\(\s*\d+\s+tokens\s*\)\s+leaves\s+no\s+room\s+to\s+answer\s+in\s+the\s+context\s*\(\s*\d+\s*\)/i,
|
|
728
914
|
/requested tokens?.*exceed.*context (window|length|size)/i,
|
|
729
915
|
/context (window|length|size).*(exceeded|overflow|too small)/i,
|
|
730
916
|
/(prompt|input).*(too long|too large).*(context|n_ctx)/i,
|
|
@@ -786,19 +972,66 @@ function matchesPayloadRejectionText(text) {
|
|
|
786
972
|
}
|
|
787
973
|
const TIMEOUT_PATTERN = /\b(?:operation\s+)?timed?\s*out\b|\btimeout\b|\bstream stall\b/i;
|
|
788
974
|
const TRANSIENT_ENVELOPE_PATTERN = /anthropic stream envelope error:/i;
|
|
789
|
-
const TRANSIENT_ENVELOPE_TRUNCATION_PATTERN = /before message_(?:start|stop)/i;
|
|
975
|
+
const TRANSIENT_ENVELOPE_TRUNCATION_PATTERN = /before message_(?:start|delta|stop)/i;
|
|
790
976
|
const STREAM_READ_ERROR_PATTERN = /stream[_ -]?read[_ -]?error/i;
|
|
791
977
|
/** Python h2/httpx diagnostics forwarded through provider or proxy error events. */
|
|
792
978
|
const PYTHON_HTTP2_STREAM_RESET_PATTERN = /<StreamReset stream_id:\d+, error_code:(?:2|7), remote_reset:True>/;
|
|
793
979
|
/** Python h11/httpx EOF while reading an HTTP/1.1 chunked response body. */
|
|
794
980
|
const PYTHON_HTTP_INCOMPLETE_CHUNK_PATTERN = /peer closed connection without sending complete message body \(incomplete chunked read\)/;
|
|
795
|
-
|
|
981
|
+
/** reqwest body-frame failures forwarded by the Codex HTTP proxy. */
|
|
982
|
+
const CODEX_HTTP_BODY_READ_ERROR_PATTERN = /\btransport error reading codex response body\b/i;
|
|
983
|
+
const RESPONSES_REQUEST_BODY_READ_TIMEOUT_PATTERN = /\btimed out reading request body\b/i;
|
|
984
|
+
/** Exact HTTP request-body-read timeout diagnostic. */
|
|
985
|
+
function isRequestBodyReadTimeout(status, message) {
|
|
986
|
+
return status === 408 && RESPONSES_REQUEST_BODY_READ_TIMEOUT_PATTERN.test(message ?? "");
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Codex code for the experimental native turn lane refusing a mid-response
|
|
990
|
+
* `response.steer`; the server then drops the in-flight response and closes
|
|
991
|
+
* the socket.
|
|
992
|
+
*/
|
|
993
|
+
const CODEX_NATIVE_LANE_STEER_REJECTED_CODE = "unsupported_native_inflight_message";
|
|
994
|
+
/**
|
|
995
|
+
* A Codex turn the native turn lane dropped because omp steered it. The
|
|
996
|
+
* rejection answers our own `response.steer`, not the model's health: the
|
|
997
|
+
* provider stops steering the session, so the same model replays cleanly.
|
|
998
|
+
*/
|
|
999
|
+
function isCodexSteerRejection(message) {
|
|
1000
|
+
return message.api === "openai-codex-responses" && message.errorMessage?.includes(`code=unsupported_native_inflight_message`) === true;
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Transport-failure wording that marks an error transient. Covers
|
|
1004
|
+
* diagnostics forwarded verbatim by gateways/proxies in other runtimes, e.g.
|
|
1005
|
+
* undici's "other side closed" and Go's `net.ErrClosed` ("use of closed
|
|
1006
|
+
* network connection", #15385). Also covers OMP's own network-failure
|
|
1007
|
+
* sentences from `networkFailureMessage` (offline / unreachable / refused /
|
|
1008
|
+
* TLS), which must stay at least as retryable as the bare `Connection error.`
|
|
1009
|
+
* text they replaced.
|
|
1010
|
+
*/
|
|
1011
|
+
const TRANSIENT_TRANSPORT_PATTERN = /\b(?:no[_ -]?capacity|(?:high|peak)[ _-]?demand|(?:at|over|insufficient)[ _-]?capacity|capacity[ _-]?(?:exceeded|exhausted)|peak[ _-]?load)\b|overloaded|provider.?returned.?error|rate.?limit|too many requests|auth-gateway\s+5\d{2}(?=[:\s]|$)|\b(?:429|500|502|503|504)\b|service.?unavailable|temporar(?:y|ily)[ _-]?unavailable|server.?error|internal.?error|retry your request|network.?error|connection.?error|connection.?refused|unable.?to.?connect\.\s*is the computer able to access the url\?|other side closed|use of closed network connection|fetch failed|upstream.?connect|upstream.?request.?failed|reset before headers|socket hang up|timed? out|timeout|terminated|retry delay|stream stall|no error details in response|HTTP2(?:StreamReset|RefusedStream|EnhanceYourCalm)|nghttp2_(?:internal_error|refused_stream)|stream closed with error code nghttp2_(?:internal_error|refused_stream)|\bE(?:TIMEOUT|NOTFOUND|NETUNREACH|HOSTUNREACH)\b|\bFailedToOpenSocket\b|no internet connection|couldn.?t reach|couldn.?t connect to|tls certificate verification failed|malformed.?function.?call/i;
|
|
796
1012
|
const AUTH_FAILURE_PATTERN = /\b(?:401|403|unauthorized|forbidden|authentication|auth[_ ]?unavailable|no auth available|(?:invalid|no)[_ ]?api[_ ]?key)\b/i;
|
|
797
1013
|
const MALFORMED_FUNCTION_CALL_PATTERN = /\bmalformed.?function.?call\b/i;
|
|
798
1014
|
const PROVIDER_FINISH_ERROR_PATTERN = /\bProvider (?:returned error finish_reason|finish_reason:\s*error)\b/i;
|
|
799
1015
|
const EMPTY_RESPONSE_PATTERN = /\bthought-only response without final output\b/i;
|
|
800
1016
|
const CONTENT_FILTER_PATTERN = /\b(?:incomplete:\s*)?content_filter\b/i;
|
|
801
1017
|
const ACCOUNT_POLICY_PATTERN = /\bcyber_policy\b|trusted access for cyber/i;
|
|
1018
|
+
const ANTHROPIC_ACCOUNT_POLICY_PATTERN = /\b(?:oauth_not_allowed_for_organization|permission_error)\b|\bOAuth authentication is currently not allowed for this organization\b/i;
|
|
1019
|
+
/** Whether an error message represents an Anthropic account-scoped permission/policy denial. */
|
|
1020
|
+
function isAnthropicAccountPolicyText(text, provider, statusArg) {
|
|
1021
|
+
if (provider !== void 0 && provider !== "anthropic") return false;
|
|
1022
|
+
const statusCandidate = statusArg ?? (text ? status({ message: text }) : void 0);
|
|
1023
|
+
if (statusCandidate !== void 0 && statusCandidate !== 403) return false;
|
|
1024
|
+
return ANTHROPIC_ACCOUNT_POLICY_PATTERN.test(text);
|
|
1025
|
+
}
|
|
1026
|
+
const IMMUTABLE_LATEST_THINKING_PATTERN = /messages\.\d+\.content\.\d+.*\b(?:thinking|redacted_thinking)\b.*\blatest assistant message cannot be modified\b/is;
|
|
1027
|
+
/**
|
|
1028
|
+
* Anthropic's rejection of a replayed latest assistant turn whose `thinking` or
|
|
1029
|
+
* `redacted_thinking` blocks no longer verify. Resending the same turn fails the
|
|
1030
|
+
* same way; only a request that changes that turn's reasoning can succeed.
|
|
1031
|
+
*/
|
|
1032
|
+
function isImmutableLatestThinkingText(text) {
|
|
1033
|
+
return IMMUTABLE_LATEST_THINKING_PATTERN.test(text);
|
|
1034
|
+
}
|
|
802
1035
|
const CODEX_CHATGPT_ACCOUNT_MODEL_POLICY_PATTERN = /\bThe ['"]([^'"\r\n]+)['"] model is not supported when using Codex with a ChatGPT account\./i;
|
|
803
1036
|
const CODEX_CHATGPT_ACCOUNT_MODEL_MAX_LENGTH = 256;
|
|
804
1037
|
const CURSOR_PLAN_POLICY_MARKER_PATTERN = /\bERROR_RATE_LIMITED_CHANGEABLE\b/i;
|
|
@@ -843,14 +1076,20 @@ const STRUCTURED_OUTPUTS_PATTERN = /structured[_ -]?outputs?/i;
|
|
|
843
1076
|
const FEATURE_NOT_SUPPORTED_PATTERN = /not (?:supported|available|enabled)|unsupported|does(?: not|n'?t) support/i;
|
|
844
1077
|
const ANTHROPIC_STRICT_FIELD_PATTERN = /\btools\.\d+\.custom\.strict\b/i;
|
|
845
1078
|
const EXTRA_INPUTS_NOT_PERMITTED_PATTERN = /extra inputs? (?:are|is) not permitted/i;
|
|
1079
|
+
const STRICT_TOOL_SCHEMA_REJECTION_PATTERN = /invalid schema for function|invalid tool parameters schema/i;
|
|
846
1080
|
const FAST_MODE_SPEED_PARAM_PATTERN = /\bspeed\b/i;
|
|
847
1081
|
const FAST_MODE_NOT_SUPPORTED_PATTERN = /not support/i;
|
|
848
1082
|
const FAST_MODE_RATE_LIMIT_PATTERN = /rate_limit_error/i;
|
|
849
1083
|
const FAST_MODE_ENTITLEMENT_PATTERN = /fast mode/i;
|
|
1084
|
+
const CACHE_CONTROL_FIELD_PATTERN = /\bcache_control\b/i;
|
|
1085
|
+
const CACHE_CONTROL_REJECTION_PATTERN = /\bunexpected\b|\bunrecognized\b|\bnot permitted\b|\bnot allowed\b|\bnot recognized\b|\bnot supported\b|\bunsupported\b|\binvalid[_ ]field\b|\bextra (?:inputs?|fields?)\b/i;
|
|
1086
|
+
const CACHE_CONTROL_MEMBER_REFUSAL_PATTERN = /\b(?:un(?:known|permitted|supported|recognized|expected)|invalid|bad|not (?:an? )?(?:known|valid|accepted|supported|permitted|allowed|recognized))[_ -](?:field|name|param(?:eter)?|argument|key|propert(?:y|ies)|attribute|member|option|input)s?\b/i;
|
|
1087
|
+
const CACHE_CONTROL_EMPTY_TEXT_PATTERN = /empty text block|text content block.*non-(?:empty|whitespace)|text.{0,40}must (?:be non-empty|not be empty)/i;
|
|
850
1088
|
function matchesStrictToolsRejection(message, errorStatus) {
|
|
851
1089
|
if (errorStatus !== 400) return false;
|
|
852
1090
|
if (ANTHROPIC_STRICT_FIELD_PATTERN.test(message) && EXTRA_INPUTS_NOT_PERMITTED_PATTERN.test(message)) return true;
|
|
853
1091
|
if (STRUCTURED_OUTPUTS_PATTERN.test(message) && FEATURE_NOT_SUPPORTED_PATTERN.test(message)) return true;
|
|
1092
|
+
if (STRICT_TOOL_SCHEMA_REJECTION_PATTERN.test(message)) return true;
|
|
854
1093
|
if (!INVALID_REQUEST_PATTERN.test(message)) return false;
|
|
855
1094
|
const grammarTooLarge = GRAMMAR_TOO_LARGE_PATTERN.test(message) && GRAMMAR_TOO_LARGE_DETAIL_PATTERN.test(message);
|
|
856
1095
|
const schemaTooComplex = SCHEMA_TOO_COMPLEX_PATTERN.test(message) && SCHEMA_TOO_COMPLEX_DETAIL_PATTERN.test(message) && SCHEMA_COMPILE_PATTERN.test(message);
|
|
@@ -861,6 +1100,12 @@ function matchesFastModeUnsupported(message, errorStatus) {
|
|
|
861
1100
|
if (errorStatus === 400 && INVALID_REQUEST_PATTERN.test(message) && FAST_MODE_SPEED_PARAM_PATTERN.test(message) && FAST_MODE_NOT_SUPPORTED_PATTERN.test(message)) return true;
|
|
862
1101
|
return errorStatus === 429 && FAST_MODE_RATE_LIMIT_PATTERN.test(message) && FAST_MODE_ENTITLEMENT_PATTERN.test(message);
|
|
863
1102
|
}
|
|
1103
|
+
function matchesCacheControlRejection(message, errorStatus) {
|
|
1104
|
+
if (errorStatus !== 400) return false;
|
|
1105
|
+
if (!CACHE_CONTROL_FIELD_PATTERN.test(message)) return false;
|
|
1106
|
+
if (CACHE_CONTROL_EMPTY_TEXT_PATTERN.test(message)) return false;
|
|
1107
|
+
return CACHE_CONTROL_REJECTION_PATTERN.test(message) || CACHE_CONTROL_MEMBER_REFUSAL_PATTERN.test(message);
|
|
1108
|
+
}
|
|
864
1109
|
Flag.ThinkingLoop, Flag.Transient, Flag.Timeout, Flag.UsageLimit, Flag.StaleResponsesItem, Flag.MalformedFunctionCall, Flag.ProviderFinishError, Flag.EmptyResponse, Flag.ContentBlocked, Flag.AccountPolicy, Flag.ContextOverflow, Flag.PayloadRejected, Flag.AuthFailed, Flag.SilentAbort, Flag.UserInterrupt, Flag.Abort;
|
|
865
1110
|
const STATUS_MESSAGE_PATTERNS = [
|
|
866
1111
|
/\bstatus(?:_code)?[:=]\s*(\d{3})\b/i,
|
|
@@ -899,6 +1144,7 @@ function statusInternal(error, depth) {
|
|
|
899
1144
|
const errObj = error;
|
|
900
1145
|
if (typeof errObj.status === "number" && errObj.status >= 100 && errObj.status <= 599) return errObj.status;
|
|
901
1146
|
if (typeof errObj.statusCode === "number" && errObj.statusCode >= 100 && errObj.statusCode <= 599) return errObj.statusCode;
|
|
1147
|
+
if (typeof errObj.errorStatus === "number" && errObj.errorStatus >= 100 && errObj.errorStatus <= 599) return errObj.errorStatus;
|
|
902
1148
|
if (typeof errObj.response === "object" && errObj.response !== null) {
|
|
903
1149
|
const resp = errObj.response;
|
|
904
1150
|
if (typeof resp.status === "number" && resp.status >= 100 && resp.status <= 599) return resp.status;
|
|
@@ -946,6 +1192,16 @@ function isContentBlockedText(text) {
|
|
|
946
1192
|
function matchesOverflowText(text) {
|
|
947
1193
|
return OVERFLOW_PATTERNS.some((p) => p.test(text)) || OVERFLOW_NO_BODY_PATTERN.test(text);
|
|
948
1194
|
}
|
|
1195
|
+
/**
|
|
1196
|
+
* A 4xx the provider rejected as a deterministic client error — every 4xx
|
|
1197
|
+
* except 408 (Request Timeout) and 429 (Too Many Requests), the retryable
|
|
1198
|
+
* pair. Mirrors the 4xx policy in {@link isProviderRetryableError}: such a
|
|
1199
|
+
* request replays identically, so a transient signal riding on it (e.g. a
|
|
1200
|
+
* truncation phrase in the body) must not flip it to retryable.
|
|
1201
|
+
*/
|
|
1202
|
+
function isTerminalClientErrorStatus(status) {
|
|
1203
|
+
return status !== void 0 && status >= 400 && status < 500 && status !== 408 && status !== 429;
|
|
1204
|
+
}
|
|
949
1205
|
function classifyText(errorMessage, errorStatus, priorTokenOverflowEvidence = false, api, provider, modelId) {
|
|
950
1206
|
let kinds = 0;
|
|
951
1207
|
if (errorMessage) {
|
|
@@ -955,22 +1211,31 @@ function classifyText(errorMessage, errorStatus, priorTokenOverflowEvidence = fa
|
|
|
955
1211
|
if (isProviderFinishErrorText(errorMessage)) kinds |= Flag.ProviderFinishError;
|
|
956
1212
|
if (EMPTY_RESPONSE_PATTERN.test(errorMessage)) kinds |= Flag.EmptyResponse | Flag.Transient;
|
|
957
1213
|
if (isContentBlockedText(errorMessage)) kinds |= Flag.ContentBlocked;
|
|
1214
|
+
const statusClean = errorStatus ? errorStatus : status({ message: errorMessage }) ?? void 0;
|
|
958
1215
|
if (ACCOUNT_POLICY_PATTERN.test(errorMessage) || isCodexChatGPTAccountPolicyText(errorMessage, provider, modelId) || provider === "cursor" && isCursorPlanPolicyText(errorMessage)) kinds |= Flag.AccountPolicy | Flag.ContentBlocked;
|
|
1216
|
+
if (isAnthropicAccountPolicyText(errorMessage, provider, statusClean)) kinds |= Flag.AccountPolicy;
|
|
959
1217
|
if (isAuthFailureText(errorMessage)) kinds |= Flag.AuthFailed;
|
|
960
|
-
const statusClean = errorStatus ? errorStatus : status({ message: errorMessage }) ?? void 0;
|
|
961
1218
|
const cleanMessage = errorMessage;
|
|
962
1219
|
const isOpaque = isOpaqueStatusBody(cleanMessage);
|
|
963
1220
|
const isLimitStatus = isUsageLimitStatus(statusClean);
|
|
964
1221
|
const reason = parseRateLimitReason(cleanMessage);
|
|
965
1222
|
const is402BillingCap = statusClean === 402 && is402BillingCapBody(cleanMessage);
|
|
966
1223
|
if (!(reason === "CONCURRENT_LIMIT" && statusClean !== 402) && (is402BillingCap || matchesUsageLimitText(cleanMessage) || (statusClean === 403 || statusClean === void 0) && isAccountScopedCapText(cleanMessage) || isLimitStatus && (isOpaque || reason === "QUOTA_EXHAUSTED"))) kinds |= Flag.UsageLimit;
|
|
967
|
-
if (
|
|
968
|
-
|
|
1224
|
+
if (!isTerminalClientErrorStatus(statusClean)) {
|
|
1225
|
+
if (isTimeoutText(errorMessage)) kinds |= Flag.Transient | Flag.Timeout;
|
|
1226
|
+
else if (isTransientErrorText(errorMessage)) kinds |= Flag.Transient;
|
|
1227
|
+
if (isTransientStreamParseError(errorMessage) || isTransientStreamDropError(errorMessage) || CODEX_HTTP_BODY_READ_ERROR_PATTERN.test(errorMessage)) kinds |= Flag.Transient;
|
|
1228
|
+
}
|
|
969
1229
|
if (reason === "CONCURRENT_LIMIT") kinds |= Flag.Transient;
|
|
970
1230
|
if ((api === "openai-responses" || api === "openai-codex-responses") && isStaleResponsesText(errorMessage)) kinds |= Flag.StaleResponsesItem;
|
|
1231
|
+
if (isCodexSteerRejection({
|
|
1232
|
+
api,
|
|
1233
|
+
errorMessage
|
|
1234
|
+
})) kinds |= Flag.Transient;
|
|
971
1235
|
if (statusClean === 400 && GENERATION_NAN_PATTERN.test(cleanMessage)) kinds |= Flag.Transient;
|
|
972
1236
|
if (matchesStrictToolsRejection(cleanMessage, statusClean)) kinds |= Flag.Grammar;
|
|
973
1237
|
if (matchesFastModeUnsupported(cleanMessage, statusClean)) kinds |= Flag.FastModeUnsupported;
|
|
1238
|
+
if (matchesCacheControlRejection(cleanMessage, statusClean)) kinds |= Flag.CacheControlUnsupported;
|
|
974
1239
|
}
|
|
975
1240
|
const statusEvidence = errorStatus ?? (errorMessage ? status({ message: errorMessage }) : void 0);
|
|
976
1241
|
if (statusEvidence === 413 && !priorTokenOverflowEvidence && !(errorMessage && hasTokenContextOverflowEvidence(errorMessage))) kinds |= Flag.PayloadRejected;
|
|
@@ -985,12 +1250,16 @@ function classify(error, api) {
|
|
|
985
1250
|
const seen = /* @__PURE__ */ new Set();
|
|
986
1251
|
const causeTokenEvidence = hasCauseTokenContextOverflowEvidence(error);
|
|
987
1252
|
let link = error;
|
|
1253
|
+
let governingTerminalStatus;
|
|
988
1254
|
while (link !== void 0 && link !== null) {
|
|
989
1255
|
if (typeof link === "object") {
|
|
990
1256
|
if (seen.has(link)) break;
|
|
991
1257
|
seen.add(link);
|
|
992
1258
|
if ("errorId" in link && typeof link.errorId === "number") kinds |= link.errorId & KIND_MASK;
|
|
993
|
-
if ("code" in link && typeof link.code === "string"
|
|
1259
|
+
if ("code" in link && typeof link.code === "string") {
|
|
1260
|
+
if (ACCOUNT_POLICY_PATTERN.test(link.code)) kinds |= Flag.AccountPolicy | Flag.ContentBlocked;
|
|
1261
|
+
else if (ANTHROPIC_ACCOUNT_POLICY_PATTERN.test(link.code)) kinds |= Flag.AccountPolicy;
|
|
1262
|
+
}
|
|
994
1263
|
}
|
|
995
1264
|
if (link instanceof AwsCredentialsError) kinds |= Flag.AuthFailed;
|
|
996
1265
|
else if (link instanceof AnthropicConnectionTimeoutError) kinds |= Flag.Timeout | Flag.Transient;
|
|
@@ -1000,8 +1269,9 @@ function classify(error, api) {
|
|
|
1000
1269
|
else if (link instanceof ProviderHttpError) {
|
|
1001
1270
|
let linkKinds = 0;
|
|
1002
1271
|
const { status: codeStatus, code } = link;
|
|
1003
|
-
if (code === "usage_limit_reached" || code === "insufficient_quota" && !isDashScopeTokenLimitText(link.message) || codeStatus === 402 && (code
|
|
1272
|
+
if (code === "usage_limit_reached" || code === "insufficient_quota" && !isDashScopeTokenLimitText(link.message) || codeStatus === 402 && (is402BillingCapBody(link.message) || code !== void 0 && !isOpaqueStatusBody(code) && is402BillingCapBody(code))) linkKinds |= Flag.UsageLimit;
|
|
1004
1273
|
if (code === "overloaded_error" || code === "rate_limit_error") linkKinds |= Flag.Transient;
|
|
1274
|
+
if (code === "oauth_not_allowed_for_organization" || code === "permission_error" || codeStatus === 403 && ANTHROPIC_ACCOUNT_POLICY_PATTERN.test(link.message)) linkKinds |= Flag.AccountPolicy;
|
|
1005
1275
|
if ((codeStatus === 401 || codeStatus === 403) && !(codeStatus === 403 && parseRateLimitReason(link.message) === "CONCURRENT_LIMIT")) linkKinds |= Flag.AuthFailed;
|
|
1006
1276
|
else if (codeStatus === 429) {
|
|
1007
1277
|
if ((linkKinds & Flag.UsageLimit) === 0) linkKinds |= Flag.Transient;
|
|
@@ -1011,9 +1281,14 @@ function classify(error, api) {
|
|
|
1011
1281
|
let linkMessage;
|
|
1012
1282
|
if (link instanceof Error) linkMessage = link.message;
|
|
1013
1283
|
else if (typeof link === "string") linkMessage = link;
|
|
1014
|
-
else if (typeof link === "object"
|
|
1015
|
-
|
|
1284
|
+
else if (typeof link === "object") {
|
|
1285
|
+
if ("message" in link && typeof link.message === "string") linkMessage = link.message;
|
|
1286
|
+
else if ("errorMessage" in link && typeof link.errorMessage === "string") linkMessage = link.errorMessage;
|
|
1287
|
+
}
|
|
1288
|
+
const linkStatus = status(link);
|
|
1289
|
+
const textId = classifyText(linkMessage, linkStatus ?? governingTerminalStatus, causeTokenEvidence, api);
|
|
1016
1290
|
kinds |= textId & KIND_MASK;
|
|
1291
|
+
if (isTerminalClientErrorStatus(linkStatus)) governingTerminalStatus = linkStatus;
|
|
1017
1292
|
link = typeof link === "object" && "cause" in link ? link.cause : void 0;
|
|
1018
1293
|
}
|
|
1019
1294
|
return kinds !== 0 ? create(kinds) : status(error) ?? 0;
|
|
@@ -1042,6 +1317,22 @@ function isGrammarError(error) {
|
|
|
1042
1317
|
function isFastModeUnsupported(error) {
|
|
1043
1318
|
return is(classify(error), Flag.FastModeUnsupported);
|
|
1044
1319
|
}
|
|
1320
|
+
/**
|
|
1321
|
+
* An Anthropic-compatible endpoint returned a 400 rejecting something about
|
|
1322
|
+
* `cache_control`. Whether it refused the field or one nested option is not
|
|
1323
|
+
* decidable here (see {@link CACHE_CONTROL_FIELD_PATTERN}); the caller's retry
|
|
1324
|
+
* ladder settles it by replaying.
|
|
1325
|
+
* Accessor for {@link Flag.CacheControlUnsupported}.
|
|
1326
|
+
*
|
|
1327
|
+
* Unlike the high-bit accessors this also requires a classified id. The flag
|
|
1328
|
+
* sits in the raw-status lane (see {@link Flag.CacheControlUnsupported}), and
|
|
1329
|
+
* while no HTTP status reaches 0x800, `is` is a bare bit test — the extra gate
|
|
1330
|
+
* keeps a stray non-HTTP status out of the retry path.
|
|
1331
|
+
*/
|
|
1332
|
+
function isCacheControlUnsupported(error) {
|
|
1333
|
+
const id = classify(error);
|
|
1334
|
+
return isClassified(id) && is(id, Flag.CacheControlUnsupported);
|
|
1335
|
+
}
|
|
1045
1336
|
const CLINE_PASS_SURFACE_GATE_PATTERN = /only available via cline product surfaces/i;
|
|
1046
1337
|
/**
|
|
1047
1338
|
* Cline's gateway gates some roster entries (certain free-tier models) to its
|
|
@@ -1087,6 +1378,28 @@ function isTransientStreamParseError(error) {
|
|
|
1087
1378
|
if (typeof error === "string") return STREAM_PARSE_DIAGNOSTIC_PATTERN.test(error);
|
|
1088
1379
|
return error instanceof Error && STREAM_PARSE_TRUNCATION_PATTERN.test(error.message);
|
|
1089
1380
|
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Transport-level stream drops: the connection or upstream stream ended before a
|
|
1383
|
+
* terminal event, with no JSON-parse signal and no retryable status attached.
|
|
1384
|
+
*
|
|
1385
|
+
* Distinct from {@link STREAM_PARSE_TRUNCATION_PATTERN} (mid-body JSON
|
|
1386
|
+
* truncation) — these name the transport itself dropping (proxy/gateway closing
|
|
1387
|
+
* the SSE stream, socket dying before the TLS handshake completes). The wording
|
|
1388
|
+
* is the statusless twin of a `408 stream disconnected`, which the status path
|
|
1389
|
+
* already retries; an identical replay recovers it, so callers under a
|
|
1390
|
+
* non-terminal status treat it as transient (#11805).
|
|
1391
|
+
*/
|
|
1392
|
+
const STREAM_DROP_PATTERN = /stream disconnected before completion|(?:stream|websocket) closed before response\.completed|stream was interrupted|stream ended before (?:terminal (?:chunk|completion event)|message_(?:start|delta|stop))|socket disconnected before secure tls connection/i;
|
|
1393
|
+
/**
|
|
1394
|
+
* Transport stream-drop diagnostic (see {@link STREAM_DROP_PATTERN}). Unlike
|
|
1395
|
+
* {@link isTransientStreamParseError}, one pattern serves both the live `Error`
|
|
1396
|
+
* and the persisted-string forms: the phrasings are high-signal enough to trust
|
|
1397
|
+
* detached from a transport `Error`.
|
|
1398
|
+
*/
|
|
1399
|
+
function isTransientStreamDropError(error) {
|
|
1400
|
+
if (typeof error === "string") return STREAM_DROP_PATTERN.test(error);
|
|
1401
|
+
return error instanceof Error && STREAM_DROP_PATTERN.test(error.message);
|
|
1402
|
+
}
|
|
1090
1403
|
/** Any malformed stream-envelope error (prefix-tagged or out-of-order events). */
|
|
1091
1404
|
function isStreamEnvelopeError(error) {
|
|
1092
1405
|
return error instanceof Error && (error.message.includes("Anthropic stream envelope error:") || STREAM_EVENT_ORDER_PATTERN.test(error.message));
|
|
@@ -1096,7 +1409,7 @@ function isRetryableStreamEnvelopeError(error) {
|
|
|
1096
1409
|
return error instanceof Error && STREAM_EVENT_ORDER_PATTERN.test(error.message);
|
|
1097
1410
|
}
|
|
1098
1411
|
//#endregion
|
|
1099
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
1412
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/abort.ts
|
|
1100
1413
|
/**
|
|
1101
1414
|
* A request was cancelled — by the caller's `AbortSignal` or a provider-local
|
|
1102
1415
|
* watchdog. Carries the {@link Flag.Abort} classification structurally so retry
|
|
@@ -1114,7 +1427,7 @@ var AbortError = class extends Error {
|
|
|
1114
1427
|
}
|
|
1115
1428
|
};
|
|
1116
1429
|
//#endregion
|
|
1117
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
1430
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/auth.ts
|
|
1118
1431
|
/**
|
|
1119
1432
|
* No API key / credential was available to dispatch a request.
|
|
1120
1433
|
*
|
|
@@ -1158,7 +1471,7 @@ var LoginCancelledError = class extends Error {
|
|
|
1158
1471
|
}
|
|
1159
1472
|
};
|
|
1160
1473
|
//#endregion
|
|
1161
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
1474
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/oauth.ts
|
|
1162
1475
|
/**
|
|
1163
1476
|
* A failure inside an interactive OAuth / device-code login flow. The `kind`
|
|
1164
1477
|
* pinpoints the stage. Timeout/polling are classified transient; everything
|
|
@@ -1179,7 +1492,259 @@ var OAuthError = class extends Error {
|
|
|
1179
1492
|
}
|
|
1180
1493
|
};
|
|
1181
1494
|
//#endregion
|
|
1182
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
1495
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/provider.ts
|
|
1496
|
+
/**
|
|
1497
|
+
* A non-HTTP provider failure: a truncated stream, an error stop reason, an
|
|
1498
|
+
* empty body, a malformed envelope, or a runtime fault. For non-2xx HTTP
|
|
1499
|
+
* responses use {@link ProviderHttpError} (or a provider subclass) instead.
|
|
1500
|
+
*/
|
|
1501
|
+
var ProviderResponseError = class extends Error {
|
|
1502
|
+
provider;
|
|
1503
|
+
kind;
|
|
1504
|
+
constructor(message, options = {}) {
|
|
1505
|
+
super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
1506
|
+
this.name = "ProviderResponseError";
|
|
1507
|
+
this.provider = options.provider;
|
|
1508
|
+
this.kind = options.kind ?? "output";
|
|
1509
|
+
if (this.kind === "content-blocked") attach(this, create(Flag.ContentBlocked));
|
|
1510
|
+
else if (this.kind === "empty-output") attach(this, create(Flag.Transient, Flag.EmptyResponse));
|
|
1511
|
+
else if (this.kind === "incomplete-stream" || this.kind === "empty-body") attach(this, create(Flag.Transient));
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
/** Non-2xx response from the Devin API. */
|
|
1515
|
+
var DevinApiError = class extends ProviderHttpError {
|
|
1516
|
+
name = "DevinApiError";
|
|
1517
|
+
};
|
|
1518
|
+
//#endregion
|
|
1519
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/body-error.ts
|
|
1520
|
+
/**
|
|
1521
|
+
* In-band provider failures: upstream 429/5xx payloads that arrive inside an
|
|
1522
|
+
* HTTP 200 response body, or mid-stream after the SSE headers were already sent.
|
|
1523
|
+
*
|
|
1524
|
+
* Providers that front a retry/queue layer — Azure OpenAI, LiteLLM-style
|
|
1525
|
+
* aggregators, Bedrock-compatible shims — answer a throttled request with
|
|
1526
|
+
* `200 OK` + `text/event-stream` and put the real status in the payload:
|
|
1527
|
+
* `data: {"error":{"type":"rate_limit_error"}}`, `data: {"code":429}`, or a bare
|
|
1528
|
+
* non-JSON frame such as `data: 429 Too Many Requests` / an nginx throttle page.
|
|
1529
|
+
* Those bodies used to be either dropped silently (the stream then looked like a
|
|
1530
|
+
* successful empty completion) or surfaced as an unclassified
|
|
1531
|
+
* {@link ProviderResponseError} whose `errorId` stayed 0 — so `AIError.retriable`
|
|
1532
|
+
* answered "terminal" and `retry.fallbackChains` never advanced, pinning the
|
|
1533
|
+
* session on a provider that was merely busy.
|
|
1534
|
+
*
|
|
1535
|
+
* Both probes hand the classifier the structured signal it already trusts for an
|
|
1536
|
+
* out-of-band failure: a {@link ProviderHttpError} carrying a status the upstream
|
|
1537
|
+
* *reported*, so the two routes reach one code path. The invariants that make
|
|
1538
|
+
* that safe, and that callers rely on:
|
|
1539
|
+
*
|
|
1540
|
+
* - **No invented HTTP metadata.** A status is taken only from an error
|
|
1541
|
+
* `status`/`code` *field* (numeric, or a 3-digit string as compat hosts send)
|
|
1542
|
+
* or from {@link RETRYABLE_STATUS_BY_CODE}, and only for `429`/`5xx`. A status
|
|
1543
|
+
* mentioned inside error prose is never promoted to a status: 401/403 wording
|
|
1544
|
+
* stays text and cannot route the failure into the auth-retry lane.
|
|
1545
|
+
* - **No credential rotation on an unreadable body.** A `429` whose body is
|
|
1546
|
+
* empty, `{}`, or framing-only is opaque, and an opaque 429 is the conservative
|
|
1547
|
+
* rotate-to-a-sibling-credential signal. That verdict belongs to a body the
|
|
1548
|
+
* server actually sent, not to a payload we synthesised, so
|
|
1549
|
+
* {@link formatInBandMessage} substitutes {@link IN_BAND_DETAIL_PLACEHOLDER}
|
|
1550
|
+
* and the composed message always stays informative.
|
|
1551
|
+
* - **Unknown envelopes fall through.** Anything without a retryable status
|
|
1552
|
+
* field, a retryable code, or unambiguous throttle wording returns
|
|
1553
|
+
* `undefined` and keeps its pre-existing handling and message.
|
|
1554
|
+
*
|
|
1555
|
+
* Where no numeric status exists, the returned error keeps the upstream wording
|
|
1556
|
+
* and code visible in its message instead of asserting HTTP metadata the provider
|
|
1557
|
+
* never sent, and carries {@link Flag.Transient} directly: throttle spellings like
|
|
1558
|
+
* `Throttled` / `Please retry` are what this probe recognises but the transport
|
|
1559
|
+
* text pattern is not required to match, so the retry decision is stated rather
|
|
1560
|
+
* than hoped for.
|
|
1561
|
+
*/
|
|
1562
|
+
/** Cap on synthesized message length, mirroring the transport-level `MAX_DETAIL_CHARS`. */
|
|
1563
|
+
const MAX_IN_BAND_DETAIL_CHARS = 4096;
|
|
1564
|
+
/**
|
|
1565
|
+
* Filler used when an in-band failure frame carries no readable detail. It has
|
|
1566
|
+
* to be informative prose on purpose: an opaque message on a `429` is read as
|
|
1567
|
+
* "the server gave us nothing" and rotates a credential, and that judgement must
|
|
1568
|
+
* never be triggered by wording of ours.
|
|
1569
|
+
*/
|
|
1570
|
+
const IN_BAND_DETAIL_PLACEHOLDER = "Provider returned an in-band provider error";
|
|
1571
|
+
/**
|
|
1572
|
+
* Machine error codes that mean "shed this request and back off", mapped to the
|
|
1573
|
+
* HTTP status the upstream would have used had it not wrapped the failure in a
|
|
1574
|
+
* 200. Keys are compared after lower-casing, splitting camel/Pascal word
|
|
1575
|
+
* boundaries, and collapsing `_`/`-`/`.`/spaces, so `Throttling.AllocationQuota`
|
|
1576
|
+
* and `ThrottlingAllocationQuota` both resolve. The list is deliberately limited
|
|
1577
|
+
* to throttle/overload spellings so an unlisted code keeps its pre-existing
|
|
1578
|
+
* classification: request-validation failures (`invalid_request_error`) and
|
|
1579
|
+
* account caps (`insufficient_quota`, `usage_limit_reached`) are never
|
|
1580
|
+
* reinterpreted as retries.
|
|
1581
|
+
*/
|
|
1582
|
+
const RETRYABLE_STATUS_BY_CODE = {
|
|
1583
|
+
rate_limit_error: 429,
|
|
1584
|
+
rate_limit_exceeded: 429,
|
|
1585
|
+
rate_limit: 429,
|
|
1586
|
+
rate_limit_reached: 429,
|
|
1587
|
+
rate_limited: 429,
|
|
1588
|
+
ratelimit: 429,
|
|
1589
|
+
too_many_requests: 429,
|
|
1590
|
+
request_throttled: 429,
|
|
1591
|
+
throttled: 429,
|
|
1592
|
+
throttling: 429,
|
|
1593
|
+
throttling_error: 429,
|
|
1594
|
+
throttling_exception: 429,
|
|
1595
|
+
throttling_allocation_quota: 429,
|
|
1596
|
+
request_limit_exceeded: 429,
|
|
1597
|
+
retry_later: 429,
|
|
1598
|
+
overloaded_error: 503,
|
|
1599
|
+
server_overloaded: 503,
|
|
1600
|
+
model_overloaded: 503,
|
|
1601
|
+
overloaded: 503,
|
|
1602
|
+
service_unavailable: 503,
|
|
1603
|
+
server_busy: 503,
|
|
1604
|
+
high_demand: 503,
|
|
1605
|
+
capacity_exceeded: 503
|
|
1606
|
+
};
|
|
1607
|
+
/**
|
|
1608
|
+
* Wording that identifies a throttle/overload in an error code or body. Kept as
|
|
1609
|
+
* an explicit list rather than reusing the classifier's pattern, so this probe
|
|
1610
|
+
* stays independent of the text rules it feeds.
|
|
1611
|
+
*/
|
|
1612
|
+
const IN_BAND_RETRYABLE_TEXT_PATTERN = /\brate.?limit|too many requests|too\s+many\s+concurren|service.{0,20}unavailable|temporarily\s+unavailable|server.?error|internal.?error|overloaded|capacity|throttl|retry\s+(?:your\s+)?request|please\s+retry/i;
|
|
1613
|
+
/**
|
|
1614
|
+
* A status in the position a proxy error page puts it: the very first token,
|
|
1615
|
+
* optionally after an `HTTP/1.1 ` prefix. Delimited by a word boundary so
|
|
1616
|
+
* identifiers (`chatcmpl-500321`, `gpt-500x`, `req500502`) cannot fabricate a
|
|
1617
|
+
* status — the same hazard `error-transient-status-boundary.test.ts` guards.
|
|
1618
|
+
* Prose that merely *mentions* a number (`Too many requests (401 from …)`) is
|
|
1619
|
+
* deliberately not read as status metadata.
|
|
1620
|
+
*/
|
|
1621
|
+
const LEADING_STATUS_PATTERN = /^\s*(?:HTTP[/.]\d(?:\.\d)?\s+)?([45]\d{2})(?:\b|$)/i;
|
|
1622
|
+
/** Codes that mean a persistent account/billing cap or a bad request; never shed-and-retry. */
|
|
1623
|
+
const NON_RETRYABLE_CODE_PATTERN = /insufficient.?quota|usage.?limit|quota.?(?:exceeded|reached|insufficient)|invalid_request|content_filter|context_length|context_window|billing|balance/i;
|
|
1624
|
+
/** Flags this module asserts for a body it has itself recognised as shed-and-retry. */
|
|
1625
|
+
const IN_BAND_FLAGS = create(Flag.Transient);
|
|
1626
|
+
function normalizeCodeToken(value) {
|
|
1627
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
1628
|
+
if (typeof value !== "string") return void 0;
|
|
1629
|
+
const collapsed = value.trim().replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[-.\s]+/g, "_").replace(/_+/g, "_");
|
|
1630
|
+
return collapsed.length > 0 ? collapsed : void 0;
|
|
1631
|
+
}
|
|
1632
|
+
function readInBandDetail(value) {
|
|
1633
|
+
if (typeof value !== "string") return void 0;
|
|
1634
|
+
const flattened = value.replace(/<[^>]*>/g, " ").replace(/[\u0000-\u001f\u007f]+/g, " ").replace(/\s+/g, " ").trim();
|
|
1635
|
+
if (flattened.length === 0) return void 0;
|
|
1636
|
+
return flattened.length > MAX_IN_BAND_DETAIL_CHARS ? flattened.slice(0, MAX_IN_BAND_DETAIL_CHARS) : flattened;
|
|
1637
|
+
}
|
|
1638
|
+
/** A numeric HTTP status field, accepting the `"429"` string form compat hosts emit. */
|
|
1639
|
+
function readStatusField(value) {
|
|
1640
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) return value;
|
|
1641
|
+
if (typeof value === "string" && /^\d{3}$/.test(value.trim())) {
|
|
1642
|
+
const parsed = Number(value.trim());
|
|
1643
|
+
return Number.isInteger(parsed) && parsed >= 100 && parsed <= 599 ? parsed : void 0;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
/** Only `429` and genuine server faults are shed-and-retry; 4xx of any other kind is not. */
|
|
1647
|
+
function isRetryableStatus(status) {
|
|
1648
|
+
return status === 429 || status !== void 0 && status >= 500 && status <= 599;
|
|
1649
|
+
}
|
|
1650
|
+
function readLeadingStatus(text) {
|
|
1651
|
+
if (text === void 0) return void 0;
|
|
1652
|
+
const match = LEADING_STATUS_PATTERN.exec(text);
|
|
1653
|
+
return match?.[1] ? Number(match[1]) : void 0;
|
|
1654
|
+
}
|
|
1655
|
+
/**
|
|
1656
|
+
* Pull the failure signal out of an OpenAI-wire frame. Accepts the nested
|
|
1657
|
+
* `{ error: { code, type, status, message } }` shape, the `response.error`
|
|
1658
|
+
* position of Responses-API terminal events, the flat `{ code, status, message }`
|
|
1659
|
+
* bodies compat hosts emit, and string envelopes (`{ error: "..." }`).
|
|
1660
|
+
*
|
|
1661
|
+
* `undefined` means "not an in-band failure worth retrying". The probe is
|
|
1662
|
+
* intentionally narrow: a bare `type` is present on every Responses event and so
|
|
1663
|
+
* never counts as a signal by itself, statuses come only from fields (never from
|
|
1664
|
+
* prose), and a frame with neither a retryable status nor throttle wording is
|
|
1665
|
+
* left to the caller's existing handling.
|
|
1666
|
+
*/
|
|
1667
|
+
function readInBandSignal(frame) {
|
|
1668
|
+
if (typeof frame !== "object" || frame === null || Array.isArray(frame)) return void 0;
|
|
1669
|
+
const root = frame;
|
|
1670
|
+
const nested = root.error ?? root.response?.error;
|
|
1671
|
+
let error;
|
|
1672
|
+
if (typeof nested === "object" && nested !== null) {
|
|
1673
|
+
error = nested;
|
|
1674
|
+
for (let depth = 0; depth < 2; depth++) {
|
|
1675
|
+
const inner = error.error;
|
|
1676
|
+
if (typeof inner !== "object" || inner === null) break;
|
|
1677
|
+
error = inner;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
const code = normalizeCodeToken(error?.code ?? root.code) ?? normalizeCodeToken(error?.type ?? root.type);
|
|
1681
|
+
if (code !== void 0 && NON_RETRYABLE_CODE_PATTERN.test(code)) return void 0;
|
|
1682
|
+
if (!(code !== void 0 && IN_BAND_RETRYABLE_TEXT_PATTERN.test(code)) && nested === void 0 && root.status === void 0 && root.code === void 0 && root.message === void 0) return;
|
|
1683
|
+
const detail = readInBandDetail(error?.message) ?? readInBandDetail(root.message) ?? (typeof nested === "string" ? readInBandDetail(nested) : void 0);
|
|
1684
|
+
const holder = error ?? root;
|
|
1685
|
+
const status = (holder === root ? [root.status, root.code] : [
|
|
1686
|
+
holder.status,
|
|
1687
|
+
holder.code,
|
|
1688
|
+
root.status,
|
|
1689
|
+
root.code
|
|
1690
|
+
]).map(readStatusField).find(isRetryableStatus) ?? (code !== void 0 && Object.hasOwn(RETRYABLE_STATUS_BY_CODE, code) ? readStatusField(RETRYABLE_STATUS_BY_CODE[code]) : void 0);
|
|
1691
|
+
if (status !== void 0) return {
|
|
1692
|
+
status,
|
|
1693
|
+
code,
|
|
1694
|
+
detail
|
|
1695
|
+
};
|
|
1696
|
+
if (detail === void 0 || !IN_BAND_RETRYABLE_TEXT_PATTERN.test(detail)) return void 0;
|
|
1697
|
+
return {
|
|
1698
|
+
code,
|
|
1699
|
+
detail
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Compose the message for a status-bearing in-band failure. The numeric status
|
|
1704
|
+
* leads (matching `captureOpenAIHttpError`'s `"<status> <detail>"` phrasing)
|
|
1705
|
+
* unless the detail already carries it as its leading token; the machine code is
|
|
1706
|
+
* appended only when it adds information the text classifier or a human reader
|
|
1707
|
+
* can use. A detail that leaves the whole line opaque is replaced by the
|
|
1708
|
+
* placeholder, so a body we generated can never be read as "the server said
|
|
1709
|
+
* nothing".
|
|
1710
|
+
*/
|
|
1711
|
+
function formatInBandMessage(status, detail, code) {
|
|
1712
|
+
const body = detail ?? IN_BAND_DETAIL_PLACEHOLDER;
|
|
1713
|
+
const suffix = code !== void 0 && !/^\d+$/.test(code) && !body.toLowerCase().includes(code.toLowerCase()) ? ` (${code})` : "";
|
|
1714
|
+
let message = readLeadingStatus(body) === status ? body : `${status} ${body}`;
|
|
1715
|
+
if (isOpaqueStatusBody(message)) message = `${status} ${IN_BAND_DETAIL_PLACEHOLDER}`;
|
|
1716
|
+
return `${message}${suffix}`;
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
* Build the classified error for an in-band failure frame, or `undefined` when
|
|
1720
|
+
* the frame is not a retryable in-band failure (in which case the caller keeps
|
|
1721
|
+
* its existing handling and message).
|
|
1722
|
+
*
|
|
1723
|
+
* @param frame decoded SSE `data:` payload, or the `{ error, response }` subset of one
|
|
1724
|
+
*/
|
|
1725
|
+
function createInBandProviderError(frame) {
|
|
1726
|
+
const signal = readInBandSignal(frame);
|
|
1727
|
+
if (!signal) return void 0;
|
|
1728
|
+
const { status, code, detail } = signal;
|
|
1729
|
+
if (isRetryableStatus(status)) return attach(new ProviderHttpError(formatInBandMessage(status, detail, code), status, { code }), IN_BAND_FLAGS);
|
|
1730
|
+
if (detail === void 0 && code === void 0) return void 0;
|
|
1731
|
+
return attach(new ProviderResponseError(`${detail ?? IN_BAND_DETAIL_PLACEHOLDER}${code ? ` (${code})` : ""}`, { kind: "runtime" }), IN_BAND_FLAGS);
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Build the classified error for a non-JSON SSE frame: gateways and reverse
|
|
1735
|
+
* proxies that answer `data: 429 Too Many Requests` or an HTML throttle page
|
|
1736
|
+
* instead of an OpenAI envelope. `undefined` when the text is not recognisable
|
|
1737
|
+
* as a throttle, so genuinely malformed payloads keep failing loudly.
|
|
1738
|
+
*/
|
|
1739
|
+
function createInBandProviderErrorFromText(text) {
|
|
1740
|
+
const detail = readInBandDetail(text);
|
|
1741
|
+
if (detail === void 0 || !IN_BAND_RETRYABLE_TEXT_PATTERN.test(detail)) return void 0;
|
|
1742
|
+
const status = readLeadingStatus(detail);
|
|
1743
|
+
if (isRetryableStatus(status)) return attach(new ProviderHttpError(formatInBandMessage(status, detail, void 0), status), IN_BAND_FLAGS);
|
|
1744
|
+
return attach(new ProviderResponseError(detail, { kind: "runtime" }), IN_BAND_FLAGS);
|
|
1745
|
+
}
|
|
1746
|
+
//#endregion
|
|
1747
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/retry-after.ts
|
|
1183
1748
|
const RETRY_AFTER_HINT = "retry-after-ms=";
|
|
1184
1749
|
function formatErrorMessageWithRetryAfter(error, headers) {
|
|
1185
1750
|
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
@@ -1255,15 +1820,17 @@ function parseResetHeader(value, unit) {
|
|
|
1255
1820
|
return Math.ceil(targetMs - nowMs);
|
|
1256
1821
|
}
|
|
1257
1822
|
//#endregion
|
|
1258
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1823
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/utils/http-inspector.ts
|
|
1824
|
+
/**
|
|
1825
|
+
* Matches any header name whose value carries a credential, so a persisted dump
|
|
1826
|
+
* never leaks one. A substring match — not a hand-maintained allow-list — so
|
|
1827
|
+
* provider-specific auth headers (`x-goog-api-key`, `x-amz-security-token`, …)
|
|
1828
|
+
* are redacted without enumerating every provider's spelling; the fixed list it
|
|
1829
|
+
* replaced silently leaked any auth header it did not name. Redacting a benign
|
|
1830
|
+
* header that happens to match is harmless: dumps exist to diagnose the request
|
|
1831
|
+
* body, not its transport headers.
|
|
1832
|
+
*/
|
|
1833
|
+
const SENSITIVE_HEADER_PATTERN = /key|token|secret|auth|credential|cookie/i;
|
|
1267
1834
|
/**
|
|
1268
1835
|
* Build the JSON persisted for a rejected request. Request fields stay at the
|
|
1269
1836
|
* top level (so existing dump parsers still read `body`); the provider's error
|
|
@@ -1289,16 +1856,72 @@ function shouldDumpRejectedRequest(error) {
|
|
|
1289
1856
|
const status$1 = status(error);
|
|
1290
1857
|
return status$1 === 400 || status$1 === 413;
|
|
1291
1858
|
}
|
|
1859
|
+
const RAW_HTTP_REQUEST_LINE = "raw-http-request=";
|
|
1860
|
+
const RAW_HTTP_REQUEST_SAVE_FAILED_LINE = "raw-http-request-save-failed=";
|
|
1292
1861
|
async function appendRawHttpRequestDumpFor400(message, error, dump) {
|
|
1293
1862
|
if (!dump || isBunTestRuntime() || !shouldDumpRejectedRequest(error)) return message;
|
|
1294
1863
|
const payload = buildHttp400DumpPayload(dump, error, message);
|
|
1295
1864
|
const fileName = `${Date.now()}-${Bun.hash(JSON.stringify(payload)).toString(36)}.json`;
|
|
1296
|
-
const
|
|
1865
|
+
const dumpDir = path$1.join(getLogsDir(), HTTP_DUMP_DIR_NAME);
|
|
1866
|
+
const filePath = path$1.join(dumpDir, fileName);
|
|
1297
1867
|
try {
|
|
1298
1868
|
await Bun.write(filePath, `${JSON.stringify(payload, null, 2)}\n`);
|
|
1299
|
-
|
|
1869
|
+
pruneHttpRequestDumps(dumpDir, { keep: fileName }).catch((err) => {
|
|
1870
|
+
warn("Failed to prune HTTP request dumps", {
|
|
1871
|
+
dir: dumpDir,
|
|
1872
|
+
err
|
|
1873
|
+
});
|
|
1874
|
+
});
|
|
1875
|
+
return `${message}\n${RAW_HTTP_REQUEST_LINE}${filePath}`;
|
|
1300
1876
|
} catch (writeError) {
|
|
1301
|
-
|
|
1877
|
+
const writeMessage = writeError instanceof Error ? writeError.message : String(writeError);
|
|
1878
|
+
return `${message}\n${RAW_HTTP_REQUEST_SAVE_FAILED_LINE}${writeMessage}`;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
const HTTP_DUMP_DIR_NAME = "http-400-requests";
|
|
1882
|
+
const HTTP_DUMP_MAX_AGE_MS = 6048e5;
|
|
1883
|
+
const HTTP_DUMP_MAX_TOTAL_BYTES = 67108864;
|
|
1884
|
+
/**
|
|
1885
|
+
* Bound the rejected-request dump directory: delete `*.json` dumps older than
|
|
1886
|
+
* the age limit, then the oldest survivors until the total fits the size cap.
|
|
1887
|
+
*/
|
|
1888
|
+
async function pruneHttpRequestDumps(dir, retention = {}) {
|
|
1889
|
+
const maxAgeMs = retention.maxAgeMs ?? HTTP_DUMP_MAX_AGE_MS;
|
|
1890
|
+
const maxTotalBytes = retention.maxTotalBytes ?? HTTP_DUMP_MAX_TOTAL_BYTES;
|
|
1891
|
+
const now = retention.now ?? Date.now();
|
|
1892
|
+
let names;
|
|
1893
|
+
try {
|
|
1894
|
+
names = await fs_promises_shim_exports.readdir(dir);
|
|
1895
|
+
} catch (err) {
|
|
1896
|
+
if (isEnoent(err)) return;
|
|
1897
|
+
throw err;
|
|
1898
|
+
}
|
|
1899
|
+
const dumps = [];
|
|
1900
|
+
for (const name of names) {
|
|
1901
|
+
if (!name.endsWith(".json")) continue;
|
|
1902
|
+
try {
|
|
1903
|
+
const stat = await fs_promises_shim_exports.stat(path$1.join(dir, name));
|
|
1904
|
+
if (stat.isFile()) dumps.push({
|
|
1905
|
+
name,
|
|
1906
|
+
mtimeMs: stat.mtimeMs,
|
|
1907
|
+
size: stat.size
|
|
1908
|
+
});
|
|
1909
|
+
} catch (err) {
|
|
1910
|
+
if (!isEnoent(err)) throw err;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
dumps.sort((a, b) => b.mtimeMs - a.mtimeMs || (a.name < b.name ? 1 : a.name > b.name ? -1 : 0));
|
|
1914
|
+
let retainedBytes = 0;
|
|
1915
|
+
for (const dump of dumps) {
|
|
1916
|
+
if (dump.name === retention.keep) {
|
|
1917
|
+
retainedBytes += dump.size;
|
|
1918
|
+
continue;
|
|
1919
|
+
}
|
|
1920
|
+
if (now - dump.mtimeMs <= maxAgeMs && retainedBytes + dump.size <= maxTotalBytes) {
|
|
1921
|
+
retainedBytes += dump.size;
|
|
1922
|
+
continue;
|
|
1923
|
+
}
|
|
1924
|
+
await fs_promises_shim_exports.rm(path$1.join(dir, dump.name), { force: true });
|
|
1302
1925
|
}
|
|
1303
1926
|
}
|
|
1304
1927
|
async function finalizeErrorMessage(error, rawRequestDump, capturedErrorResponse) {
|
|
@@ -1360,14 +1983,34 @@ function rewriteClinePassError(errorMessage, provider) {
|
|
|
1360
1983
|
function sanitizeDump(dump) {
|
|
1361
1984
|
return {
|
|
1362
1985
|
...dump,
|
|
1986
|
+
url: redactUrlQuery(dump.url),
|
|
1363
1987
|
headers: redactHeaders(dump.headers)
|
|
1364
1988
|
};
|
|
1365
1989
|
}
|
|
1990
|
+
/**
|
|
1991
|
+
* Strips a persisted dump's query string entirely rather than picking sensitive
|
|
1992
|
+
* params by name: a configurable `baseUrl` (e.g. Bedrock's gateway routing) can
|
|
1993
|
+
* carry an arbitrary query-based credential the way `SENSITIVE_HEADER_PATTERN`
|
|
1994
|
+
* matches arbitrary header names, and dumps exist to diagnose the request body,
|
|
1995
|
+
* not the query.
|
|
1996
|
+
*/
|
|
1997
|
+
function redactUrlQuery(url) {
|
|
1998
|
+
if (!url) return url;
|
|
1999
|
+
try {
|
|
2000
|
+
const parsed = new URL(url);
|
|
2001
|
+
if (!parsed.search) return url;
|
|
2002
|
+
parsed.search = "";
|
|
2003
|
+
return `${parsed.toString()}[redacted-query]`;
|
|
2004
|
+
} catch {
|
|
2005
|
+
return url;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
/** Copy of `headers` with every credential value replaced by `[redacted]`; shared by every persisted dump. */
|
|
1366
2009
|
function redactHeaders(headers) {
|
|
1367
2010
|
if (!headers) return;
|
|
1368
2011
|
const redacted = {};
|
|
1369
2012
|
for (const [key, value] of Object.entries(headers)) {
|
|
1370
|
-
if (
|
|
2013
|
+
if (SENSITIVE_HEADER_PATTERN.test(key)) {
|
|
1371
2014
|
redacted[key] = "[redacted]";
|
|
1372
2015
|
continue;
|
|
1373
2016
|
}
|
|
@@ -1396,28 +2039,25 @@ function formatCapturedHttpError(captured) {
|
|
|
1396
2039
|
return extras.length > 0 ? `${message} (${extras.join(" ")})` : message;
|
|
1397
2040
|
}
|
|
1398
2041
|
function parseCapturedErrorPayload(captured) {
|
|
1399
|
-
if (
|
|
2042
|
+
if (isRecord(captured.bodyJson)) return captured.bodyJson;
|
|
1400
2043
|
if (!captured.bodyText) return void 0;
|
|
1401
2044
|
try {
|
|
1402
2045
|
const parsed = JSON.parse(captured.bodyText);
|
|
1403
|
-
return
|
|
2046
|
+
return isRecord(parsed) ? parsed : void 0;
|
|
1404
2047
|
} catch {
|
|
1405
2048
|
return;
|
|
1406
2049
|
}
|
|
1407
2050
|
}
|
|
1408
2051
|
function getObjectProperty(value, key) {
|
|
1409
2052
|
const property = value[key];
|
|
1410
|
-
return
|
|
2053
|
+
return isRecord(property) ? property : void 0;
|
|
1411
2054
|
}
|
|
1412
2055
|
function getStringProperty(value, key) {
|
|
1413
2056
|
const property = value[key];
|
|
1414
2057
|
return typeof property === "string" && property.trim().length > 0 ? property : void 0;
|
|
1415
2058
|
}
|
|
1416
|
-
function isObject(value) {
|
|
1417
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1418
|
-
}
|
|
1419
2059
|
//#endregion
|
|
1420
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
2060
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/format.ts
|
|
1421
2061
|
function rewriteOllamaToolCallJsonError(message) {
|
|
1422
2062
|
if (!LLAMA_CPP_TOOL_CALL_PARSE_PATTERN.test(message)) return message;
|
|
1423
2063
|
return `Local Ollama model emitted malformed tool-call JSON and llama.cpp rejected it (HTTP 500). This is usually a deterministic model-output failure after context degradation, not a transient server outage; reload the model or reduce context, then retry.\n${message}`;
|
|
@@ -1439,7 +2079,7 @@ async function formatMessage(error, opts = {}) {
|
|
|
1439
2079
|
return message;
|
|
1440
2080
|
}
|
|
1441
2081
|
//#endregion
|
|
1442
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
2082
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/finalize.ts
|
|
1443
2083
|
/**
|
|
1444
2084
|
* Build the complete error bundle for a provider catch block, replacing the
|
|
1445
2085
|
* `stopReason` / `errorStatus` / `errorId` / `errorMessage` boilerplate.
|
|
@@ -1451,19 +2091,24 @@ async function formatMessage(error, opts = {}) {
|
|
|
1451
2091
|
*/
|
|
1452
2092
|
async function finalize(error, opts = {}) {
|
|
1453
2093
|
const aborted = opts.abortTracker ? opts.abortTracker.wasCallerAbort() : opts.signal?.aborted === true;
|
|
1454
|
-
const
|
|
2094
|
+
const errorStatus = status(error);
|
|
2095
|
+
const currentStatus = errorStatus ?? opts.capturedErrorResponse?.status;
|
|
1455
2096
|
let message;
|
|
1456
2097
|
try {
|
|
1457
2098
|
message = (opts.abortTracker?.getLocalAbortReason())?.message ?? await formatMessage(error, opts);
|
|
1458
2099
|
} catch {
|
|
1459
2100
|
message = error instanceof Error ? error.message : String(error);
|
|
1460
2101
|
}
|
|
2102
|
+
const classificationError = errorStatus === void 0 && currentStatus !== void 0 ? {
|
|
2103
|
+
status: currentStatus,
|
|
2104
|
+
cause: error
|
|
2105
|
+
} : error;
|
|
1461
2106
|
return {
|
|
1462
2107
|
id: classifyMessage({
|
|
1463
2108
|
api: opts.api,
|
|
1464
2109
|
provider: opts.provider,
|
|
1465
2110
|
model: opts.model,
|
|
1466
|
-
errorId: classify(
|
|
2111
|
+
errorId: classify(classificationError, opts.api),
|
|
1467
2112
|
errorMessage: message,
|
|
1468
2113
|
errorStatus: currentStatus
|
|
1469
2114
|
}),
|
|
@@ -1473,31 +2118,7 @@ async function finalize(error, opts = {}) {
|
|
|
1473
2118
|
};
|
|
1474
2119
|
}
|
|
1475
2120
|
//#endregion
|
|
1476
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
1477
|
-
/**
|
|
1478
|
-
* A non-HTTP provider failure: a truncated stream, an error stop reason, an
|
|
1479
|
-
* empty body, a malformed envelope, or a runtime fault. For non-2xx HTTP
|
|
1480
|
-
* responses use {@link ProviderHttpError} (or a provider subclass) instead.
|
|
1481
|
-
*/
|
|
1482
|
-
var ProviderResponseError = class extends Error {
|
|
1483
|
-
provider;
|
|
1484
|
-
kind;
|
|
1485
|
-
constructor(message, options = {}) {
|
|
1486
|
-
super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
1487
|
-
this.name = "ProviderResponseError";
|
|
1488
|
-
this.provider = options.provider;
|
|
1489
|
-
this.kind = options.kind ?? "output";
|
|
1490
|
-
if (this.kind === "content-blocked") attach(this, create(Flag.ContentBlocked));
|
|
1491
|
-
else if (this.kind === "empty-output") attach(this, create(Flag.Transient, Flag.EmptyResponse));
|
|
1492
|
-
else if (this.kind === "incomplete-stream" || this.kind === "empty-body") attach(this, create(Flag.Transient));
|
|
1493
|
-
}
|
|
1494
|
-
};
|
|
1495
|
-
/** Non-2xx response from the Devin API. */
|
|
1496
|
-
var DevinApiError = class extends ProviderHttpError {
|
|
1497
|
-
name = "DevinApiError";
|
|
1498
|
-
};
|
|
1499
|
-
//#endregion
|
|
1500
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.1.17/node_modules/@oh-my-pi/pi-ai/src/error/retryable.ts
|
|
2121
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/retryable.ts
|
|
1501
2122
|
/**
|
|
1502
2123
|
* Whether a numeric HTTP status is in the canonical transient/retryable set:
|
|
1503
2124
|
* 408 (Request Timeout), 429 (Too Many Requests), and any 5xx.
|
|
@@ -1529,11 +2150,11 @@ function isProviderRetryableError(error) {
|
|
|
1529
2150
|
const httpStatus = status(error);
|
|
1530
2151
|
if (httpStatus !== void 0 && httpStatus >= 400 && httpStatus < 500 && httpStatus !== 408 && httpStatus !== 429) return false;
|
|
1531
2152
|
const msg = error.message.toLowerCase();
|
|
1532
|
-
if (isUnexpectedSocketCloseMessage(msg) || isTransientTransportMessage(msg) || TRANSIENT_TRANSPORT_PATTERN.test(msg) || PROVIDER_TRANSIENT_EXTRA_PATTERN.test(msg) || isTransientStreamParseError(error) || isRetryableStreamEnvelopeError(error)) return true;
|
|
2153
|
+
if (isUnexpectedSocketCloseMessage(msg) || isTransientTransportMessage(msg) || TRANSIENT_TRANSPORT_PATTERN.test(msg) || CODEX_HTTP_BODY_READ_ERROR_PATTERN.test(msg) || PROVIDER_TRANSIENT_EXTRA_PATTERN.test(msg) || isTransientStreamParseError(error) || isTransientStreamDropError(error) || isRetryableStreamEnvelopeError(error)) return true;
|
|
1533
2154
|
return isRetryableError(error);
|
|
1534
2155
|
}
|
|
1535
2156
|
//#endregion
|
|
1536
|
-
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.
|
|
2157
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.12.6/node_modules/@oh-my-pi/pi-ai/src/error/validation.ts
|
|
1537
2158
|
/**
|
|
1538
2159
|
* Caller-supplied input failed validation before/while building a provider
|
|
1539
2160
|
* request: bad request body, malformed tool arguments, unsupported content
|
|
@@ -1567,4 +2188,4 @@ var StreamTimeoutError = class extends Error {
|
|
|
1567
2188
|
}
|
|
1568
2189
|
};
|
|
1569
2190
|
//#endregion
|
|
1570
|
-
export {
|
|
2191
|
+
export { EventStreamFrameError as $, is as A, isUsageLimitStatus as B, LLAMA_CPP_TOOL_CALL_PARSE_PATTERN as C, classify as D, attach as E, isRequestBodyReadTimeout as F, BedrockApiError as G, AnthropicConnectionError as H, isStreamEnvelopeError as I, OllamaApiError as J, GeminiCliApiError as K, isTransientStreamParseError as L, isFastModeUnsupported as M, isGrammarError as N, classifyMessage as O, isImmutableLatestThinkingText as P, AwsCredentialsError as Q, retriable as R, Flag as S, PYTHON_HTTP_INCOMPLETE_CHUNK_PATTERN as T, AnthropicConnectionTimeoutError as U, AnthropicApiError as V, AnthropicStreamEnvelopeError as W, ProviderHttpError as X, OpenAIHttpError as Y, networkFailureError as Z, LoginCancelledError as _, isTransientStatus as a, AbortError as b, redactHeaders as c, createInBandProviderError as d, extractHttpStatusFromError as et, createInBandProviderErrorFromText as f, ApiKeyRequiredError as g, OAuthError as h, isProviderRetryableError as i, isCacheControlUnsupported as j, create as k, getHeadersFromError as l, ProviderResponseError as m, StreamTimeoutError as n, fetchWithRetry as nt, finalize as o, DevinApiError as p, GoogleApiError as q, ValidationError as r, isUnexpectedSocketCloseMessage as rt, finalizeErrorMessage as s, ConfigurationError as t, extractRetryHint as tt, getRetryAfterMsFromHeaders as u, MissingApiKeyError as v, PYTHON_HTTP2_STREAM_RESET_PATTERN as w, CODEX_NATIVE_LANE_STEER_REJECTED_CODE as x, OnPromptRequiredError as y, status as z };
|