@clinebot/llms 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/README.md +198 -0
  2. package/dist/config-browser.d.ts +3 -0
  3. package/dist/config.d.ts +3 -0
  4. package/dist/index.browser.d.ts +4 -0
  5. package/dist/index.browser.js +1 -0
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.js +7 -0
  8. package/dist/models/generated-access.d.ts +4 -0
  9. package/dist/models/generated-provider-loaders.d.ts +13 -0
  10. package/dist/models/generated.d.ts +14 -0
  11. package/dist/models/index.d.ts +43 -0
  12. package/dist/models/models-dev-catalog.d.ts +32 -0
  13. package/dist/models/providers/aihubmix.d.ts +5 -0
  14. package/dist/models/providers/anthropic.d.ts +53 -0
  15. package/dist/models/providers/asksage.d.ts +5 -0
  16. package/dist/models/providers/baseten.d.ts +5 -0
  17. package/dist/models/providers/bedrock.d.ts +7 -0
  18. package/dist/models/providers/cerebras.d.ts +7 -0
  19. package/dist/models/providers/claude-code.d.ts +4 -0
  20. package/dist/models/providers/cline.d.ts +34 -0
  21. package/dist/models/providers/deepseek.d.ts +8 -0
  22. package/dist/models/providers/dify.d.ts +5 -0
  23. package/dist/models/providers/doubao.d.ts +7 -0
  24. package/dist/models/providers/fireworks.d.ts +8 -0
  25. package/dist/models/providers/gemini.d.ts +9 -0
  26. package/dist/models/providers/groq.d.ts +8 -0
  27. package/dist/models/providers/hicap.d.ts +5 -0
  28. package/dist/models/providers/huawei-cloud-maas.d.ts +5 -0
  29. package/dist/models/providers/huggingface.d.ts +6 -0
  30. package/dist/models/providers/index.d.ts +45 -0
  31. package/dist/models/providers/litellm.d.ts +5 -0
  32. package/dist/models/providers/lmstudio.d.ts +5 -0
  33. package/dist/models/providers/minimax.d.ts +7 -0
  34. package/dist/models/providers/mistral.d.ts +5 -0
  35. package/dist/models/providers/moonshot.d.ts +7 -0
  36. package/dist/models/providers/nebius.d.ts +7 -0
  37. package/dist/models/providers/nous-research.d.ts +7 -0
  38. package/dist/models/providers/oca.d.ts +9 -0
  39. package/dist/models/providers/ollama.d.ts +5 -0
  40. package/dist/models/providers/openai-codex.d.ts +10 -0
  41. package/dist/models/providers/openai.d.ts +9 -0
  42. package/dist/models/providers/opencode.d.ts +10 -0
  43. package/dist/models/providers/openrouter.d.ts +7 -0
  44. package/dist/models/providers/qwen-code.d.ts +7 -0
  45. package/dist/models/providers/qwen.d.ts +7 -0
  46. package/dist/models/providers/requesty.d.ts +6 -0
  47. package/dist/models/providers/sambanova.d.ts +7 -0
  48. package/dist/models/providers/sapaicore.d.ts +7 -0
  49. package/dist/models/providers/together.d.ts +8 -0
  50. package/dist/models/providers/vercel-ai-gateway.d.ts +5 -0
  51. package/dist/models/providers/vertex.d.ts +7 -0
  52. package/dist/models/providers/xai.d.ts +8 -0
  53. package/dist/models/providers/zai.d.ts +7 -0
  54. package/dist/models/query.d.ts +181 -0
  55. package/dist/models/registry.d.ts +123 -0
  56. package/dist/models/schemas/index.d.ts +7 -0
  57. package/dist/models/schemas/model.d.ts +340 -0
  58. package/dist/models/schemas/query.d.ts +191 -0
  59. package/dist/providers/handlers/ai-sdk-community.d.ts +46 -0
  60. package/dist/providers/handlers/ai-sdk-provider-base.d.ts +32 -0
  61. package/dist/providers/handlers/anthropic-base.d.ts +26 -0
  62. package/dist/providers/handlers/asksage.d.ts +12 -0
  63. package/dist/providers/handlers/auth.d.ts +5 -0
  64. package/dist/providers/handlers/base.d.ts +55 -0
  65. package/dist/providers/handlers/bedrock-base.d.ts +23 -0
  66. package/dist/providers/handlers/bedrock-client.d.ts +4 -0
  67. package/dist/providers/handlers/community-sdk.d.ts +97 -0
  68. package/dist/providers/handlers/fetch-base.d.ts +18 -0
  69. package/dist/providers/handlers/gemini-base.d.ts +25 -0
  70. package/dist/providers/handlers/index.d.ts +19 -0
  71. package/dist/providers/handlers/openai-base.d.ts +54 -0
  72. package/dist/providers/handlers/openai-responses.d.ts +64 -0
  73. package/dist/providers/handlers/providers.d.ts +43 -0
  74. package/dist/providers/handlers/r1-base.d.ts +62 -0
  75. package/dist/providers/handlers/registry.d.ts +106 -0
  76. package/dist/providers/handlers/vertex.d.ts +32 -0
  77. package/dist/providers/index.d.ts +100 -0
  78. package/dist/providers/public.browser.d.ts +2 -0
  79. package/dist/providers/public.d.ts +3 -0
  80. package/dist/providers/shared/openai-compatible.d.ts +10 -0
  81. package/dist/providers/transform/ai-sdk-community-format.d.ts +9 -0
  82. package/dist/providers/transform/anthropic-format.d.ts +24 -0
  83. package/dist/providers/transform/content-format.d.ts +3 -0
  84. package/dist/providers/transform/gemini-format.d.ts +19 -0
  85. package/dist/providers/transform/index.d.ts +10 -0
  86. package/dist/providers/transform/openai-format.d.ts +36 -0
  87. package/dist/providers/transform/r1-format.d.ts +26 -0
  88. package/dist/providers/types/config.d.ts +261 -0
  89. package/dist/providers/types/handler.d.ts +71 -0
  90. package/dist/providers/types/index.d.ts +11 -0
  91. package/dist/providers/types/messages.d.ts +139 -0
  92. package/dist/providers/types/model-info.d.ts +32 -0
  93. package/dist/providers/types/provider-ids.d.ts +63 -0
  94. package/dist/providers/types/settings.d.ts +308 -0
  95. package/dist/providers/types/stream.d.ts +106 -0
  96. package/dist/providers/utils/index.d.ts +7 -0
  97. package/dist/providers/utils/retry.d.ts +38 -0
  98. package/dist/providers/utils/stream-processor.d.ts +110 -0
  99. package/dist/providers/utils/tool-processor.d.ts +34 -0
  100. package/dist/sdk.d.ts +18 -0
  101. package/dist/types.d.ts +60 -0
  102. package/package.json +66 -0
  103. package/src/catalog.ts +20 -0
  104. package/src/config-browser.ts +11 -0
  105. package/src/config.ts +49 -0
  106. package/src/index.browser.ts +9 -0
  107. package/src/index.ts +10 -0
  108. package/src/live-providers.test.ts +137 -0
  109. package/src/models/generated-access.ts +41 -0
  110. package/src/models/generated-provider-loaders.ts +166 -0
  111. package/src/models/generated.ts +11997 -0
  112. package/src/models/index.ts +271 -0
  113. package/src/models/models-dev-catalog.test.ts +161 -0
  114. package/src/models/models-dev-catalog.ts +161 -0
  115. package/src/models/providers/aihubmix.ts +19 -0
  116. package/src/models/providers/anthropic.ts +60 -0
  117. package/src/models/providers/asksage.ts +19 -0
  118. package/src/models/providers/baseten.ts +21 -0
  119. package/src/models/providers/bedrock.ts +30 -0
  120. package/src/models/providers/cerebras.ts +24 -0
  121. package/src/models/providers/claude-code.ts +51 -0
  122. package/src/models/providers/cline.ts +25 -0
  123. package/src/models/providers/deepseek.ts +33 -0
  124. package/src/models/providers/dify.ts +17 -0
  125. package/src/models/providers/doubao.ts +33 -0
  126. package/src/models/providers/fireworks.ts +34 -0
  127. package/src/models/providers/gemini.ts +43 -0
  128. package/src/models/providers/groq.ts +33 -0
  129. package/src/models/providers/hicap.ts +18 -0
  130. package/src/models/providers/huawei-cloud-maas.ts +18 -0
  131. package/src/models/providers/huggingface.ts +22 -0
  132. package/src/models/providers/index.ts +162 -0
  133. package/src/models/providers/litellm.ts +19 -0
  134. package/src/models/providers/lmstudio.ts +22 -0
  135. package/src/models/providers/minimax.ts +34 -0
  136. package/src/models/providers/mistral.ts +19 -0
  137. package/src/models/providers/moonshot.ts +34 -0
  138. package/src/models/providers/nebius.ts +24 -0
  139. package/src/models/providers/nous-research.ts +21 -0
  140. package/src/models/providers/oca.ts +30 -0
  141. package/src/models/providers/ollama.ts +18 -0
  142. package/src/models/providers/openai-codex.ts +30 -0
  143. package/src/models/providers/openai.ts +43 -0
  144. package/src/models/providers/opencode.ts +28 -0
  145. package/src/models/providers/openrouter.ts +24 -0
  146. package/src/models/providers/qwen-code.ts +33 -0
  147. package/src/models/providers/qwen.ts +34 -0
  148. package/src/models/providers/requesty.ts +23 -0
  149. package/src/models/providers/sambanova.ts +23 -0
  150. package/src/models/providers/sapaicore.ts +34 -0
  151. package/src/models/providers/together.ts +35 -0
  152. package/src/models/providers/vercel-ai-gateway.ts +23 -0
  153. package/src/models/providers/vertex.ts +36 -0
  154. package/src/models/providers/xai.ts +34 -0
  155. package/src/models/providers/zai.ts +25 -0
  156. package/src/models/query.ts +407 -0
  157. package/src/models/registry.ts +511 -0
  158. package/src/models/schemas/index.ts +62 -0
  159. package/src/models/schemas/model.ts +308 -0
  160. package/src/models/schemas/query.ts +336 -0
  161. package/src/providers/browser.ts +4 -0
  162. package/src/providers/handlers/ai-sdk-community.ts +226 -0
  163. package/src/providers/handlers/ai-sdk-provider-base.ts +193 -0
  164. package/src/providers/handlers/anthropic-base.ts +372 -0
  165. package/src/providers/handlers/asksage.test.ts +103 -0
  166. package/src/providers/handlers/asksage.ts +138 -0
  167. package/src/providers/handlers/auth.test.ts +19 -0
  168. package/src/providers/handlers/auth.ts +121 -0
  169. package/src/providers/handlers/base.test.ts +46 -0
  170. package/src/providers/handlers/base.ts +160 -0
  171. package/src/providers/handlers/bedrock-base.ts +390 -0
  172. package/src/providers/handlers/bedrock-client.ts +100 -0
  173. package/src/providers/handlers/codex.test.ts +123 -0
  174. package/src/providers/handlers/community-sdk.test.ts +288 -0
  175. package/src/providers/handlers/community-sdk.ts +392 -0
  176. package/src/providers/handlers/fetch-base.ts +68 -0
  177. package/src/providers/handlers/gemini-base.ts +302 -0
  178. package/src/providers/handlers/index.ts +67 -0
  179. package/src/providers/handlers/openai-base.ts +277 -0
  180. package/src/providers/handlers/openai-responses.ts +598 -0
  181. package/src/providers/handlers/providers.test.ts +120 -0
  182. package/src/providers/handlers/providers.ts +563 -0
  183. package/src/providers/handlers/r1-base.ts +280 -0
  184. package/src/providers/handlers/registry.ts +185 -0
  185. package/src/providers/handlers/vertex.test.ts +124 -0
  186. package/src/providers/handlers/vertex.ts +292 -0
  187. package/src/providers/index.ts +534 -0
  188. package/src/providers/public.browser.ts +20 -0
  189. package/src/providers/public.ts +51 -0
  190. package/src/providers/shared/openai-compatible.ts +63 -0
  191. package/src/providers/transform/ai-sdk-community-format.test.ts +73 -0
  192. package/src/providers/transform/ai-sdk-community-format.ts +115 -0
  193. package/src/providers/transform/anthropic-format.ts +218 -0
  194. package/src/providers/transform/content-format.ts +34 -0
  195. package/src/providers/transform/format-conversion.test.ts +310 -0
  196. package/src/providers/transform/gemini-format.ts +167 -0
  197. package/src/providers/transform/index.ts +22 -0
  198. package/src/providers/transform/openai-format.ts +247 -0
  199. package/src/providers/transform/r1-format.ts +287 -0
  200. package/src/providers/types/config.ts +388 -0
  201. package/src/providers/types/handler.ts +87 -0
  202. package/src/providers/types/index.ts +120 -0
  203. package/src/providers/types/messages.ts +158 -0
  204. package/src/providers/types/model-info.test.ts +57 -0
  205. package/src/providers/types/model-info.ts +65 -0
  206. package/src/providers/types/provider-ids.test.ts +12 -0
  207. package/src/providers/types/provider-ids.ts +89 -0
  208. package/src/providers/types/settings.test.ts +49 -0
  209. package/src/providers/types/settings.ts +533 -0
  210. package/src/providers/types/stream.ts +117 -0
  211. package/src/providers/utils/index.ts +27 -0
  212. package/src/providers/utils/retry.test.ts +140 -0
  213. package/src/providers/utils/retry.ts +188 -0
  214. package/src/providers/utils/stream-processor.test.ts +232 -0
  215. package/src/providers/utils/stream-processor.ts +472 -0
  216. package/src/providers/utils/tool-processor.test.ts +34 -0
  217. package/src/providers/utils/tool-processor.ts +111 -0
  218. package/src/sdk.ts +264 -0
  219. package/src/types.ts +79 -0
@@ -0,0 +1,73 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import type { Message } from "../types/messages";
3
+ import { toAiSdkMessages } from "./ai-sdk-community-format";
4
+
5
+ describe("ai sdk community format conversion", () => {
6
+ it("converts file content to text and serializes tool_result file blocks", () => {
7
+ const messages: Message[] = [
8
+ {
9
+ role: "user",
10
+ content: [
11
+ { type: "file", path: "/repo/readme.md", content: "hello file body" },
12
+ ],
13
+ },
14
+ {
15
+ role: "assistant",
16
+ content: [
17
+ {
18
+ type: "tool_use",
19
+ id: "call_1",
20
+ name: "run_commands",
21
+ input: ["ls -la", "pwd"] as unknown as Record<string, unknown>,
22
+ },
23
+ ],
24
+ },
25
+ {
26
+ role: "user",
27
+ content: [
28
+ {
29
+ type: "tool_result",
30
+ tool_use_id: "call_1",
31
+ content: [
32
+ {
33
+ type: "file",
34
+ path: "/repo/readme.md",
35
+ content: "hello file body",
36
+ },
37
+ ],
38
+ },
39
+ ],
40
+ },
41
+ ];
42
+
43
+ const converted = toAiSdkMessages("system", messages);
44
+ expect(converted[0]).toMatchObject({ role: "system", content: "system" });
45
+ expect(converted[1]).toMatchObject({
46
+ role: "user",
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: '<file_content path="/repo/readme.md">\nhello file body\n</file_content>',
51
+ },
52
+ ],
53
+ });
54
+ const assistantParts = Array.isArray(converted[2]?.content)
55
+ ? converted[2].content
56
+ : [];
57
+ expect(assistantParts[0]).toMatchObject({
58
+ args: { commands: ["ls -la", "pwd"] },
59
+ });
60
+ expect(converted[3]).toMatchObject({
61
+ role: "tool",
62
+ content: [
63
+ {
64
+ type: "tool-result",
65
+ toolCallId: "call_1",
66
+ output:
67
+ '<file_content path="/repo/readme.md">\nhello file body\n</file_content>',
68
+ isError: false,
69
+ },
70
+ ],
71
+ });
72
+ });
73
+ });
@@ -0,0 +1,115 @@
1
+ import { formatFileContentBlock } from "@clinebot/shared";
2
+ import type { Message } from "../types/messages";
3
+ import {
4
+ normalizeToolUseInput,
5
+ serializeToolResultContent,
6
+ } from "./content-format";
7
+
8
+ export type AiSdkMessagePart = Record<string, unknown>;
9
+ export type AiSdkMessage = {
10
+ role: "system" | "user" | "assistant" | "tool";
11
+ content: string | AiSdkMessagePart[];
12
+ };
13
+
14
+ export function toAiSdkMessages(
15
+ systemContent: string | AiSdkMessagePart[],
16
+ messages: Message[],
17
+ options?: { assistantToolCallArgKey?: "args" | "input" },
18
+ ): AiSdkMessage[] {
19
+ const toolCallArgKey = options?.assistantToolCallArgKey ?? "args";
20
+ const result: AiSdkMessage[] = [{ role: "system", content: systemContent }];
21
+ const toolNamesById = new Map<string, string>();
22
+
23
+ for (const message of messages) {
24
+ if (typeof message.content === "string") {
25
+ result.push({ role: message.role, content: message.content });
26
+ continue;
27
+ }
28
+
29
+ if (message.role === "assistant") {
30
+ const parts: AiSdkMessagePart[] = [];
31
+ for (const block of message.content) {
32
+ if (block.type === "text") {
33
+ parts.push({ type: "text", text: block.text });
34
+ continue;
35
+ }
36
+
37
+ if (block.type === "file") {
38
+ parts.push({
39
+ type: "text",
40
+ text: formatFileContentBlock(block.path, block.content),
41
+ });
42
+ continue;
43
+ }
44
+
45
+ if (block.type === "tool_use") {
46
+ toolNamesById.set(block.id, block.name);
47
+ parts.push({
48
+ type: "tool-call",
49
+ toolCallId: block.id,
50
+ toolName: block.name,
51
+ [toolCallArgKey]: normalizeToolUseInput(block.input),
52
+ });
53
+ }
54
+ }
55
+
56
+ if (parts.length > 0) {
57
+ result.push({ role: "assistant", content: parts });
58
+ }
59
+ continue;
60
+ }
61
+
62
+ const userParts: AiSdkMessagePart[] = [];
63
+ for (const block of message.content) {
64
+ if (block.type === "text") {
65
+ userParts.push({ type: "text", text: block.text });
66
+ continue;
67
+ }
68
+
69
+ if (block.type === "file") {
70
+ userParts.push({
71
+ type: "text",
72
+ text: formatFileContentBlock(block.path, block.content),
73
+ });
74
+ continue;
75
+ }
76
+
77
+ if (block.type === "image") {
78
+ userParts.push({
79
+ type: "image",
80
+ image: Buffer.from(block.data, "base64"),
81
+ mediaType: block.mediaType,
82
+ });
83
+ continue;
84
+ }
85
+
86
+ if (block.type === "tool_result") {
87
+ if (userParts.length > 0) {
88
+ result.push({
89
+ role: "user",
90
+ content: userParts.splice(0, userParts.length),
91
+ });
92
+ }
93
+
94
+ result.push({
95
+ role: "tool",
96
+ content: [
97
+ {
98
+ type: "tool-result",
99
+ toolCallId: block.tool_use_id,
100
+ toolName: toolNamesById.get(block.tool_use_id) ?? "tool",
101
+ output: serializeToolResultContent(block.content),
102
+ isError: block.is_error ?? false,
103
+ },
104
+ ],
105
+ });
106
+ }
107
+ }
108
+
109
+ if (userParts.length > 0) {
110
+ result.push({ role: "user", content: userParts });
111
+ }
112
+ }
113
+
114
+ return result;
115
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Anthropic Message Format Converter
3
+ *
4
+ * Converts our unified Message format to Anthropic's MessageParam format.
5
+ */
6
+
7
+ import type { Anthropic } from "@anthropic-ai/sdk";
8
+ import { formatFileContentBlock } from "@clinebot/shared";
9
+ import type {
10
+ ContentBlock,
11
+ FileContent,
12
+ ImageContent,
13
+ Message,
14
+ RedactedThinkingContent,
15
+ TextContent,
16
+ ThinkingContent,
17
+ ToolResultContent,
18
+ ToolUseContent,
19
+ } from "../types/messages";
20
+ import { normalizeToolUseInput } from "./content-format";
21
+
22
+ type AnthropicMessage = Anthropic.MessageParam;
23
+ type AnthropicContentBlock = Anthropic.ContentBlockParam;
24
+
25
+ /**
26
+ * Convert messages to Anthropic format
27
+ *
28
+ * @param messages - Messages to convert
29
+ * @param enableCaching - Whether to add cache control markers
30
+ */
31
+ export function convertToAnthropicMessages(
32
+ messages: Message[],
33
+ enableCaching = false,
34
+ ): AnthropicMessage[] {
35
+ const result: AnthropicMessage[] = [];
36
+
37
+ for (const message of messages) {
38
+ const converted = convertMessage(
39
+ message,
40
+ enableCaching && messages.indexOf(message) === messages.length - 1,
41
+ );
42
+ if (converted) {
43
+ result.push(converted);
44
+ }
45
+ }
46
+
47
+ return result;
48
+ }
49
+
50
+ function convertMessage(
51
+ message: Message,
52
+ addCacheControl: boolean,
53
+ ): AnthropicMessage | null {
54
+ const { role, content } = message;
55
+
56
+ // Simple string content
57
+ if (typeof content === "string") {
58
+ const textBlock: AnthropicContentBlock = { type: "text", text: content };
59
+ if (addCacheControl) {
60
+ (textBlock as any).cache_control = { type: "ephemeral" };
61
+ }
62
+ return { role, content: [textBlock] };
63
+ }
64
+
65
+ // Array content - need to process blocks
66
+ const blocks = convertContentBlocks(content, addCacheControl);
67
+ if (blocks.length === 0) {
68
+ return null;
69
+ }
70
+
71
+ return { role, content: blocks };
72
+ }
73
+
74
+ function convertContentBlocks(
75
+ content: ContentBlock[],
76
+ addCacheControl: boolean,
77
+ ): AnthropicContentBlock[] {
78
+ const blocks: AnthropicContentBlock[] = [];
79
+
80
+ for (let i = 0; i < content.length; i++) {
81
+ const block = content[i];
82
+ const isLast = i === content.length - 1;
83
+ const converted = convertContentBlock(block, addCacheControl && isLast);
84
+ if (converted) {
85
+ blocks.push(converted);
86
+ }
87
+ }
88
+
89
+ return blocks;
90
+ }
91
+
92
+ function convertContentBlock(
93
+ block: ContentBlock,
94
+ addCacheControl: boolean,
95
+ ): AnthropicContentBlock | null {
96
+ switch (block.type) {
97
+ case "text": {
98
+ const textBlock = block as TextContent;
99
+ const result: AnthropicContentBlock = {
100
+ type: "text",
101
+ text: textBlock.text,
102
+ };
103
+ if (addCacheControl) {
104
+ (result as any).cache_control = { type: "ephemeral" };
105
+ }
106
+ return result;
107
+ }
108
+
109
+ case "file": {
110
+ const fileBlock = block as FileContent;
111
+ return {
112
+ type: "text",
113
+ text: formatFileContentBlock(fileBlock.path, fileBlock.content),
114
+ };
115
+ }
116
+
117
+ case "image": {
118
+ const imageBlock = block as ImageContent;
119
+ return {
120
+ type: "image",
121
+ source: {
122
+ type: "base64",
123
+ media_type: imageBlock.mediaType as
124
+ | "image/jpeg"
125
+ | "image/png"
126
+ | "image/gif"
127
+ | "image/webp",
128
+ data: imageBlock.data,
129
+ },
130
+ };
131
+ }
132
+
133
+ case "tool_use": {
134
+ const toolBlock = block as ToolUseContent;
135
+ return {
136
+ type: "tool_use",
137
+ id: toolBlock.id,
138
+ name: toolBlock.name,
139
+ input: normalizeToolUseInput(toolBlock.input),
140
+ };
141
+ }
142
+
143
+ case "tool_result": {
144
+ const resultBlock = block as ToolResultContent;
145
+ let resultContent: Anthropic.ToolResultBlockParam["content"];
146
+
147
+ if (typeof resultBlock.content === "string") {
148
+ resultContent = resultBlock.content;
149
+ } else {
150
+ // Convert array of text/image to Anthropic format
151
+ resultContent = resultBlock.content.map((item) => {
152
+ if (item.type === "text") {
153
+ return { type: "text" as const, text: item.text };
154
+ } else if (item.type === "file") {
155
+ const fileItem = item as FileContent;
156
+ return {
157
+ type: "text" as const,
158
+ text: formatFileContentBlock(fileItem.path, fileItem.content),
159
+ };
160
+ } else {
161
+ return {
162
+ type: "image" as const,
163
+ source: {
164
+ type: "base64" as const,
165
+ media_type: item.mediaType as
166
+ | "image/jpeg"
167
+ | "image/png"
168
+ | "image/gif"
169
+ | "image/webp",
170
+ data: item.data,
171
+ },
172
+ };
173
+ }
174
+ });
175
+ }
176
+
177
+ return {
178
+ type: "tool_result",
179
+ tool_use_id: resultBlock.tool_use_id,
180
+ content: resultContent,
181
+ is_error: resultBlock.is_error,
182
+ };
183
+ }
184
+
185
+ case "thinking": {
186
+ const thinkingBlock = block as ThinkingContent;
187
+ return {
188
+ type: "thinking",
189
+ thinking: thinkingBlock.thinking,
190
+ signature: thinkingBlock.signature,
191
+ } as any; // Anthropic SDK types may not include this yet
192
+ }
193
+
194
+ case "redacted_thinking": {
195
+ const redactedBlock = block as RedactedThinkingContent;
196
+ return {
197
+ type: "redacted_thinking",
198
+ data: redactedBlock.data,
199
+ } as any;
200
+ }
201
+
202
+ default:
203
+ return null;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Convert tool definitions to Anthropic format
209
+ */
210
+ export function convertToolsToAnthropic(
211
+ tools: Array<{ name: string; description: string; inputSchema: unknown }>,
212
+ ): Anthropic.Tool[] {
213
+ return tools.map((tool) => ({
214
+ name: tool.name,
215
+ description: tool.description,
216
+ input_schema: tool.inputSchema as Anthropic.Tool.InputSchema,
217
+ }));
218
+ }
@@ -0,0 +1,34 @@
1
+ import { formatFileContentBlock } from "@clinebot/shared";
2
+ import type { FileContent, ImageContent, TextContent } from "../types/messages";
3
+
4
+ export function normalizeToolUseInput(
5
+ input: Record<string, unknown>,
6
+ ): Record<string, unknown> {
7
+ if (Array.isArray(input)) {
8
+ return { commands: input };
9
+ }
10
+ return input;
11
+ }
12
+
13
+ export function serializeToolResultContent(
14
+ content: string | Array<TextContent | ImageContent | FileContent>,
15
+ ): string {
16
+ if (typeof content === "string") {
17
+ return content;
18
+ }
19
+
20
+ const parts: string[] = [];
21
+ for (const part of content) {
22
+ if (part.type === "text") {
23
+ parts.push(part.text);
24
+ continue;
25
+ }
26
+ if (part.type === "file") {
27
+ parts.push(formatFileContentBlock(part.path, part.content));
28
+ continue;
29
+ }
30
+ parts.push(JSON.stringify(part));
31
+ }
32
+
33
+ return parts.join("\n");
34
+ }