qlogicagent 0.2.1 → 0.3.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.
Files changed (229) hide show
  1. package/dist/agent.js +1 -0
  2. package/dist/cli.js +9 -0
  3. package/dist/contracts.js +1 -0
  4. package/dist/index.js +5 -15
  5. package/dist/orchestration.js +118 -0
  6. package/package.json +56 -42
  7. package/dist/agent/agent.js +0 -113
  8. package/dist/agent/tool-loop.js +0 -575
  9. package/dist/agent/types.js +0 -14
  10. package/dist/cli/main.js +0 -23
  11. package/dist/cli/stdio-server.js +0 -463
  12. package/dist/config/config.js +0 -21
  13. package/dist/contracts/hooks.js +0 -7
  14. package/dist/contracts/index.js +0 -10
  15. package/dist/contracts/planner.js +0 -2
  16. package/dist/contracts/skill-candidate.js +0 -195
  17. package/dist/contracts/todo.js +0 -9
  18. package/dist/llm/builtin-providers.js +0 -531
  19. package/dist/llm/index.js +0 -14
  20. package/dist/llm/llm-client.js +0 -67
  21. package/dist/llm/model-catalog.js +0 -191
  22. package/dist/llm/provider-def.js +0 -12
  23. package/dist/llm/provider-registry.js +0 -147
  24. package/dist/llm/transport.js +0 -27
  25. package/dist/llm/transports/anthropic-messages.js +0 -293
  26. package/dist/llm/transports/openai-chat.js +0 -165
  27. package/dist/orchestration/agent-registry.js +0 -116
  28. package/dist/orchestration/approval-aware-tool-plan.js +0 -87
  29. package/dist/orchestration/context-compression.js +0 -583
  30. package/dist/orchestration/conversation-repair.js +0 -429
  31. package/dist/orchestration/curator-scheduler.js +0 -135
  32. package/dist/orchestration/embedded-failover-policy.js +0 -168
  33. package/dist/orchestration/error-classification.js +0 -77
  34. package/dist/orchestration/failover-classification.js +0 -381
  35. package/dist/orchestration/failover-error.js +0 -198
  36. package/dist/orchestration/fork-subagent.js +0 -98
  37. package/dist/orchestration/index.js +0 -267
  38. package/dist/orchestration/memory-flush-policy.js +0 -85
  39. package/dist/orchestration/memory-provider.js +0 -2
  40. package/dist/orchestration/parallel-tool-calls.js +0 -59
  41. package/dist/orchestration/prompt-cache-strategy.js +0 -228
  42. package/dist/orchestration/reactive-compact.js +0 -78
  43. package/dist/orchestration/retry-loop.js +0 -24
  44. package/dist/orchestration/skill-candidate.js +0 -141
  45. package/dist/orchestration/skill-consolidation.js +0 -220
  46. package/dist/orchestration/skill-improvement.js +0 -66
  47. package/dist/orchestration/skill-similarity.js +0 -131
  48. package/dist/orchestration/streaming-tool-executor.js +0 -96
  49. package/dist/orchestration/team-orchestration.js +0 -369
  50. package/dist/orchestration/team-tool-loop-wiring.js +0 -147
  51. package/dist/orchestration/tool-choice-policy.js +0 -164
  52. package/dist/orchestration/tool-loop-state.js +0 -133
  53. package/dist/orchestration/tool-schema.js +0 -297
  54. package/dist/orchestration/transcript-repair.js +0 -426
  55. package/dist/orchestration/turn-loop-guard.js +0 -92
  56. package/dist/orchestration/web-browser-policy.js +0 -39
  57. package/dist/runtime/context-compression.js +0 -274
  58. package/dist/runtime/hook-registry.js +0 -53
  59. package/dist/runtime/memory-hooks.js +0 -65
  60. package/dist/runtime/tool-eligibility.js +0 -111
  61. package/dist/skills/index.js +0 -82
  62. package/dist/skills/memory-extractor.js +0 -173
  63. package/dist/skills/memory-query-tool.js +0 -127
  64. package/dist/skills/memory-store.js +0 -228
  65. package/dist/skills/memory-tool.js +0 -192
  66. package/dist/skills/portable-tool.js +0 -14
  67. package/dist/skills/qmemory-adapter.js +0 -165
  68. package/dist/skills/skill-frontmatter.js +0 -344
  69. package/dist/skills/skill-guard.js +0 -229
  70. package/dist/skills/skill-loader.js +0 -303
  71. package/dist/skills/skill-source.js +0 -126
  72. package/dist/skills/skill-types.js +0 -6
  73. package/dist/skills/think-tool.js +0 -59
  74. package/dist/skills/todo-tool.js +0 -114
  75. package/dist/skills/tools/agent-tool.js +0 -142
  76. package/dist/skills/tools/apply-patch-tool.js +0 -184
  77. package/dist/skills/tools/ask-user-tool.js +0 -121
  78. package/dist/skills/tools/brief-tool.js +0 -95
  79. package/dist/skills/tools/browser-tool.js +0 -155
  80. package/dist/skills/tools/checkpoint-tool.js +0 -102
  81. package/dist/skills/tools/config-tool.js +0 -143
  82. package/dist/skills/tools/cron-tool.js +0 -175
  83. package/dist/skills/tools/edit-tool.js +0 -70
  84. package/dist/skills/tools/exec-tool.js +0 -133
  85. package/dist/skills/tools/image-generate-tool.js +0 -67
  86. package/dist/skills/tools/instructions-tool.js +0 -187
  87. package/dist/skills/tools/lsp-tool.js +0 -227
  88. package/dist/skills/tools/mcp-client-types.js +0 -53
  89. package/dist/skills/tools/mcp-tool.js +0 -503
  90. package/dist/skills/tools/memory-tool.js +0 -88
  91. package/dist/skills/tools/monitor-tool.js +0 -131
  92. package/dist/skills/tools/music-generate-tool.js +0 -62
  93. package/dist/skills/tools/notify-tool.js +0 -62
  94. package/dist/skills/tools/patch-tool.js +0 -505
  95. package/dist/skills/tools/pdf-tool.js +0 -88
  96. package/dist/skills/tools/plan-mode-tool.js +0 -122
  97. package/dist/skills/tools/read-tool.js +0 -84
  98. package/dist/skills/tools/repl-tool.js +0 -69
  99. package/dist/skills/tools/search-tool.js +0 -225
  100. package/dist/skills/tools/send-message-tool.js +0 -76
  101. package/dist/skills/tools/skill-list-tool.js +0 -54
  102. package/dist/skills/tools/skill-manage-tool.js +0 -153
  103. package/dist/skills/tools/skill-view-tool.js +0 -72
  104. package/dist/skills/tools/sleep-tool.js +0 -81
  105. package/dist/skills/tools/structured-output-tool.js +0 -176
  106. package/dist/skills/tools/task-tool.js +0 -161
  107. package/dist/skills/tools/team-tool.js +0 -105
  108. package/dist/skills/tools/tool-search-tool.js +0 -110
  109. package/dist/skills/tools/tts-tool.js +0 -45
  110. package/dist/skills/tools/video-edit-tool.js +0 -74
  111. package/dist/skills/tools/video-generate-tool.js +0 -66
  112. package/dist/skills/tools/video-merge-tool.js +0 -92
  113. package/dist/skills/tools/video-upscale-tool.js +0 -52
  114. package/dist/skills/tools/web-fetch-tool.js +0 -92
  115. package/dist/skills/tools/web-search-tool.js +0 -86
  116. package/dist/skills/tools/worktree-tool.js +0 -147
  117. package/dist/skills/tools/write-tool.js +0 -81
  118. /package/dist/{agent → types/agent}/agent.d.ts +0 -0
  119. /package/dist/{agent → types/agent}/tool-loop.d.ts +0 -0
  120. /package/dist/{agent → types/agent}/types.d.ts +0 -0
  121. /package/dist/{cli → types/cli}/main.d.ts +0 -0
  122. /package/dist/{cli → types/cli}/stdio-server.d.ts +0 -0
  123. /package/dist/{config → types/config}/config.d.ts +0 -0
  124. /package/dist/{contracts → types/contracts}/hooks.d.ts +0 -0
  125. /package/dist/{contracts → types/contracts}/index.d.ts +0 -0
  126. /package/dist/{contracts → types/contracts}/planner.d.ts +0 -0
  127. /package/dist/{contracts → types/contracts}/skill-candidate.d.ts +0 -0
  128. /package/dist/{contracts → types/contracts}/todo.d.ts +0 -0
  129. /package/dist/{index.d.ts → types/index.d.ts} +0 -0
  130. /package/dist/{llm → types/llm}/builtin-providers.d.ts +0 -0
  131. /package/dist/{llm → types/llm}/index.d.ts +0 -0
  132. /package/dist/{llm → types/llm}/llm-client.d.ts +0 -0
  133. /package/dist/{llm → types/llm}/model-catalog.d.ts +0 -0
  134. /package/dist/{llm → types/llm}/provider-def.d.ts +0 -0
  135. /package/dist/{llm → types/llm}/provider-registry.d.ts +0 -0
  136. /package/dist/{llm → types/llm}/transport.d.ts +0 -0
  137. /package/dist/{llm → types/llm}/transports/anthropic-messages.d.ts +0 -0
  138. /package/dist/{llm → types/llm}/transports/openai-chat.d.ts +0 -0
  139. /package/dist/{orchestration → types/orchestration}/agent-registry.d.ts +0 -0
  140. /package/dist/{orchestration → types/orchestration}/approval-aware-tool-plan.d.ts +0 -0
  141. /package/dist/{orchestration → types/orchestration}/context-compression.d.ts +0 -0
  142. /package/dist/{orchestration → types/orchestration}/conversation-repair.d.ts +0 -0
  143. /package/dist/{orchestration → types/orchestration}/curator-scheduler.d.ts +0 -0
  144. /package/dist/{orchestration → types/orchestration}/embedded-failover-policy.d.ts +0 -0
  145. /package/dist/{orchestration → types/orchestration}/error-classification.d.ts +0 -0
  146. /package/dist/{orchestration → types/orchestration}/failover-classification.d.ts +0 -0
  147. /package/dist/{orchestration → types/orchestration}/failover-error.d.ts +0 -0
  148. /package/dist/{orchestration → types/orchestration}/fork-subagent.d.ts +0 -0
  149. /package/dist/{orchestration → types/orchestration}/index.d.ts +0 -0
  150. /package/dist/{orchestration → types/orchestration}/memory-flush-policy.d.ts +0 -0
  151. /package/dist/{orchestration → types/orchestration}/memory-provider.d.ts +0 -0
  152. /package/dist/{orchestration → types/orchestration}/parallel-tool-calls.d.ts +0 -0
  153. /package/dist/{orchestration → types/orchestration}/prompt-cache-strategy.d.ts +0 -0
  154. /package/dist/{orchestration → types/orchestration}/reactive-compact.d.ts +0 -0
  155. /package/dist/{orchestration → types/orchestration}/retry-loop.d.ts +0 -0
  156. /package/dist/{orchestration → types/orchestration}/skill-candidate.d.ts +0 -0
  157. /package/dist/{orchestration → types/orchestration}/skill-consolidation.d.ts +0 -0
  158. /package/dist/{orchestration → types/orchestration}/skill-improvement.d.ts +0 -0
  159. /package/dist/{orchestration → types/orchestration}/skill-similarity.d.ts +0 -0
  160. /package/dist/{orchestration → types/orchestration}/streaming-tool-executor.d.ts +0 -0
  161. /package/dist/{orchestration → types/orchestration}/team-orchestration.d.ts +0 -0
  162. /package/dist/{orchestration → types/orchestration}/team-tool-loop-wiring.d.ts +0 -0
  163. /package/dist/{orchestration → types/orchestration}/tool-choice-policy.d.ts +0 -0
  164. /package/dist/{orchestration → types/orchestration}/tool-loop-state.d.ts +0 -0
  165. /package/dist/{orchestration → types/orchestration}/tool-schema.d.ts +0 -0
  166. /package/dist/{orchestration → types/orchestration}/transcript-repair.d.ts +0 -0
  167. /package/dist/{orchestration → types/orchestration}/turn-loop-guard.d.ts +0 -0
  168. /package/dist/{orchestration → types/orchestration}/web-browser-policy.d.ts +0 -0
  169. /package/dist/{runtime → types/runtime}/context-compression.d.ts +0 -0
  170. /package/dist/{runtime → types/runtime}/hook-registry.d.ts +0 -0
  171. /package/dist/{runtime → types/runtime}/memory-hooks.d.ts +0 -0
  172. /package/dist/{runtime → types/runtime}/tool-eligibility.d.ts +0 -0
  173. /package/dist/{skills → types/skills}/index.d.ts +0 -0
  174. /package/dist/{skills → types/skills}/memory-extractor.d.ts +0 -0
  175. /package/dist/{skills → types/skills}/memory-query-tool.d.ts +0 -0
  176. /package/dist/{skills → types/skills}/memory-store.d.ts +0 -0
  177. /package/dist/{skills → types/skills}/memory-tool.d.ts +0 -0
  178. /package/dist/{skills → types/skills}/portable-tool.d.ts +0 -0
  179. /package/dist/{skills → types/skills}/qmemory-adapter.d.ts +0 -0
  180. /package/dist/{skills → types/skills}/skill-frontmatter.d.ts +0 -0
  181. /package/dist/{skills → types/skills}/skill-guard.d.ts +0 -0
  182. /package/dist/{skills → types/skills}/skill-loader.d.ts +0 -0
  183. /package/dist/{skills → types/skills}/skill-source.d.ts +0 -0
  184. /package/dist/{skills → types/skills}/skill-types.d.ts +0 -0
  185. /package/dist/{skills → types/skills}/think-tool.d.ts +0 -0
  186. /package/dist/{skills → types/skills}/todo-tool.d.ts +0 -0
  187. /package/dist/{skills → types/skills}/tools/agent-tool.d.ts +0 -0
  188. /package/dist/{skills → types/skills}/tools/apply-patch-tool.d.ts +0 -0
  189. /package/dist/{skills → types/skills}/tools/ask-user-tool.d.ts +0 -0
  190. /package/dist/{skills → types/skills}/tools/brief-tool.d.ts +0 -0
  191. /package/dist/{skills → types/skills}/tools/browser-tool.d.ts +0 -0
  192. /package/dist/{skills → types/skills}/tools/checkpoint-tool.d.ts +0 -0
  193. /package/dist/{skills → types/skills}/tools/config-tool.d.ts +0 -0
  194. /package/dist/{skills → types/skills}/tools/cron-tool.d.ts +0 -0
  195. /package/dist/{skills → types/skills}/tools/edit-tool.d.ts +0 -0
  196. /package/dist/{skills → types/skills}/tools/exec-tool.d.ts +0 -0
  197. /package/dist/{skills → types/skills}/tools/image-generate-tool.d.ts +0 -0
  198. /package/dist/{skills → types/skills}/tools/instructions-tool.d.ts +0 -0
  199. /package/dist/{skills → types/skills}/tools/lsp-tool.d.ts +0 -0
  200. /package/dist/{skills → types/skills}/tools/mcp-client-types.d.ts +0 -0
  201. /package/dist/{skills → types/skills}/tools/mcp-tool.d.ts +0 -0
  202. /package/dist/{skills → types/skills}/tools/memory-tool.d.ts +0 -0
  203. /package/dist/{skills → types/skills}/tools/monitor-tool.d.ts +0 -0
  204. /package/dist/{skills → types/skills}/tools/music-generate-tool.d.ts +0 -0
  205. /package/dist/{skills → types/skills}/tools/notify-tool.d.ts +0 -0
  206. /package/dist/{skills → types/skills}/tools/patch-tool.d.ts +0 -0
  207. /package/dist/{skills → types/skills}/tools/pdf-tool.d.ts +0 -0
  208. /package/dist/{skills → types/skills}/tools/plan-mode-tool.d.ts +0 -0
  209. /package/dist/{skills → types/skills}/tools/read-tool.d.ts +0 -0
  210. /package/dist/{skills → types/skills}/tools/repl-tool.d.ts +0 -0
  211. /package/dist/{skills → types/skills}/tools/search-tool.d.ts +0 -0
  212. /package/dist/{skills → types/skills}/tools/send-message-tool.d.ts +0 -0
  213. /package/dist/{skills → types/skills}/tools/skill-list-tool.d.ts +0 -0
  214. /package/dist/{skills → types/skills}/tools/skill-manage-tool.d.ts +0 -0
  215. /package/dist/{skills → types/skills}/tools/skill-view-tool.d.ts +0 -0
  216. /package/dist/{skills → types/skills}/tools/sleep-tool.d.ts +0 -0
  217. /package/dist/{skills → types/skills}/tools/structured-output-tool.d.ts +0 -0
  218. /package/dist/{skills → types/skills}/tools/task-tool.d.ts +0 -0
  219. /package/dist/{skills → types/skills}/tools/team-tool.d.ts +0 -0
  220. /package/dist/{skills → types/skills}/tools/tool-search-tool.d.ts +0 -0
  221. /package/dist/{skills → types/skills}/tools/tts-tool.d.ts +0 -0
  222. /package/dist/{skills → types/skills}/tools/video-edit-tool.d.ts +0 -0
  223. /package/dist/{skills → types/skills}/tools/video-generate-tool.d.ts +0 -0
  224. /package/dist/{skills → types/skills}/tools/video-merge-tool.d.ts +0 -0
  225. /package/dist/{skills → types/skills}/tools/video-upscale-tool.d.ts +0 -0
  226. /package/dist/{skills → types/skills}/tools/web-fetch-tool.d.ts +0 -0
  227. /package/dist/{skills → types/skills}/tools/web-search-tool.d.ts +0 -0
  228. /package/dist/{skills → types/skills}/tools/worktree-tool.d.ts +0 -0
  229. /package/dist/{skills → types/skills}/tools/write-tool.d.ts +0 -0
@@ -1,168 +0,0 @@
1
- export function resolveRetryableFailureReason(params) {
2
- if (!params.reason) {
3
- return null;
4
- }
5
- if ((params.nonRetryableReasons ?? []).includes(params.reason)) {
6
- return null;
7
- }
8
- return params.reason;
9
- }
10
- export function resolveAuthProfileFailoverReason(params) {
11
- if (params.allInCooldown) {
12
- return params.unavailableReason ?? params.cooldownFallbackReason;
13
- }
14
- return params.classifiedReason ?? params.defaultReason;
15
- }
16
- export function resolveFallbackThinkingDecision(params) {
17
- if (params.aborted || !params.fallbackThinking) {
18
- return undefined;
19
- }
20
- return {
21
- thinkLevel: params.fallbackThinking,
22
- warningMessage: `unsupported thinking level for ${params.provider}/${params.modelId}; ` +
23
- `retrying with ${params.fallbackThinking}`,
24
- };
25
- }
26
- function extractSupportedThinkingValues(raw) {
27
- const match = raw.match(/supported values are:\s*([^\n.]+)/i) ??
28
- raw.match(/supported values:\s*([^\n.]+)/i);
29
- if (!match?.[1]) {
30
- return [];
31
- }
32
- const fragment = match[1];
33
- const quoted = Array.from(fragment.matchAll(/['"]([^'"]+)['"]/g)).map((entry) => entry[1]?.trim());
34
- if (quoted.length > 0) {
35
- return quoted.filter((entry) => Boolean(entry));
36
- }
37
- return fragment
38
- .split(/,|\band\b/gi)
39
- .map((entry) => entry.replace(/^[^a-zA-Z]+|[^a-zA-Z]+$/g, "").trim())
40
- .filter(Boolean);
41
- }
42
- export function pickFallbackThinkingLevel(params) {
43
- const raw = params.message?.trim();
44
- if (!raw) {
45
- return undefined;
46
- }
47
- const supported = extractSupportedThinkingValues(raw);
48
- if (supported.length === 0) {
49
- if (/not supported/i.test(raw) &&
50
- params.offLevel &&
51
- !params.attempted.has(params.offLevel)) {
52
- return params.offLevel;
53
- }
54
- return undefined;
55
- }
56
- for (const entry of supported) {
57
- const normalized = params.normalizeThinkLevel(entry);
58
- if (!normalized || params.attempted.has(normalized)) {
59
- continue;
60
- }
61
- return normalized;
62
- }
63
- return undefined;
64
- }
65
- export function shouldAttemptPromptFailureRotation(params) {
66
- if (!params.promptFailoverFailure) {
67
- return false;
68
- }
69
- return !(params.nonRotatableReasons ?? []).includes(params.promptFailoverReason);
70
- }
71
- export function shouldAttemptAssistantFailureRotation(params) {
72
- return params.failoverFailure || (params.timedOut && !params.timedOutDuringCompaction);
73
- }
74
- export function resolvePromptFailureActionDecision(params) {
75
- if (params.canRotate) {
76
- return { kind: "retry-rotated" };
77
- }
78
- if (params.fallbackThinking) {
79
- return {
80
- kind: "retry-thinking",
81
- thinkLevel: params.fallbackThinking,
82
- };
83
- }
84
- if (params.fallbackConfigured && params.promptFailoverFailure) {
85
- return {
86
- kind: "throw-failover",
87
- reason: params.promptFailoverReason,
88
- };
89
- }
90
- return { kind: "unhandled" };
91
- }
92
- export function resolveAssistantFailureActionDecision(params) {
93
- const shouldRotate = shouldAttemptAssistantFailureRotation({
94
- timedOut: params.timedOut,
95
- timedOutDuringCompaction: params.timedOutDuringCompaction,
96
- failoverFailure: params.failoverFailure,
97
- });
98
- if (!shouldRotate) {
99
- return { kind: "unhandled" };
100
- }
101
- if (params.canRotate) {
102
- return { kind: "retry-rotated" };
103
- }
104
- if (params.shouldThrowFailover) {
105
- return {
106
- kind: "throw-failover",
107
- reason: params.failoverReason,
108
- };
109
- }
110
- return { kind: "unhandled" };
111
- }
112
- export function resolvePromptErrorPolicy(params) {
113
- if (!params.hasPromptError || params.aborted) {
114
- return { kind: "noop" };
115
- }
116
- if (params.roleAlternationError) {
117
- return {
118
- kind: "return-error",
119
- errorKind: "role_ordering",
120
- text: "Message ordering conflict - please try again. " +
121
- "If this persists, use /new to start a fresh session.",
122
- message: params.errorText,
123
- };
124
- }
125
- if (typeof params.imageSizeMaxMb === "number" && Number.isFinite(params.imageSizeMaxMb)) {
126
- const maxBytesHint = ` (max ${params.imageSizeMaxMb}MB)`;
127
- return {
128
- kind: "return-error",
129
- errorKind: "image_size",
130
- text: `Image too large for the model${maxBytesHint}. ` +
131
- "Please compress or resize the image and try again.",
132
- message: params.errorText,
133
- };
134
- }
135
- if (params.promptFailureAction.kind === "retry-rotated") {
136
- return { kind: "retry-rotated" };
137
- }
138
- if (params.promptFailureAction.kind === "retry-thinking") {
139
- return {
140
- kind: "retry-thinking",
141
- thinkLevel: params.promptFailureAction.thinkLevel,
142
- };
143
- }
144
- if (params.promptFailureAction.kind === "throw-failover") {
145
- return {
146
- kind: "throw-failover",
147
- reason: params.promptFailureAction.reason,
148
- };
149
- }
150
- return { kind: "throw-original" };
151
- }
152
- export function buildAssistantFailoverErrorDetails(params) {
153
- const message = params.formattedAssistantErrorText ||
154
- params.assistantErrorMessage?.trim() ||
155
- (params.timedOut
156
- ? "LLM request timed out."
157
- : params.rateLimitFailure
158
- ? "LLM request rate limited."
159
- : params.billingFailureMessage
160
- ? params.billingFailureMessage
161
- : params.authFailure
162
- ? "LLM request unauthorized."
163
- : "LLM request failed.");
164
- return {
165
- message,
166
- status: params.failoverStatus ?? (params.timeoutDetectedFromMessage ? (params.timeoutStatus ?? 408) : undefined),
167
- };
168
- }
@@ -1,77 +0,0 @@
1
- // ============================================================
2
- // Error classification — maps FailoverReason to high-level
3
- // retry categories for consumers that need a simple decision.
4
- // ============================================================
5
- import { classifyFailoverReason, classifyFailoverReasonFromHttpStatus, } from "./failover-classification.js";
6
- const FAILOVER_TO_CATEGORY = {
7
- timeout: "RETRYABLE_TRANSIENT",
8
- overloaded: "RETRYABLE_TRANSIENT",
9
- rate_limit: "RETRYABLE_DEGRADED",
10
- auth: "NON_RETRYABLE_AUTH",
11
- auth_permanent: "NON_RETRYABLE_AUTH",
12
- billing: "NON_RETRYABLE_QUOTA",
13
- format: "NON_RETRYABLE_CONTENT",
14
- model_not_found: "NON_RETRYABLE_CONTENT",
15
- session_expired: "NON_RETRYABLE_CONTENT",
16
- unknown: "RETRYABLE_TRANSIENT",
17
- };
18
- const RETRY_STRATEGIES = {
19
- RETRYABLE_TRANSIENT: {
20
- retryable: true,
21
- maxRetries: 3,
22
- baseDelayMs: 1000,
23
- backoffMultiplier: 2,
24
- switchProvider: true,
25
- },
26
- RETRYABLE_DEGRADED: {
27
- retryable: true,
28
- maxRetries: 2,
29
- baseDelayMs: 5000,
30
- backoffMultiplier: 3,
31
- switchProvider: true,
32
- },
33
- NON_RETRYABLE_AUTH: {
34
- retryable: false,
35
- maxRetries: 0,
36
- baseDelayMs: 0,
37
- backoffMultiplier: 1,
38
- switchProvider: true,
39
- },
40
- NON_RETRYABLE_CONTENT: {
41
- retryable: false,
42
- maxRetries: 0,
43
- baseDelayMs: 0,
44
- backoffMultiplier: 1,
45
- switchProvider: false,
46
- },
47
- NON_RETRYABLE_QUOTA: {
48
- retryable: false,
49
- maxRetries: 0,
50
- baseDelayMs: 0,
51
- backoffMultiplier: 1,
52
- switchProvider: true,
53
- },
54
- TOOL_EXECUTION_FAILED: {
55
- retryable: true,
56
- maxRetries: 1,
57
- baseDelayMs: 500,
58
- backoffMultiplier: 1,
59
- switchProvider: false,
60
- },
61
- };
62
- export function classifyError(status, message) {
63
- const reason = classifyFailoverReasonFromHttpStatus(status, message) ??
64
- (message ? classifyFailoverReason(message) : null);
65
- if (!reason) {
66
- return typeof status === "number" && status >= 400 && status < 500
67
- ? "NON_RETRYABLE_CONTENT"
68
- : "RETRYABLE_TRANSIENT";
69
- }
70
- return FAILOVER_TO_CATEGORY[reason];
71
- }
72
- export function classifyErrorFromReason(reason) {
73
- return FAILOVER_TO_CATEGORY[reason];
74
- }
75
- export function getRetryStrategy(category) {
76
- return RETRY_STRATEGIES[category];
77
- }
@@ -1,381 +0,0 @@
1
- const PERIODIC_USAGE_LIMIT_RE = /\b(?:daily|weekly|monthly)(?:\/(?:daily|weekly|monthly))* (?:usage )?limit(?:s)?(?: (?:exhausted|reached|exceeded))?\b/i;
2
- const ERROR_PATTERNS = {
3
- rateLimit: [
4
- /rate[_ ]limit|too many requests|429/,
5
- "model_cooldown",
6
- "exceeded your current quota",
7
- "resource has been exhausted",
8
- "quota exceeded",
9
- "resource_exhausted",
10
- "usage limit",
11
- /\btpm\b/i,
12
- "tokens per minute",
13
- "tokens per day",
14
- ],
15
- overloaded: [
16
- /overloaded_error|"type"\s*:\s*"overloaded_error"/i,
17
- "overloaded",
18
- /service[_ ]unavailable.*(?:overload|capacity|high[_ ]demand)|(?:overload|capacity|high[_ ]demand).*service[_ ]unavailable/i,
19
- "high demand",
20
- ],
21
- timeout: [
22
- "timeout",
23
- "timed out",
24
- "service unavailable",
25
- "deadline exceeded",
26
- "context deadline exceeded",
27
- "connection error",
28
- "network error",
29
- "network request failed",
30
- "fetch failed",
31
- "socket hang up",
32
- /\beconn(?:refused|reset|aborted)\b/i,
33
- /\benotfound\b/i,
34
- /\beai_again\b/i,
35
- /without sending (?:any )?chunks?/i,
36
- /\bstop reason:\s*(?:abort|error|network_error)\b/i,
37
- /\breason:\s*(?:abort|error|network_error)\b/i,
38
- /\bunhandled stop reason:\s*(?:abort|error|network_error)\b/i,
39
- ],
40
- billing: [
41
- /["']?(?: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,
42
- "payment required",
43
- "insufficient credits",
44
- /insufficient[_ ]quota/i,
45
- "credit balance",
46
- "plans & billing",
47
- "insufficient balance",
48
- ],
49
- authPermanent: [
50
- /api[_ ]?key[_ ]?(?:revoked|invalid|deactivated|deleted)/i,
51
- "invalid_api_key",
52
- "key has been disabled",
53
- "key has been revoked",
54
- "account has been deactivated",
55
- /could not (?:authenticate|validate).*(?:api[_ ]?key|credentials)/i,
56
- "permission_error",
57
- "not allowed for this organization",
58
- ],
59
- auth: [
60
- /invalid[_ ]?api[_ ]?key/,
61
- "incorrect api key",
62
- "invalid token",
63
- "authentication",
64
- "re-authenticate",
65
- "oauth token refresh failed",
66
- "unauthorized",
67
- "forbidden",
68
- "access denied",
69
- "insufficient permissions",
70
- "insufficient permission",
71
- /missing scopes?:/i,
72
- "expired",
73
- "token has expired",
74
- /\b401\b/,
75
- /\b403\b/,
76
- "no credentials found",
77
- "no api key found",
78
- ],
79
- format: [
80
- "string should match pattern",
81
- "tool_use.id",
82
- "tool_use_id",
83
- "messages.1.content.1.tool_use.id",
84
- "invalid request format",
85
- /tool call id was.*must be/i,
86
- ],
87
- };
88
- const BILLING_ERROR_HEAD_RE = /^(?:error[:\s-]+)?billing(?:\s+error)?(?:[:\s-]+|$)|^(?:error[:\s-]+)?(?:credit balance|insufficient credits?|payment required|http\s*402\b)/i;
89
- const BILLING_ERROR_HARD_402_RE = /["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|^\s*402\s+payment/i;
90
- const BILLING_ERROR_MAX_LENGTH = 512;
91
- const HTTP_STATUS_CODE_PREFIX_RE = /^(?:http\s*)?(\d{3})(?:\s+([\s\S]+))?$/i;
92
- const HTML_ERROR_PREFIX_RE = /^\s*(?:<!doctype\s+html\b|<html\b)/i;
93
- const CLOUDFLARE_HTML_ERROR_CODES = new Set([521, 522, 523, 524, 525, 526, 530]);
94
- const TRANSIENT_HTTP_ERROR_CODES = new Set([500, 502, 503, 504, 521, 522, 523, 524, 529]);
95
- const BILLING_402_HINTS = [
96
- "insufficient credits",
97
- "insufficient quota",
98
- "credit balance",
99
- "insufficient balance",
100
- "plans & billing",
101
- "add more credits",
102
- "top up",
103
- ];
104
- const BILLING_402_PLAN_HINTS = [
105
- "upgrade your plan",
106
- "upgrade plan",
107
- "current plan",
108
- "subscription",
109
- ];
110
- const PERIODIC_402_HINTS = ["daily", "weekly", "monthly"];
111
- const RETRYABLE_402_RETRY_HINTS = ["try again", "retry", "temporary", "cooldown"];
112
- const RETRYABLE_402_LIMIT_HINTS = ["usage limit", "rate limit", "organization usage"];
113
- const RETRYABLE_402_SCOPED_HINTS = ["organization", "workspace"];
114
- const RETRYABLE_402_SCOPED_RESULT_HINTS = ["billing period", "exceeded", "reached", "exhausted"];
115
- 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/i;
116
- const LEADING_402_WRAPPER_RE = /^(?:error[:\s-]+)?(?:(?:http\s*)?402(?:\s+payment required)?|payment required)(?:[:\s-]+|$)/i;
117
- function matchesErrorPatterns(raw, patterns) {
118
- if (!raw) {
119
- return false;
120
- }
121
- const value = raw.toLowerCase();
122
- return patterns.some((pattern) => pattern instanceof RegExp ? pattern.test(value) : value.includes(pattern));
123
- }
124
- function matchesFormatErrorPattern(raw) {
125
- return matchesErrorPatterns(raw, ERROR_PATTERNS.format);
126
- }
127
- function isRateLimitErrorMessage(raw) {
128
- return matchesErrorPatterns(raw, ERROR_PATTERNS.rateLimit);
129
- }
130
- export function isTimeoutErrorMessage(raw) {
131
- return matchesErrorPatterns(raw, ERROR_PATTERNS.timeout);
132
- }
133
- function isPeriodicUsageLimitErrorMessage(raw) {
134
- return PERIODIC_USAGE_LIMIT_RE.test(raw);
135
- }
136
- function isBillingErrorMessage(raw) {
137
- const value = raw.toLowerCase();
138
- if (!value) {
139
- return false;
140
- }
141
- if (raw.length > BILLING_ERROR_MAX_LENGTH) {
142
- return BILLING_ERROR_HARD_402_RE.test(value);
143
- }
144
- if (matchesErrorPatterns(value, ERROR_PATTERNS.billing)) {
145
- return true;
146
- }
147
- if (!BILLING_ERROR_HEAD_RE.test(raw)) {
148
- return false;
149
- }
150
- return (value.includes("upgrade") ||
151
- value.includes("credits") ||
152
- value.includes("payment") ||
153
- value.includes("plan"));
154
- }
155
- function isAuthPermanentErrorMessage(raw) {
156
- return matchesErrorPatterns(raw, ERROR_PATTERNS.authPermanent);
157
- }
158
- function isAuthErrorMessage(raw) {
159
- return matchesErrorPatterns(raw, ERROR_PATTERNS.auth);
160
- }
161
- function isOverloadedErrorMessage(raw) {
162
- return matchesErrorPatterns(raw, ERROR_PATTERNS.overloaded);
163
- }
164
- function includesAnyHint(text, hints) {
165
- return hints.some((hint) => text.includes(hint));
166
- }
167
- function hasExplicit402BillingSignal(text) {
168
- return (includesAnyHint(text, BILLING_402_HINTS) ||
169
- (includesAnyHint(text, BILLING_402_PLAN_HINTS) && text.includes("limit")) ||
170
- text.includes("billing hard limit") ||
171
- text.includes("hard limit reached") ||
172
- (text.includes("maximum allowed") && text.includes("limit")));
173
- }
174
- function hasRetryable402TransientSignal(text) {
175
- const hasPeriodicHint = includesAnyHint(text, PERIODIC_402_HINTS);
176
- const hasSpendLimit = text.includes("spend limit") || text.includes("spending limit");
177
- const hasScopedHint = includesAnyHint(text, RETRYABLE_402_SCOPED_HINTS);
178
- return ((includesAnyHint(text, RETRYABLE_402_RETRY_HINTS) &&
179
- includesAnyHint(text, RETRYABLE_402_LIMIT_HINTS)) ||
180
- (hasPeriodicHint && (text.includes("usage limit") || hasSpendLimit)) ||
181
- (hasPeriodicHint && text.includes("limit") && text.includes("reset")) ||
182
- (hasScopedHint &&
183
- text.includes("limit") &&
184
- (hasSpendLimit || includesAnyHint(text, RETRYABLE_402_SCOPED_RESULT_HINTS))));
185
- }
186
- function normalize402Message(raw) {
187
- return raw.trim().toLowerCase().replace(LEADING_402_WRAPPER_RE, "").trim();
188
- }
189
- function classify402Message(message) {
190
- const normalized = normalize402Message(message);
191
- if (!normalized) {
192
- return "billing";
193
- }
194
- if (hasExplicit402BillingSignal(normalized)) {
195
- return "billing";
196
- }
197
- if (isRateLimitErrorMessage(normalized)) {
198
- return "rate_limit";
199
- }
200
- if (hasRetryable402TransientSignal(normalized)) {
201
- return "rate_limit";
202
- }
203
- return "billing";
204
- }
205
- function classifyFailoverReasonFrom402Text(raw) {
206
- if (!RAW_402_MARKER_RE.test(raw)) {
207
- return null;
208
- }
209
- return classify402Message(raw);
210
- }
211
- function extractLeadingHttpStatus(raw) {
212
- const match = raw.match(HTTP_STATUS_CODE_PREFIX_RE);
213
- if (!match) {
214
- return null;
215
- }
216
- const code = Number(match[1]);
217
- if (!Number.isFinite(code)) {
218
- return null;
219
- }
220
- return { code, rest: (match[2] ?? "").trim() };
221
- }
222
- function isJsonApiInternalServerError(raw) {
223
- if (!raw) {
224
- return false;
225
- }
226
- const value = raw.toLowerCase();
227
- return value.includes('"type":"api_error"') && value.includes("internal server error");
228
- }
229
- export function isCloudflareOrHtmlErrorPage(raw) {
230
- const trimmed = raw.trim();
231
- if (!trimmed) {
232
- return false;
233
- }
234
- const status = extractLeadingHttpStatus(trimmed);
235
- if (!status || status.code < 500) {
236
- return false;
237
- }
238
- if (CLOUDFLARE_HTML_ERROR_CODES.has(status.code)) {
239
- return true;
240
- }
241
- return status.code < 600 && HTML_ERROR_PREFIX_RE.test(status.rest) && /<\/html>/i.test(status.rest);
242
- }
243
- export function isTransientHttpError(raw) {
244
- const trimmed = raw.trim();
245
- if (!trimmed) {
246
- return false;
247
- }
248
- const status = extractLeadingHttpStatus(trimmed);
249
- if (!status) {
250
- return false;
251
- }
252
- return TRANSIENT_HTTP_ERROR_CODES.has(status.code);
253
- }
254
- export function classifyFailoverReasonFromHttpStatus(status, message) {
255
- if (typeof status !== "number" || !Number.isFinite(status)) {
256
- return null;
257
- }
258
- if (status === 402) {
259
- return message ? classify402Message(message) : "billing";
260
- }
261
- if (status === 429) {
262
- return "rate_limit";
263
- }
264
- if (status === 401 || status === 403) {
265
- if (message && isAuthPermanentErrorMessage(message)) {
266
- return "auth_permanent";
267
- }
268
- return "auth";
269
- }
270
- if (status === 408) {
271
- return "timeout";
272
- }
273
- if (status === 503) {
274
- if (message && isOverloadedErrorMessage(message)) {
275
- return "overloaded";
276
- }
277
- return "timeout";
278
- }
279
- if (status === 502 || status === 504) {
280
- return "timeout";
281
- }
282
- if (status === 529) {
283
- return "overloaded";
284
- }
285
- if (status === 400) {
286
- if (message && isBillingErrorMessage(message)) {
287
- return "billing";
288
- }
289
- return "format";
290
- }
291
- return null;
292
- }
293
- export function isModelNotFoundErrorMessage(raw) {
294
- if (!raw) {
295
- return false;
296
- }
297
- const lower = raw.toLowerCase();
298
- if (lower.includes("unknown model") ||
299
- lower.includes("model not found") ||
300
- lower.includes("model_not_found") ||
301
- lower.includes("not_found_error") ||
302
- (lower.includes("does not exist") && lower.includes("model")) ||
303
- (lower.includes("invalid model") && !lower.includes("invalid model reference"))) {
304
- return true;
305
- }
306
- if (/models\/[^\s]+ is not found/i.test(raw)) {
307
- return true;
308
- }
309
- if (/\b404\b/.test(raw) && /not[-_ ]?found/i.test(raw)) {
310
- return true;
311
- }
312
- return false;
313
- }
314
- function isCliSessionExpiredErrorMessage(raw) {
315
- if (!raw) {
316
- return false;
317
- }
318
- const lower = raw.toLowerCase();
319
- return (lower.includes("session not found") ||
320
- lower.includes("session does not exist") ||
321
- lower.includes("session expired") ||
322
- lower.includes("session invalid") ||
323
- lower.includes("conversation not found") ||
324
- lower.includes("conversation does not exist") ||
325
- lower.includes("conversation expired") ||
326
- lower.includes("conversation invalid") ||
327
- lower.includes("no such session") ||
328
- lower.includes("invalid session") ||
329
- lower.includes("session id not found") ||
330
- lower.includes("conversation id not found"));
331
- }
332
- export function classifyFailoverReason(raw) {
333
- if (isCliSessionExpiredErrorMessage(raw)) {
334
- return "session_expired";
335
- }
336
- if (isModelNotFoundErrorMessage(raw)) {
337
- return "model_not_found";
338
- }
339
- const reasonFrom402Text = classifyFailoverReasonFrom402Text(raw);
340
- if (reasonFrom402Text) {
341
- return reasonFrom402Text;
342
- }
343
- if (isPeriodicUsageLimitErrorMessage(raw)) {
344
- return isBillingErrorMessage(raw) ? "billing" : "rate_limit";
345
- }
346
- if (isRateLimitErrorMessage(raw)) {
347
- return "rate_limit";
348
- }
349
- if (isOverloadedErrorMessage(raw)) {
350
- return "overloaded";
351
- }
352
- if (isTransientHttpError(raw)) {
353
- const status = extractLeadingHttpStatus(raw.trim());
354
- if (status?.code === 529) {
355
- return "overloaded";
356
- }
357
- return "timeout";
358
- }
359
- if (isJsonApiInternalServerError(raw)) {
360
- return "timeout";
361
- }
362
- if (matchesFormatErrorPattern(raw)) {
363
- return "format";
364
- }
365
- if (isBillingErrorMessage(raw)) {
366
- return "billing";
367
- }
368
- if (isTimeoutErrorMessage(raw)) {
369
- return "timeout";
370
- }
371
- if (isAuthPermanentErrorMessage(raw)) {
372
- return "auth_permanent";
373
- }
374
- if (isAuthErrorMessage(raw)) {
375
- return "auth";
376
- }
377
- return null;
378
- }
379
- export function isFailoverErrorMessage(raw) {
380
- return classifyFailoverReason(raw) !== null;
381
- }