@clinebot/llms 0.0.18 → 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 +3 -4
  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,387 +0,0 @@
1
- /**
2
- * Anthropic Base Handler
3
- *
4
- * Handler for Anthropic's API using the official SDK.
5
- * Supports prompt caching, extended thinking, and native tool calling.
6
- */
7
-
8
- import { Anthropic } from "@anthropic-ai/sdk";
9
- import type {
10
- Tool as AnthropicTool,
11
- RawMessageStreamEvent,
12
- } from "@anthropic-ai/sdk/resources";
13
- import {
14
- convertToAnthropicMessages,
15
- convertToolsToAnthropic,
16
- } from "../transform/anthropic-format";
17
- import {
18
- type ApiStream,
19
- type HandlerModelInfo,
20
- type ProviderConfig,
21
- supportsModelThinking,
22
- } from "../types";
23
- import type { Message, ToolDefinition } from "../types/messages";
24
- import { retryStream } from "../utils/retry";
25
- import { getMissingApiKeyError, resolveApiKeyForProvider } from "./auth";
26
- import { BaseHandler } from "./base";
27
-
28
- const DEFAULT_THINKING_BUDGET_TOKENS = 1024;
29
- const THINKING_DEBUG_ENV = "CLINE_DEBUG_THINKING";
30
-
31
- function isThinkingDebugEnabled(): boolean {
32
- const raw = process.env[THINKING_DEBUG_ENV];
33
- if (!raw) {
34
- return false;
35
- }
36
- const normalized = raw.trim().toLowerCase();
37
- return normalized === "1" || normalized === "true" || normalized === "yes";
38
- }
39
-
40
- /**
41
- * Handler for Anthropic's API
42
- */
43
- export class AnthropicHandler extends BaseHandler {
44
- private client: Anthropic | undefined;
45
-
46
- private ensureClient(): Anthropic {
47
- if (!this.client) {
48
- const apiKey = resolveApiKeyForProvider(
49
- this.config.providerId,
50
- this.config.apiKey,
51
- );
52
- if (!apiKey) {
53
- throw new Error(getMissingApiKeyError(this.config.providerId));
54
- }
55
-
56
- this.client = new Anthropic({
57
- apiKey,
58
- baseURL: this.config.baseUrl || undefined,
59
- defaultHeaders: this.getRequestHeaders(),
60
- });
61
- }
62
- return this.client;
63
- }
64
-
65
- getModel(): HandlerModelInfo {
66
- const modelId = this.config.modelId;
67
- const knownModels = this.config.knownModels ?? {};
68
- const fallbackModel = knownModels[modelId] ?? {};
69
- const modelInfo = this.config.modelInfo ?? fallbackModel;
70
-
71
- return { id: modelId, info: { ...modelInfo, id: modelId } };
72
- }
73
-
74
- getMessages(
75
- _systemPrompt: string,
76
- messages: Message[],
77
- ): Anthropic.MessageParam[] {
78
- const supportsPromptCache = this.supportsPromptCache(this.getModel().info);
79
- return convertToAnthropicMessages(
80
- messages,
81
- supportsPromptCache,
82
- ) as Anthropic.MessageParam[];
83
- }
84
-
85
- async *createMessage(
86
- systemPrompt: string,
87
- messages: Message[],
88
- tools?: ToolDefinition[],
89
- ): ApiStream {
90
- yield* retryStream(() =>
91
- this.createMessageInternal(systemPrompt, messages, tools),
92
- );
93
- }
94
-
95
- private async *createMessageInternal(
96
- systemPrompt: string,
97
- messages: Message[],
98
- tools?: ToolDefinition[],
99
- ): ApiStream {
100
- const client = this.ensureClient();
101
- const model = this.getModel();
102
- const abortSignal = this.getAbortSignal();
103
- const responseId = this.createResponseId();
104
-
105
- const thinkingSupported = supportsModelThinking(model.info);
106
- const requestedBudget =
107
- this.config.thinkingBudgetTokens ??
108
- (this.config.thinking ? DEFAULT_THINKING_BUDGET_TOKENS : 0);
109
- const budgetTokens =
110
- thinkingSupported && requestedBudget > 0 ? requestedBudget : 0;
111
- const nativeToolsOn = tools && tools.length > 0;
112
- const supportsPromptCache = this.supportsPromptCache(model.info);
113
- const reasoningOn = thinkingSupported && budgetTokens > 0;
114
- const debugThinking = isThinkingDebugEnabled();
115
- const debugChunkCounts: Record<string, number> = {};
116
- const countChunk = (type: string): void => {
117
- debugChunkCounts[type] = (debugChunkCounts[type] ?? 0) + 1;
118
- };
119
-
120
- if (debugThinking) {
121
- console.error(
122
- `[thinking-debug][anthropic][request] model=${model.id} thinkingFlag=${this.config.thinking === true} supportsModelThinking=${thinkingSupported} requestedBudget=${requestedBudget} effectiveBudget=${budgetTokens} reasoningOn=${reasoningOn} promptCache=${supportsPromptCache}`,
123
- );
124
- }
125
-
126
- // Convert messages
127
- const anthropicMessages = this.getMessages(systemPrompt, messages);
128
-
129
- // Convert tools
130
- const anthropicTools: AnthropicTool[] | undefined = nativeToolsOn
131
- ? convertToolsToAnthropic(tools)
132
- : undefined;
133
-
134
- // Request options with abort signal
135
- const requestOptions = { signal: abortSignal };
136
-
137
- // Create the request
138
- // Use top-level automatic caching so the entire prefix (system +
139
- // messages) is cached and the breakpoint advances each turn.
140
- const createParams: Record<string, unknown> &
141
- Anthropic.MessageCreateParamsStreaming = {
142
- model: model.id,
143
- thinking: reasoningOn
144
- ? { type: "enabled", budget_tokens: budgetTokens }
145
- : undefined,
146
- max_tokens:
147
- model.info.maxTokens ?? this.config.maxOutputTokens ?? 128_000,
148
- temperature: reasoningOn ? undefined : 0,
149
- system: [
150
- supportsPromptCache
151
- ? {
152
- text: systemPrompt,
153
- type: "text",
154
- cache_control: { type: "ephemeral" },
155
- }
156
- : { text: systemPrompt, type: "text" },
157
- ],
158
- messages: anthropicMessages as Anthropic.MessageParam[],
159
- stream: true,
160
- tools: anthropicTools,
161
- tool_choice: nativeToolsOn && !reasoningOn ? { type: "auto" } : undefined,
162
- };
163
-
164
- const stream = await client.messages.create(
165
- createParams as Anthropic.MessageCreateParamsStreaming,
166
- requestOptions,
167
- );
168
-
169
- // Track tool call state
170
- const currentToolCall = { id: "", name: "", arguments: "" };
171
- const usageSnapshot = {
172
- inputTokens: 0,
173
- outputTokens: 0,
174
- cacheReadTokens: 0,
175
- cacheWriteTokens: 0,
176
- };
177
- let stopReason: string | null = null;
178
-
179
- for await (const chunk of stream) {
180
- if (debugThinking) {
181
- countChunk(`event:${chunk.type}`);
182
- if (chunk.type === "content_block_start") {
183
- countChunk(
184
- `content_block_start:${chunk.content_block?.type ?? "unknown"}`,
185
- );
186
- } else if (chunk.type === "content_block_delta") {
187
- countChunk(`content_block_delta:${chunk.delta?.type ?? "unknown"}`);
188
- }
189
- }
190
- if (chunk.type === "message_delta") {
191
- stopReason =
192
- (chunk as { delta?: { stop_reason?: string } }).delta?.stop_reason ??
193
- stopReason;
194
- }
195
- yield* this.withResponseIdForAll(
196
- this.processChunk(chunk, currentToolCall, usageSnapshot, responseId),
197
- responseId,
198
- );
199
- }
200
-
201
- if (debugThinking) {
202
- const summary = Object.entries(debugChunkCounts)
203
- .map(([key, count]) => `${key}=${count}`)
204
- .sort()
205
- .join(" ");
206
- console.error(`[thinking-debug][anthropic][stream] ${summary}`);
207
- }
208
-
209
- yield {
210
- type: "done",
211
- success: true,
212
- id: responseId,
213
- incompleteReason: stopReason === "max_tokens" ? "max_tokens" : undefined,
214
- };
215
- }
216
-
217
- protected *processChunk(
218
- chunk: RawMessageStreamEvent,
219
- currentToolCall: { id: string; name: string; arguments: string },
220
- usageSnapshot: {
221
- inputTokens: number;
222
- outputTokens: number;
223
- cacheReadTokens: number;
224
- cacheWriteTokens: number;
225
- },
226
- responseId: string,
227
- ): Generator<import("../types").ApiStreamChunk> {
228
- switch (chunk.type) {
229
- case "message_start": {
230
- const usage = chunk.message.usage;
231
- usageSnapshot.inputTokens = usage.input_tokens || 0;
232
- usageSnapshot.outputTokens = usage.output_tokens || 0;
233
- usageSnapshot.cacheWriteTokens =
234
- (usage as any).cache_creation_input_tokens || 0;
235
- usageSnapshot.cacheReadTokens =
236
- (usage as any).cache_read_input_tokens || 0;
237
- yield {
238
- type: "usage",
239
- inputTokens: usageSnapshot.inputTokens,
240
- outputTokens: usageSnapshot.outputTokens,
241
- cacheWriteTokens: usageSnapshot.cacheWriteTokens,
242
- cacheReadTokens: usageSnapshot.cacheReadTokens,
243
- totalCost: this.calculateCost(
244
- usageSnapshot.inputTokens,
245
- usageSnapshot.outputTokens,
246
- usageSnapshot.cacheReadTokens,
247
- usageSnapshot.cacheWriteTokens,
248
- ),
249
- id: responseId,
250
- };
251
- break;
252
- }
253
-
254
- case "message_delta": {
255
- usageSnapshot.outputTokens =
256
- chunk.usage.output_tokens || usageSnapshot.outputTokens;
257
- yield {
258
- type: "usage",
259
- inputTokens: usageSnapshot.inputTokens,
260
- outputTokens: usageSnapshot.outputTokens,
261
- cacheWriteTokens: usageSnapshot.cacheWriteTokens,
262
- cacheReadTokens: usageSnapshot.cacheReadTokens,
263
- totalCost: this.calculateCost(
264
- usageSnapshot.inputTokens,
265
- usageSnapshot.outputTokens,
266
- usageSnapshot.cacheReadTokens,
267
- usageSnapshot.cacheWriteTokens,
268
- ),
269
- id: responseId,
270
- };
271
- break;
272
- }
273
-
274
- case "content_block_start": {
275
- const block = chunk.content_block;
276
- switch (block.type) {
277
- case "thinking":
278
- yield {
279
- type: "reasoning",
280
- reasoning:
281
- typeof (block as { thinking?: unknown }).thinking === "string"
282
- ? ((block as { thinking: string }).thinking ?? "")
283
- : "",
284
- signature:
285
- typeof (block as { signature?: unknown }).signature === "string"
286
- ? ((block as { signature: string }).signature ?? undefined)
287
- : undefined,
288
- id: responseId,
289
- };
290
- break;
291
- case "redacted_thinking":
292
- yield {
293
- type: "reasoning",
294
- reasoning: "",
295
- redacted_data:
296
- typeof (block as { data?: unknown }).data === "string"
297
- ? ((block as { data: string }).data ?? undefined)
298
- : undefined,
299
- id: responseId,
300
- };
301
- break;
302
- case "text":
303
- yield { type: "text", text: "", id: responseId };
304
- break;
305
- case "tool_use":
306
- currentToolCall.id = block.id;
307
- currentToolCall.name = block.name;
308
- currentToolCall.arguments = "";
309
- break;
310
- }
311
- break;
312
- }
313
-
314
- case "content_block_delta": {
315
- const delta = chunk.delta;
316
- switch (delta.type) {
317
- case "thinking_delta":
318
- yield {
319
- type: "reasoning",
320
- reasoning: delta.thinking,
321
- id: responseId,
322
- };
323
- break;
324
- case "signature_delta":
325
- yield {
326
- type: "reasoning",
327
- reasoning: "",
328
- signature:
329
- typeof (delta as { signature?: unknown }).signature === "string"
330
- ? ((delta as { signature: string }).signature ?? undefined)
331
- : undefined,
332
- id: responseId,
333
- };
334
- break;
335
- case "text_delta":
336
- yield { type: "text", text: delta.text, id: responseId };
337
- break;
338
- case "input_json_delta":
339
- currentToolCall.arguments += delta.partial_json;
340
- break;
341
- }
342
- break;
343
- }
344
-
345
- case "content_block_stop": {
346
- // If we have a tool call, yield it
347
- if (currentToolCall.id) {
348
- let parsedArgs: string | Record<string, unknown>;
349
- try {
350
- parsedArgs = JSON.parse(currentToolCall.arguments || "{}");
351
- } catch {
352
- // Preserve the raw JSON fragment so downstream can classify it
353
- // as an invalid tool call instead of silently turning it into {}.
354
- parsedArgs = currentToolCall.arguments;
355
- }
356
-
357
- yield {
358
- type: "tool_calls",
359
- id: responseId,
360
- tool_call: {
361
- call_id: currentToolCall.id,
362
- function: {
363
- name: currentToolCall.name,
364
- arguments: parsedArgs,
365
- },
366
- },
367
- };
368
-
369
- // Reset tool call state
370
- currentToolCall.id = "";
371
- currentToolCall.name = "";
372
- currentToolCall.arguments = "";
373
- }
374
- break;
375
- }
376
- }
377
- }
378
- }
379
-
380
- /**
381
- * Create an Anthropic handler
382
- */
383
- export function createAnthropicHandler(
384
- config: ProviderConfig,
385
- ): AnthropicHandler {
386
- return new AnthropicHandler(config);
387
- }
@@ -1,103 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
- import { createHandler } from "../index";
3
- import type { ApiStreamChunk } from "../types";
4
- import { AskSageHandler } from "./asksage";
5
-
6
- vi.mock("./auth", async () => {
7
- const actual = await vi.importActual("./auth");
8
- return {
9
- ...(actual as object),
10
- resolveApiKeyForProvider: (_providerId: string, explicitApiKey?: string) =>
11
- explicitApiKey?.trim() || undefined,
12
- };
13
- });
14
-
15
- describe("AskSageHandler", () => {
16
- beforeEach(() => {
17
- vi.restoreAllMocks();
18
- });
19
-
20
- it("formats request payload and emits text/usage/done chunks", async () => {
21
- const fetchMock = vi.fn(async () => ({
22
- ok: true,
23
- json: async () => ({
24
- message: "final answer",
25
- tool_responses: [{ name: "search", ok: true }],
26
- usage: {
27
- model_tokens: {
28
- prompt_tokens: 123,
29
- completion_tokens: 45,
30
- total_tokens: 168,
31
- },
32
- asksage_tokens: 17.5,
33
- },
34
- }),
35
- }));
36
- globalThis.fetch = fetchMock as unknown as typeof fetch;
37
-
38
- const handler = new AskSageHandler({
39
- providerId: "asksage",
40
- modelId: "gpt-4o",
41
- apiKey: "ask-key",
42
- });
43
-
44
- const chunks: ApiStreamChunk[] = [];
45
- for await (const chunk of handler.createMessage("system prompt", [
46
- { role: "user", content: [{ type: "text", text: "hello" }] },
47
- { role: "assistant", content: "hi there" },
48
- ])) {
49
- chunks.push(chunk);
50
- }
51
-
52
- expect(fetchMock).toHaveBeenCalledTimes(1);
53
- const [url, init] = fetchMock.mock.calls[0] as unknown as [
54
- string,
55
- RequestInit & { body?: string },
56
- ];
57
- expect(url).toBe("https://api.asksage.ai/server/query");
58
- expect(init.method).toBe("POST");
59
- expect(init.headers).toMatchObject({
60
- "Content-Type": "application/json",
61
- "x-access-tokens": "ask-key",
62
- });
63
- expect(JSON.parse(init.body ?? "{}")).toEqual({
64
- system_prompt: "system prompt",
65
- message: [
66
- { user: "me", message: "hello" },
67
- { user: "gpt", message: "hi there" },
68
- ],
69
- model: "gpt-4o",
70
- dataset: "none",
71
- usage: true,
72
- });
73
-
74
- expect(chunks.map((chunk) => chunk.type)).toEqual([
75
- "text",
76
- "text",
77
- "usage",
78
- "done",
79
- ]);
80
- });
81
-
82
- it("is used by createHandler for built-in asksage provider id", () => {
83
- const handler = createHandler({
84
- providerId: "asksage",
85
- modelId: "gpt-4o",
86
- apiKey: "ask-key",
87
- });
88
- expect(handler).toBeInstanceOf(AskSageHandler);
89
- });
90
-
91
- it("throws when API key is missing", async () => {
92
- const handler = new AskSageHandler({
93
- providerId: "asksage",
94
- modelId: "gpt-4o",
95
- });
96
-
97
- await expect(async () => {
98
- for await (const _chunk of handler.createMessage("system", [])) {
99
- // noop
100
- }
101
- }).rejects.toThrow("AskSage API key is required");
102
- });
103
- });
@@ -1,138 +0,0 @@
1
- import type { ApiStream, HandlerModelInfo, ProviderConfig } from "../types";
2
- import type { ContentBlock, Message } from "../types/messages";
3
- import { resolveApiKeyForProvider } from "./auth";
4
- import { FetchBaseHandler } from "./fetch-base";
5
-
6
- export const DEFAULT_ASKSAGE_BASE_URL = "https://api.asksage.ai/server";
7
- const DEFAULT_ASKSAGE_MODEL_ID = "gpt-4o";
8
-
9
- type AskSageRequest = {
10
- system_prompt: string;
11
- message: Array<{
12
- user: "gpt" | "me";
13
- message: string;
14
- }>;
15
- model: string;
16
- dataset: "none";
17
- usage: boolean;
18
- };
19
-
20
- type AskSageUsage = {
21
- model_tokens: {
22
- completion_tokens: number;
23
- prompt_tokens: number;
24
- total_tokens: number;
25
- };
26
- asksage_tokens: number;
27
- };
28
-
29
- type AskSageResponse = {
30
- message?: string;
31
- usage?: AskSageUsage | null;
32
- tool_responses?: unknown[];
33
- };
34
-
35
- export class AskSageHandler extends FetchBaseHandler {
36
- protected getDefaultBaseUrl(): string {
37
- return DEFAULT_ASKSAGE_BASE_URL;
38
- }
39
-
40
- getModel(): HandlerModelInfo {
41
- const modelId = this.config.modelId?.trim() || DEFAULT_ASKSAGE_MODEL_ID;
42
- const modelInfo = this.config.modelInfo ??
43
- this.config.knownModels?.[modelId] ?? {
44
- id: modelId,
45
- capabilities: ["tools"],
46
- };
47
- return { id: modelId, info: { ...modelInfo, id: modelId } };
48
- }
49
-
50
- protected getJsonHeaders(
51
- extra?: Record<string, string>,
52
- ): Record<string, string> {
53
- const apiKey = resolveApiKeyForProvider(
54
- this.config.providerId,
55
- this.config.apiKey,
56
- );
57
- if (!apiKey) {
58
- throw new Error("AskSage API key is required");
59
- }
60
- return super.getJsonHeaders({
61
- "x-access-tokens": apiKey,
62
- ...(extra ?? {}),
63
- });
64
- }
65
-
66
- protected async *createMessageWithFetch(
67
- systemPrompt: string,
68
- messages: Message[],
69
- ): ApiStream {
70
- const responseId = this.createResponseId();
71
- const { id: modelId } = this.getModel();
72
-
73
- const payload: AskSageRequest = {
74
- system_prompt: systemPrompt,
75
- message: messages.map((message) => ({
76
- user: message.role === "assistant" ? "gpt" : "me",
77
- message: this.serializeMessageContent(message.content),
78
- })),
79
- model: modelId,
80
- dataset: "none",
81
- usage: true,
82
- };
83
-
84
- let result: AskSageResponse;
85
- try {
86
- result = await this.fetchJson<AskSageResponse>("/query", {
87
- method: "POST",
88
- body: payload,
89
- });
90
- } catch (error) {
91
- const details = error instanceof Error ? error.message : String(error);
92
- throw new Error(`AskSage request failed: ${details}`);
93
- }
94
-
95
- for (const toolResponse of result.tool_responses ?? []) {
96
- yield {
97
- type: "text",
98
- text: `[Tool Response: ${JSON.stringify(toolResponse)}]\n`,
99
- id: responseId,
100
- };
101
- }
102
-
103
- const text = result.message?.trim();
104
- if (!text) {
105
- throw new Error("AskSage request failed: no content in response");
106
- }
107
-
108
- yield { type: "text", text, id: responseId };
109
-
110
- if (result.usage) {
111
- yield {
112
- type: "usage",
113
- inputTokens: result.usage.model_tokens.prompt_tokens,
114
- outputTokens: result.usage.model_tokens.completion_tokens,
115
- cacheReadTokens: 0,
116
- cacheWriteTokens: 0,
117
- totalCost: result.usage.asksage_tokens,
118
- id: responseId,
119
- };
120
- }
121
-
122
- yield { type: "done", success: true, id: responseId };
123
- }
124
-
125
- private serializeMessageContent(content: string | ContentBlock[]): string {
126
- if (typeof content === "string") {
127
- return content;
128
- }
129
- return content
130
- .map((block) => ("text" in block ? block.text : ""))
131
- .join("")
132
- .trim();
133
- }
134
- }
135
-
136
- export function createAskSageHandler(config: ProviderConfig): AskSageHandler {
137
- return new AskSageHandler(config);
138
- }
@@ -1,19 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { resolveApiKeyForProvider } from "./auth";
3
-
4
- describe("resolveApiKeyForProvider", () => {
5
- it("returns noop for lmstudio when no key is provided", () => {
6
- const apiKey = resolveApiKeyForProvider("lmstudio", undefined, {});
7
- expect(apiKey).toBe("noop");
8
- });
9
-
10
- it("prefers explicit api keys over provider defaults", () => {
11
- const apiKey = resolveApiKeyForProvider("lmstudio", "real-key", {});
12
- expect(apiKey).toBe("real-key");
13
- });
14
-
15
- it("does not apply lmstudio fallback to zai", () => {
16
- const apiKey = resolveApiKeyForProvider("zai", undefined, {});
17
- expect(apiKey).toBeUndefined();
18
- });
19
- });