@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,413 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import type { Message } from "../types/messages";
3
- import {
4
- convertToAnthropicMessages,
5
- convertToGeminiMessages,
6
- convertToOpenAIMessages,
7
- convertToolsToAnthropic,
8
- convertToolsToGemini,
9
- convertToolsToOpenAI,
10
- convertToR1Messages,
11
- } from "./index";
12
-
13
- describe("format conversion", () => {
14
- it("converts file content blocks to text for user and tool_result payloads", () => {
15
- const fileText =
16
- '<file_content path="/repo/README.md">\nhello from file\n</file_content>';
17
- const messages: Message[] = [
18
- {
19
- role: "user",
20
- content: [
21
- { type: "file", path: "/repo/README.md", content: "hello from file" },
22
- ],
23
- },
24
- {
25
- role: "assistant",
26
- content: [
27
- {
28
- type: "tool_use",
29
- id: "call_1",
30
- name: "read_file",
31
- input: { path: "/repo/README.md" },
32
- },
33
- ],
34
- },
35
- {
36
- role: "user",
37
- content: [
38
- {
39
- type: "tool_result",
40
- tool_use_id: "call_1",
41
- content: [
42
- {
43
- type: "file",
44
- path: "/repo/README.md",
45
- content: "hello from file",
46
- },
47
- ],
48
- },
49
- ],
50
- },
51
- ];
52
-
53
- const openai = convertToOpenAIMessages(messages) as any[];
54
- expect(openai[0]).toMatchObject({ role: "user", content: fileText });
55
- expect(openai[2]).toMatchObject({ role: "tool", content: fileText });
56
-
57
- const gemini = convertToGeminiMessages(messages) as any[];
58
- expect(gemini[0]?.parts?.[0]?.text).toBe(fileText);
59
- expect(gemini[1]?.parts?.[0]?.functionCall?.id).toBe("call_1");
60
- expect(gemini[2]?.parts?.[0]?.functionResponse?.response?.result).toBe(
61
- fileText,
62
- );
63
- expect(gemini[2]?.parts?.[0]?.functionResponse?.id).toBe("call_1");
64
- expect(gemini[2]?.parts?.[0]?.functionResponse?.name).toBe("read_file");
65
-
66
- const anthropic = convertToAnthropicMessages(messages) as any[];
67
- expect(anthropic[0]?.content?.[0]).toMatchObject({
68
- type: "text",
69
- text: fileText,
70
- });
71
- expect(anthropic[2]?.content?.[0]).toMatchObject({
72
- type: "tool_result",
73
- content: [{ type: "text", text: fileText }],
74
- });
75
-
76
- const r1 = convertToR1Messages(messages) as any[];
77
- expect(r1[0]).toMatchObject({ role: "user", content: fileText });
78
- expect(r1[2]).toMatchObject({ role: "tool", content: fileText });
79
- });
80
-
81
- it("replays gemini thought signatures on text/tool_use/thinking parts", () => {
82
- const messages: Message[] = [
83
- { role: "user", content: "start" },
84
- {
85
- role: "assistant",
86
- content: [
87
- {
88
- type: "tool_use",
89
- id: "call_1",
90
- name: "run_commands",
91
- input: { command: "echo hi" },
92
- signature: "sig-a",
93
- },
94
- { type: "thinking", thinking: "need to run", signature: "sig-think" },
95
- { type: "text", text: "done", signature: "sig-text" },
96
- ],
97
- },
98
- {
99
- role: "user",
100
- content: [
101
- { type: "tool_result", tool_use_id: "run_commands", content: "ok" },
102
- ],
103
- },
104
- ];
105
-
106
- const gemini = convertToGeminiMessages(messages);
107
- const assistant = gemini[1] as any;
108
- expect(assistant.role).toBe("model");
109
- expect(assistant.parts[0].functionCall.name).toBe("run_commands");
110
- expect(assistant.parts[0].functionCall.id).toBe("call_1");
111
- expect(assistant.parts[0].thoughtSignature).toBe("sig-a");
112
- expect(assistant.parts[1].thought).toBe(true);
113
- expect(assistant.parts[1].thoughtSignature).toBe("sig-think");
114
- expect(assistant.parts[2].text).toBe("done");
115
- expect(assistant.parts[2].thoughtSignature).toBe("sig-text");
116
- });
117
-
118
- it("maps out-of-order gemini tool results by call id", () => {
119
- const messages: Message[] = [
120
- { role: "user", content: "check both" },
121
- {
122
- role: "assistant",
123
- content: [
124
- {
125
- type: "tool_use",
126
- id: "call_1",
127
- name: "read_file",
128
- input: { path: "a.ts" },
129
- },
130
- {
131
- type: "tool_use",
132
- id: "call_2",
133
- name: "search_files",
134
- input: { query: "TODO" },
135
- },
136
- ],
137
- },
138
- {
139
- role: "user",
140
- content: [
141
- {
142
- type: "tool_result",
143
- tool_use_id: "call_2",
144
- content: '{"matches":1}',
145
- },
146
- {
147
- type: "tool_result",
148
- tool_use_id: "call_1",
149
- content: '{"text":"ok"}',
150
- },
151
- ],
152
- },
153
- ];
154
-
155
- const gemini = convertToGeminiMessages(messages) as any[];
156
- expect(gemini[2]?.parts?.[0]?.functionResponse).toMatchObject({
157
- id: "call_2",
158
- name: "search_files",
159
- response: { result: { matches: 1 } },
160
- });
161
- expect(gemini[2]?.parts?.[1]?.functionResponse).toMatchObject({
162
- id: "call_1",
163
- name: "read_file",
164
- response: { result: { text: "ok" } },
165
- });
166
- });
167
-
168
- it("converts multiple tool_result blocks for openai without dropping any", () => {
169
- const messages: Message[] = [
170
- { role: "user", content: "check both" },
171
- {
172
- role: "assistant",
173
- content: [
174
- {
175
- type: "tool_use",
176
- id: "call_1",
177
- name: "get_weather",
178
- input: { city: "Paris" },
179
- signature: "sig1",
180
- },
181
- {
182
- type: "tool_use",
183
- id: "call_2",
184
- name: "get_weather",
185
- input: { city: "London" },
186
- },
187
- ],
188
- },
189
- {
190
- role: "user",
191
- content: [
192
- {
193
- type: "tool_result",
194
- tool_use_id: "call_1",
195
- content: '{"temp":"15C"}',
196
- },
197
- {
198
- type: "tool_result",
199
- tool_use_id: "call_2",
200
- content: '{"temp":"12C"}',
201
- },
202
- { type: "text", text: "summarize now" },
203
- ],
204
- },
205
- ];
206
-
207
- const openai = convertToOpenAIMessages(messages) as any[];
208
- expect(openai).toHaveLength(5);
209
- expect(openai[1].role).toBe("assistant");
210
- expect(openai[1].tool_calls).toHaveLength(2);
211
- expect(openai[1].tool_calls[0].function.name).toBe("get_weather");
212
- expect(openai[2]).toMatchObject({ role: "tool", tool_call_id: "call_1" });
213
- expect(openai[3]).toMatchObject({ role: "tool", tool_call_id: "call_2" });
214
- expect(openai[4]).toMatchObject({ role: "user", content: "summarize now" });
215
- // Ensure Gemini-specific signature metadata does not leak into OpenAI messages.
216
- expect(openai[1].tool_calls[0].extra_content).toBeUndefined();
217
- });
218
-
219
- it("applies OpenAI cache markers only to the final user message", () => {
220
- const messages: Message[] = [
221
- { role: "user", content: "first prompt" },
222
- { role: "assistant", content: "intermediate response" },
223
- { role: "user", content: "second prompt" },
224
- ];
225
-
226
- const openai = convertToOpenAIMessages(messages, true) as any[];
227
- expect(openai[0]).toMatchObject({ role: "user", content: "first prompt" });
228
- expect(openai[2].role).toBe("user");
229
- expect(openai[2].content).toMatchObject([
230
- {
231
- type: "text",
232
- text: "second prompt",
233
- cache_control: { type: "ephemeral" },
234
- },
235
- ]);
236
-
237
- const cacheMarkerCount = openai
238
- .flatMap((message) =>
239
- Array.isArray(message.content) ? message.content : [],
240
- )
241
- .filter((part) => part?.cache_control?.type === "ephemeral").length;
242
- expect(cacheMarkerCount).toBe(1);
243
- });
244
-
245
- it("normalizes array-shaped tool_use input for openai replay", () => {
246
- const messages: Message[] = [
247
- { role: "user", content: "run these" },
248
- {
249
- role: "assistant",
250
- content: [
251
- {
252
- type: "tool_use",
253
- id: "call_1",
254
- name: "run_commands",
255
- input: ["ls -la", "pwd"] as unknown as Record<string, unknown>,
256
- },
257
- ],
258
- },
259
- ];
260
-
261
- const openai = convertToOpenAIMessages(messages) as any[];
262
- expect(openai[1]?.tool_calls?.[0]).toMatchObject({
263
- id: "call_1",
264
- type: "function",
265
- function: {
266
- name: "run_commands",
267
- arguments: JSON.stringify({ commands: ["ls -la", "pwd"] }),
268
- },
269
- });
270
- });
271
-
272
- it("keeps anthropic thinking signature and cache marker behavior", () => {
273
- const messages: Message[] = [
274
- { role: "user", content: "hello" },
275
- {
276
- role: "assistant",
277
- content: [
278
- {
279
- type: "thinking",
280
- thinking: "reasoning",
281
- signature: "anthropic-sig",
282
- },
283
- ],
284
- },
285
- ];
286
-
287
- const anthropic = convertToAnthropicMessages(messages, true) as any[];
288
- expect(anthropic[0].content[0].cache_control).toEqual({
289
- type: "ephemeral",
290
- });
291
- expect(anthropic[1].content[0].type).toBe("thinking");
292
- expect(anthropic[1].content[0].signature).toBe("anthropic-sig");
293
- });
294
-
295
- it("applies anthropic cache markers to the last two user messages", () => {
296
- const messages: Message[] = [
297
- { role: "user", content: "first prompt" },
298
- { role: "assistant", content: "intermediate response" },
299
- { role: "user", content: "second prompt" },
300
- { role: "assistant", content: "another response" },
301
- { role: "user", content: "third prompt" },
302
- ];
303
-
304
- const anthropic = convertToAnthropicMessages(messages, true) as any[];
305
-
306
- expect(anthropic[0].content[0].cache_control).toBeUndefined();
307
- expect(anthropic[2].content[0].cache_control).toEqual({
308
- type: "ephemeral",
309
- });
310
- expect(anthropic[4].content[0].cache_control).toEqual({
311
- type: "ephemeral",
312
- });
313
- });
314
-
315
- it("normalizes array-shaped tool_use input for anthropic replay", () => {
316
- const messages: Message[] = [
317
- { role: "user", content: "run these" },
318
- {
319
- role: "assistant",
320
- content: [
321
- {
322
- type: "tool_use",
323
- id: "call_1",
324
- name: "run_commands",
325
- input: ["ls -la", "pwd"] as unknown as Record<string, unknown>,
326
- },
327
- ],
328
- },
329
- ];
330
-
331
- const anthropic = convertToAnthropicMessages(messages) as any[];
332
- expect(anthropic[1]?.content?.[0]).toMatchObject({
333
- type: "tool_use",
334
- id: "call_1",
335
- name: "run_commands",
336
- input: {
337
- commands: ["ls -la", "pwd"],
338
- },
339
- });
340
- });
341
-
342
- it("handles R1 interchange with tool results and reasoning_content", () => {
343
- const messages: Message[] = [
344
- { role: "user", content: "check weather" },
345
- {
346
- role: "assistant",
347
- content: [
348
- { type: "thinking", thinking: "need both cities" },
349
- {
350
- type: "tool_use",
351
- id: "call_1",
352
- name: "get_weather",
353
- input: { city: "Paris" },
354
- },
355
- {
356
- type: "tool_use",
357
- id: "call_2",
358
- name: "get_weather",
359
- input: { city: "London" },
360
- },
361
- ],
362
- },
363
- {
364
- role: "user",
365
- content: [
366
- {
367
- type: "tool_result",
368
- tool_use_id: "call_1",
369
- content: '{"temp":"15C"}',
370
- },
371
- {
372
- type: "tool_result",
373
- tool_use_id: "call_2",
374
- content: '{"temp":"12C"}',
375
- },
376
- ],
377
- },
378
- ];
379
-
380
- const r1 = convertToR1Messages(messages) as any[];
381
- expect(r1[1].role).toBe("assistant");
382
- expect(r1[1].tool_calls).toHaveLength(2);
383
- expect(r1[1].reasoning_content).toBe("need both cities");
384
- expect(r1[2]).toMatchObject({ role: "tool", tool_call_id: "call_1" });
385
- expect(r1[3]).toMatchObject({ role: "tool", tool_call_id: "call_2" });
386
- });
387
-
388
- it("converts tools for all providers", () => {
389
- const tools = [
390
- {
391
- name: "read_file",
392
- description: "Read file",
393
- inputSchema: {
394
- type: "object",
395
- properties: { path: { type: "string" } },
396
- },
397
- },
398
- ];
399
-
400
- expect(convertToolsToOpenAI(tools)[0]).toMatchObject({
401
- type: "function",
402
- function: { name: "read_file", strict: true },
403
- });
404
- expect(convertToolsToOpenAI(tools, { strict: false })[0]).toMatchObject({
405
- type: "function",
406
- function: { name: "read_file", strict: false },
407
- });
408
- expect(convertToolsToAnthropic(tools)[0]).toMatchObject({
409
- name: "read_file",
410
- });
411
- expect(convertToolsToGemini(tools)[0]).toMatchObject({ name: "read_file" });
412
- });
413
- });
@@ -1,262 +0,0 @@
1
- /**
2
- * Gemini Message Format Converter
3
- *
4
- * Converts our unified Message format to Google Gemini's Content format.
5
- */
6
-
7
- import { formatFileContentBlock, parseJsonStream } from "@clinebot/shared";
8
- import type { Content, FunctionDeclaration, Part } from "@google/genai";
9
- import type {
10
- ContentBlock,
11
- FileContent,
12
- ImageContent,
13
- Message,
14
- TextContent,
15
- ThinkingContent,
16
- ToolResultContent,
17
- ToolUseContent,
18
- } from "../types/messages";
19
- import {
20
- normalizeToolUseInput,
21
- serializeToolResultContent,
22
- } from "./content-format";
23
-
24
- /**
25
- * Convert messages to Gemini format
26
- */
27
- export function convertToGeminiMessages(messages: Message[]): Content[] {
28
- const toolNameByCallId = new Map<string, string>();
29
- return messages
30
- .map((message) => convertMessage(message, toolNameByCallId))
31
- .filter((m): m is Content => m !== null);
32
- }
33
-
34
- function convertMessage(
35
- message: Message,
36
- toolNameByCallId: Map<string, string>,
37
- ): Content | null {
38
- const { role, content } = message;
39
-
40
- // Map roles: Gemini uses "user" and "model"
41
- const geminiRole = role === "assistant" ? "model" : "user";
42
-
43
- // Simple string content
44
- if (typeof content === "string") {
45
- return {
46
- role: geminiRole,
47
- parts: [{ text: content }],
48
- };
49
- }
50
-
51
- // Array content
52
- const parts = convertContentBlocks(content, toolNameByCallId);
53
- if (parts.length === 0) {
54
- return null;
55
- }
56
-
57
- return {
58
- role: geminiRole,
59
- parts,
60
- };
61
- }
62
-
63
- function convertContentBlocks(
64
- content: ContentBlock[],
65
- toolNameByCallId: Map<string, string>,
66
- ): Part[] {
67
- const parts: Part[] = [];
68
-
69
- for (const block of content) {
70
- if (block.type === "tool_use") {
71
- toolNameByCallId.set(block.id, block.name);
72
- }
73
- const converted = convertContentBlock(block, toolNameByCallId);
74
- if (converted) {
75
- parts.push(converted);
76
- }
77
- }
78
-
79
- return parts;
80
- }
81
-
82
- function convertContentBlock(
83
- block: ContentBlock,
84
- toolNameByCallId: Map<string, string>,
85
- ): Part | null {
86
- switch (block.type) {
87
- case "text": {
88
- const textBlock = block as TextContent;
89
- const part: Part = { text: textBlock.text };
90
- if (textBlock.signature) {
91
- (part as any).thoughtSignature = textBlock.signature;
92
- }
93
- return part;
94
- }
95
-
96
- case "file": {
97
- const fileBlock = block as FileContent;
98
- const part: Part = {
99
- text: formatFileContentBlock(fileBlock.path, fileBlock.content),
100
- };
101
-
102
- return part;
103
- }
104
-
105
- case "image": {
106
- const imageBlock = block as ImageContent;
107
- return {
108
- inlineData: {
109
- mimeType: imageBlock.mediaType,
110
- data: imageBlock.data,
111
- },
112
- };
113
- }
114
-
115
- case "tool_use": {
116
- const toolBlock = block as ToolUseContent;
117
- const part: Part = {
118
- functionCall: {
119
- id: toolBlock.id,
120
- name: toolBlock.name,
121
- args: normalizeToolUseInput(toolBlock.input),
122
- },
123
- };
124
- if (toolBlock.signature) {
125
- (part as any).thoughtSignature = toolBlock.signature;
126
- }
127
- return part;
128
- }
129
-
130
- case "tool_result": {
131
- const resultBlock = block as ToolResultContent;
132
- let responseContent: Record<string, unknown>;
133
-
134
- if (typeof resultBlock.content === "string") {
135
- responseContent = { result: parseJsonStream(resultBlock.content) };
136
- } else {
137
- responseContent = {
138
- result: serializeToolResultContent(resultBlock.content),
139
- };
140
- }
141
-
142
- if (resultBlock.is_error) {
143
- responseContent.error = true;
144
- }
145
-
146
- return {
147
- functionResponse: {
148
- id: resultBlock.tool_use_id,
149
- name:
150
- toolNameByCallId.get(resultBlock.tool_use_id) ??
151
- resultBlock.tool_use_id,
152
- response: responseContent,
153
- },
154
- };
155
- }
156
-
157
- case "thinking": {
158
- const thinkingBlock = block as ThinkingContent;
159
- // Gemini uses thought: true to mark thinking blocks
160
- const part = {
161
- text: thinkingBlock.thinking,
162
- thought: true,
163
- } as Part;
164
- if (thinkingBlock.signature) {
165
- (part as any).thoughtSignature = thinkingBlock.signature;
166
- }
167
- return part;
168
- }
169
-
170
- default:
171
- return null;
172
- }
173
- }
174
-
175
- /**
176
- * Allowed JSON Schema properties per Gemini's supported subset.
177
- * See: https://ai.google.dev/gemini-api/docs/structured-output
178
- */
179
- const GEMINI_ALLOWED_PROPERTIES = new Set([
180
- // Common
181
- "type",
182
- "title",
183
- "description",
184
- "enum",
185
- // Object
186
- "properties",
187
- "required",
188
- "additionalProperties",
189
- // String
190
- "format",
191
- // Number / Integer
192
- "minimum",
193
- "maximum",
194
- // Array
195
- "items",
196
- "prefixItems",
197
- "minItems",
198
- "maxItems",
199
- ]);
200
-
201
- /**
202
- * Recursively sanitize a JSON Schema to only include properties supported by Gemini.
203
- * Converts exclusiveMinimum/exclusiveMaximum to minimum/maximum as a best-effort fallback.
204
- */
205
- function sanitizeSchemaForGemini(schema: unknown): unknown {
206
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
207
- return schema;
208
- }
209
-
210
- const input = schema as Record<string, unknown>;
211
- const output: Record<string, unknown> = {};
212
-
213
- for (const [key, value] of Object.entries(input)) {
214
- if (!GEMINI_ALLOWED_PROPERTIES.has(key)) {
215
- continue;
216
- }
217
-
218
- if (key === "properties" && value && typeof value === "object") {
219
- const sanitized: Record<string, unknown> = {};
220
- for (const [propName, propSchema] of Object.entries(
221
- value as Record<string, unknown>,
222
- )) {
223
- sanitized[propName] = sanitizeSchemaForGemini(propSchema);
224
- }
225
- output[key] = sanitized;
226
- } else if (key === "items" || key === "additionalProperties") {
227
- output[key] =
228
- typeof value === "object" && value !== null
229
- ? sanitizeSchemaForGemini(value)
230
- : value;
231
- } else if (key === "prefixItems" && Array.isArray(value)) {
232
- output[key] = value.map((item) => sanitizeSchemaForGemini(item));
233
- } else {
234
- output[key] = value;
235
- }
236
- }
237
-
238
- // Convert exclusiveMinimum/exclusiveMaximum to minimum/maximum
239
- if (input.exclusiveMinimum !== undefined && output.minimum === undefined) {
240
- output.minimum = input.exclusiveMinimum;
241
- }
242
- if (input.exclusiveMaximum !== undefined && output.maximum === undefined) {
243
- output.maximum = input.exclusiveMaximum;
244
- }
245
-
246
- return output;
247
- }
248
-
249
- /**
250
- * Convert tool definitions to Gemini format
251
- */
252
- export function convertToolsToGemini(
253
- tools: Array<{ name: string; description: string; inputSchema: unknown }>,
254
- ): FunctionDeclaration[] {
255
- return tools.map((tool) => ({
256
- name: tool.name,
257
- description: tool.description,
258
- parameters: sanitizeSchemaForGemini(
259
- tool.inputSchema,
260
- ) as FunctionDeclaration["parameters"],
261
- }));
262
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * Transform Module Index
3
- *
4
- * Re-exports all message format converters.
5
- */
6
-
7
- export {
8
- type AiSdkMessage,
9
- type AiSdkMessagePart,
10
- toAiSdkMessages,
11
- } from "./ai-sdk-community-format";
12
- export {
13
- convertToAnthropicMessages,
14
- convertToolsToAnthropic,
15
- } from "./anthropic-format";
16
- export { convertToGeminiMessages, convertToolsToGemini } from "./gemini-format";
17
- export {
18
- convertToOpenAIMessages,
19
- convertToolsToOpenAI,
20
- getOpenAIToolParams,
21
- } from "./openai-format";
22
- export { convertToR1Messages, type R1Message } from "./r1-format";