@imenam/unified-llm-client 1.2.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 (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +233 -0
  3. package/dist/adapters/anthropic/AnthropicLogAdapter.d.ts +6 -0
  4. package/dist/adapters/anthropic/AnthropicLogAdapter.d.ts.map +1 -0
  5. package/dist/adapters/anthropic/AnthropicLogAdapter.js +41 -0
  6. package/dist/adapters/anthropic/AnthropicOutputAdapter.d.ts +6 -0
  7. package/dist/adapters/anthropic/AnthropicOutputAdapter.d.ts.map +1 -0
  8. package/dist/adapters/anthropic/AnthropicOutputAdapter.js +41 -0
  9. package/dist/adapters/anthropic/AnthropicPromptAdapter.d.ts +12 -0
  10. package/dist/adapters/anthropic/AnthropicPromptAdapter.d.ts.map +1 -0
  11. package/dist/adapters/anthropic/AnthropicPromptAdapter.js +249 -0
  12. package/dist/adapters/anthropic/AnthropicToolAdapter.d.ts +6 -0
  13. package/dist/adapters/anthropic/AnthropicToolAdapter.d.ts.map +1 -0
  14. package/dist/adapters/anthropic/AnthropicToolAdapter.js +20 -0
  15. package/dist/adapters/gemini/GeminiAudioAdapter.d.ts +40 -0
  16. package/dist/adapters/gemini/GeminiAudioAdapter.d.ts.map +1 -0
  17. package/dist/adapters/gemini/GeminiAudioAdapter.js +273 -0
  18. package/dist/adapters/gemini/GeminiLogAdapter.d.ts +6 -0
  19. package/dist/adapters/gemini/GeminiLogAdapter.d.ts.map +1 -0
  20. package/dist/adapters/gemini/GeminiLogAdapter.js +43 -0
  21. package/dist/adapters/gemini/GeminiOutputAdapter.d.ts +6 -0
  22. package/dist/adapters/gemini/GeminiOutputAdapter.d.ts.map +1 -0
  23. package/dist/adapters/gemini/GeminiOutputAdapter.js +38 -0
  24. package/dist/adapters/gemini/GeminiPromptAdapter.d.ts +26 -0
  25. package/dist/adapters/gemini/GeminiPromptAdapter.d.ts.map +1 -0
  26. package/dist/adapters/gemini/GeminiPromptAdapter.js +334 -0
  27. package/dist/adapters/gemini/GeminiToolAdapter.d.ts +8 -0
  28. package/dist/adapters/gemini/GeminiToolAdapter.d.ts.map +1 -0
  29. package/dist/adapters/gemini/GeminiToolAdapter.js +42 -0
  30. package/dist/adapters/gemini/types.d.ts +14 -0
  31. package/dist/adapters/gemini/types.d.ts.map +1 -0
  32. package/dist/adapters/gemini/types.js +2 -0
  33. package/dist/adapters/openai/OpenAIOutputAdapter.d.ts +6 -0
  34. package/dist/adapters/openai/OpenAIOutputAdapter.d.ts.map +1 -0
  35. package/dist/adapters/openai/OpenAIOutputAdapter.js +18 -0
  36. package/dist/adapters/openai/OpenAIPromptAdapter.d.ts +13 -0
  37. package/dist/adapters/openai/OpenAIPromptAdapter.d.ts.map +1 -0
  38. package/dist/adapters/openai/OpenAIPromptAdapter.js +215 -0
  39. package/dist/adapters/openai/OpenAiLogAdapter.d.ts +6 -0
  40. package/dist/adapters/openai/OpenAiLogAdapter.d.ts.map +1 -0
  41. package/dist/adapters/openai/OpenAiLogAdapter.js +37 -0
  42. package/dist/adapters/openai/OpenAiToolAdapter.d.ts +6 -0
  43. package/dist/adapters/openai/OpenAiToolAdapter.d.ts.map +1 -0
  44. package/dist/adapters/openai/OpenAiToolAdapter.js +20 -0
  45. package/dist/adapters/qwen/QwenLogAdapter.d.ts +7 -0
  46. package/dist/adapters/qwen/QwenLogAdapter.d.ts.map +1 -0
  47. package/dist/adapters/qwen/QwenLogAdapter.js +49 -0
  48. package/dist/adapters/qwen/QwenOutputAdapter.d.ts +6 -0
  49. package/dist/adapters/qwen/QwenOutputAdapter.d.ts.map +1 -0
  50. package/dist/adapters/qwen/QwenOutputAdapter.js +9 -0
  51. package/dist/adapters/qwen/QwenPromptAdapter.d.ts +13 -0
  52. package/dist/adapters/qwen/QwenPromptAdapter.d.ts.map +1 -0
  53. package/dist/adapters/qwen/QwenPromptAdapter.js +313 -0
  54. package/dist/adapters/qwen/QwenToolAdapter.d.ts +6 -0
  55. package/dist/adapters/qwen/QwenToolAdapter.d.ts.map +1 -0
  56. package/dist/adapters/qwen/QwenToolAdapter.js +20 -0
  57. package/dist/common/types.d.ts +106 -0
  58. package/dist/common/types.d.ts.map +1 -0
  59. package/dist/common/types.js +2 -0
  60. package/dist/core/LLMAdapter.d.ts +74 -0
  61. package/dist/core/LLMAdapter.d.ts.map +1 -0
  62. package/dist/core/LLMAdapter.js +70 -0
  63. package/dist/core/Models.d.ts +16 -0
  64. package/dist/core/Models.d.ts.map +1 -0
  65. package/dist/core/Models.js +118 -0
  66. package/dist/core/UnifiedLLMClient.d.ts +68 -0
  67. package/dist/core/UnifiedLLMClient.d.ts.map +1 -0
  68. package/dist/core/UnifiedLLMClient.js +185 -0
  69. package/dist/examples/anthropic-example.d.ts +2 -0
  70. package/dist/examples/anthropic-example.d.ts.map +1 -0
  71. package/dist/examples/anthropic-example.js +243 -0
  72. package/dist/examples/audio-example.d.ts +14 -0
  73. package/dist/examples/audio-example.d.ts.map +1 -0
  74. package/dist/examples/audio-example.js +204 -0
  75. package/dist/examples/example-logging.d.ts +2 -0
  76. package/dist/examples/example-logging.d.ts.map +1 -0
  77. package/dist/examples/example-logging.js +53 -0
  78. package/dist/examples/example.d.ts +2 -0
  79. package/dist/examples/example.d.ts.map +1 -0
  80. package/dist/examples/example.js +373 -0
  81. package/dist/examples/qwen-vl-example.d.ts +26 -0
  82. package/dist/examples/qwen-vl-example.d.ts.map +1 -0
  83. package/dist/examples/qwen-vl-example.js +314 -0
  84. package/dist/examples/test-multiturn-tools.d.ts +2 -0
  85. package/dist/examples/test-multiturn-tools.d.ts.map +1 -0
  86. package/dist/examples/test-multiturn-tools.js +139 -0
  87. package/dist/index.d.ts +7 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +7 -0
  90. package/dist/utils/audioUtils.d.ts +41 -0
  91. package/dist/utils/audioUtils.d.ts.map +1 -0
  92. package/dist/utils/audioUtils.js +185 -0
  93. package/package.json +64 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 imenam
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,233 @@
1
+ # @imenam/unified-llm-client
2
+
3
+ A unified interface for multiple LLM providers — OpenAI, Gemini, Anthropic, and Qwen — with built-in support for tool-calling, streaming, multimodal inputs, and audio generation.
4
+
5
+ ## Features
6
+
7
+ - **Unified API** — one interface, four providers
8
+ - **Tool-calling** — automatic execution loop with structured results
9
+ - **Streaming** — chunk-by-chunk responses via callbacks
10
+ - **Multimodal** — image and audio file inputs
11
+ - **Audio generation** — Text-to-Speech (Gemini)
12
+ - **Usage tracking** — token counts and estimated costs
13
+ - **Full TypeScript support** — exported types and `.d.ts` declarations
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @imenam/unified-llm-client
19
+ ```
20
+
21
+ ## Supported Providers
22
+
23
+ | Provider | Chat | Streaming | Tool-calling | Multimodal | Audio TTS |
24
+ |-----------|:----:|:---------:|:------------:|:----------:|:---------:|
25
+ | OpenAI | ✅ | ✅ | ✅ | ✅ | ❌ |
26
+ | Gemini | ✅ | ✅ | ✅ | ✅ | ✅ |
27
+ | Anthropic | ✅ | ✅ | ✅ | ✅ | ❌ |
28
+ | Qwen | ✅ | ✅ | ✅ | ✅ | ❌ |
29
+
30
+ ## Quick Start
31
+
32
+ Set your API keys in a `.env` file:
33
+
34
+ ```env
35
+ OPENAI_API_KEY=sk-...
36
+ GOOGLE_API_KEY=...
37
+ ANTHROPIC_API_KEY=sk-ant-...
38
+ DASHSCOPE_API_KEY=... # for Qwen
39
+ ```
40
+
41
+ ```typescript
42
+ import { UnifiedLLMClient, MODELS } from "@imenam/unified-llm-client";
43
+
44
+ const client = new UnifiedLLMClient(MODELS.GPT_4O_MINI);
45
+
46
+ const response = await client.chat({
47
+ message: "What is the capital of France?",
48
+ });
49
+
50
+ console.log(response.content); // "The capital of France is Paris."
51
+ ```
52
+
53
+ ## Available Models
54
+
55
+ ```typescript
56
+ import { MODELS } from "@imenam/unified-llm-client";
57
+
58
+ // OpenAI
59
+ MODELS.GPT_4O_MINI
60
+ MODELS.GPT_5
61
+
62
+ // Gemini
63
+ MODELS.GEMINI_FLASH_2_5
64
+ MODELS.GEMINI_2_5_PRO
65
+ MODELS.GEMINI_3_FLASH
66
+ MODELS.GEMINI_3_PRO
67
+ MODELS.GEMINI_3_1_PRO
68
+
69
+ // Anthropic
70
+ MODELS.CLAUDE_SONNET_4_6
71
+ MODELS.CLAUDE_OPUS_4_6
72
+
73
+ // Qwen
74
+ MODELS.QWEN_VL_3
75
+ MODELS.QWEN_VL_FLASH
76
+ ```
77
+
78
+ You can also pass a custom model:
79
+
80
+ ```typescript
81
+ const client = new UnifiedLLMClient({
82
+ provider: "openai",
83
+ modelName: "gpt-4o",
84
+ });
85
+ ```
86
+
87
+ ## Tool-calling
88
+
89
+ Define tools with an `executor` function — the client will call them automatically and loop until the LLM produces a final text response.
90
+
91
+ ```typescript
92
+ import { UnifiedLLMClient, MODELS } from "@imenam/unified-llm-client";
93
+ import type { ToolDefinition } from "@imenam/unified-llm-client";
94
+
95
+ const tools: ToolDefinition[] = [
96
+ {
97
+ name: "get_weather",
98
+ description: "Get the current weather for a city",
99
+ parameters: {
100
+ type: "object",
101
+ properties: {
102
+ city: { type: "string", description: "City name" },
103
+ },
104
+ required: ["city"],
105
+ },
106
+ executor: async ({ city }) => {
107
+ return `The weather in ${city} is sunny and 22°C.`;
108
+ },
109
+ },
110
+ ];
111
+
112
+ const client = new UnifiedLLMClient(MODELS.GEMINI_FLASH_2_5);
113
+
114
+ const response = await client.chat({
115
+ message: "What's the weather like in Paris?",
116
+ tools,
117
+ });
118
+
119
+ console.log(response.content);
120
+ ```
121
+
122
+ ## Streaming
123
+
124
+ ```typescript
125
+ const client = new UnifiedLLMClient(MODELS.GPT_4O_MINI);
126
+
127
+ const response = await client.chat({
128
+ message: "Tell me a short story.",
129
+ stream: true,
130
+ onChunk: (chunk) => {
131
+ process.stdout.write(chunk.content ?? "");
132
+ },
133
+ onFinalResponse: (final) => {
134
+ console.log("\n\nTotal tokens:", final.usage?.totalTokens);
135
+ },
136
+ });
137
+ ```
138
+
139
+ ## Conversation History
140
+
141
+ The client maintains conversation history internally. Use `getHistory()` and `setHistory()` to persist or restore it:
142
+
143
+ ```typescript
144
+ const client = new UnifiedLLMClient(MODELS.CLAUDE_SONNET_4_6);
145
+
146
+ await client.chat({ message: "My name is Alice." });
147
+ await client.chat({ message: "What's my name?" });
148
+ // → "Your name is Alice."
149
+
150
+ const history = client.getHistory();
151
+ // Save and restore later:
152
+ const newClient = new UnifiedLLMClient(MODELS.CLAUDE_SONNET_4_6);
153
+ newClient.setHistory(history);
154
+ ```
155
+
156
+ ## Multimodal Inputs
157
+
158
+ Attach images or audio files directly to a message:
159
+
160
+ ```typescript
161
+ const response = await client.chat({
162
+ message: {
163
+ role: "user",
164
+ content: "What do you see in this image?",
165
+ attachedFile: "./photo.jpg",
166
+ },
167
+ });
168
+ ```
169
+
170
+ ## Audio Generation (Gemini)
171
+
172
+ ```typescript
173
+ import { UnifiedLLMClient, MODELS } from "@imenam/unified-llm-client";
174
+
175
+ const client = new UnifiedLLMClient(MODELS.GEMINI_FLASH_2_5);
176
+
177
+ const audio = await client.generateAudio({
178
+ text: "Hello, this is a test of text-to-speech.",
179
+ outputPath: "./output.wav",
180
+ voiceConfig: { voiceName: "Kore" },
181
+ });
182
+ ```
183
+
184
+ ## Logging
185
+
186
+ Pass a `logger` callback to capture structured logs for every request:
187
+
188
+ ```typescript
189
+ const client = new UnifiedLLMClient(MODELS.GPT_4O_MINI, {
190
+ logger: (log) => {
191
+ console.log(`[${log.provider}] ${log.model} — ${log.totalTokens} tokens`);
192
+ },
193
+ });
194
+ ```
195
+
196
+ ## API Reference
197
+
198
+ ### `new UnifiedLLMClient(model, options?)`
199
+
200
+ | Parameter | Type | Description |
201
+ |-----------|------|-------------|
202
+ | `model` | `Model` | Model object from `MODELS` or a custom `{ provider, modelName }` |
203
+ | `options.logger` | `(log: UnifiedLog) => void` | Optional logging callback |
204
+
205
+ ### `client.chat(options)`
206
+
207
+ | Option | Type | Default | Description |
208
+ |--------|------|---------|-------------|
209
+ | `message` | `string \| ChatMessage \| ChatMessage[]` | — | User message or history |
210
+ | `tools` | `ToolDefinition[]` | `[]` | Tools available to the LLM |
211
+ | `toolChoice` | `"auto" \| "none" \| string` | `"auto"` | Tool selection strategy |
212
+ | `stream` | `boolean` | `false` | Enable streaming |
213
+ | `onChunk` | `(chunk: StreamedChatChunk) => void` | — | Streaming chunk callback |
214
+ | `onFinalResponse` | `(res: ChatResponse) => void` | — | Final response callback |
215
+
216
+ ### `ChatResponse`
217
+
218
+ ```typescript
219
+ interface ChatResponse {
220
+ content: string | null;
221
+ toolCalls?: ToolCall[];
222
+ usage?: {
223
+ promptTokens: number;
224
+ completionTokens: number;
225
+ totalTokens: number;
226
+ };
227
+ raw: unknown;
228
+ }
229
+ ```
230
+
231
+ ## License
232
+
233
+ MIT
@@ -0,0 +1,6 @@
1
+ import { UnifiedLog } from "../../common/types";
2
+ import { LogAdapter, LogData } from "../../core/LLMAdapter";
3
+ export declare class AnthropicLogAdapter implements LogAdapter {
4
+ toUnifiedLog(data: LogData): UnifiedLog;
5
+ }
6
+ //# sourceMappingURL=AnthropicLogAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnthropicLogAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/anthropic/AnthropicLogAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAE5D,qBAAa,mBAAoB,YAAW,UAAU;IACpD,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU;CAoCxC"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AnthropicLogAdapter = void 0;
4
+ class AnthropicLogAdapter {
5
+ toUnifiedLog(data) {
6
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
7
+ const { model, provider, messages, response, latencyMs, metadata } = data;
8
+ const usage = response.usage;
9
+ const raw = response.raw;
10
+ const inputTokens = (_c = (_b = (_a = raw === null || raw === void 0 ? void 0 : raw.usage) === null || _a === void 0 ? void 0 : _a.input_tokens) !== null && _b !== void 0 ? _b : usage === null || usage === void 0 ? void 0 : usage.promptTokens) !== null && _c !== void 0 ? _c : 0;
11
+ const outputTokens = (_f = (_e = (_d = raw === null || raw === void 0 ? void 0 : raw.usage) === null || _d === void 0 ? void 0 : _d.output_tokens) !== null && _e !== void 0 ? _e : usage === null || usage === void 0 ? void 0 : usage.completionTokens) !== null && _f !== void 0 ? _f : 0;
12
+ const cacheCreationTokens = (_h = (_g = raw === null || raw === void 0 ? void 0 : raw.usage) === null || _g === void 0 ? void 0 : _g.cache_creation_input_tokens) !== null && _h !== void 0 ? _h : 0;
13
+ const cacheReadTokens = (_k = (_j = raw === null || raw === void 0 ? void 0 : raw.usage) === null || _j === void 0 ? void 0 : _j.cache_read_input_tokens) !== null && _k !== void 0 ? _k : 0;
14
+ return {
15
+ requestId: (_l = raw === null || raw === void 0 ? void 0 : raw.id) !== null && _l !== void 0 ? _l : `anthropic-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
16
+ timestamp: new Date(),
17
+ provider: provider,
18
+ model,
19
+ prompt: messages,
20
+ output: {
21
+ content: response.content,
22
+ toolCalls: response.toolCalls,
23
+ finishReason: response.finishReason,
24
+ },
25
+ usage: {
26
+ promptTokens: inputTokens,
27
+ completionTokens: outputTokens,
28
+ totalTokens: inputTokens + outputTokens,
29
+ promptDetails: {
30
+ cachedTokens: cacheCreationTokens + cacheReadTokens,
31
+ },
32
+ completionDetails: {
33
+ textTokens: outputTokens,
34
+ },
35
+ },
36
+ latencyMs,
37
+ metadata,
38
+ };
39
+ }
40
+ }
41
+ exports.AnthropicLogAdapter = AnthropicLogAdapter;
@@ -0,0 +1,6 @@
1
+ import { ChatResponse } from "../../common/types";
2
+ import { OutputAdapter } from "../../core/LLMAdapter";
3
+ export declare class AnthropicOutputAdapter implements OutputAdapter {
4
+ parse(providerResponse: any): ChatResponse;
5
+ }
6
+ //# sourceMappingURL=AnthropicOutputAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnthropicOutputAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/anthropic/AnthropicOutputAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAY,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,qBAAa,sBAAuB,YAAW,aAAa;IAC1D,KAAK,CAAC,gBAAgB,EAAE,GAAG,GAAG,YAAY;CAqC3C"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AnthropicOutputAdapter = void 0;
4
+ class AnthropicOutputAdapter {
5
+ parse(providerResponse) {
6
+ var _a, _b, _c, _d;
7
+ const raw = (_a = providerResponse.raw) !== null && _a !== void 0 ? _a : providerResponse;
8
+ let textContent = null;
9
+ const toolCalls = [];
10
+ for (const block of (_b = raw.content) !== null && _b !== void 0 ? _b : []) {
11
+ if (block.type === "text") {
12
+ textContent = (textContent !== null && textContent !== void 0 ? textContent : "") + block.text;
13
+ }
14
+ else if (block.type === "tool_use") {
15
+ toolCalls.push({
16
+ id: block.id,
17
+ name: block.name,
18
+ arguments: block.input,
19
+ });
20
+ }
21
+ }
22
+ const usage = raw.usage;
23
+ return {
24
+ content: textContent,
25
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
26
+ lastToolArguments: (_c = toolCalls[0]) === null || _c === void 0 ? void 0 : _c.arguments,
27
+ raw,
28
+ usage: usage
29
+ ? {
30
+ promptTokens: usage.input_tokens,
31
+ completionTokens: usage.output_tokens,
32
+ totalTokens: usage.input_tokens + usage.output_tokens,
33
+ promptTokensDetails: null,
34
+ thoughtsToken: 0,
35
+ }
36
+ : undefined,
37
+ finishReason: (_d = raw.stop_reason) !== null && _d !== void 0 ? _d : undefined,
38
+ };
39
+ }
40
+ }
41
+ exports.AnthropicOutputAdapter = AnthropicOutputAdapter;
@@ -0,0 +1,12 @@
1
+ import { ChatMessage, ChatResponse, ToolDefinition } from "../../common/types";
2
+ import { ChatOptionalConfig, ChatStreamOptions, PromptAdapter, PromptAdapterOptions } from "../../core/LLMAdapter";
3
+ export declare class AnthropicPromptAdapter implements PromptAdapter {
4
+ private client;
5
+ private opts;
6
+ constructor(opts: PromptAdapterOptions);
7
+ formatMessage(message: ChatMessage): Promise<any>;
8
+ private buildRequestParams;
9
+ sendToProvider(messages: any[], tools?: ToolDefinition[], toolChoice?: "auto" | "none" | string, _attachedFile?: string | string[], model?: string, _config?: ChatOptionalConfig): Promise<ChatResponse>;
10
+ streamFromProvider({ messages, tools, toolChoice, model, onChunk, onFinalResponse, }: ChatStreamOptions): Promise<ChatResponse>;
11
+ }
12
+ //# sourceMappingURL=AnthropicPromptAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnthropicPromptAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/anthropic/AnthropicPromptAdapter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAY,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,aAAa,EAAE,oBAAoB,EAAqB,MAAM,uBAAuB,CAAC;AA4BtI,qBAAa,sBAAuB,YAAW,aAAa;IAC1D,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,IAAI,CAAuB;gBAEvB,IAAI,EAAE,oBAAoB;IAKhC,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;IAsEvD,OAAO,CAAC,kBAAkB;IAmCpB,cAAc,CAClB,QAAQ,EAAE,GAAG,EAAE,EACf,KAAK,GAAE,cAAc,EAAO,EAC5B,UAAU,GAAE,MAAM,GAAG,MAAM,GAAG,MAAe,EAC7C,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EACjC,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,YAAY,CAAC;IAgDlB,kBAAkB,CAAC,EACvB,QAAQ,EACR,KAAK,EACL,UAAU,EACV,KAAK,EACL,OAAO,EACP,eAAe,GAChB,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;CA8D7C"}
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __importDefault = (this && this.__importDefault) || function (mod) {
45
+ return (mod && mod.__esModule) ? mod : { "default": mod };
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.AnthropicPromptAdapter = void 0;
49
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
50
+ const fs_1 = __importDefault(require("fs"));
51
+ const mime = __importStar(require("mime-types"));
52
+ const sharp_1 = __importDefault(require("sharp"));
53
+ const IMAGE_MIME_TYPES = ["image/jpeg", "image/png", "image/gif", "image/webp"];
54
+ const ANTHROPIC_MAX_IMAGE_BYTES = 5 * 1024 * 1024; // 5 MB
55
+ function compressImageIfNeeded(filePath, mimeType) {
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ const raw = fs_1.default.readFileSync(filePath);
58
+ if (raw.byteLength <= ANTHROPIC_MAX_IMAGE_BYTES) {
59
+ return { data: raw.toString("base64"), media_type: mimeType };
60
+ }
61
+ // Compression progressive jusqu'à passer sous la limite
62
+ let quality = 85;
63
+ let compressed;
64
+ do {
65
+ compressed = yield (0, sharp_1.default)(raw).jpeg({ quality }).toBuffer();
66
+ quality -= 10;
67
+ } while (compressed.byteLength > ANTHROPIC_MAX_IMAGE_BYTES && quality > 10);
68
+ return { data: compressed.toString("base64"), media_type: "image/jpeg" };
69
+ });
70
+ }
71
+ class AnthropicPromptAdapter {
72
+ constructor(opts) {
73
+ this.opts = opts;
74
+ this.client = new sdk_1.default({ apiKey: opts.apiKey });
75
+ }
76
+ formatMessage(message) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ var _a, _b;
79
+ if (message.role === "system") {
80
+ return { role: "system", content: message.content };
81
+ }
82
+ // Tool result message → user turn with tool_result content block
83
+ if (message.role === "tool") {
84
+ return {
85
+ role: "user",
86
+ content: [{
87
+ type: "tool_result",
88
+ tool_use_id: (_a = message.tool_call_id) !== null && _a !== void 0 ? _a : "",
89
+ content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
90
+ }],
91
+ };
92
+ }
93
+ // Assistant message with tool calls → assistant turn with tool_use content blocks
94
+ if (message.role === "assistant" && message.tool_calls && message.tool_calls.length > 0) {
95
+ const contentBlocks = [];
96
+ if (message.content) {
97
+ contentBlocks.push({ type: "text", text: message.content });
98
+ }
99
+ for (const tc of message.tool_calls) {
100
+ contentBlocks.push({
101
+ type: "tool_use",
102
+ id: (_b = tc.id) !== null && _b !== void 0 ? _b : tc.name,
103
+ name: tc.name,
104
+ input: tc.arguments,
105
+ });
106
+ }
107
+ return { role: "assistant", content: contentBlocks };
108
+ }
109
+ if (message.attachedFile) {
110
+ const files = Array.isArray(message.attachedFile) ? message.attachedFile : [message.attachedFile];
111
+ const contentBlocks = [];
112
+ for (const filePath of files) {
113
+ const mimeType = mime.lookup(filePath) || "application/octet-stream";
114
+ if (IMAGE_MIME_TYPES.includes(mimeType)) {
115
+ const { data, media_type } = yield compressImageIfNeeded(filePath, mimeType);
116
+ contentBlocks.push({
117
+ type: "image",
118
+ source: { type: "base64", media_type, data },
119
+ });
120
+ }
121
+ else if (mimeType === "application/pdf") {
122
+ const base64Data = fs_1.default.readFileSync(filePath).toString("base64");
123
+ contentBlocks.push({
124
+ type: "document",
125
+ source: { type: "base64", media_type: "application/pdf", data: base64Data },
126
+ });
127
+ }
128
+ }
129
+ contentBlocks.push({ type: "text", text: message.content });
130
+ return {
131
+ role: message.role === "assistant" ? "assistant" : "user",
132
+ content: contentBlocks,
133
+ };
134
+ }
135
+ return {
136
+ role: message.role === "assistant" ? "assistant" : "user",
137
+ content: message.content,
138
+ };
139
+ });
140
+ }
141
+ buildRequestParams(messages, tools = [], toolChoice = "auto", model) {
142
+ const systemMessages = messages.filter((m) => m.role === "system");
143
+ const nonSystemMessages = messages.filter((m) => m.role !== "system");
144
+ const systemPrompt = systemMessages.map((m) => m.content).join("\n") || undefined;
145
+ let sdkTools = undefined;
146
+ let sdkToolChoice = undefined;
147
+ if (toolChoice !== "none" && tools.length > 0) {
148
+ sdkTools = tools.map((t) => {
149
+ var _a, _b;
150
+ return ({
151
+ name: t.name,
152
+ description: t.description,
153
+ input_schema: {
154
+ type: "object",
155
+ properties: ((_a = t.parameters) === null || _a === void 0 ? void 0 : _a.properties) || {},
156
+ required: ((_b = t.parameters) === null || _b === void 0 ? void 0 : _b.required) || [],
157
+ },
158
+ });
159
+ });
160
+ if (toolChoice === "auto") {
161
+ sdkToolChoice = { type: "auto" };
162
+ }
163
+ else {
164
+ sdkToolChoice = { type: "tool", name: toolChoice };
165
+ }
166
+ }
167
+ return { systemPrompt, nonSystemMessages, sdkTools, sdkToolChoice, model: model || this.opts.model };
168
+ }
169
+ sendToProvider(messages_1) {
170
+ return __awaiter(this, arguments, void 0, function* (messages, tools = [], toolChoice = "auto", _attachedFile, model, _config) {
171
+ var _a, _b;
172
+ const { systemPrompt, nonSystemMessages, sdkTools, sdkToolChoice, model: resolvedModel } = this.buildRequestParams(messages, tools, toolChoice, model);
173
+ const response = yield this.client.messages.create(Object.assign(Object.assign(Object.assign({ model: resolvedModel, max_tokens: 8096, messages: nonSystemMessages }, (systemPrompt ? { system: systemPrompt } : {})), (sdkTools ? { tools: sdkTools } : {})), (sdkToolChoice ? { tool_choice: sdkToolChoice } : {})));
174
+ let textContent = null;
175
+ const toolCalls = [];
176
+ for (const block of response.content) {
177
+ if (block.type === "text") {
178
+ textContent = (textContent !== null && textContent !== void 0 ? textContent : "") + block.text;
179
+ }
180
+ else if (block.type === "tool_use") {
181
+ toolCalls.push({
182
+ id: block.id,
183
+ name: block.name,
184
+ arguments: block.input,
185
+ });
186
+ }
187
+ }
188
+ return {
189
+ content: textContent,
190
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
191
+ lastToolArguments: (_a = toolCalls[0]) === null || _a === void 0 ? void 0 : _a.arguments,
192
+ raw: response,
193
+ usage: {
194
+ promptTokens: response.usage.input_tokens,
195
+ completionTokens: response.usage.output_tokens,
196
+ totalTokens: response.usage.input_tokens + response.usage.output_tokens,
197
+ promptTokensDetails: null,
198
+ thoughtsToken: 0,
199
+ },
200
+ finishReason: (_b = response.stop_reason) !== null && _b !== void 0 ? _b : undefined,
201
+ };
202
+ });
203
+ }
204
+ streamFromProvider(_a) {
205
+ return __awaiter(this, arguments, void 0, function* ({ messages, tools, toolChoice, model, onChunk, onFinalResponse, }) {
206
+ var _b, _c;
207
+ const { systemPrompt, nonSystemMessages, sdkTools, sdkToolChoice, model: resolvedModel } = this.buildRequestParams(messages, tools !== null && tools !== void 0 ? tools : [], toolChoice !== null && toolChoice !== void 0 ? toolChoice : "auto", model);
208
+ const stream = this.client.messages.stream(Object.assign(Object.assign(Object.assign({ model: resolvedModel, max_tokens: 8096, messages: nonSystemMessages }, (systemPrompt ? { system: systemPrompt } : {})), (sdkTools ? { tools: sdkTools } : {})), (sdkToolChoice ? { tool_choice: sdkToolChoice } : {})));
209
+ const toolCalls = [];
210
+ stream.on("text", (text) => {
211
+ onChunk === null || onChunk === void 0 ? void 0 : onChunk({ contentChunk: text });
212
+ });
213
+ stream.on("contentBlock", (block) => {
214
+ if (block.type === "tool_use") {
215
+ toolCalls.push({
216
+ id: block.id,
217
+ name: block.name,
218
+ arguments: block.input,
219
+ });
220
+ }
221
+ });
222
+ const finalMessage = yield stream.finalMessage();
223
+ let textContent = null;
224
+ for (const block of finalMessage.content) {
225
+ if (block.type === "text") {
226
+ textContent = (textContent !== null && textContent !== void 0 ? textContent : "") + block.text;
227
+ }
228
+ }
229
+ const finalResponse = {
230
+ content: textContent,
231
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
232
+ lastToolArguments: (_b = toolCalls[0]) === null || _b === void 0 ? void 0 : _b.arguments,
233
+ raw: finalMessage,
234
+ usage: {
235
+ promptTokens: finalMessage.usage.input_tokens,
236
+ completionTokens: finalMessage.usage.output_tokens,
237
+ totalTokens: finalMessage.usage.input_tokens + finalMessage.usage.output_tokens,
238
+ promptTokensDetails: null,
239
+ thoughtsToken: 0,
240
+ },
241
+ finishReason: (_c = finalMessage.stop_reason) !== null && _c !== void 0 ? _c : undefined,
242
+ };
243
+ onChunk === null || onChunk === void 0 ? void 0 : onChunk({ isFinal: true, contentChunk: "" });
244
+ onFinalResponse === null || onFinalResponse === void 0 ? void 0 : onFinalResponse(finalResponse);
245
+ return finalResponse;
246
+ });
247
+ }
248
+ }
249
+ exports.AnthropicPromptAdapter = AnthropicPromptAdapter;
@@ -0,0 +1,6 @@
1
+ import { ToolCall } from "../../common/types";
2
+ import { ToolAdapter } from "../../core/LLMAdapter";
3
+ export declare class AnthropicToolAdapter implements ToolAdapter {
4
+ formatToolCallResult(toolCall: ToolCall): any;
5
+ }
6
+ //# sourceMappingURL=AnthropicToolAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnthropicToolAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/anthropic/AnthropicToolAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,qBAAa,oBAAqB,YAAW,WAAW;IACtD,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,GAAG;CAe9C"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AnthropicToolAdapter = void 0;
4
+ class AnthropicToolAdapter {
5
+ formatToolCallResult(toolCall) {
6
+ return {
7
+ role: "user",
8
+ content: [
9
+ {
10
+ type: "tool_result",
11
+ tool_use_id: toolCall.id,
12
+ content: typeof toolCall.result === "string"
13
+ ? toolCall.result
14
+ : JSON.stringify(toolCall.result),
15
+ },
16
+ ],
17
+ };
18
+ }
19
+ }
20
+ exports.AnthropicToolAdapter = AnthropicToolAdapter;