@clinebot/llms 0.0.20 → 0.0.21

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 (319) hide show
  1. package/dist/config-browser.d.ts +1 -0
  2. package/dist/config-browser.d.ts.map +1 -0
  3. package/dist/config.d.ts +1 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/index.browser.d.ts +1 -0
  6. package/dist/index.browser.d.ts.map +1 -0
  7. package/dist/index.browser.js +5 -5
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +12 -12
  11. package/dist/models/generated-access.d.ts +1 -0
  12. package/dist/models/generated-access.d.ts.map +1 -0
  13. package/dist/models/generated-provider-loaders.d.ts +1 -0
  14. package/dist/models/generated-provider-loaders.d.ts.map +1 -0
  15. package/dist/models/generated.d.ts +1 -0
  16. package/dist/models/generated.d.ts.map +1 -0
  17. package/dist/models/index.d.ts +1 -0
  18. package/dist/models/index.d.ts.map +1 -0
  19. package/dist/models/models-dev-catalog.d.ts +1 -0
  20. package/dist/models/models-dev-catalog.d.ts.map +1 -0
  21. package/dist/models/providers/aihubmix.d.ts +1 -0
  22. package/dist/models/providers/aihubmix.d.ts.map +1 -0
  23. package/dist/models/providers/anthropic.d.ts +1 -0
  24. package/dist/models/providers/anthropic.d.ts.map +1 -0
  25. package/dist/models/providers/asksage.d.ts +1 -0
  26. package/dist/models/providers/asksage.d.ts.map +1 -0
  27. package/dist/models/providers/baseten.d.ts +1 -0
  28. package/dist/models/providers/baseten.d.ts.map +1 -0
  29. package/dist/models/providers/bedrock.d.ts +1 -0
  30. package/dist/models/providers/bedrock.d.ts.map +1 -0
  31. package/dist/models/providers/cerebras.d.ts +1 -0
  32. package/dist/models/providers/cerebras.d.ts.map +1 -0
  33. package/dist/models/providers/claude-code.d.ts +1 -0
  34. package/dist/models/providers/claude-code.d.ts.map +1 -0
  35. package/dist/models/providers/cline.d.ts +1 -0
  36. package/dist/models/providers/cline.d.ts.map +1 -0
  37. package/dist/models/providers/deepseek.d.ts +1 -0
  38. package/dist/models/providers/deepseek.d.ts.map +1 -0
  39. package/dist/models/providers/dify.d.ts +1 -0
  40. package/dist/models/providers/dify.d.ts.map +1 -0
  41. package/dist/models/providers/doubao.d.ts +1 -0
  42. package/dist/models/providers/doubao.d.ts.map +1 -0
  43. package/dist/models/providers/fireworks.d.ts +1 -0
  44. package/dist/models/providers/fireworks.d.ts.map +1 -0
  45. package/dist/models/providers/gemini.d.ts +1 -0
  46. package/dist/models/providers/gemini.d.ts.map +1 -0
  47. package/dist/models/providers/groq.d.ts +1 -0
  48. package/dist/models/providers/groq.d.ts.map +1 -0
  49. package/dist/models/providers/hicap.d.ts +1 -0
  50. package/dist/models/providers/hicap.d.ts.map +1 -0
  51. package/dist/models/providers/huawei-cloud-maas.d.ts +1 -0
  52. package/dist/models/providers/huawei-cloud-maas.d.ts.map +1 -0
  53. package/dist/models/providers/huggingface.d.ts +1 -0
  54. package/dist/models/providers/huggingface.d.ts.map +1 -0
  55. package/dist/models/providers/index.d.ts +1 -0
  56. package/dist/models/providers/index.d.ts.map +1 -0
  57. package/dist/models/providers/litellm.d.ts +1 -0
  58. package/dist/models/providers/litellm.d.ts.map +1 -0
  59. package/dist/models/providers/lmstudio.d.ts +1 -0
  60. package/dist/models/providers/lmstudio.d.ts.map +1 -0
  61. package/dist/models/providers/minimax.d.ts +1 -0
  62. package/dist/models/providers/minimax.d.ts.map +1 -0
  63. package/dist/models/providers/mistral.d.ts +1 -0
  64. package/dist/models/providers/mistral.d.ts.map +1 -0
  65. package/dist/models/providers/moonshot.d.ts +1 -0
  66. package/dist/models/providers/moonshot.d.ts.map +1 -0
  67. package/dist/models/providers/nebius.d.ts +1 -0
  68. package/dist/models/providers/nebius.d.ts.map +1 -0
  69. package/dist/models/providers/nous-research.d.ts +1 -0
  70. package/dist/models/providers/nous-research.d.ts.map +1 -0
  71. package/dist/models/providers/oca.d.ts +1 -0
  72. package/dist/models/providers/oca.d.ts.map +1 -0
  73. package/dist/models/providers/ollama.d.ts +1 -0
  74. package/dist/models/providers/ollama.d.ts.map +1 -0
  75. package/dist/models/providers/openai-codex.d.ts +1 -0
  76. package/dist/models/providers/openai-codex.d.ts.map +1 -0
  77. package/dist/models/providers/openai.d.ts +1 -0
  78. package/dist/models/providers/openai.d.ts.map +1 -0
  79. package/dist/models/providers/opencode.d.ts +1 -0
  80. package/dist/models/providers/opencode.d.ts.map +1 -0
  81. package/dist/models/providers/openrouter.d.ts +1 -0
  82. package/dist/models/providers/openrouter.d.ts.map +1 -0
  83. package/dist/models/providers/qwen-code.d.ts +1 -0
  84. package/dist/models/providers/qwen-code.d.ts.map +1 -0
  85. package/dist/models/providers/qwen.d.ts +1 -0
  86. package/dist/models/providers/qwen.d.ts.map +1 -0
  87. package/dist/models/providers/requesty.d.ts +1 -0
  88. package/dist/models/providers/requesty.d.ts.map +1 -0
  89. package/dist/models/providers/sambanova.d.ts +1 -0
  90. package/dist/models/providers/sambanova.d.ts.map +1 -0
  91. package/dist/models/providers/sapaicore.d.ts +1 -0
  92. package/dist/models/providers/sapaicore.d.ts.map +1 -0
  93. package/dist/models/providers/together.d.ts +1 -0
  94. package/dist/models/providers/together.d.ts.map +1 -0
  95. package/dist/models/providers/vercel-ai-gateway.d.ts +1 -0
  96. package/dist/models/providers/vercel-ai-gateway.d.ts.map +1 -0
  97. package/dist/models/providers/vertex.d.ts +1 -0
  98. package/dist/models/providers/vertex.d.ts.map +1 -0
  99. package/dist/models/providers/xai.d.ts +1 -0
  100. package/dist/models/providers/xai.d.ts.map +1 -0
  101. package/dist/models/providers/zai.d.ts +1 -0
  102. package/dist/models/providers/zai.d.ts.map +1 -0
  103. package/dist/models/query.d.ts +1 -0
  104. package/dist/models/query.d.ts.map +1 -0
  105. package/dist/models/registry.d.ts +1 -0
  106. package/dist/models/registry.d.ts.map +1 -0
  107. package/dist/models/schemas/index.d.ts +1 -0
  108. package/dist/models/schemas/index.d.ts.map +1 -0
  109. package/dist/models/schemas/model.d.ts +1 -0
  110. package/dist/models/schemas/model.d.ts.map +1 -0
  111. package/dist/models/schemas/query.d.ts +1 -0
  112. package/dist/models/schemas/query.d.ts.map +1 -0
  113. package/dist/providers/handlers/ai-sdk-community.d.ts +1 -0
  114. package/dist/providers/handlers/ai-sdk-community.d.ts.map +1 -0
  115. package/dist/providers/handlers/ai-sdk-provider-base.d.ts +1 -0
  116. package/dist/providers/handlers/ai-sdk-provider-base.d.ts.map +1 -0
  117. package/dist/providers/handlers/anthropic-base.d.ts +1 -0
  118. package/dist/providers/handlers/anthropic-base.d.ts.map +1 -0
  119. package/dist/providers/handlers/asksage.d.ts +1 -0
  120. package/dist/providers/handlers/asksage.d.ts.map +1 -0
  121. package/dist/providers/handlers/auth.d.ts +1 -0
  122. package/dist/providers/handlers/auth.d.ts.map +1 -0
  123. package/dist/providers/handlers/base.d.ts +1 -0
  124. package/dist/providers/handlers/base.d.ts.map +1 -0
  125. package/dist/providers/handlers/bedrock-base.d.ts +1 -0
  126. package/dist/providers/handlers/bedrock-base.d.ts.map +1 -0
  127. package/dist/providers/handlers/bedrock-client.d.ts +1 -0
  128. package/dist/providers/handlers/bedrock-client.d.ts.map +1 -0
  129. package/dist/providers/handlers/community-sdk.d.ts +1 -0
  130. package/dist/providers/handlers/community-sdk.d.ts.map +1 -0
  131. package/dist/providers/handlers/fetch-base.d.ts +1 -0
  132. package/dist/providers/handlers/fetch-base.d.ts.map +1 -0
  133. package/dist/providers/handlers/gemini-base.d.ts +1 -0
  134. package/dist/providers/handlers/gemini-base.d.ts.map +1 -0
  135. package/dist/providers/handlers/index.d.ts +1 -0
  136. package/dist/providers/handlers/index.d.ts.map +1 -0
  137. package/dist/providers/handlers/openai-base.d.ts +1 -0
  138. package/dist/providers/handlers/openai-base.d.ts.map +1 -0
  139. package/dist/providers/handlers/openai-responses.d.ts +1 -0
  140. package/dist/providers/handlers/openai-responses.d.ts.map +1 -0
  141. package/dist/providers/handlers/providers.d.ts +1 -0
  142. package/dist/providers/handlers/providers.d.ts.map +1 -0
  143. package/dist/providers/handlers/r1-base.d.ts +1 -0
  144. package/dist/providers/handlers/r1-base.d.ts.map +1 -0
  145. package/dist/providers/handlers/registry.d.ts +1 -0
  146. package/dist/providers/handlers/registry.d.ts.map +1 -0
  147. package/dist/providers/handlers/vertex.d.ts +1 -0
  148. package/dist/providers/handlers/vertex.d.ts.map +1 -0
  149. package/dist/providers/index.d.ts +1 -0
  150. package/dist/providers/index.d.ts.map +1 -0
  151. package/dist/providers/public.browser.d.ts +1 -0
  152. package/dist/providers/public.browser.d.ts.map +1 -0
  153. package/dist/providers/public.d.ts +1 -0
  154. package/dist/providers/public.d.ts.map +1 -0
  155. package/dist/providers/shared/openai-compatible.d.ts +1 -0
  156. package/dist/providers/shared/openai-compatible.d.ts.map +1 -0
  157. package/dist/providers/transform/ai-sdk-community-format.d.ts +1 -0
  158. package/dist/providers/transform/ai-sdk-community-format.d.ts.map +1 -0
  159. package/dist/providers/transform/anthropic-format.d.ts +1 -0
  160. package/dist/providers/transform/anthropic-format.d.ts.map +1 -0
  161. package/dist/providers/transform/content-format.d.ts +1 -0
  162. package/dist/providers/transform/content-format.d.ts.map +1 -0
  163. package/dist/providers/transform/gemini-format.d.ts +1 -0
  164. package/dist/providers/transform/gemini-format.d.ts.map +1 -0
  165. package/dist/providers/transform/index.d.ts +1 -0
  166. package/dist/providers/transform/index.d.ts.map +1 -0
  167. package/dist/providers/transform/openai-format.d.ts +1 -0
  168. package/dist/providers/transform/openai-format.d.ts.map +1 -0
  169. package/dist/providers/transform/r1-format.d.ts +1 -0
  170. package/dist/providers/transform/r1-format.d.ts.map +1 -0
  171. package/dist/providers/types/config.d.ts +1 -0
  172. package/dist/providers/types/config.d.ts.map +1 -0
  173. package/dist/providers/types/handler.d.ts +1 -0
  174. package/dist/providers/types/handler.d.ts.map +1 -0
  175. package/dist/providers/types/index.d.ts +1 -0
  176. package/dist/providers/types/index.d.ts.map +1 -0
  177. package/dist/providers/types/messages.d.ts +1 -0
  178. package/dist/providers/types/messages.d.ts.map +1 -0
  179. package/dist/providers/types/model-info.d.ts +1 -0
  180. package/dist/providers/types/model-info.d.ts.map +1 -0
  181. package/dist/providers/types/provider-ids.d.ts +1 -1
  182. package/dist/providers/types/provider-ids.d.ts.map +1 -0
  183. package/dist/providers/types/settings.d.ts +1 -0
  184. package/dist/providers/types/settings.d.ts.map +1 -0
  185. package/dist/providers/types/stream.d.ts +1 -0
  186. package/dist/providers/types/stream.d.ts.map +1 -0
  187. package/dist/providers/utils/index.d.ts +1 -0
  188. package/dist/providers/utils/index.d.ts.map +1 -0
  189. package/dist/providers/utils/retry.d.ts +1 -0
  190. package/dist/providers/utils/retry.d.ts.map +1 -0
  191. package/dist/providers/utils/stream-processor.d.ts +1 -0
  192. package/dist/providers/utils/stream-processor.d.ts.map +1 -0
  193. package/dist/providers/utils/tool-processor.d.ts +1 -0
  194. package/dist/providers/utils/tool-processor.d.ts.map +1 -0
  195. package/dist/sdk.d.ts +1 -0
  196. package/dist/sdk.d.ts.map +1 -0
  197. package/dist/types.d.ts +1 -0
  198. package/dist/types.d.ts.map +1 -0
  199. package/package.json +2 -3
  200. package/src/catalog.ts +0 -20
  201. package/src/config-browser.ts +0 -11
  202. package/src/config.ts +0 -49
  203. package/src/index.browser.ts +0 -9
  204. package/src/index.ts +0 -10
  205. package/src/live-providers.test.ts +0 -138
  206. package/src/models/generated-access.ts +0 -41
  207. package/src/models/generated-provider-loaders.ts +0 -166
  208. package/src/models/generated.ts +0 -11785
  209. package/src/models/index.ts +0 -271
  210. package/src/models/models-dev-catalog.test.ts +0 -161
  211. package/src/models/models-dev-catalog.ts +0 -168
  212. package/src/models/providers/aihubmix.ts +0 -19
  213. package/src/models/providers/anthropic.ts +0 -60
  214. package/src/models/providers/asksage.ts +0 -19
  215. package/src/models/providers/baseten.ts +0 -21
  216. package/src/models/providers/bedrock.ts +0 -30
  217. package/src/models/providers/cerebras.ts +0 -24
  218. package/src/models/providers/claude-code.ts +0 -51
  219. package/src/models/providers/cline.ts +0 -25
  220. package/src/models/providers/deepseek.ts +0 -33
  221. package/src/models/providers/dify.ts +0 -17
  222. package/src/models/providers/doubao.ts +0 -33
  223. package/src/models/providers/fireworks.ts +0 -34
  224. package/src/models/providers/gemini.ts +0 -43
  225. package/src/models/providers/groq.ts +0 -33
  226. package/src/models/providers/hicap.ts +0 -18
  227. package/src/models/providers/huawei-cloud-maas.ts +0 -18
  228. package/src/models/providers/huggingface.ts +0 -22
  229. package/src/models/providers/index.ts +0 -162
  230. package/src/models/providers/litellm.ts +0 -19
  231. package/src/models/providers/lmstudio.ts +0 -22
  232. package/src/models/providers/minimax.ts +0 -34
  233. package/src/models/providers/mistral.ts +0 -19
  234. package/src/models/providers/moonshot.ts +0 -34
  235. package/src/models/providers/nebius.ts +0 -24
  236. package/src/models/providers/nous-research.ts +0 -21
  237. package/src/models/providers/oca.ts +0 -30
  238. package/src/models/providers/ollama.ts +0 -18
  239. package/src/models/providers/openai-codex.ts +0 -46
  240. package/src/models/providers/openai.ts +0 -43
  241. package/src/models/providers/opencode.ts +0 -28
  242. package/src/models/providers/openrouter.ts +0 -24
  243. package/src/models/providers/qwen-code.ts +0 -33
  244. package/src/models/providers/qwen.ts +0 -34
  245. package/src/models/providers/requesty.ts +0 -23
  246. package/src/models/providers/sambanova.ts +0 -23
  247. package/src/models/providers/sapaicore.ts +0 -34
  248. package/src/models/providers/together.ts +0 -35
  249. package/src/models/providers/vercel-ai-gateway.ts +0 -23
  250. package/src/models/providers/vertex.ts +0 -36
  251. package/src/models/providers/xai.ts +0 -34
  252. package/src/models/providers/zai.ts +0 -25
  253. package/src/models/query.ts +0 -407
  254. package/src/models/registry.ts +0 -511
  255. package/src/models/schemas/index.ts +0 -62
  256. package/src/models/schemas/model.ts +0 -308
  257. package/src/models/schemas/query.ts +0 -336
  258. package/src/providers/browser.ts +0 -4
  259. package/src/providers/handlers/ai-sdk-community.ts +0 -229
  260. package/src/providers/handlers/ai-sdk-provider-base.ts +0 -203
  261. package/src/providers/handlers/anthropic-base.test.ts +0 -30
  262. package/src/providers/handlers/anthropic-base.ts +0 -387
  263. package/src/providers/handlers/asksage.test.ts +0 -103
  264. package/src/providers/handlers/asksage.ts +0 -138
  265. package/src/providers/handlers/auth.test.ts +0 -19
  266. package/src/providers/handlers/auth.ts +0 -121
  267. package/src/providers/handlers/base.test.ts +0 -230
  268. package/src/providers/handlers/base.ts +0 -310
  269. package/src/providers/handlers/bedrock-base.ts +0 -390
  270. package/src/providers/handlers/bedrock-client.ts +0 -100
  271. package/src/providers/handlers/codex.test.ts +0 -160
  272. package/src/providers/handlers/community-sdk.test.ts +0 -321
  273. package/src/providers/handlers/community-sdk.ts +0 -391
  274. package/src/providers/handlers/fetch-base.ts +0 -68
  275. package/src/providers/handlers/gemini-base.test.ts +0 -261
  276. package/src/providers/handlers/gemini-base.ts +0 -307
  277. package/src/providers/handlers/index.ts +0 -67
  278. package/src/providers/handlers/openai-base.ts +0 -341
  279. package/src/providers/handlers/openai-responses.test.ts +0 -259
  280. package/src/providers/handlers/openai-responses.ts +0 -634
  281. package/src/providers/handlers/providers.test.ts +0 -120
  282. package/src/providers/handlers/providers.ts +0 -563
  283. package/src/providers/handlers/r1-base.ts +0 -283
  284. package/src/providers/handlers/registry.ts +0 -185
  285. package/src/providers/handlers/vertex.test.ts +0 -124
  286. package/src/providers/handlers/vertex.ts +0 -302
  287. package/src/providers/index.ts +0 -534
  288. package/src/providers/public.browser.ts +0 -20
  289. package/src/providers/public.ts +0 -51
  290. package/src/providers/shared/openai-compatible.ts +0 -63
  291. package/src/providers/transform/ai-sdk-community-format.test.ts +0 -73
  292. package/src/providers/transform/ai-sdk-community-format.ts +0 -115
  293. package/src/providers/transform/anthropic-format.ts +0 -230
  294. package/src/providers/transform/content-format.ts +0 -34
  295. package/src/providers/transform/format-conversion.test.ts +0 -413
  296. package/src/providers/transform/gemini-format.ts +0 -262
  297. package/src/providers/transform/index.ts +0 -22
  298. package/src/providers/transform/openai-format.ts +0 -290
  299. package/src/providers/transform/r1-format.ts +0 -287
  300. package/src/providers/types/config.ts +0 -396
  301. package/src/providers/types/handler.ts +0 -92
  302. package/src/providers/types/index.ts +0 -120
  303. package/src/providers/types/messages.ts +0 -162
  304. package/src/providers/types/model-info.test.ts +0 -57
  305. package/src/providers/types/model-info.ts +0 -65
  306. package/src/providers/types/provider-ids.test.ts +0 -12
  307. package/src/providers/types/provider-ids.ts +0 -89
  308. package/src/providers/types/settings.test.ts +0 -49
  309. package/src/providers/types/settings.ts +0 -533
  310. package/src/providers/types/stream.ts +0 -117
  311. package/src/providers/utils/index.ts +0 -27
  312. package/src/providers/utils/retry.test.ts +0 -140
  313. package/src/providers/utils/retry.ts +0 -188
  314. package/src/providers/utils/stream-processor.test.ts +0 -232
  315. package/src/providers/utils/stream-processor.ts +0 -472
  316. package/src/providers/utils/tool-processor.test.ts +0 -235
  317. package/src/providers/utils/tool-processor.ts +0 -146
  318. package/src/sdk.ts +0 -264
  319. package/src/types.ts +0 -79
@@ -1,140 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest";
2
- import {
3
- calculateRetryDelay,
4
- isRetriableError,
5
- RetriableError,
6
- retryAsync,
7
- retryStream,
8
- } from "./retry";
9
-
10
- describe("retry utils", () => {
11
- it("detects retriable errors from known patterns", () => {
12
- expect(isRetriableError(new RetriableError("try again"))).toBe(true);
13
- expect(isRetriableError(new Error("HTTP 429: Too Many Requests"))).toBe(
14
- true,
15
- );
16
- expect(isRetriableError(new Error("upstream 503 failure"))).toBe(true);
17
- expect(isRetriableError(new Error("network timeout occurred"))).toBe(true);
18
- expect(isRetriableError(new Error("validation failed"))).toBe(false);
19
- expect(isRetriableError("not-an-error")).toBe(false);
20
- });
21
-
22
- it("calculates exponential delay with jitter and max cap", () => {
23
- const randomSpy = vi.spyOn(Math, "random").mockReturnValue(0);
24
-
25
- const noJitter = calculateRetryDelay(2, { baseDelay: 10, maxDelay: 1000 });
26
- expect(noJitter).toBe(40);
27
-
28
- randomSpy.mockReturnValue(1);
29
- const capped = calculateRetryDelay(10, { baseDelay: 1000, maxDelay: 1500 });
30
- expect(capped).toBe(1500);
31
-
32
- randomSpy.mockRestore();
33
- });
34
-
35
- it("retries async function until success and calls onRetryAttempt", async () => {
36
- let attempts = 0;
37
- const onRetryAttempt = vi.fn();
38
-
39
- const value = await retryAsync(
40
- async () => {
41
- attempts++;
42
- if (attempts < 3) {
43
- throw new RetriableError("retry me");
44
- }
45
- return "ok";
46
- },
47
- {
48
- maxRetries: 3,
49
- baseDelay: 0,
50
- maxDelay: 0,
51
- onRetryAttempt,
52
- },
53
- );
54
-
55
- expect(value).toBe("ok");
56
- expect(attempts).toBe(3);
57
- expect(onRetryAttempt).toHaveBeenCalledTimes(2);
58
- expect(onRetryAttempt).toHaveBeenNthCalledWith(
59
- 1,
60
- 1,
61
- 3,
62
- 0,
63
- expect.any(RetriableError),
64
- );
65
- expect(onRetryAttempt).toHaveBeenNthCalledWith(
66
- 2,
67
- 2,
68
- 3,
69
- 0,
70
- expect.any(RetriableError),
71
- );
72
- });
73
-
74
- it("respects retry-after seconds for retriable errors", async () => {
75
- let attempts = 0;
76
- const onRetryAttempt = vi.fn();
77
-
78
- vi.useFakeTimers();
79
-
80
- const pending = retryAsync(
81
- async () => {
82
- attempts++;
83
- if (attempts === 1) {
84
- throw new RetriableError("rate limited", 2);
85
- }
86
- return "done";
87
- },
88
- {
89
- maxRetries: 2,
90
- onRetryAttempt,
91
- },
92
- );
93
- await vi.runAllTimersAsync();
94
- await pending;
95
- vi.useRealTimers();
96
-
97
- expect(onRetryAttempt).toHaveBeenCalledWith(
98
- 1,
99
- 2,
100
- 2000,
101
- expect.any(RetriableError),
102
- );
103
- });
104
-
105
- it("does not retry non-retriable errors", async () => {
106
- const fn = vi.fn(async () => {
107
- throw new Error("bad input");
108
- });
109
-
110
- await expect(
111
- retryAsync(fn, {
112
- maxRetries: 3,
113
- baseDelay: 0,
114
- maxDelay: 0,
115
- }),
116
- ).rejects.toThrow("bad input");
117
- expect(fn).toHaveBeenCalledTimes(1);
118
- });
119
-
120
- it("retries async generators and preserves yielded chunks", async () => {
121
- let attempts = 0;
122
- const chunks: Array<{ type: string; text?: string }> = [];
123
- for await (const chunk of retryStream(
124
- async function* () {
125
- attempts++;
126
- if (attempts < 3) {
127
- throw new RetriableError("temporary");
128
- }
129
- yield { type: "text", text: "hello" };
130
- yield { type: "done" };
131
- },
132
- { maxRetries: 3, baseDelay: 0, maxDelay: 0 },
133
- )) {
134
- chunks.push(chunk);
135
- }
136
-
137
- expect(chunks).toEqual([{ type: "text", text: "hello" }, { type: "done" }]);
138
- expect(attempts).toBe(3);
139
- });
140
- });
@@ -1,188 +0,0 @@
1
- /**
2
- * Retry Utilities
3
- *
4
- * Provides retry logic with exponential backoff for API calls.
5
- */
6
-
7
- export interface RetryOptions {
8
- maxRetries?: number;
9
- baseDelay?: number;
10
- maxDelay?: number;
11
- onRetryAttempt?: (
12
- attempt: number,
13
- maxRetries: number,
14
- delay: number,
15
- error: unknown,
16
- ) => void;
17
- }
18
-
19
- const DEFAULT_OPTIONS: Required<Omit<RetryOptions, "onRetryAttempt">> = {
20
- maxRetries: 4,
21
- baseDelay: 2000,
22
- maxDelay: 15000,
23
- };
24
-
25
- /**
26
- * Error that indicates the operation should be retried
27
- */
28
- export class RetriableError extends Error {
29
- constructor(
30
- message: string,
31
- public readonly retryAfterSeconds?: number,
32
- options?: ErrorOptions,
33
- ) {
34
- super(message, options);
35
- this.name = "RetriableError";
36
- }
37
- }
38
-
39
- /**
40
- * Check if an error is retriable
41
- */
42
- export function isRetriableError(error: unknown): boolean {
43
- if (error instanceof RetriableError) {
44
- return true;
45
- }
46
-
47
- if (error instanceof Error) {
48
- const message = error.message.toLowerCase();
49
-
50
- // Rate limit errors
51
- if (
52
- message.includes("429") ||
53
- message.includes("rate limit") ||
54
- message.includes("too many requests")
55
- ) {
56
- return true;
57
- }
58
-
59
- // Server errors (5xx)
60
- if (
61
- message.includes("500") ||
62
- message.includes("502") ||
63
- message.includes("503") ||
64
- message.includes("504")
65
- ) {
66
- return true;
67
- }
68
-
69
- // Network errors
70
- if (
71
- message.includes("network") ||
72
- message.includes("timeout") ||
73
- message.includes("econnreset") ||
74
- message.includes("econnrefused")
75
- ) {
76
- return true;
77
- }
78
- }
79
-
80
- return false;
81
- }
82
-
83
- /**
84
- * Calculate delay for retry attempt with exponential backoff and jitter
85
- */
86
- export function calculateRetryDelay(
87
- attempt: number,
88
- options: RetryOptions = {},
89
- ): number {
90
- const {
91
- baseDelay = DEFAULT_OPTIONS.baseDelay,
92
- maxDelay = DEFAULT_OPTIONS.maxDelay,
93
- } = options;
94
-
95
- // Exponential backoff: 2^attempt * baseDelay
96
- const exponentialDelay = 2 ** attempt * baseDelay;
97
-
98
- // Add jitter (0-25% of delay)
99
- const jitter = Math.random() * 0.25 * exponentialDelay;
100
-
101
- // Cap at maxDelay
102
- return Math.min(exponentialDelay + jitter, maxDelay);
103
- }
104
-
105
- /**
106
- * Sleep for a given number of milliseconds
107
- */
108
- export function sleep(ms: number): Promise<void> {
109
- return new Promise((resolve) => setTimeout(resolve, ms));
110
- }
111
-
112
- /**
113
- * Retry an async generator factory using the same retry policy as retryAsync.
114
- */
115
- export async function* retryStream<T>(
116
- createStream: () => AsyncGenerator<T, void, unknown>,
117
- options: RetryOptions = {},
118
- ): AsyncGenerator<T, void, unknown> {
119
- const { maxRetries = DEFAULT_OPTIONS.maxRetries, onRetryAttempt } = options;
120
-
121
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
122
- try {
123
- yield* createStream();
124
- return;
125
- } catch (error) {
126
- const isLastAttempt = attempt === maxRetries;
127
- const shouldRetry = !isLastAttempt && isRetriableError(error);
128
-
129
- if (!shouldRetry) {
130
- throw error;
131
- }
132
-
133
- let delay: number;
134
- if (error instanceof RetriableError && error.retryAfterSeconds) {
135
- delay = error.retryAfterSeconds * 1000;
136
- } else {
137
- delay = calculateRetryDelay(attempt, options);
138
- }
139
-
140
- if (onRetryAttempt) {
141
- onRetryAttempt(attempt + 1, maxRetries, delay, error);
142
- }
143
-
144
- await sleep(delay);
145
- }
146
- }
147
-
148
- throw new Error("Retry logic exhausted without returning or throwing");
149
- }
150
-
151
- /**
152
- * Wrap an async function with retry logic
153
- */
154
- export async function retryAsync<T>(
155
- fn: () => Promise<T>,
156
- options: RetryOptions = {},
157
- ): Promise<T> {
158
- const { maxRetries = DEFAULT_OPTIONS.maxRetries, onRetryAttempt } = options;
159
-
160
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
161
- try {
162
- return await fn();
163
- } catch (error) {
164
- const isLastAttempt = attempt === maxRetries;
165
- const shouldRetry = !isLastAttempt && isRetriableError(error);
166
-
167
- if (!shouldRetry) {
168
- throw error;
169
- }
170
-
171
- let delay: number;
172
- if (error instanceof RetriableError && error.retryAfterSeconds) {
173
- delay = error.retryAfterSeconds * 1000;
174
- } else {
175
- delay = calculateRetryDelay(attempt, options);
176
- }
177
-
178
- if (onRetryAttempt) {
179
- onRetryAttempt(attempt + 1, maxRetries, delay, error);
180
- }
181
-
182
- await sleep(delay);
183
- }
184
- }
185
-
186
- // This should never be reached
187
- throw new Error("Retry logic exhausted without returning or throwing");
188
- }
@@ -1,232 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { StreamResponseProcessor } from "./stream-processor";
3
-
4
- describe("StreamResponseProcessor", () => {
5
- it("assembles text, reasoning, tool calls, usage, and completion metadata", () => {
6
- const processor = new StreamResponseProcessor();
7
-
8
- processor.process({
9
- type: "reasoning",
10
- id: "resp_1",
11
- reasoning: "thinking...",
12
- details: {
13
- type: "reasoning.text",
14
- text: "step 1",
15
- signature: "sig-r",
16
- format: "anthropic-claude-v1",
17
- index: 0,
18
- },
19
- redacted_data: "encrypted",
20
- });
21
- processor.process({
22
- type: "text",
23
- id: "resp_1",
24
- text: "Hello ",
25
- });
26
- processor.process({
27
- type: "text",
28
- id: "resp_1",
29
- text: "world",
30
- signature: "sig-text",
31
- });
32
- processor.process({
33
- type: "tool_calls",
34
- id: "resp_1",
35
- signature: "sig-tool",
36
- tool_call: {
37
- call_id: "call_1",
38
- function: {
39
- id: "tool_1",
40
- name: "read_file",
41
- arguments: '{"path":"/tmp/a',
42
- },
43
- },
44
- });
45
- processor.process({
46
- type: "tool_calls",
47
- id: "resp_1",
48
- tool_call: {
49
- function: {
50
- id: "tool_1",
51
- arguments: '.ts"}',
52
- },
53
- },
54
- });
55
- processor.process({
56
- type: "usage",
57
- id: "resp_1",
58
- inputTokens: 10,
59
- outputTokens: 20,
60
- cacheReadTokens: 5,
61
- cacheWriteTokens: 0,
62
- thoughtsTokenCount: 3,
63
- totalCost: 0.001,
64
- });
65
- const partial = processor.process({
66
- type: "done",
67
- id: "resp_1",
68
- success: true,
69
- incompleteReason: "max_output_tokens",
70
- });
71
-
72
- expect(partial.responseId).toBe("resp_1");
73
- expect(partial.content[0]).toMatchObject({
74
- type: "thinking",
75
- thinking: "thinking...",
76
- signature: "sig-r",
77
- });
78
- expect(partial.content[1]).toMatchObject({
79
- type: "text",
80
- text: "Hello world",
81
- signature: "sig-text",
82
- });
83
- expect(partial.content[2]).toMatchObject({
84
- type: "tool_use",
85
- id: "tool_1",
86
- name: "read_file",
87
- input: { path: "/tmp/a.ts" },
88
- signature: "sig-tool",
89
- });
90
-
91
- const final = processor.finalize();
92
- expect(final.responseId).toBe("resp_1");
93
- expect(final.incompleteReason).toBe("max_output_tokens");
94
- expect(final.usage).toEqual({
95
- inputTokens: 10,
96
- outputTokens: 20,
97
- cacheReadTokens: 5,
98
- cacheWriteTokens: 0,
99
- thoughtsTokenCount: 3,
100
- totalCost: 0.001,
101
- });
102
- expect(final.content[0]).toMatchObject({
103
- type: "thinking",
104
- thinking: "thinking...",
105
- summary: [
106
- {
107
- type: "reasoning.text",
108
- text: "step 1",
109
- signature: "sig-r",
110
- format: "anthropic-claude-v1",
111
- index: 0,
112
- },
113
- ],
114
- });
115
- expect(final.content[1]).toEqual({
116
- type: "redacted_thinking",
117
- data: "encrypted",
118
- call_id: "resp_1",
119
- });
120
- expect(final.content[2]).toMatchObject({
121
- type: "text",
122
- text: "Hello world",
123
- signature: "sig-text",
124
- reasoning_details: [
125
- {
126
- type: "reasoning.text",
127
- text: "step 1",
128
- signature: "sig-r",
129
- format: "anthropic-claude-v1",
130
- index: 0,
131
- },
132
- ],
133
- });
134
- expect(final.content[3]).toMatchObject({
135
- type: "tool_use",
136
- id: "tool_1",
137
- name: "read_file",
138
- input: { path: "/tmp/a.ts" },
139
- signature: "sig-tool",
140
- });
141
- });
142
-
143
- it("extracts partial JSON fields while arguments are incomplete", () => {
144
- const processor = new StreamResponseProcessor();
145
-
146
- const partial = processor.process({
147
- type: "tool_calls",
148
- id: "resp_2",
149
- tool_call: {
150
- call_id: "call_partial",
151
- function: {
152
- id: "tool_partial",
153
- name: "run_command",
154
- arguments:
155
- '{"command":"echo \\"hi\\"","cwd":"/Users/beatrix/dev/cline-packages',
156
- },
157
- },
158
- });
159
-
160
- expect(partial.content).toEqual([
161
- {
162
- type: "tool_use",
163
- id: "tool_partial",
164
- name: "run_command",
165
- input: {
166
- command: 'echo "hi"',
167
- cwd: "/Users/beatrix/dev/cline-packages",
168
- },
169
- call_id: "call_partial",
170
- signature: undefined,
171
- },
172
- ]);
173
- });
174
-
175
- it("handles object arguments and reset()", () => {
176
- const processor = new StreamResponseProcessor();
177
-
178
- processor.process({
179
- type: "tool_calls",
180
- id: "resp_3",
181
- tool_call: {
182
- call_id: "call_obj",
183
- function: {
184
- id: "tool_obj",
185
- name: "edit_file",
186
- arguments: {
187
- path: "a.ts",
188
- content: "x",
189
- },
190
- },
191
- },
192
- });
193
-
194
- const finalBeforeReset = processor.finalize();
195
- expect(finalBeforeReset.content).toEqual([
196
- {
197
- type: "tool_use",
198
- id: "tool_obj",
199
- name: "edit_file",
200
- input: { path: "a.ts", content: "x" },
201
- call_id: "call_obj",
202
- signature: undefined,
203
- reasoning_details: undefined,
204
- },
205
- ]);
206
-
207
- processor.reset();
208
- expect(processor.finalize()).toEqual({
209
- content: [],
210
- usage: undefined,
211
- responseId: undefined,
212
- incompleteReason: undefined,
213
- });
214
- });
215
-
216
- it("ignores tool call chunks that do not have an id", () => {
217
- const processor = new StreamResponseProcessor();
218
-
219
- processor.process({
220
- type: "tool_calls",
221
- id: "resp_4",
222
- tool_call: {
223
- function: {
224
- name: "ignored",
225
- arguments: "{}",
226
- },
227
- },
228
- });
229
-
230
- expect(processor.finalize().content).toEqual([]);
231
- });
232
- });