@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,472 +0,0 @@
1
- /**
2
- * Stream Response Processor
3
- *
4
- * Processes ApiStreamChunks and assembles them into Cline's message content format.
5
- * This provides a clean interface between the streaming API and Cline's storage format.
6
- */
7
-
8
- import { parseJsonStream } from "@clinebot/shared";
9
- import { JSONParser } from "@streamparser/json";
10
- import type {
11
- ApiStreamChunk,
12
- ApiStreamReasoningChunk,
13
- ApiStreamTextChunk,
14
- ApiStreamToolCallsChunk,
15
- ApiStreamUsageChunk,
16
- } from "../types/stream";
17
-
18
- // ============================================================================
19
- // Output Types (Cline Storage Format)
20
- // ============================================================================
21
-
22
- export interface ReasoningDetailParam {
23
- type: "reasoning.text" | string;
24
- text: string;
25
- signature: string;
26
- format: "anthropic-claude-v1" | string;
27
- index: number;
28
- }
29
-
30
- export interface AssistantTextBlock {
31
- type: "text";
32
- text: string;
33
- call_id?: string;
34
- reasoning_details?: ReasoningDetailParam[];
35
- signature?: string;
36
- }
37
-
38
- export interface AssistantToolUseBlock {
39
- type: "tool_use";
40
- id: string;
41
- name: string;
42
- input: Record<string, unknown>;
43
- call_id?: string;
44
- reasoning_details?: ReasoningDetailParam[];
45
- signature?: string;
46
- }
47
-
48
- export interface AssistantThinkingBlock {
49
- type: "thinking";
50
- thinking: string;
51
- signature: string;
52
- call_id?: string;
53
- summary?: ReasoningDetailParam[];
54
- }
55
-
56
- export interface AssistantRedactedThinkingBlock {
57
- type: "redacted_thinking";
58
- data: string;
59
- call_id?: string;
60
- }
61
-
62
- export type AssistantContentBlock =
63
- | AssistantTextBlock
64
- | AssistantToolUseBlock
65
- | AssistantThinkingBlock
66
- | AssistantRedactedThinkingBlock;
67
-
68
- export interface UsageInfo {
69
- inputTokens: number;
70
- outputTokens: number;
71
- cacheWriteTokens?: number;
72
- cacheReadTokens?: number;
73
- thoughtsTokenCount?: number;
74
- totalCost?: number;
75
- }
76
-
77
- export interface ProcessedResponse {
78
- content: AssistantContentBlock[];
79
- usage?: UsageInfo;
80
- responseId?: string;
81
- incompleteReason?: string;
82
- }
83
-
84
- // ============================================================================
85
- // Internal State
86
- // ============================================================================
87
-
88
- interface PendingToolUse {
89
- id: string;
90
- name: string;
91
- rawInput: string;
92
- parsedInput?: Record<string, unknown>;
93
- signature?: string;
94
- callId: string;
95
- parser: JSONParser;
96
- }
97
-
98
- interface PendingReasoning {
99
- thinking: string;
100
- signature: string;
101
- details: ReasoningDetailParam[];
102
- redactedBlocks: AssistantRedactedThinkingBlock[];
103
- callId?: string;
104
- }
105
-
106
- // ============================================================================
107
- // Stream Response Processor
108
- // ============================================================================
109
-
110
- /**
111
- * Processes streaming API responses and assembles content blocks.
112
- *
113
- * Usage:
114
- * ```ts
115
- * const processor = new StreamResponseProcessor()
116
- * for await (const chunk of apiStream) {
117
- * const partial = processor.process(chunk)
118
- * // Use partial for live updates
119
- * }
120
- * const final = processor.finalize()
121
- * ```
122
- */
123
- export class StreamResponseProcessor {
124
- private text = "";
125
- private textSignature?: string;
126
- private toolUses = new Map<string, PendingToolUse>();
127
- private reasoning: PendingReasoning | null = null;
128
- private usage: UsageInfo | null = null;
129
- private responseId?: string;
130
- private incompleteReason?: string;
131
-
132
- /**
133
- * Process a single stream chunk and return current partial state.
134
- * Call this for each chunk to get live updates.
135
- */
136
- process(chunk: ApiStreamChunk): ProcessedResponse {
137
- switch (chunk.type) {
138
- case "text":
139
- this.processText(chunk);
140
- break;
141
- case "reasoning":
142
- this.processReasoning(chunk);
143
- break;
144
- case "tool_calls":
145
- this.processToolCall(chunk);
146
- break;
147
- case "usage":
148
- this.processUsage(chunk);
149
- break;
150
- case "done":
151
- this.incompleteReason = chunk.incompleteReason;
152
- if (chunk.id) this.responseId = chunk.id;
153
- break;
154
- }
155
-
156
- return this.getPartialResponse();
157
- }
158
-
159
- /**
160
- * Finalize and return the complete response.
161
- * Call this after all chunks have been processed.
162
- */
163
- finalize(): ProcessedResponse {
164
- const content: AssistantContentBlock[] = [];
165
-
166
- // Add thinking block if present
167
- if (
168
- this.reasoning &&
169
- (this.reasoning.thinking || this.reasoning.details.length)
170
- ) {
171
- content.push({
172
- type: "thinking",
173
- thinking: this.reasoning.thinking,
174
- signature: this.reasoning.signature,
175
- call_id: this.reasoning.callId,
176
- summary: this.reasoning.details.length
177
- ? this.reasoning.details
178
- : undefined,
179
- });
180
-
181
- // Add any redacted thinking blocks
182
- content.push(...this.reasoning.redactedBlocks);
183
- }
184
-
185
- // Add text if present
186
- if (this.text) {
187
- content.push({
188
- type: "text",
189
- text: this.text,
190
- signature: this.textSignature,
191
- reasoning_details: this.reasoning?.details.length
192
- ? this.reasoning.details
193
- : undefined,
194
- });
195
- }
196
-
197
- // Add finalized tool uses
198
- for (const pending of this.toolUses.values()) {
199
- if (!pending.name) continue;
200
-
201
- const input = this.finalizeToolInput(pending);
202
- content.push({
203
- type: "tool_use",
204
- id: pending.id,
205
- name: pending.name,
206
- input,
207
- call_id: pending.callId,
208
- signature: pending.signature,
209
- reasoning_details: this.reasoning?.details.length
210
- ? this.reasoning.details
211
- : undefined,
212
- });
213
- }
214
-
215
- return {
216
- content,
217
- usage: this.usage ?? undefined,
218
- responseId: this.responseId,
219
- incompleteReason: this.incompleteReason,
220
- };
221
- }
222
-
223
- /**
224
- * Get current partial response for live streaming updates.
225
- */
226
- getPartialResponse(): ProcessedResponse {
227
- const content: AssistantContentBlock[] = [];
228
-
229
- // Add partial thinking
230
- if (
231
- this.reasoning &&
232
- (this.reasoning.thinking || this.reasoning.details.length)
233
- ) {
234
- content.push({
235
- type: "thinking",
236
- thinking: this.reasoning.thinking,
237
- signature: this.reasoning.signature,
238
- call_id: this.reasoning.callId,
239
- summary: this.reasoning.details.length
240
- ? this.reasoning.details
241
- : undefined,
242
- });
243
- }
244
-
245
- // Add partial text
246
- if (this.text) {
247
- content.push({
248
- type: "text",
249
- text: this.text,
250
- signature: this.textSignature,
251
- });
252
- }
253
-
254
- // Add partial tool uses
255
- for (const pending of this.toolUses.values()) {
256
- if (!pending.name) continue;
257
-
258
- const input =
259
- pending.parsedInput ?? this.extractPartialJson(pending.rawInput);
260
- content.push({
261
- type: "tool_use",
262
- id: pending.id,
263
- name: pending.name,
264
- input,
265
- call_id: pending.callId,
266
- signature: pending.signature,
267
- });
268
- }
269
-
270
- return {
271
- content,
272
- usage: this.usage ?? undefined,
273
- responseId: this.responseId,
274
- };
275
- }
276
-
277
- /**
278
- * Reset processor state for reuse.
279
- */
280
- reset(): void {
281
- this.text = "";
282
- this.textSignature = undefined;
283
- this.toolUses.clear();
284
- this.reasoning = null;
285
- this.usage = null;
286
- this.responseId = undefined;
287
- this.incompleteReason = undefined;
288
- }
289
-
290
- // ============================================================================
291
- // Private Methods
292
- // ============================================================================
293
-
294
- private processText(chunk: ApiStreamTextChunk): void {
295
- this.text += chunk.text;
296
- if (chunk.signature) this.textSignature = chunk.signature;
297
- if (chunk.id) this.responseId = chunk.id;
298
- }
299
-
300
- private processReasoning(chunk: ApiStreamReasoningChunk): void {
301
- if (!this.reasoning) {
302
- this.reasoning = {
303
- thinking: "",
304
- signature: "",
305
- details: [],
306
- redactedBlocks: [],
307
- callId: chunk.id,
308
- };
309
- }
310
-
311
- if (chunk.reasoning) {
312
- this.reasoning.thinking += chunk.reasoning;
313
- }
314
-
315
- if (chunk.signature) {
316
- this.reasoning.signature = chunk.signature;
317
- }
318
-
319
- if (chunk.details) {
320
- const details = Array.isArray(chunk.details)
321
- ? chunk.details
322
- : [chunk.details];
323
- for (const detail of details) {
324
- if (this.isReasoningDetail(detail)) {
325
- this.reasoning.details.push(detail);
326
- // Extract signature from details if not set at top level
327
- if (!this.reasoning.signature && detail.signature) {
328
- this.reasoning.signature = detail.signature;
329
- }
330
- }
331
- }
332
- }
333
-
334
- if (chunk.redacted_data) {
335
- this.reasoning.redactedBlocks.push({
336
- type: "redacted_thinking",
337
- data: chunk.redacted_data,
338
- call_id: chunk.id ?? this.reasoning.callId,
339
- });
340
- }
341
-
342
- if (chunk.id) this.responseId = chunk.id;
343
- }
344
-
345
- private processToolCall(chunk: ApiStreamToolCallsChunk): void {
346
- const tc = chunk.tool_call;
347
- const fn = tc.function;
348
- const id = fn.id ?? tc.call_id ?? "";
349
-
350
- if (!id) return;
351
-
352
- let pending = this.toolUses.get(id);
353
- if (!pending) {
354
- pending = this.createPendingToolUse(id, tc.call_id ?? id);
355
- this.toolUses.set(id, pending);
356
- }
357
-
358
- if (fn.name) {
359
- pending.name = fn.name;
360
- }
361
-
362
- if (chunk.signature) {
363
- pending.signature = chunk.signature;
364
- }
365
-
366
- if (fn.arguments) {
367
- const args =
368
- typeof fn.arguments === "string"
369
- ? fn.arguments
370
- : JSON.stringify(fn.arguments);
371
- pending.rawInput += args;
372
- try {
373
- pending.parser.write(args);
374
- } catch {
375
- // Expected during streaming - parser may not have complete JSON
376
- }
377
- }
378
-
379
- if (chunk.id) this.responseId = chunk.id;
380
- }
381
-
382
- private processUsage(chunk: ApiStreamUsageChunk): void {
383
- this.usage = {
384
- inputTokens: chunk.inputTokens,
385
- outputTokens: chunk.outputTokens,
386
- cacheWriteTokens: chunk.cacheWriteTokens,
387
- cacheReadTokens: chunk.cacheReadTokens,
388
- thoughtsTokenCount: chunk.thoughtsTokenCount,
389
- totalCost: chunk.totalCost,
390
- };
391
- if (chunk.id) this.responseId = chunk.id;
392
- }
393
-
394
- private createPendingToolUse(id: string, callId: string): PendingToolUse {
395
- const pending: PendingToolUse = {
396
- id,
397
- name: "",
398
- rawInput: "",
399
- parsedInput: undefined,
400
- signature: undefined,
401
- callId,
402
- parser: new JSONParser(),
403
- };
404
-
405
- pending.parser.onValue = (info: { stack: unknown[]; value?: unknown }) => {
406
- if (
407
- info.stack.length === 0 &&
408
- info.value &&
409
- typeof info.value === "object"
410
- ) {
411
- pending.parsedInput = info.value as Record<string, unknown>;
412
- }
413
- };
414
- pending.parser.onError = () => {};
415
-
416
- return pending;
417
- }
418
-
419
- private finalizeToolInput(pending: PendingToolUse): Record<string, unknown> {
420
- if (pending.parsedInput) {
421
- return pending.parsedInput;
422
- }
423
-
424
- if (pending.rawInput) {
425
- const parsed = parseJsonStream(pending.rawInput);
426
- if (this.isRecord(parsed)) {
427
- return parsed;
428
- }
429
-
430
- return this.extractPartialJson(pending.rawInput);
431
- }
432
-
433
- return {};
434
- }
435
-
436
- /**
437
- * Extract fields from incomplete JSON during streaming.
438
- */
439
- private extractPartialJson(partial: string): Record<string, unknown> {
440
- const result: Record<string, unknown> = {};
441
- const pattern = /"(\w+)":\s*"((?:[^"\\]|\\.)*)(?:")?/g;
442
-
443
- for (const match of partial.matchAll(pattern)) {
444
- result[match[1]] = this.unescapeString(match[2]);
445
- }
446
-
447
- return result;
448
- }
449
-
450
- private unescapeString(str: string): string {
451
- return str
452
- .replace(/\\n/g, "\n")
453
- .replace(/\\t/g, "\t")
454
- .replace(/\\r/g, "\r")
455
- .replace(/\\"/g, '"')
456
- .replace(/\\\\/g, "\\");
457
- }
458
-
459
- private isReasoningDetail(value: unknown): value is ReasoningDetailParam {
460
- return (
461
- typeof value === "object" &&
462
- value !== null &&
463
- "type" in value &&
464
- "text" in value &&
465
- typeof (value as ReasoningDetailParam).text === "string"
466
- );
467
- }
468
-
469
- private isRecord(value: unknown): value is Record<string, unknown> {
470
- return typeof value === "object" && value !== null && !Array.isArray(value);
471
- }
472
- }
@@ -1,235 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { getOpenAIToolParams } from "../transform/openai-format";
3
- import { ToolCallProcessor } from "./tool-processor";
4
-
5
- describe("ToolCallProcessor", () => {
6
- it("emits delta arguments (not cumulative) so downstream can accumulate once", () => {
7
- const processor = new ToolCallProcessor();
8
-
9
- const first = processor.processToolCallDeltas(
10
- [
11
- {
12
- index: 0,
13
- id: "call_1",
14
- function: { name: "run_commands", arguments: '{"commands":["ls' },
15
- },
16
- ],
17
- "resp_1",
18
- );
19
-
20
- const second = processor.processToolCallDeltas(
21
- [
22
- {
23
- index: 0,
24
- function: { arguments: ' -la"]}' },
25
- },
26
- ],
27
- "resp_1",
28
- );
29
-
30
- expect(first).toHaveLength(1);
31
- expect(second).toHaveLength(1);
32
- expect(first[0].tool_call.function.arguments).toBe('{"commands":["ls');
33
- expect(second[0].tool_call.function.arguments).toBe(' -la"]}');
34
- });
35
-
36
- it("normalizes cumulative argument snapshots into deltas", () => {
37
- const processor = new ToolCallProcessor();
38
-
39
- const first = processor.processToolCallDeltas(
40
- [
41
- {
42
- index: 0,
43
- id: "call_1",
44
- function: { name: "editor", arguments: '{"command":"create"' },
45
- },
46
- ],
47
- "resp_1",
48
- );
49
-
50
- const second = processor.processToolCallDeltas(
51
- [
52
- {
53
- index: 0,
54
- function: {
55
- arguments: '{"command":"create","path":"/tmp/file.txt"}',
56
- },
57
- },
58
- ],
59
- "resp_1",
60
- );
61
-
62
- expect(first).toHaveLength(1);
63
- expect(second).toHaveLength(1);
64
- expect(first[0].tool_call.function.arguments).toBe('{"command":"create"');
65
- expect(second[0].tool_call.function.arguments).toBe(
66
- ',"path":"/tmp/file.txt"}',
67
- );
68
- });
69
-
70
- it("serializes object-shaped arguments instead of concatenating [object Object]", () => {
71
- const processor = new ToolCallProcessor();
72
-
73
- const result = processor.processToolCallDeltas(
74
- [
75
- {
76
- index: 0,
77
- id: "call_1",
78
- function: {
79
- name: "editor",
80
- arguments: {
81
- command: "create",
82
- path: "/tmp/file.txt",
83
- },
84
- },
85
- },
86
- ],
87
- "resp_1",
88
- );
89
-
90
- expect(result).toHaveLength(1);
91
- expect(result[0].tool_call.function.arguments).toBe(
92
- '{"command":"create","path":"/tmp/file.txt"}',
93
- );
94
- });
95
-
96
- it("preserves tool call id/name for interleaved parallel deltas", () => {
97
- const processor = new ToolCallProcessor();
98
-
99
- const firstChunk = [
100
- {
101
- index: 0,
102
- id: "call_a",
103
- function: { name: "read_file" },
104
- },
105
- {
106
- index: 1,
107
- id: "call_b",
108
- function: { name: "search_files" },
109
- },
110
- ];
111
-
112
- const secondChunk = [
113
- {
114
- index: 1,
115
- function: { arguments: '{"path":"src"}' },
116
- },
117
- {
118
- index: 0,
119
- function: { arguments: '{"path":"README.md"}' },
120
- },
121
- ];
122
-
123
- const firstResult = processor.processToolCallDeltas(firstChunk, "resp_1");
124
- const secondResult = processor.processToolCallDeltas(secondChunk, "resp_1");
125
-
126
- // Current implementation emits tool call chunks once id+name are known,
127
- // even before argument deltas arrive.
128
- expect(firstResult).toHaveLength(2);
129
- expect(secondResult).toHaveLength(2);
130
-
131
- // Intentionally reversed from the setup chunk: output follows incoming
132
- // argument-delta order while reconstruction remains index-safe.
133
- const firstToolCall = secondResult[0].tool_call;
134
- const secondToolCall = secondResult[1].tool_call;
135
-
136
- expect(firstToolCall.function.id).toBe("call_b");
137
- expect(firstToolCall.function.name).toBe("search_files");
138
- expect(firstToolCall.function.arguments).toBe('{"path":"src"}');
139
-
140
- expect(secondToolCall.function.id).toBe("call_a");
141
- expect(secondToolCall.function.name).toBe("read_file");
142
- expect(secondToolCall.function.arguments).toBe('{"path":"README.md"}');
143
- });
144
-
145
- it("clears accumulated state on reset", () => {
146
- const processor = new ToolCallProcessor();
147
-
148
- const setupChunk = [
149
- {
150
- index: 0,
151
- id: "call_reset",
152
- function: { name: "read_file" },
153
- },
154
- ];
155
-
156
- const argsChunk = [
157
- {
158
- index: 0,
159
- function: { arguments: '{"path":"after-reset"}' },
160
- },
161
- ];
162
-
163
- expect(processor.processToolCallDeltas(setupChunk, "resp_1")).toHaveLength(
164
- 1,
165
- );
166
- processor.reset();
167
- expect(processor.processToolCallDeltas(argsChunk, "resp_1")).toHaveLength(
168
- 0,
169
- );
170
-
171
- const newSetupChunk = [
172
- {
173
- index: 0,
174
- id: "call_new",
175
- function: { name: "write_file" },
176
- },
177
- ];
178
-
179
- const newArgsChunk = [
180
- {
181
- index: 0,
182
- function: { arguments: '{"path":"file.txt"}' },
183
- },
184
- ];
185
-
186
- expect(
187
- processor.processToolCallDeltas(newSetupChunk, "resp_1"),
188
- ).toHaveLength(1);
189
- expect(
190
- processor.processToolCallDeltas(newArgsChunk, "resp_1"),
191
- ).toHaveLength(1);
192
- });
193
- });
194
-
195
- describe("getOpenAIToolParams", () => {
196
- it("returns tools and tool_choice when tools are present", () => {
197
- const tools = [
198
- {
199
- name: "read_file",
200
- description: "",
201
- inputSchema: { type: "object" },
202
- },
203
- ];
204
-
205
- const params = getOpenAIToolParams(tools);
206
-
207
- expect(params.tools).toHaveLength(1);
208
- expect(params.tool_choice).toBe("auto");
209
- expect(params).not.toHaveProperty("parallel_tool_calls");
210
- });
211
-
212
- it("returns empty object when tools are absent", () => {
213
- const params = getOpenAIToolParams(undefined);
214
-
215
- expect(params).toEqual({});
216
- expect(params).not.toHaveProperty("parallel_tool_calls");
217
- });
218
-
219
- it("supports strict option passthrough", () => {
220
- const tools = [
221
- {
222
- name: "read_file",
223
- description: "",
224
- inputSchema: { type: "object" },
225
- },
226
- ];
227
-
228
- const params = getOpenAIToolParams(tools, { strict: false });
229
-
230
- expect(params.tools?.[0]).toMatchObject({
231
- type: "function",
232
- function: { strict: false },
233
- });
234
- });
235
- });