cloison-runtime 0.1.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/LICENSE +21 -0
- package/README.md +313 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +47 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +57 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +27 -0
- package/dist/config/index.js.map +1 -0
- package/dist/credentials/index.d.ts +4 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +3 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/proxy.d.ts +3 -0
- package/dist/credentials/proxy.d.ts.map +1 -0
- package/dist/credentials/proxy.js +11 -0
- package/dist/credentials/proxy.js.map +1 -0
- package/dist/credentials/store.d.ts +7 -0
- package/dist/credentials/store.d.ts.map +1 -0
- package/dist/credentials/store.js +115 -0
- package/dist/credentials/store.js.map +1 -0
- package/dist/credentials/types.d.ts +14 -0
- package/dist/credentials/types.d.ts.map +1 -0
- package/dist/credentials/types.js +2 -0
- package/dist/credentials/types.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/runner.d.ts +7 -0
- package/dist/hooks/runner.d.ts.map +1 -0
- package/dist/hooks/runner.js +20 -0
- package/dist/hooks/runner.js.map +1 -0
- package/dist/hooks/types.d.ts +39 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +2 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/env.d.ts +2 -0
- package/dist/infra/env.d.ts.map +1 -0
- package/dist/infra/env.js +6 -0
- package/dist/infra/env.js.map +1 -0
- package/dist/infra/warning-filter.d.ts +8 -0
- package/dist/infra/warning-filter.d.ts.map +1 -0
- package/dist/infra/warning-filter.js +66 -0
- package/dist/infra/warning-filter.js.map +1 -0
- package/dist/logging/subsystem.d.ts +29 -0
- package/dist/logging/subsystem.d.ts.map +1 -0
- package/dist/logging/subsystem.js +322 -0
- package/dist/logging/subsystem.js.map +1 -0
- package/dist/memory/embedding-batch.d.ts +38 -0
- package/dist/memory/embedding-batch.d.ts.map +1 -0
- package/dist/memory/embedding-batch.js +253 -0
- package/dist/memory/embedding-batch.js.map +1 -0
- package/dist/memory/embedding-cache.d.ts +16 -0
- package/dist/memory/embedding-cache.d.ts.map +1 -0
- package/dist/memory/embedding-cache.js +113 -0
- package/dist/memory/embedding-cache.js.map +1 -0
- package/dist/memory/embeddings-debug.d.ts +2 -0
- package/dist/memory/embeddings-debug.d.ts.map +1 -0
- package/dist/memory/embeddings-debug.js +12 -0
- package/dist/memory/embeddings-debug.js.map +1 -0
- package/dist/memory/embeddings.d.ts +17 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +203 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/file-indexer.d.ts +26 -0
- package/dist/memory/file-indexer.d.ts.map +1 -0
- package/dist/memory/file-indexer.js +260 -0
- package/dist/memory/file-indexer.js.map +1 -0
- package/dist/memory/fs-utils.d.ts +12 -0
- package/dist/memory/fs-utils.d.ts.map +1 -0
- package/dist/memory/fs-utils.js +24 -0
- package/dist/memory/fs-utils.js.map +1 -0
- package/dist/memory/hybrid.d.ts +46 -0
- package/dist/memory/hybrid.d.ts.map +1 -0
- package/dist/memory/hybrid.js +85 -0
- package/dist/memory/hybrid.js.map +1 -0
- package/dist/memory/index.d.ts +17 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +15 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/internal.d.ts +39 -0
- package/dist/memory/internal.d.ts.map +1 -0
- package/dist/memory/internal.js +292 -0
- package/dist/memory/internal.js.map +1 -0
- package/dist/memory/manager-search.d.ts +61 -0
- package/dist/memory/manager-search.d.ts.map +1 -0
- package/dist/memory/manager-search.js +102 -0
- package/dist/memory/manager-search.js.map +1 -0
- package/dist/memory/mmr.d.ts +63 -0
- package/dist/memory/mmr.d.ts.map +1 -0
- package/dist/memory/mmr.js +165 -0
- package/dist/memory/mmr.js.map +1 -0
- package/dist/memory/query-expansion.d.ts +42 -0
- package/dist/memory/query-expansion.d.ts.map +1 -0
- package/dist/memory/query-expansion.js +776 -0
- package/dist/memory/query-expansion.js.map +1 -0
- package/dist/memory/session-indexer.d.ts +41 -0
- package/dist/memory/session-indexer.d.ts.map +1 -0
- package/dist/memory/session-indexer.js +367 -0
- package/dist/memory/session-indexer.js.map +1 -0
- package/dist/memory/simple-manager.d.ts +29 -0
- package/dist/memory/simple-manager.d.ts.map +1 -0
- package/dist/memory/simple-manager.js +216 -0
- package/dist/memory/simple-manager.js.map +1 -0
- package/dist/memory/sqlite.d.ts +2 -0
- package/dist/memory/sqlite.d.ts.map +1 -0
- package/dist/memory/sqlite.js +16 -0
- package/dist/memory/sqlite.js.map +1 -0
- package/dist/memory/ssrf.d.ts +18 -0
- package/dist/memory/ssrf.d.ts.map +1 -0
- package/dist/memory/ssrf.js +396 -0
- package/dist/memory/ssrf.js.map +1 -0
- package/dist/memory/temporal-decay.d.ts +26 -0
- package/dist/memory/temporal-decay.d.ts.map +1 -0
- package/dist/memory/temporal-decay.js +120 -0
- package/dist/memory/temporal-decay.js.map +1 -0
- package/dist/memory/types.d.ts +95 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +2 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/package.json +68 -0
- package/dist/platform/index.d.ts +3 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +2 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/platform.d.ts +3 -0
- package/dist/platform/platform.d.ts.map +1 -0
- package/dist/platform/platform.js +91 -0
- package/dist/platform/platform.js.map +1 -0
- package/dist/platform/types.d.ts +18 -0
- package/dist/platform/types.d.ts.map +1 -0
- package/dist/platform/types.js +2 -0
- package/dist/platform/types.js.map +1 -0
- package/dist/runtime/agent.d.ts +36 -0
- package/dist/runtime/agent.d.ts.map +1 -0
- package/dist/runtime/agent.js +250 -0
- package/dist/runtime/agent.js.map +1 -0
- package/dist/runtime/api-key-rotation.d.ts +26 -0
- package/dist/runtime/api-key-rotation.d.ts.map +1 -0
- package/dist/runtime/api-key-rotation.js +174 -0
- package/dist/runtime/api-key-rotation.js.map +1 -0
- package/dist/runtime/context-guard.d.ts +32 -0
- package/dist/runtime/context-guard.d.ts.map +1 -0
- package/dist/runtime/context-guard.js +61 -0
- package/dist/runtime/context-guard.js.map +1 -0
- package/dist/runtime/failover-error.d.ts +62 -0
- package/dist/runtime/failover-error.d.ts.map +1 -0
- package/dist/runtime/failover-error.js +733 -0
- package/dist/runtime/failover-error.js.map +1 -0
- package/dist/runtime/failover-policy.d.ts +5 -0
- package/dist/runtime/failover-policy.d.ts.map +1 -0
- package/dist/runtime/failover-policy.js +18 -0
- package/dist/runtime/failover-policy.js.map +1 -0
- package/dist/runtime/index.d.ts +13 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +13 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/memory-flush.d.ts +24 -0
- package/dist/runtime/memory-flush.d.ts.map +1 -0
- package/dist/runtime/memory-flush.js +64 -0
- package/dist/runtime/memory-flush.js.map +1 -0
- package/dist/runtime/memory-tools.d.ts +14 -0
- package/dist/runtime/memory-tools.d.ts.map +1 -0
- package/dist/runtime/memory-tools.js +58 -0
- package/dist/runtime/memory-tools.js.map +1 -0
- package/dist/runtime/model-fallback.d.ts +56 -0
- package/dist/runtime/model-fallback.d.ts.map +1 -0
- package/dist/runtime/model-fallback.js +301 -0
- package/dist/runtime/model-fallback.js.map +1 -0
- package/dist/runtime/model-fallback.types.d.ts +14 -0
- package/dist/runtime/model-fallback.types.d.ts.map +1 -0
- package/dist/runtime/model-fallback.types.js +3 -0
- package/dist/runtime/model-fallback.types.js.map +1 -0
- package/dist/runtime/retry.d.ts +24 -0
- package/dist/runtime/retry.d.ts.map +1 -0
- package/dist/runtime/retry.js +100 -0
- package/dist/runtime/retry.js.map +1 -0
- package/dist/runtime/session-pruning.d.ts +22 -0
- package/dist/runtime/session-pruning.d.ts.map +1 -0
- package/dist/runtime/session-pruning.js +118 -0
- package/dist/runtime/session-pruning.js.map +1 -0
- package/dist/runtime/stream-adapters.d.ts +11 -0
- package/dist/runtime/stream-adapters.d.ts.map +1 -0
- package/dist/runtime/stream-adapters.js +46 -0
- package/dist/runtime/stream-adapters.js.map +1 -0
- package/dist/runtime/subagent.d.ts +83 -0
- package/dist/runtime/subagent.d.ts.map +1 -0
- package/dist/runtime/subagent.js +190 -0
- package/dist/runtime/subagent.js.map +1 -0
- package/dist/runtime/tool-result-truncation.d.ts +25 -0
- package/dist/runtime/tool-result-truncation.d.ts.map +1 -0
- package/dist/runtime/tool-result-truncation.js +115 -0
- package/dist/runtime/tool-result-truncation.js.map +1 -0
- package/dist/sandbox/cgroup.d.ts +20 -0
- package/dist/sandbox/cgroup.d.ts.map +1 -0
- package/dist/sandbox/cgroup.js +82 -0
- package/dist/sandbox/cgroup.js.map +1 -0
- package/dist/sandbox/index.d.ts +12 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +10 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/ipc.d.ts +26 -0
- package/dist/sandbox/ipc.d.ts.map +1 -0
- package/dist/sandbox/ipc.js +154 -0
- package/dist/sandbox/ipc.js.map +1 -0
- package/dist/sandbox/manager.d.ts +4 -0
- package/dist/sandbox/manager.d.ts.map +1 -0
- package/dist/sandbox/manager.js +251 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/namespace.d.ts +12 -0
- package/dist/sandbox/namespace.d.ts.map +1 -0
- package/dist/sandbox/namespace.js +119 -0
- package/dist/sandbox/namespace.js.map +1 -0
- package/dist/sandbox/proxy-tools.d.ts +14 -0
- package/dist/sandbox/proxy-tools.d.ts.map +1 -0
- package/dist/sandbox/proxy-tools.js +63 -0
- package/dist/sandbox/proxy-tools.js.map +1 -0
- package/dist/sandbox/rootfs.d.ts +20 -0
- package/dist/sandbox/rootfs.d.ts.map +1 -0
- package/dist/sandbox/rootfs.js +247 -0
- package/dist/sandbox/rootfs.js.map +1 -0
- package/dist/sandbox/seccomp-apply.d.ts +9 -0
- package/dist/sandbox/seccomp-apply.d.ts.map +1 -0
- package/dist/sandbox/seccomp-apply.js +227 -0
- package/dist/sandbox/seccomp-apply.js.map +1 -0
- package/dist/sandbox/seccomp.d.ts +13 -0
- package/dist/sandbox/seccomp.d.ts.map +1 -0
- package/dist/sandbox/seccomp.js +120 -0
- package/dist/sandbox/seccomp.js.map +1 -0
- package/dist/sandbox/types.d.ts +66 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +8 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/sandbox/worker.d.ts +15 -0
- package/dist/sandbox/worker.d.ts.map +1 -0
- package/dist/sandbox/worker.js +151 -0
- package/dist/sandbox/worker.js.map +1 -0
- package/dist/sessions/index.d.ts +3 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +3 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/store.d.ts +17 -0
- package/dist/sessions/store.d.ts.map +1 -0
- package/dist/sessions/store.js +70 -0
- package/dist/sessions/store.js.map +1 -0
- package/dist/sessions/transcript-events.d.ts +11 -0
- package/dist/sessions/transcript-events.d.ts.map +1 -0
- package/dist/sessions/transcript-events.js +40 -0
- package/dist/sessions/transcript-events.js.map +1 -0
- package/dist/shared/agent-session.d.ts +10 -0
- package/dist/shared/agent-session.d.ts.map +1 -0
- package/dist/shared/agent-session.js +33 -0
- package/dist/shared/agent-session.js.map +1 -0
- package/dist/shared/constants.d.ts +6 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +17 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/fs.d.ts +7 -0
- package/dist/shared/fs.d.ts.map +1 -0
- package/dist/shared/fs.js +14 -0
- package/dist/shared/fs.js.map +1 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/skills/enablement.d.ts +10 -0
- package/dist/skills/enablement.d.ts.map +1 -0
- package/dist/skills/enablement.js +52 -0
- package/dist/skills/enablement.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +4 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/loader.d.ts +8 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +8 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/registry.d.ts +19 -0
- package/dist/skills/registry.d.ts.map +1 -0
- package/dist/skills/registry.js +106 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/utils/boolean.d.ts +6 -0
- package/dist/utils/boolean.d.ts.map +1 -0
- package/dist/utils/boolean.js +28 -0
- package/dist/utils/boolean.js.map +1 -0
- package/dist/utils/run-with-concurrency.d.ts +12 -0
- package/dist/utils/run-with-concurrency.d.ts.map +1 -0
- package/dist/utils/run-with-concurrency.js +40 -0
- package/dist/utils/run-with-concurrency.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +38 -0
- package/dist/utils.js.map +1 -0
- package/dist/workspace/index.d.ts +3 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +2 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/runner.d.ts +19 -0
- package/dist/workspace/runner.d.ts.map +1 -0
- package/dist/workspace/runner.js +491 -0
- package/dist/workspace/runner.js.map +1 -0
- package/dist/workspace/types.d.ts +37 -0
- package/dist/workspace/types.d.ts.map +1 -0
- package/dist/workspace/types.js +2 -0
- package/dist/workspace/types.js.map +1 -0
- package/dist/workspace/workspace.d.ts +12 -0
- package/dist/workspace/workspace.d.ts.map +1 -0
- package/dist/workspace/workspace.js +85 -0
- package/dist/workspace/workspace.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,733 @@
|
|
|
1
|
+
// Ported from OpenClaw src/agents/failover-error.ts + pi-embedded-helpers/errors.ts + failover-matches.ts
|
|
2
|
+
// Consolidated into a single module. All classification logic, patterns, and constants are identical.
|
|
3
|
+
// --- FailoverError class (from failover-error.ts) ---
|
|
4
|
+
const ABORT_TIMEOUT_RE = /request was aborted|request aborted/i;
|
|
5
|
+
export class FailoverError extends Error {
|
|
6
|
+
reason;
|
|
7
|
+
provider;
|
|
8
|
+
model;
|
|
9
|
+
profileId;
|
|
10
|
+
status;
|
|
11
|
+
code;
|
|
12
|
+
constructor(message, params) {
|
|
13
|
+
super(message, { cause: params.cause });
|
|
14
|
+
this.name = "FailoverError";
|
|
15
|
+
this.reason = params.reason;
|
|
16
|
+
this.provider = params.provider;
|
|
17
|
+
this.model = params.model;
|
|
18
|
+
this.profileId = params.profileId;
|
|
19
|
+
this.status = params.status;
|
|
20
|
+
this.code = params.code;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function isFailoverError(err) {
|
|
24
|
+
return err instanceof FailoverError;
|
|
25
|
+
}
|
|
26
|
+
export function resolveFailoverStatus(reason) {
|
|
27
|
+
switch (reason) {
|
|
28
|
+
case "billing": return 402;
|
|
29
|
+
case "rate_limit": return 429;
|
|
30
|
+
case "overloaded": return 503;
|
|
31
|
+
case "auth": return 401;
|
|
32
|
+
case "auth_permanent": return 403;
|
|
33
|
+
case "timeout": return 408;
|
|
34
|
+
case "format": return 400;
|
|
35
|
+
case "model_not_found": return 404;
|
|
36
|
+
case "session_expired": return 410;
|
|
37
|
+
default: return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const ERROR_PATTERNS = {
|
|
41
|
+
rateLimit: [
|
|
42
|
+
/rate[_ ]limit|too many requests|429/,
|
|
43
|
+
"model_cooldown",
|
|
44
|
+
"exceeded your current quota",
|
|
45
|
+
"resource has been exhausted",
|
|
46
|
+
"quota exceeded",
|
|
47
|
+
"resource_exhausted",
|
|
48
|
+
"usage limit",
|
|
49
|
+
/\btpm\b/i,
|
|
50
|
+
"tokens per minute",
|
|
51
|
+
"tokens per day",
|
|
52
|
+
],
|
|
53
|
+
overloaded: [
|
|
54
|
+
/overloaded_error|"type"\s*:\s*"overloaded_error"/i,
|
|
55
|
+
"overloaded",
|
|
56
|
+
/service[_ ]unavailable.*(?:overload|capacity|high[_ ]demand)|(?:overload|capacity|high[_ ]demand).*service[_ ]unavailable/i,
|
|
57
|
+
"high demand",
|
|
58
|
+
],
|
|
59
|
+
serverError: [
|
|
60
|
+
"an error occurred while processing",
|
|
61
|
+
"internal server error",
|
|
62
|
+
"internal_error",
|
|
63
|
+
"server_error",
|
|
64
|
+
"service temporarily unavailable",
|
|
65
|
+
"service_unavailable",
|
|
66
|
+
"bad gateway",
|
|
67
|
+
"gateway timeout",
|
|
68
|
+
"upstream error",
|
|
69
|
+
"upstream connect error",
|
|
70
|
+
"connection reset",
|
|
71
|
+
],
|
|
72
|
+
timeout: [
|
|
73
|
+
"timeout",
|
|
74
|
+
"timed out",
|
|
75
|
+
"service unavailable",
|
|
76
|
+
"deadline exceeded",
|
|
77
|
+
"context deadline exceeded",
|
|
78
|
+
"connection error",
|
|
79
|
+
"network error",
|
|
80
|
+
"network request failed",
|
|
81
|
+
"fetch failed",
|
|
82
|
+
"socket hang up",
|
|
83
|
+
/\beconn(?:refused|reset|aborted)\b/i,
|
|
84
|
+
/\benetunreach\b/i,
|
|
85
|
+
/\behostunreach\b/i,
|
|
86
|
+
/\behostdown\b/i,
|
|
87
|
+
/\benetreset\b/i,
|
|
88
|
+
/\betimedout\b/i,
|
|
89
|
+
/\besockettimedout\b/i,
|
|
90
|
+
/\bepipe\b/i,
|
|
91
|
+
/\benotfound\b/i,
|
|
92
|
+
/\beai_again\b/i,
|
|
93
|
+
/without sending (?:any )?chunks?/i,
|
|
94
|
+
/\bstop reason:\s*(?:abort|error|malformed_response|network_error)\b/i,
|
|
95
|
+
/\breason:\s*(?:abort|error|malformed_response|network_error)\b/i,
|
|
96
|
+
/\bunhandled stop reason:\s*(?:abort|error|malformed_response|network_error)\b/i,
|
|
97
|
+
],
|
|
98
|
+
billing: [
|
|
99
|
+
/["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|\b(?:got|returned|received)\s+(?:a\s+)?402\b|^\s*402\s+payment/i,
|
|
100
|
+
"payment required",
|
|
101
|
+
"insufficient credits",
|
|
102
|
+
/insufficient[_ ]quota/i,
|
|
103
|
+
"credit balance",
|
|
104
|
+
"plans & billing",
|
|
105
|
+
"insufficient balance",
|
|
106
|
+
"insufficient usd or diem balance",
|
|
107
|
+
/requires?\s+more\s+credits/i,
|
|
108
|
+
],
|
|
109
|
+
authPermanent: [
|
|
110
|
+
/api[_ ]?key[_ ]?(?:revoked|invalid|deactivated|deleted)/i,
|
|
111
|
+
"invalid_api_key",
|
|
112
|
+
"key has been disabled",
|
|
113
|
+
"key has been revoked",
|
|
114
|
+
"account has been deactivated",
|
|
115
|
+
/could not (?:authenticate|validate).*(?:api[_ ]?key|credentials)/i,
|
|
116
|
+
"permission_error",
|
|
117
|
+
"not allowed for this organization",
|
|
118
|
+
],
|
|
119
|
+
auth: [
|
|
120
|
+
/invalid[_ ]?api[_ ]?key/,
|
|
121
|
+
"incorrect api key",
|
|
122
|
+
"invalid token",
|
|
123
|
+
"authentication",
|
|
124
|
+
"re-authenticate",
|
|
125
|
+
"oauth token refresh failed",
|
|
126
|
+
"unauthorized",
|
|
127
|
+
"forbidden",
|
|
128
|
+
"access denied",
|
|
129
|
+
"insufficient permissions",
|
|
130
|
+
"insufficient permission",
|
|
131
|
+
/missing scopes?:/i,
|
|
132
|
+
"expired",
|
|
133
|
+
"token has expired",
|
|
134
|
+
/\b401\b/,
|
|
135
|
+
/\b403\b/,
|
|
136
|
+
"no credentials found",
|
|
137
|
+
"no api key found",
|
|
138
|
+
/\bfailed to (?:extract|parse|validate|decode)\b.*\btoken\b/,
|
|
139
|
+
],
|
|
140
|
+
format: [
|
|
141
|
+
"string should match pattern",
|
|
142
|
+
"tool_use.id",
|
|
143
|
+
"tool_use_id",
|
|
144
|
+
"messages.1.content.1.tool_use.id",
|
|
145
|
+
"invalid request format",
|
|
146
|
+
/tool call id was.*must be/i,
|
|
147
|
+
],
|
|
148
|
+
modelNotFound: [
|
|
149
|
+
"model_not_found",
|
|
150
|
+
"model not found",
|
|
151
|
+
"the model does not exist",
|
|
152
|
+
/model.*does not exist/i,
|
|
153
|
+
/model.*not available/i,
|
|
154
|
+
"no such model",
|
|
155
|
+
],
|
|
156
|
+
};
|
|
157
|
+
function matchesErrorPatterns(raw, patterns) {
|
|
158
|
+
if (!raw)
|
|
159
|
+
return false;
|
|
160
|
+
const value = raw.toLowerCase();
|
|
161
|
+
return patterns.some((pattern) => pattern instanceof RegExp ? pattern.test(value) : value.includes(pattern));
|
|
162
|
+
}
|
|
163
|
+
export function isRateLimitErrorMessage(raw) {
|
|
164
|
+
return matchesErrorPatterns(raw, ERROR_PATTERNS.rateLimit);
|
|
165
|
+
}
|
|
166
|
+
export function isTimeoutErrorMessage(raw) {
|
|
167
|
+
return matchesErrorPatterns(raw, ERROR_PATTERNS.timeout);
|
|
168
|
+
}
|
|
169
|
+
export function isOverloadedErrorMessage(raw) {
|
|
170
|
+
return matchesErrorPatterns(raw, ERROR_PATTERNS.overloaded);
|
|
171
|
+
}
|
|
172
|
+
export function isBillingErrorMessage(raw) {
|
|
173
|
+
if (!raw)
|
|
174
|
+
return false;
|
|
175
|
+
const value = raw.toLowerCase();
|
|
176
|
+
if (value.length > 5000) {
|
|
177
|
+
return /["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b/i.test(value);
|
|
178
|
+
}
|
|
179
|
+
if (matchesErrorPatterns(value, ERROR_PATTERNS.billing))
|
|
180
|
+
return true;
|
|
181
|
+
if (!/\b(?:402|billing|credit|payment|quota|balance)\b/i.test(raw))
|
|
182
|
+
return false;
|
|
183
|
+
return (value.includes("upgrade") ||
|
|
184
|
+
value.includes("credits") ||
|
|
185
|
+
value.includes("payment") ||
|
|
186
|
+
value.includes("plan"));
|
|
187
|
+
}
|
|
188
|
+
export function isAuthPermanentErrorMessage(raw) {
|
|
189
|
+
return matchesErrorPatterns(raw, ERROR_PATTERNS.authPermanent);
|
|
190
|
+
}
|
|
191
|
+
export function isAuthErrorMessage(raw) {
|
|
192
|
+
return matchesErrorPatterns(raw, ERROR_PATTERNS.auth);
|
|
193
|
+
}
|
|
194
|
+
function isServerErrorMessage(raw) {
|
|
195
|
+
return matchesErrorPatterns(raw, ERROR_PATTERNS.serverError);
|
|
196
|
+
}
|
|
197
|
+
const TRANSIENT_HTTP_ERROR_CODES = new Set([499, 500, 502, 503, 504, 521, 522, 523, 524, 529]);
|
|
198
|
+
export function isTransientHttpError(raw) {
|
|
199
|
+
const match = raw.match(/\b(\d{3})\b/);
|
|
200
|
+
if (!match)
|
|
201
|
+
return false;
|
|
202
|
+
const code = Number(match[1]);
|
|
203
|
+
return TRANSIENT_HTTP_ERROR_CODES.has(code) && !isRateLimitErrorMessage(raw);
|
|
204
|
+
}
|
|
205
|
+
export function isModelNotFoundErrorMessage(raw) {
|
|
206
|
+
return matchesErrorPatterns(raw, ERROR_PATTERNS.modelNotFound);
|
|
207
|
+
}
|
|
208
|
+
function hasRateLimitTpmHint(raw) {
|
|
209
|
+
const lower = raw.toLowerCase();
|
|
210
|
+
return /\btpm\b/i.test(lower) || lower.includes("tokens per minute");
|
|
211
|
+
}
|
|
212
|
+
function isReasoningConstraintErrorMessage(raw) {
|
|
213
|
+
if (!raw)
|
|
214
|
+
return false;
|
|
215
|
+
const lower = raw.toLowerCase();
|
|
216
|
+
return (lower.includes("reasoning is mandatory") ||
|
|
217
|
+
lower.includes("reasoning is required") ||
|
|
218
|
+
lower.includes("requires reasoning") ||
|
|
219
|
+
(lower.includes("reasoning") && lower.includes("cannot be disabled")));
|
|
220
|
+
}
|
|
221
|
+
// --- Image error detection (from errors.ts) ---
|
|
222
|
+
const IMAGE_DIMENSION_ERROR_RE = /image dimensions exceed max allowed size for many-image requests:\s*(\d+)\s*pixels/i;
|
|
223
|
+
export function isImageDimensionErrorMessage(raw) {
|
|
224
|
+
if (!raw)
|
|
225
|
+
return false;
|
|
226
|
+
return raw.toLowerCase().includes("image dimensions exceed max allowed size");
|
|
227
|
+
}
|
|
228
|
+
const IMAGE_SIZE_ERROR_RE = /image exceeds\s*(\d+(?:\.\d+)?)\s*mb/i;
|
|
229
|
+
export function isImageSizeError(errorMessage) {
|
|
230
|
+
if (!errorMessage)
|
|
231
|
+
return false;
|
|
232
|
+
const lower = errorMessage.toLowerCase();
|
|
233
|
+
return lower.includes("image exceeds") && lower.includes("mb");
|
|
234
|
+
}
|
|
235
|
+
// --- Session expired detection (from errors.ts) ---
|
|
236
|
+
export function isCliSessionExpiredErrorMessage(raw) {
|
|
237
|
+
if (!raw)
|
|
238
|
+
return false;
|
|
239
|
+
const lower = raw.toLowerCase();
|
|
240
|
+
return (lower.includes("session not found") ||
|
|
241
|
+
lower.includes("session does not exist") ||
|
|
242
|
+
lower.includes("session expired") ||
|
|
243
|
+
lower.includes("session invalid") ||
|
|
244
|
+
lower.includes("conversation not found") ||
|
|
245
|
+
lower.includes("conversation does not exist") ||
|
|
246
|
+
lower.includes("conversation expired") ||
|
|
247
|
+
lower.includes("conversation invalid") ||
|
|
248
|
+
lower.includes("no such session") ||
|
|
249
|
+
lower.includes("invalid session") ||
|
|
250
|
+
lower.includes("session id not found") ||
|
|
251
|
+
lower.includes("conversation id not found"));
|
|
252
|
+
}
|
|
253
|
+
// --- Periodic usage limit (from failover-matches.ts) ---
|
|
254
|
+
const PERIODIC_USAGE_LIMIT_RE = /\b(?:daily|weekly|monthly)(?:\/(?:daily|weekly|monthly))* (?:usage )?limit(?:s)?(?: (?:exhausted|reached|exceeded))?\b/i;
|
|
255
|
+
export function isPeriodicUsageLimitErrorMessage(raw) {
|
|
256
|
+
return PERIODIC_USAGE_LIMIT_RE.test(raw);
|
|
257
|
+
}
|
|
258
|
+
// --- Provider-specific patterns (from provider-error-patterns.ts) ---
|
|
259
|
+
const PROVIDER_CONTEXT_OVERFLOW_PATTERNS = [
|
|
260
|
+
/ValidationException.*(?:input is too long|max input token|input token.*exceed)/i,
|
|
261
|
+
/ValidationException.*(?:exceeds? the (?:maximum|max) (?:number of )?(?:input )?tokens)/i,
|
|
262
|
+
/ModelStreamErrorException.*(?:Input is too long|too many input tokens)/i,
|
|
263
|
+
/content_filter.*(?:prompt|input).*(?:too long|exceed)/i,
|
|
264
|
+
/\bollama\b.*(?:context length|too many tokens|context window)/i,
|
|
265
|
+
/\btruncating input\b.*\btoo long\b/i,
|
|
266
|
+
/\bmistral\b.*(?:input.*too long|token limit.*exceeded)/i,
|
|
267
|
+
/\btotal tokens?.*exceeds? (?:the )?(?:model(?:'s)? )?(?:max|maximum|limit)/i,
|
|
268
|
+
/\bdeepseek\b.*(?:input.*too long|context.*exceed)/i,
|
|
269
|
+
/INVALID_ARGUMENT.*(?:exceeds? the (?:maximum|max)|input.*too (?:long|large))/i,
|
|
270
|
+
/\binput (?:is )?too long for (?:the )?model\b/i,
|
|
271
|
+
];
|
|
272
|
+
export function matchesProviderContextOverflow(errorMessage) {
|
|
273
|
+
return PROVIDER_CONTEXT_OVERFLOW_PATTERNS.some((pattern) => pattern.test(errorMessage));
|
|
274
|
+
}
|
|
275
|
+
const PROVIDER_SPECIFIC_PATTERNS = [
|
|
276
|
+
{ test: /ThrottlingException|Too many concurrent requests/i, reason: "rate_limit" },
|
|
277
|
+
{ test: /ModelNotReadyException/i, reason: "overloaded" },
|
|
278
|
+
{ test: /model(?:_is)?_deactivated|model has been deactivated/i, reason: "model_not_found" },
|
|
279
|
+
{ test: /\bconcurrency limit\b.*\breached\b/i, reason: "rate_limit" },
|
|
280
|
+
{ test: /\bworkers?_ai\b.*\b(?:rate|limit|quota)\b/i, reason: "rate_limit" },
|
|
281
|
+
];
|
|
282
|
+
export function classifyProviderSpecificError(errorMessage) {
|
|
283
|
+
for (const pattern of PROVIDER_SPECIFIC_PATTERNS) {
|
|
284
|
+
if (pattern.test.test(errorMessage))
|
|
285
|
+
return pattern.reason;
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
// --- JSON API internal server error (from errors.ts) ---
|
|
290
|
+
const API_ERROR_TRANSIENT_SIGNALS_RE = /internal server error|overload|temporarily unavailable|service unavailable|unknown error|server error|bad gateway|gateway timeout|upstream error|backend error|try again later|temporarily.+unable|unexpected error/i;
|
|
291
|
+
function isJsonApiInternalServerError(raw) {
|
|
292
|
+
if (!raw)
|
|
293
|
+
return false;
|
|
294
|
+
const value = raw.toLowerCase();
|
|
295
|
+
if (!value.includes('"type":"api_error"'))
|
|
296
|
+
return false;
|
|
297
|
+
if (isBillingErrorMessage(raw) || isAuthErrorMessage(raw) || isAuthPermanentErrorMessage(raw))
|
|
298
|
+
return false;
|
|
299
|
+
return API_ERROR_TRANSIENT_SIGNALS_RE.test(raw);
|
|
300
|
+
}
|
|
301
|
+
const BILLING_402_HINTS = [
|
|
302
|
+
"insufficient credits", "insufficient quota", "credit balance", "insufficient balance",
|
|
303
|
+
"plans & billing", "add more credits", "top up",
|
|
304
|
+
];
|
|
305
|
+
const BILLING_402_PLAN_HINTS = [
|
|
306
|
+
"upgrade your plan", "upgrade plan", "current plan", "subscription",
|
|
307
|
+
];
|
|
308
|
+
const PERIODIC_402_HINTS = ["daily", "weekly", "monthly"];
|
|
309
|
+
const RETRYABLE_402_RETRY_HINTS = ["try again", "retry", "temporary", "cooldown"];
|
|
310
|
+
const RETRYABLE_402_LIMIT_HINTS = ["usage limit", "rate limit", "organization usage"];
|
|
311
|
+
const RETRYABLE_402_SCOPED_HINTS = ["organization", "workspace"];
|
|
312
|
+
const RETRYABLE_402_SCOPED_RESULT_HINTS = [
|
|
313
|
+
"billing period", "exceeded", "reached", "exhausted",
|
|
314
|
+
];
|
|
315
|
+
const RAW_402_MARKER_RE = /["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|\b(?:got|returned|received)\s+(?:a\s+)?402\b|^\s*402\s+payment required\b|^\s*402\s+.*used up your points\b/i;
|
|
316
|
+
const LEADING_402_WRAPPER_RE = /^(?:error[:\s-]+)?(?:(?:http\s*)?402(?:\s+payment required)?|payment required)(?:[:\s-]+|$)/i;
|
|
317
|
+
function includesAnyHint(text, hints) {
|
|
318
|
+
return hints.some((hint) => text.includes(hint));
|
|
319
|
+
}
|
|
320
|
+
function hasExplicit402BillingSignal(text) {
|
|
321
|
+
return (includesAnyHint(text, BILLING_402_HINTS) ||
|
|
322
|
+
(includesAnyHint(text, BILLING_402_PLAN_HINTS) && text.includes("limit")) ||
|
|
323
|
+
text.includes("billing hard limit") ||
|
|
324
|
+
text.includes("hard limit reached") ||
|
|
325
|
+
(text.includes("maximum allowed") && text.includes("limit")));
|
|
326
|
+
}
|
|
327
|
+
function hasQuotaRefreshWindowSignal(text) {
|
|
328
|
+
return (text.includes("subscription quota limit") &&
|
|
329
|
+
(text.includes("automatic quota refresh") || text.includes("rolling time window")));
|
|
330
|
+
}
|
|
331
|
+
function hasRetryable402TransientSignal(text) {
|
|
332
|
+
const hasPeriodicHint = includesAnyHint(text, PERIODIC_402_HINTS);
|
|
333
|
+
const hasSpendLimit = text.includes("spend limit") || text.includes("spending limit");
|
|
334
|
+
const hasScopedHint = includesAnyHint(text, RETRYABLE_402_SCOPED_HINTS);
|
|
335
|
+
return ((includesAnyHint(text, RETRYABLE_402_RETRY_HINTS) &&
|
|
336
|
+
includesAnyHint(text, RETRYABLE_402_LIMIT_HINTS)) ||
|
|
337
|
+
(hasPeriodicHint && (text.includes("usage limit") || hasSpendLimit)) ||
|
|
338
|
+
(hasPeriodicHint && text.includes("limit") && text.includes("reset")) ||
|
|
339
|
+
(hasScopedHint &&
|
|
340
|
+
text.includes("limit") &&
|
|
341
|
+
(hasSpendLimit || includesAnyHint(text, RETRYABLE_402_SCOPED_RESULT_HINTS))));
|
|
342
|
+
}
|
|
343
|
+
function normalize402Message(raw) {
|
|
344
|
+
return raw.trim().toLowerCase().replace(LEADING_402_WRAPPER_RE, "").trim();
|
|
345
|
+
}
|
|
346
|
+
// --- Context overflow detection (from errors.ts) ---
|
|
347
|
+
const CONTEXT_WINDOW_TOO_SMALL_RE = /context window.*(too small|minimum is)/i;
|
|
348
|
+
const CONTEXT_OVERFLOW_HINT_RE = /context.*overflow|context window.*(too (?:large|long)|exceed|over|limit|max(?:imum)?|requested|sent|tokens)|prompt.*(too (?:large|long)|exceed|over|limit|max(?:imum)?)|(?:request|input).*(?:context|window|length|token).*(too (?:large|long)|exceed|over|limit|max(?:imum)?)/i;
|
|
349
|
+
const RATE_LIMIT_HINT_RE = /rate limit|too many requests|requests per (?:minute|hour|day)|quota|throttl|429\b|tokens per day/i;
|
|
350
|
+
export function isContextOverflowError(errorMessage) {
|
|
351
|
+
if (!errorMessage)
|
|
352
|
+
return false;
|
|
353
|
+
const lower = errorMessage.toLowerCase();
|
|
354
|
+
if (hasRateLimitTpmHint(errorMessage))
|
|
355
|
+
return false;
|
|
356
|
+
if (isReasoningConstraintErrorMessage(errorMessage))
|
|
357
|
+
return false;
|
|
358
|
+
const hasRequestSizeExceeds = lower.includes("request size exceeds");
|
|
359
|
+
const hasContextWindow = lower.includes("context window") ||
|
|
360
|
+
lower.includes("context length") ||
|
|
361
|
+
lower.includes("maximum context length");
|
|
362
|
+
return (lower.includes("request_too_large") ||
|
|
363
|
+
lower.includes("request exceeds the maximum size") ||
|
|
364
|
+
lower.includes("context length exceeded") ||
|
|
365
|
+
lower.includes("maximum context length") ||
|
|
366
|
+
lower.includes("prompt is too long") ||
|
|
367
|
+
lower.includes("prompt too long") ||
|
|
368
|
+
lower.includes("exceeds model context window") ||
|
|
369
|
+
lower.includes("model token limit") ||
|
|
370
|
+
(hasRequestSizeExceeds && hasContextWindow) ||
|
|
371
|
+
lower.includes("context overflow:") ||
|
|
372
|
+
lower.includes("exceed context limit") ||
|
|
373
|
+
lower.includes("exceeds the model's maximum context") ||
|
|
374
|
+
(lower.includes("max_tokens") && lower.includes("exceed") && lower.includes("context")) ||
|
|
375
|
+
(lower.includes("input length") && lower.includes("exceed") && lower.includes("context")) ||
|
|
376
|
+
(lower.includes("413") && lower.includes("too large")) ||
|
|
377
|
+
lower.includes("context_window_exceeded") ||
|
|
378
|
+
errorMessage.includes("上下文过长") ||
|
|
379
|
+
errorMessage.includes("上下文超出") ||
|
|
380
|
+
errorMessage.includes("上下文长度超") ||
|
|
381
|
+
errorMessage.includes("超出最大上下文") ||
|
|
382
|
+
errorMessage.includes("请压缩上下文") ||
|
|
383
|
+
matchesProviderContextOverflow(errorMessage));
|
|
384
|
+
}
|
|
385
|
+
export function isLikelyContextOverflowError(errorMessage) {
|
|
386
|
+
if (!errorMessage)
|
|
387
|
+
return false;
|
|
388
|
+
if (hasRateLimitTpmHint(errorMessage))
|
|
389
|
+
return false;
|
|
390
|
+
if (isReasoningConstraintErrorMessage(errorMessage))
|
|
391
|
+
return false;
|
|
392
|
+
if (isBillingErrorMessage(errorMessage))
|
|
393
|
+
return false;
|
|
394
|
+
if (CONTEXT_WINDOW_TOO_SMALL_RE.test(errorMessage))
|
|
395
|
+
return false;
|
|
396
|
+
if (isRateLimitErrorMessage(errorMessage))
|
|
397
|
+
return false;
|
|
398
|
+
if (isContextOverflowError(errorMessage))
|
|
399
|
+
return true;
|
|
400
|
+
if (RATE_LIMIT_HINT_RE.test(errorMessage))
|
|
401
|
+
return false;
|
|
402
|
+
return CONTEXT_OVERFLOW_HINT_RE.test(errorMessage);
|
|
403
|
+
}
|
|
404
|
+
// --- HTTP status extraction (from assistant-error-format.ts) ---
|
|
405
|
+
const HTTP_STATUS_DELIMITER_RE = /(?:\s*:\s*|\s+)/;
|
|
406
|
+
const HTTP_STATUS_CODE_PREFIX_RE = new RegExp(`^(?:http\\s*)?(\\d{3})(?:${HTTP_STATUS_DELIMITER_RE.source}([\\s\\S]+))?$`, "i");
|
|
407
|
+
function extractLeadingHttpStatus(raw) {
|
|
408
|
+
const match = raw.match(HTTP_STATUS_CODE_PREFIX_RE);
|
|
409
|
+
if (!match)
|
|
410
|
+
return null;
|
|
411
|
+
const code = Number(match[1]);
|
|
412
|
+
if (!Number.isFinite(code))
|
|
413
|
+
return null;
|
|
414
|
+
return { code, rest: (match[2] ?? "").trim() };
|
|
415
|
+
}
|
|
416
|
+
// --- Error code classification ---
|
|
417
|
+
const TIMEOUT_ERROR_CODES = new Set([
|
|
418
|
+
"ECONNREFUSED", "ECONNRESET", "ECONNABORTED", "ENETUNREACH",
|
|
419
|
+
"EHOSTUNREACH", "EHOSTDOWN", "ENETRESET", "ETIMEDOUT",
|
|
420
|
+
"ESOCKETTIMEDOUT", "EPIPE", "ENOTFOUND", "EAI_AGAIN",
|
|
421
|
+
"UND_ERR_CONNECT_TIMEOUT", "UND_ERR_HEADERS_TIMEOUT",
|
|
422
|
+
"UND_ERR_BODY_TIMEOUT", "UND_ERR_SOCKET",
|
|
423
|
+
]);
|
|
424
|
+
function classifyFailoverReasonFromCode(raw) {
|
|
425
|
+
const normalized = raw?.trim().toUpperCase();
|
|
426
|
+
if (!normalized)
|
|
427
|
+
return null;
|
|
428
|
+
switch (normalized) {
|
|
429
|
+
case "RESOURCE_EXHAUSTED":
|
|
430
|
+
case "RATE_LIMIT":
|
|
431
|
+
case "RATE_LIMITED":
|
|
432
|
+
case "RATE_LIMIT_EXCEEDED":
|
|
433
|
+
case "TOO_MANY_REQUESTS":
|
|
434
|
+
case "THROTTLED":
|
|
435
|
+
case "THROTTLING":
|
|
436
|
+
case "THROTTLINGEXCEPTION":
|
|
437
|
+
case "THROTTLING_EXCEPTION":
|
|
438
|
+
return "rate_limit";
|
|
439
|
+
case "OVERLOADED":
|
|
440
|
+
case "OVERLOADED_ERROR":
|
|
441
|
+
return "overloaded";
|
|
442
|
+
default:
|
|
443
|
+
return TIMEOUT_ERROR_CODES.has(normalized) ? "timeout" : null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
// --- Message classification ---
|
|
447
|
+
function toReasonClassification(reason) {
|
|
448
|
+
return { kind: "reason", reason };
|
|
449
|
+
}
|
|
450
|
+
function failoverReasonFromClassification(c) {
|
|
451
|
+
return c?.kind === "reason" ? c.reason : null;
|
|
452
|
+
}
|
|
453
|
+
function classify402Message(message) {
|
|
454
|
+
const normalized = normalize402Message(message);
|
|
455
|
+
if (!normalized)
|
|
456
|
+
return "billing";
|
|
457
|
+
if (hasQuotaRefreshWindowSignal(normalized))
|
|
458
|
+
return "rate_limit";
|
|
459
|
+
if (hasExplicit402BillingSignal(normalized))
|
|
460
|
+
return "billing";
|
|
461
|
+
if (isRateLimitErrorMessage(normalized))
|
|
462
|
+
return "rate_limit";
|
|
463
|
+
if (hasRetryable402TransientSignal(normalized))
|
|
464
|
+
return "rate_limit";
|
|
465
|
+
return "billing";
|
|
466
|
+
}
|
|
467
|
+
function classifyFailoverReasonFrom402Text(raw) {
|
|
468
|
+
if (!RAW_402_MARKER_RE.test(raw))
|
|
469
|
+
return null;
|
|
470
|
+
return classify402Message(raw);
|
|
471
|
+
}
|
|
472
|
+
function classifyFailoverClassificationFromMessage(raw) {
|
|
473
|
+
if (isImageDimensionErrorMessage(raw))
|
|
474
|
+
return null;
|
|
475
|
+
if (isImageSizeError(raw))
|
|
476
|
+
return null;
|
|
477
|
+
if (isCliSessionExpiredErrorMessage(raw))
|
|
478
|
+
return toReasonClassification("session_expired");
|
|
479
|
+
if (isModelNotFoundErrorMessage(raw))
|
|
480
|
+
return toReasonClassification("model_not_found");
|
|
481
|
+
if (isContextOverflowError(raw))
|
|
482
|
+
return { kind: "context_overflow" };
|
|
483
|
+
const reasonFrom402Text = classifyFailoverReasonFrom402Text(raw);
|
|
484
|
+
if (reasonFrom402Text)
|
|
485
|
+
return toReasonClassification(reasonFrom402Text);
|
|
486
|
+
if (isPeriodicUsageLimitErrorMessage(raw)) {
|
|
487
|
+
return toReasonClassification(isBillingErrorMessage(raw) ? "billing" : "rate_limit");
|
|
488
|
+
}
|
|
489
|
+
if (isRateLimitErrorMessage(raw))
|
|
490
|
+
return toReasonClassification("rate_limit");
|
|
491
|
+
if (isOverloadedErrorMessage(raw))
|
|
492
|
+
return toReasonClassification("overloaded");
|
|
493
|
+
if (isTransientHttpError(raw)) {
|
|
494
|
+
const status = extractLeadingHttpStatus(raw.trim());
|
|
495
|
+
if (status?.code === 529)
|
|
496
|
+
return toReasonClassification("overloaded");
|
|
497
|
+
return toReasonClassification("timeout");
|
|
498
|
+
}
|
|
499
|
+
if (isBillingErrorMessage(raw))
|
|
500
|
+
return toReasonClassification("billing");
|
|
501
|
+
if (isAuthPermanentErrorMessage(raw))
|
|
502
|
+
return toReasonClassification("auth_permanent");
|
|
503
|
+
if (isAuthErrorMessage(raw))
|
|
504
|
+
return toReasonClassification("auth");
|
|
505
|
+
if (isServerErrorMessage(raw))
|
|
506
|
+
return toReasonClassification("timeout");
|
|
507
|
+
if (isJsonApiInternalServerError(raw))
|
|
508
|
+
return toReasonClassification("timeout");
|
|
509
|
+
if (isTimeoutErrorMessage(raw))
|
|
510
|
+
return toReasonClassification("timeout");
|
|
511
|
+
const providerSpecific = classifyProviderSpecificError(raw);
|
|
512
|
+
if (providerSpecific)
|
|
513
|
+
return toReasonClassification(providerSpecific);
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
function classifyFailoverClassificationFromHttpStatus(status, message, messageClassification) {
|
|
517
|
+
const messageReason = failoverReasonFromClassification(messageClassification);
|
|
518
|
+
if (typeof status !== "number" || !Number.isFinite(status))
|
|
519
|
+
return null;
|
|
520
|
+
if (status === 402)
|
|
521
|
+
return toReasonClassification(message ? classify402Message(message) : "billing");
|
|
522
|
+
if (status === 429)
|
|
523
|
+
return toReasonClassification("rate_limit");
|
|
524
|
+
if (status === 401 || status === 403) {
|
|
525
|
+
if (message && isAuthPermanentErrorMessage(message))
|
|
526
|
+
return toReasonClassification("auth_permanent");
|
|
527
|
+
return toReasonClassification("auth");
|
|
528
|
+
}
|
|
529
|
+
if (status === 408)
|
|
530
|
+
return toReasonClassification("timeout");
|
|
531
|
+
if (status === 410) {
|
|
532
|
+
if (messageReason === "session_expired" || messageReason === "billing" || messageReason === "auth_permanent" || messageReason === "auth") {
|
|
533
|
+
return messageClassification;
|
|
534
|
+
}
|
|
535
|
+
return toReasonClassification("timeout");
|
|
536
|
+
}
|
|
537
|
+
if (status === 503) {
|
|
538
|
+
if (messageReason === "overloaded")
|
|
539
|
+
return messageClassification;
|
|
540
|
+
return toReasonClassification("timeout");
|
|
541
|
+
}
|
|
542
|
+
if (status === 499) {
|
|
543
|
+
if (messageReason === "overloaded")
|
|
544
|
+
return messageClassification;
|
|
545
|
+
return toReasonClassification("timeout");
|
|
546
|
+
}
|
|
547
|
+
if (status === 500 || status === 502 || status === 504)
|
|
548
|
+
return toReasonClassification("timeout");
|
|
549
|
+
if (status === 529)
|
|
550
|
+
return toReasonClassification("overloaded");
|
|
551
|
+
if (status === 400 || status === 422) {
|
|
552
|
+
if (messageClassification)
|
|
553
|
+
return messageClassification;
|
|
554
|
+
return toReasonClassification("format");
|
|
555
|
+
}
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
export function classifyFailoverSignal(signal) {
|
|
559
|
+
const inferredStatus = typeof signal.status === "number" && Number.isFinite(signal.status)
|
|
560
|
+
? signal.status
|
|
561
|
+
: extractLeadingHttpStatus(signal.message?.trim() ?? "")?.code;
|
|
562
|
+
const messageClassification = signal.message
|
|
563
|
+
? classifyFailoverClassificationFromMessage(signal.message)
|
|
564
|
+
: null;
|
|
565
|
+
const statusClassification = classifyFailoverClassificationFromHttpStatus(inferredStatus, signal.message, messageClassification);
|
|
566
|
+
if (statusClassification)
|
|
567
|
+
return statusClassification;
|
|
568
|
+
const codeReason = classifyFailoverReasonFromCode(signal.code);
|
|
569
|
+
if (codeReason)
|
|
570
|
+
return toReasonClassification(codeReason);
|
|
571
|
+
return messageClassification;
|
|
572
|
+
}
|
|
573
|
+
// --- Nested error traversal (from failover-error.ts) ---
|
|
574
|
+
function readErrorName(err) {
|
|
575
|
+
if (!err || typeof err !== "object")
|
|
576
|
+
return "";
|
|
577
|
+
const name = err.name;
|
|
578
|
+
return typeof name === "string" ? name : "";
|
|
579
|
+
}
|
|
580
|
+
function findErrorProperty(err, reader, seen = new Set()) {
|
|
581
|
+
const direct = reader(err);
|
|
582
|
+
if (direct !== undefined)
|
|
583
|
+
return direct;
|
|
584
|
+
if (!err || typeof err !== "object")
|
|
585
|
+
return undefined;
|
|
586
|
+
if (seen.has(err))
|
|
587
|
+
return undefined;
|
|
588
|
+
seen.add(err);
|
|
589
|
+
const candidate = err;
|
|
590
|
+
return (findErrorProperty(candidate.error, reader, seen) ??
|
|
591
|
+
findErrorProperty(candidate.cause, reader, seen));
|
|
592
|
+
}
|
|
593
|
+
function readDirectStatusCode(err) {
|
|
594
|
+
if (!err || typeof err !== "object")
|
|
595
|
+
return undefined;
|
|
596
|
+
const candidate = err.status ??
|
|
597
|
+
err.statusCode;
|
|
598
|
+
if (typeof candidate === "number")
|
|
599
|
+
return candidate;
|
|
600
|
+
if (typeof candidate === "string" && /^\d+$/.test(candidate))
|
|
601
|
+
return Number(candidate);
|
|
602
|
+
return undefined;
|
|
603
|
+
}
|
|
604
|
+
function getStatusCode(err) {
|
|
605
|
+
return findErrorProperty(err, readDirectStatusCode);
|
|
606
|
+
}
|
|
607
|
+
function readDirectErrorCode(err) {
|
|
608
|
+
if (!err || typeof err !== "object")
|
|
609
|
+
return undefined;
|
|
610
|
+
const directCode = err.code;
|
|
611
|
+
if (typeof directCode === "string") {
|
|
612
|
+
const trimmed = directCode.trim();
|
|
613
|
+
return trimmed || undefined;
|
|
614
|
+
}
|
|
615
|
+
const status = err.status;
|
|
616
|
+
if (typeof status !== "string" || /^\d+$/.test(status))
|
|
617
|
+
return undefined;
|
|
618
|
+
const trimmed = status.trim();
|
|
619
|
+
return trimmed || undefined;
|
|
620
|
+
}
|
|
621
|
+
function getErrorCode(err) {
|
|
622
|
+
return findErrorProperty(err, readDirectErrorCode);
|
|
623
|
+
}
|
|
624
|
+
function readDirectErrorMessage(err) {
|
|
625
|
+
if (err instanceof Error)
|
|
626
|
+
return err.message || undefined;
|
|
627
|
+
if (typeof err === "string")
|
|
628
|
+
return err || undefined;
|
|
629
|
+
if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint")
|
|
630
|
+
return String(err);
|
|
631
|
+
if (typeof err === "symbol")
|
|
632
|
+
return err.description ?? undefined;
|
|
633
|
+
if (err && typeof err === "object") {
|
|
634
|
+
const message = err.message;
|
|
635
|
+
if (typeof message === "string")
|
|
636
|
+
return message || undefined;
|
|
637
|
+
}
|
|
638
|
+
return undefined;
|
|
639
|
+
}
|
|
640
|
+
function getErrorMessage(err) {
|
|
641
|
+
return findErrorProperty(err, readDirectErrorMessage) ?? "";
|
|
642
|
+
}
|
|
643
|
+
function getErrorCause(err) {
|
|
644
|
+
if (!err || typeof err !== "object" || !("cause" in err))
|
|
645
|
+
return undefined;
|
|
646
|
+
return err.cause;
|
|
647
|
+
}
|
|
648
|
+
function hasTimeoutHint(err) {
|
|
649
|
+
if (!err)
|
|
650
|
+
return false;
|
|
651
|
+
if (readErrorName(err) === "TimeoutError")
|
|
652
|
+
return true;
|
|
653
|
+
const message = getErrorMessage(err);
|
|
654
|
+
return Boolean(message && isTimeoutErrorMessage(message));
|
|
655
|
+
}
|
|
656
|
+
export function isTimeoutError(err) {
|
|
657
|
+
if (hasTimeoutHint(err))
|
|
658
|
+
return true;
|
|
659
|
+
if (!err || typeof err !== "object")
|
|
660
|
+
return false;
|
|
661
|
+
if (readErrorName(err) !== "AbortError")
|
|
662
|
+
return false;
|
|
663
|
+
const message = getErrorMessage(err);
|
|
664
|
+
if (message && ABORT_TIMEOUT_RE.test(message))
|
|
665
|
+
return true;
|
|
666
|
+
const cause = "cause" in err ? err.cause : undefined;
|
|
667
|
+
const reason = "reason" in err ? err.reason : undefined;
|
|
668
|
+
return hasTimeoutHint(cause) || hasTimeoutHint(reason);
|
|
669
|
+
}
|
|
670
|
+
// --- Public resolution API ---
|
|
671
|
+
function resolveFailoverClassificationFromError(err) {
|
|
672
|
+
if (isFailoverError(err))
|
|
673
|
+
return { kind: "reason", reason: err.reason };
|
|
674
|
+
const classification = classifyFailoverSignal(normalizeErrorSignal(err));
|
|
675
|
+
if (!classification || classification.kind === "context_overflow") {
|
|
676
|
+
const cause = getErrorCause(err);
|
|
677
|
+
if (cause && cause !== err) {
|
|
678
|
+
const causeClassification = resolveFailoverClassificationFromError(cause);
|
|
679
|
+
if (causeClassification)
|
|
680
|
+
return causeClassification;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (classification)
|
|
684
|
+
return classification;
|
|
685
|
+
if (isTimeoutError(err))
|
|
686
|
+
return { kind: "reason", reason: "timeout" };
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
function normalizeErrorSignal(err) {
|
|
690
|
+
return {
|
|
691
|
+
status: getStatusCode(err),
|
|
692
|
+
code: getErrorCode(err),
|
|
693
|
+
message: getErrorMessage(err) || undefined,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
export function resolveFailoverReasonFromError(err) {
|
|
697
|
+
const c = resolveFailoverClassificationFromError(err);
|
|
698
|
+
return c?.kind === "reason" ? c.reason : null;
|
|
699
|
+
}
|
|
700
|
+
export function describeFailoverError(err) {
|
|
701
|
+
if (isFailoverError(err)) {
|
|
702
|
+
return { message: err.message, reason: err.reason, status: err.status, code: err.code };
|
|
703
|
+
}
|
|
704
|
+
const signal = normalizeErrorSignal(err);
|
|
705
|
+
const message = signal.message ?? String(err);
|
|
706
|
+
return {
|
|
707
|
+
message,
|
|
708
|
+
reason: resolveFailoverReasonFromError(err) ?? undefined,
|
|
709
|
+
status: signal.status,
|
|
710
|
+
code: signal.code,
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
export function coerceToFailoverError(err, context) {
|
|
714
|
+
if (isFailoverError(err))
|
|
715
|
+
return err;
|
|
716
|
+
const reason = resolveFailoverReasonFromError(err);
|
|
717
|
+
if (!reason)
|
|
718
|
+
return null;
|
|
719
|
+
const signal = normalizeErrorSignal(err);
|
|
720
|
+
const message = signal.message ?? String(err);
|
|
721
|
+
const status = signal.status ?? resolveFailoverStatus(reason);
|
|
722
|
+
const code = signal.code;
|
|
723
|
+
return new FailoverError(message, {
|
|
724
|
+
reason,
|
|
725
|
+
provider: context?.provider,
|
|
726
|
+
model: context?.model,
|
|
727
|
+
profileId: context?.profileId,
|
|
728
|
+
status,
|
|
729
|
+
code,
|
|
730
|
+
cause: err instanceof Error ? err : undefined,
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
//# sourceMappingURL=failover-error.js.map
|