@yourgpt/llm-sdk 0.1.0 → 0.1.1

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 (56) hide show
  1. package/README.md +61 -40
  2. package/dist/adapters/index.d.mts +4 -258
  3. package/dist/adapters/index.d.ts +4 -258
  4. package/dist/adapters/index.js +0 -113
  5. package/dist/adapters/index.js.map +1 -1
  6. package/dist/adapters/index.mjs +1 -112
  7. package/dist/adapters/index.mjs.map +1 -1
  8. package/dist/base-D_FyHFKj.d.mts +235 -0
  9. package/dist/base-D_FyHFKj.d.ts +235 -0
  10. package/dist/index.d.mts +145 -450
  11. package/dist/index.d.ts +145 -450
  12. package/dist/index.js +1837 -307
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +1827 -305
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/providers/anthropic/index.d.mts +61 -0
  17. package/dist/providers/anthropic/index.d.ts +61 -0
  18. package/dist/providers/anthropic/index.js +939 -0
  19. package/dist/providers/anthropic/index.js.map +1 -0
  20. package/dist/providers/anthropic/index.mjs +934 -0
  21. package/dist/providers/anthropic/index.mjs.map +1 -0
  22. package/dist/providers/azure/index.d.mts +38 -0
  23. package/dist/providers/azure/index.d.ts +38 -0
  24. package/dist/providers/azure/index.js +380 -0
  25. package/dist/providers/azure/index.js.map +1 -0
  26. package/dist/providers/azure/index.mjs +377 -0
  27. package/dist/providers/azure/index.mjs.map +1 -0
  28. package/dist/providers/google/index.d.mts +72 -0
  29. package/dist/providers/google/index.d.ts +72 -0
  30. package/dist/providers/google/index.js +790 -0
  31. package/dist/providers/google/index.js.map +1 -0
  32. package/dist/providers/google/index.mjs +785 -0
  33. package/dist/providers/google/index.mjs.map +1 -0
  34. package/dist/providers/ollama/index.d.mts +24 -0
  35. package/dist/providers/ollama/index.d.ts +24 -0
  36. package/dist/providers/ollama/index.js +235 -0
  37. package/dist/providers/ollama/index.js.map +1 -0
  38. package/dist/providers/ollama/index.mjs +232 -0
  39. package/dist/providers/ollama/index.mjs.map +1 -0
  40. package/dist/providers/openai/index.d.mts +82 -0
  41. package/dist/providers/openai/index.d.ts +82 -0
  42. package/dist/providers/openai/index.js +679 -0
  43. package/dist/providers/openai/index.js.map +1 -0
  44. package/dist/providers/openai/index.mjs +674 -0
  45. package/dist/providers/openai/index.mjs.map +1 -0
  46. package/dist/providers/xai/index.d.mts +78 -0
  47. package/dist/providers/xai/index.d.ts +78 -0
  48. package/dist/providers/xai/index.js +671 -0
  49. package/dist/providers/xai/index.js.map +1 -0
  50. package/dist/providers/xai/index.mjs +666 -0
  51. package/dist/providers/xai/index.mjs.map +1 -0
  52. package/dist/types-BBCZ3Fxy.d.mts +308 -0
  53. package/dist/types-CdORv1Yu.d.mts +338 -0
  54. package/dist/types-CdORv1Yu.d.ts +338 -0
  55. package/dist/types-DcoCaVVC.d.ts +308 -0
  56. package/package.json +34 -3
@@ -0,0 +1,934 @@
1
+ import { generateMessageId } from '@yourgpt/copilot-sdk/core';
2
+
3
+ // src/providers/anthropic/provider.ts
4
+ var ANTHROPIC_MODELS = {
5
+ // Claude 4 series
6
+ "claude-sonnet-4-20250514": {
7
+ vision: true,
8
+ tools: true,
9
+ thinking: true,
10
+ pdf: true,
11
+ maxTokens: 2e5
12
+ },
13
+ "claude-opus-4-20250514": {
14
+ vision: true,
15
+ tools: true,
16
+ thinking: true,
17
+ pdf: true,
18
+ maxTokens: 2e5
19
+ },
20
+ // Claude 3.7 series
21
+ "claude-3-7-sonnet-20250219": {
22
+ vision: true,
23
+ tools: true,
24
+ thinking: true,
25
+ pdf: true,
26
+ maxTokens: 2e5
27
+ },
28
+ "claude-3-7-sonnet-latest": {
29
+ vision: true,
30
+ tools: true,
31
+ thinking: true,
32
+ pdf: true,
33
+ maxTokens: 2e5
34
+ },
35
+ // Claude 3.5 series
36
+ "claude-3-5-sonnet-20241022": {
37
+ vision: true,
38
+ tools: true,
39
+ thinking: false,
40
+ pdf: true,
41
+ maxTokens: 2e5
42
+ },
43
+ "claude-3-5-sonnet-latest": {
44
+ vision: true,
45
+ tools: true,
46
+ thinking: false,
47
+ pdf: true,
48
+ maxTokens: 2e5
49
+ },
50
+ "claude-3-5-haiku-20241022": {
51
+ vision: true,
52
+ tools: true,
53
+ thinking: false,
54
+ pdf: false,
55
+ maxTokens: 2e5
56
+ },
57
+ "claude-3-5-haiku-latest": {
58
+ vision: true,
59
+ tools: true,
60
+ thinking: false,
61
+ pdf: false,
62
+ maxTokens: 2e5
63
+ },
64
+ // Claude 3 series
65
+ "claude-3-opus-20240229": {
66
+ vision: true,
67
+ tools: true,
68
+ thinking: false,
69
+ pdf: false,
70
+ maxTokens: 2e5
71
+ },
72
+ "claude-3-sonnet-20240229": {
73
+ vision: true,
74
+ tools: true,
75
+ thinking: false,
76
+ pdf: false,
77
+ maxTokens: 2e5
78
+ },
79
+ "claude-3-haiku-20240307": {
80
+ vision: true,
81
+ tools: true,
82
+ thinking: false,
83
+ pdf: false,
84
+ maxTokens: 2e5
85
+ }
86
+ };
87
+ function anthropic(modelId, options = {}) {
88
+ const apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY;
89
+ let client = null;
90
+ async function getClient() {
91
+ if (!client) {
92
+ const { default: Anthropic } = await import('@anthropic-ai/sdk');
93
+ client = new Anthropic({
94
+ apiKey,
95
+ baseURL: options.baseURL
96
+ });
97
+ }
98
+ return client;
99
+ }
100
+ const modelConfig = ANTHROPIC_MODELS[modelId] ?? ANTHROPIC_MODELS["claude-3-5-sonnet-latest"];
101
+ return {
102
+ provider: "anthropic",
103
+ modelId,
104
+ capabilities: {
105
+ supportsVision: modelConfig.vision,
106
+ supportsTools: modelConfig.tools,
107
+ supportsStreaming: true,
108
+ supportsJsonMode: false,
109
+ supportsThinking: modelConfig.thinking,
110
+ supportsPDF: modelConfig.pdf,
111
+ maxTokens: modelConfig.maxTokens,
112
+ supportedImageTypes: modelConfig.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : []
113
+ },
114
+ async doGenerate(params) {
115
+ const client2 = await getClient();
116
+ const { system, messages } = formatMessagesForAnthropic(params.messages);
117
+ const requestOptions = {
118
+ model: modelId,
119
+ max_tokens: params.maxTokens ?? 4096,
120
+ system: system || void 0,
121
+ messages,
122
+ tools: params.tools
123
+ };
124
+ if (params.temperature !== void 0) {
125
+ requestOptions.temperature = params.temperature;
126
+ }
127
+ if (options.thinking?.enabled && modelConfig.thinking) {
128
+ requestOptions.thinking = {
129
+ type: "enabled",
130
+ budget_tokens: options.thinking.budgetTokens ?? 1e4
131
+ };
132
+ }
133
+ const response = await client2.messages.create(requestOptions);
134
+ let text = "";
135
+ const toolCalls = [];
136
+ for (const block of response.content) {
137
+ if (block.type === "text") {
138
+ text += block.text;
139
+ } else if (block.type === "tool_use") {
140
+ toolCalls.push({
141
+ id: block.id,
142
+ name: block.name,
143
+ args: block.input
144
+ });
145
+ }
146
+ }
147
+ return {
148
+ text,
149
+ toolCalls,
150
+ finishReason: mapFinishReason(response.stop_reason),
151
+ usage: {
152
+ promptTokens: response.usage?.input_tokens ?? 0,
153
+ completionTokens: response.usage?.output_tokens ?? 0,
154
+ totalTokens: (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0)
155
+ },
156
+ rawResponse: response
157
+ };
158
+ },
159
+ async *doStream(params) {
160
+ const client2 = await getClient();
161
+ const { system, messages } = formatMessagesForAnthropic(params.messages);
162
+ const requestOptions = {
163
+ model: modelId,
164
+ max_tokens: params.maxTokens ?? 4096,
165
+ system: system || void 0,
166
+ messages,
167
+ tools: params.tools
168
+ };
169
+ if (params.temperature !== void 0) {
170
+ requestOptions.temperature = params.temperature;
171
+ }
172
+ if (options.thinking?.enabled && modelConfig.thinking) {
173
+ requestOptions.thinking = {
174
+ type: "enabled",
175
+ budget_tokens: options.thinking.budgetTokens ?? 1e4
176
+ };
177
+ }
178
+ const stream = await client2.messages.stream(requestOptions);
179
+ let currentToolUse = null;
180
+ let inputTokens = 0;
181
+ let outputTokens = 0;
182
+ for await (const event of stream) {
183
+ if (params.signal?.aborted) {
184
+ yield { type: "error", error: new Error("Aborted") };
185
+ return;
186
+ }
187
+ switch (event.type) {
188
+ case "message_start":
189
+ if (event.message?.usage) {
190
+ inputTokens = event.message.usage.input_tokens ?? 0;
191
+ }
192
+ break;
193
+ case "content_block_start":
194
+ if (event.content_block?.type === "tool_use") {
195
+ currentToolUse = {
196
+ id: event.content_block.id,
197
+ name: event.content_block.name,
198
+ input: ""
199
+ };
200
+ }
201
+ break;
202
+ case "content_block_delta":
203
+ if (event.delta?.type === "text_delta") {
204
+ yield { type: "text-delta", text: event.delta.text };
205
+ } else if (event.delta?.type === "input_json_delta" && currentToolUse) {
206
+ currentToolUse.input += event.delta.partial_json;
207
+ }
208
+ break;
209
+ case "content_block_stop":
210
+ if (currentToolUse) {
211
+ yield {
212
+ type: "tool-call",
213
+ toolCall: {
214
+ id: currentToolUse.id,
215
+ name: currentToolUse.name,
216
+ args: JSON.parse(currentToolUse.input || "{}")
217
+ }
218
+ };
219
+ currentToolUse = null;
220
+ }
221
+ break;
222
+ case "message_delta":
223
+ if (event.usage) {
224
+ outputTokens = event.usage.output_tokens ?? 0;
225
+ }
226
+ if (event.delta?.stop_reason) {
227
+ yield {
228
+ type: "finish",
229
+ finishReason: mapFinishReason(event.delta.stop_reason),
230
+ usage: {
231
+ promptTokens: inputTokens,
232
+ completionTokens: outputTokens,
233
+ totalTokens: inputTokens + outputTokens
234
+ }
235
+ };
236
+ }
237
+ break;
238
+ }
239
+ }
240
+ }
241
+ };
242
+ }
243
+ function mapFinishReason(reason) {
244
+ switch (reason) {
245
+ case "end_turn":
246
+ case "stop_sequence":
247
+ return "stop";
248
+ case "max_tokens":
249
+ return "length";
250
+ case "tool_use":
251
+ return "tool-calls";
252
+ default:
253
+ return "unknown";
254
+ }
255
+ }
256
+ function formatMessagesForAnthropic(messages) {
257
+ let system = "";
258
+ const formatted = [];
259
+ const pendingToolResults = [];
260
+ for (const msg of messages) {
261
+ if (msg.role === "system") {
262
+ system += (system ? "\n" : "") + msg.content;
263
+ continue;
264
+ }
265
+ if (msg.role === "assistant" && pendingToolResults.length > 0) {
266
+ formatted.push({
267
+ role: "user",
268
+ content: pendingToolResults.map((tr) => ({
269
+ type: "tool_result",
270
+ tool_use_id: tr.toolCallId,
271
+ content: tr.content
272
+ }))
273
+ });
274
+ pendingToolResults.length = 0;
275
+ }
276
+ if (msg.role === "user") {
277
+ if (pendingToolResults.length > 0) {
278
+ formatted.push({
279
+ role: "user",
280
+ content: pendingToolResults.map((tr) => ({
281
+ type: "tool_result",
282
+ tool_use_id: tr.toolCallId,
283
+ content: tr.content
284
+ }))
285
+ });
286
+ pendingToolResults.length = 0;
287
+ }
288
+ if (typeof msg.content === "string") {
289
+ formatted.push({ role: "user", content: msg.content });
290
+ } else {
291
+ const content = [];
292
+ for (const part of msg.content) {
293
+ if (part.type === "text") {
294
+ content.push({ type: "text", text: part.text });
295
+ } else if (part.type === "image") {
296
+ const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
297
+ if (imageData.startsWith("http")) {
298
+ content.push({
299
+ type: "image",
300
+ source: { type: "url", url: imageData }
301
+ });
302
+ } else {
303
+ const base64 = imageData.startsWith("data:") ? imageData.split(",")[1] : imageData;
304
+ content.push({
305
+ type: "image",
306
+ source: {
307
+ type: "base64",
308
+ media_type: part.mimeType ?? "image/png",
309
+ data: base64
310
+ }
311
+ });
312
+ }
313
+ }
314
+ }
315
+ formatted.push({ role: "user", content });
316
+ }
317
+ } else if (msg.role === "assistant") {
318
+ const content = [];
319
+ if (msg.content) {
320
+ content.push({ type: "text", text: msg.content });
321
+ }
322
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
323
+ for (const tc of msg.toolCalls) {
324
+ content.push({
325
+ type: "tool_use",
326
+ id: tc.id,
327
+ name: tc.name,
328
+ input: tc.args
329
+ });
330
+ }
331
+ }
332
+ if (content.length > 0) {
333
+ formatted.push({ role: "assistant", content });
334
+ }
335
+ } else if (msg.role === "tool") {
336
+ pendingToolResults.push({
337
+ toolCallId: msg.toolCallId,
338
+ content: msg.content
339
+ });
340
+ }
341
+ }
342
+ if (pendingToolResults.length > 0) {
343
+ formatted.push({
344
+ role: "user",
345
+ content: pendingToolResults.map((tr) => ({
346
+ type: "tool_result",
347
+ tool_use_id: tr.toolCallId,
348
+ content: tr.content
349
+ }))
350
+ });
351
+ }
352
+ return { system, messages: formatted };
353
+ }
354
+
355
+ // src/adapters/base.ts
356
+ function hasMediaAttachments(message) {
357
+ const attachments = message.metadata?.attachments;
358
+ return attachments?.some(
359
+ (a) => a.type === "image" || a.type === "file" && a.mimeType === "application/pdf"
360
+ ) ?? false;
361
+ }
362
+ function attachmentToAnthropicImage(attachment) {
363
+ if (attachment.type !== "image") return null;
364
+ if (attachment.url) {
365
+ return {
366
+ type: "image",
367
+ source: {
368
+ type: "url",
369
+ url: attachment.url
370
+ }
371
+ };
372
+ }
373
+ if (!attachment.data) return null;
374
+ let base64Data = attachment.data;
375
+ if (base64Data.startsWith("data:")) {
376
+ const commaIndex = base64Data.indexOf(",");
377
+ if (commaIndex !== -1) {
378
+ base64Data = base64Data.slice(commaIndex + 1);
379
+ }
380
+ }
381
+ return {
382
+ type: "image",
383
+ source: {
384
+ type: "base64",
385
+ media_type: attachment.mimeType || "image/png",
386
+ data: base64Data
387
+ }
388
+ };
389
+ }
390
+ function attachmentToAnthropicDocument(attachment) {
391
+ if (attachment.type !== "file" || attachment.mimeType !== "application/pdf") {
392
+ return null;
393
+ }
394
+ if (attachment.url) {
395
+ return {
396
+ type: "document",
397
+ source: {
398
+ type: "url",
399
+ url: attachment.url
400
+ }
401
+ };
402
+ }
403
+ if (!attachment.data) return null;
404
+ let base64Data = attachment.data;
405
+ if (base64Data.startsWith("data:")) {
406
+ const commaIndex = base64Data.indexOf(",");
407
+ if (commaIndex !== -1) {
408
+ base64Data = base64Data.slice(commaIndex + 1);
409
+ }
410
+ }
411
+ return {
412
+ type: "document",
413
+ source: {
414
+ type: "base64",
415
+ media_type: "application/pdf",
416
+ data: base64Data
417
+ }
418
+ };
419
+ }
420
+ function messageToAnthropicContent(message) {
421
+ const attachments = message.metadata?.attachments;
422
+ const content = message.content ?? "";
423
+ if (!hasMediaAttachments(message)) {
424
+ return content;
425
+ }
426
+ const blocks = [];
427
+ if (attachments) {
428
+ for (const attachment of attachments) {
429
+ const imageBlock = attachmentToAnthropicImage(attachment);
430
+ if (imageBlock) {
431
+ blocks.push(imageBlock);
432
+ continue;
433
+ }
434
+ const docBlock = attachmentToAnthropicDocument(attachment);
435
+ if (docBlock) {
436
+ blocks.push(docBlock);
437
+ }
438
+ }
439
+ }
440
+ if (content) {
441
+ blocks.push({ type: "text", text: content });
442
+ }
443
+ return blocks;
444
+ }
445
+ function formatMessagesForAnthropic2(messages, systemPrompt) {
446
+ const formatted = [];
447
+ for (let i = 0; i < messages.length; i++) {
448
+ const msg = messages[i];
449
+ if (msg.role === "system") continue;
450
+ if (msg.role === "assistant") {
451
+ const content = [];
452
+ if (msg.content) {
453
+ content.push({ type: "text", text: msg.content });
454
+ }
455
+ if (msg.tool_calls && msg.tool_calls.length > 0) {
456
+ for (const tc of msg.tool_calls) {
457
+ content.push({
458
+ type: "tool_use",
459
+ id: tc.id,
460
+ name: tc.function.name,
461
+ input: JSON.parse(tc.function.arguments)
462
+ });
463
+ }
464
+ }
465
+ formatted.push({
466
+ role: "assistant",
467
+ content: content.length === 1 && content[0].type === "text" ? content[0].text : content
468
+ });
469
+ } else if (msg.role === "tool" && msg.tool_call_id) {
470
+ const toolResults = [
471
+ {
472
+ type: "tool_result",
473
+ tool_use_id: msg.tool_call_id,
474
+ content: msg.content ?? ""
475
+ }
476
+ ];
477
+ while (i + 1 < messages.length && messages[i + 1].role === "tool") {
478
+ i++;
479
+ const nextTool = messages[i];
480
+ if (nextTool.tool_call_id) {
481
+ toolResults.push({
482
+ type: "tool_result",
483
+ tool_use_id: nextTool.tool_call_id,
484
+ content: nextTool.content ?? ""
485
+ });
486
+ }
487
+ }
488
+ formatted.push({
489
+ role: "user",
490
+ content: toolResults
491
+ });
492
+ } else if (msg.role === "user") {
493
+ formatted.push({
494
+ role: "user",
495
+ content: messageToAnthropicContent(msg)
496
+ });
497
+ }
498
+ }
499
+ return {
500
+ system: "",
501
+ messages: formatted
502
+ };
503
+ }
504
+
505
+ // src/adapters/anthropic.ts
506
+ var AnthropicAdapter = class {
507
+ constructor(config) {
508
+ this.provider = "anthropic";
509
+ this.config = config;
510
+ this.model = config.model || "claude-3-5-sonnet-latest";
511
+ }
512
+ async getClient() {
513
+ if (!this.client) {
514
+ const { default: Anthropic } = await import('@anthropic-ai/sdk');
515
+ this.client = new Anthropic({
516
+ apiKey: this.config.apiKey
517
+ });
518
+ }
519
+ return this.client;
520
+ }
521
+ /**
522
+ * Convert OpenAI-style messages to Anthropic format
523
+ *
524
+ * OpenAI format:
525
+ * - { role: "assistant", content: "...", tool_calls: [...] }
526
+ * - { role: "tool", tool_call_id: "...", content: "..." }
527
+ *
528
+ * Anthropic format:
529
+ * - { role: "assistant", content: [{ type: "text", text: "..." }, { type: "tool_use", id: "...", name: "...", input: {...} }] }
530
+ * - { role: "user", content: [{ type: "tool_result", tool_use_id: "...", content: "..." }] }
531
+ */
532
+ convertToAnthropicMessages(rawMessages) {
533
+ const messages = [];
534
+ const pendingToolResults = [];
535
+ for (const msg of rawMessages) {
536
+ if (msg.role === "system") continue;
537
+ if (msg.role === "assistant") {
538
+ if (pendingToolResults.length > 0) {
539
+ messages.push({
540
+ role: "user",
541
+ content: pendingToolResults.map((tr) => ({
542
+ type: "tool_result",
543
+ tool_use_id: tr.tool_use_id,
544
+ content: tr.content
545
+ }))
546
+ });
547
+ pendingToolResults.length = 0;
548
+ }
549
+ const content = [];
550
+ if (msg.content && typeof msg.content === "string" && msg.content.trim()) {
551
+ content.push({ type: "text", text: msg.content });
552
+ }
553
+ const toolCalls = msg.tool_calls;
554
+ if (toolCalls && toolCalls.length > 0) {
555
+ for (const tc of toolCalls) {
556
+ let input = {};
557
+ try {
558
+ input = JSON.parse(tc.function.arguments);
559
+ } catch {
560
+ }
561
+ content.push({
562
+ type: "tool_use",
563
+ id: tc.id,
564
+ name: tc.function.name,
565
+ input
566
+ });
567
+ }
568
+ }
569
+ if (content.length > 0) {
570
+ messages.push({ role: "assistant", content });
571
+ }
572
+ } else if (msg.role === "tool") {
573
+ pendingToolResults.push({
574
+ tool_use_id: msg.tool_call_id,
575
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
576
+ });
577
+ } else if (msg.role === "user") {
578
+ if (pendingToolResults.length > 0) {
579
+ messages.push({
580
+ role: "user",
581
+ content: pendingToolResults.map((tr) => ({
582
+ type: "tool_result",
583
+ tool_use_id: tr.tool_use_id,
584
+ content: tr.content
585
+ }))
586
+ });
587
+ pendingToolResults.length = 0;
588
+ }
589
+ if (msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0) {
590
+ const content = [];
591
+ if (msg.content && typeof msg.content === "string") {
592
+ content.push({ type: "text", text: msg.content });
593
+ }
594
+ for (const attachment of msg.attachments) {
595
+ if (attachment.type === "image") {
596
+ if (attachment.url) {
597
+ content.push({
598
+ type: "image",
599
+ source: {
600
+ type: "url",
601
+ url: attachment.url
602
+ }
603
+ });
604
+ } else if (attachment.data) {
605
+ let base64Data = attachment.data;
606
+ if (base64Data.startsWith("data:")) {
607
+ const commaIndex = base64Data.indexOf(",");
608
+ if (commaIndex !== -1) {
609
+ base64Data = base64Data.slice(commaIndex + 1);
610
+ }
611
+ }
612
+ content.push({
613
+ type: "image",
614
+ source: {
615
+ type: "base64",
616
+ media_type: attachment.mimeType || "image/png",
617
+ data: base64Data
618
+ }
619
+ });
620
+ }
621
+ } else if (attachment.type === "file" && attachment.mimeType === "application/pdf") {
622
+ if (attachment.url) {
623
+ content.push({
624
+ type: "document",
625
+ source: {
626
+ type: "url",
627
+ url: attachment.url
628
+ }
629
+ });
630
+ } else if (attachment.data) {
631
+ let base64Data = attachment.data;
632
+ if (base64Data.startsWith("data:")) {
633
+ const commaIndex = base64Data.indexOf(",");
634
+ if (commaIndex !== -1) {
635
+ base64Data = base64Data.slice(commaIndex + 1);
636
+ }
637
+ }
638
+ content.push({
639
+ type: "document",
640
+ source: {
641
+ type: "base64",
642
+ media_type: "application/pdf",
643
+ data: base64Data
644
+ }
645
+ });
646
+ }
647
+ }
648
+ }
649
+ messages.push({ role: "user", content });
650
+ } else {
651
+ messages.push({
652
+ role: "user",
653
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
654
+ });
655
+ }
656
+ }
657
+ }
658
+ if (pendingToolResults.length > 0) {
659
+ messages.push({
660
+ role: "user",
661
+ content: pendingToolResults.map((tr) => ({
662
+ type: "tool_result",
663
+ tool_use_id: tr.tool_use_id,
664
+ content: tr.content
665
+ }))
666
+ });
667
+ }
668
+ return messages;
669
+ }
670
+ /**
671
+ * Build common request options for both streaming and non-streaming
672
+ */
673
+ buildRequestOptions(request) {
674
+ const systemMessage = request.systemPrompt || "";
675
+ let messages;
676
+ if (request.rawMessages && request.rawMessages.length > 0) {
677
+ messages = this.convertToAnthropicMessages(request.rawMessages);
678
+ } else {
679
+ const formatted = formatMessagesForAnthropic2(request.messages);
680
+ messages = formatted.messages;
681
+ }
682
+ const tools = request.actions?.map((action) => ({
683
+ name: action.name,
684
+ description: action.description,
685
+ input_schema: {
686
+ type: "object",
687
+ properties: action.parameters ? Object.fromEntries(
688
+ Object.entries(action.parameters).map(([key, param]) => [
689
+ key,
690
+ {
691
+ type: param.type,
692
+ description: param.description,
693
+ enum: param.enum
694
+ }
695
+ ])
696
+ ) : {},
697
+ required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : []
698
+ }
699
+ }));
700
+ const options = {
701
+ model: request.config?.model || this.model,
702
+ max_tokens: request.config?.maxTokens || this.config.maxTokens || 4096,
703
+ system: systemMessage,
704
+ messages,
705
+ tools: tools?.length ? tools : void 0
706
+ };
707
+ if (this.config.thinking?.type === "enabled") {
708
+ options.thinking = {
709
+ type: "enabled",
710
+ budget_tokens: this.config.thinking.budgetTokens || 1e4
711
+ };
712
+ }
713
+ return { options, messages };
714
+ }
715
+ /**
716
+ * Non-streaming completion (for debugging/comparison with original studio-ai)
717
+ */
718
+ async complete(request) {
719
+ const client = await this.getClient();
720
+ const { options } = this.buildRequestOptions(request);
721
+ const nonStreamingOptions = {
722
+ ...options,
723
+ stream: false
724
+ };
725
+ try {
726
+ const response = await client.messages.create(nonStreamingOptions);
727
+ let content = "";
728
+ let thinking = "";
729
+ const toolCalls = [];
730
+ for (const block of response.content) {
731
+ if (block.type === "text") {
732
+ content += block.text;
733
+ } else if (block.type === "thinking") {
734
+ thinking += block.thinking;
735
+ } else if (block.type === "tool_use") {
736
+ toolCalls.push({
737
+ id: block.id,
738
+ name: block.name,
739
+ args: block.input
740
+ });
741
+ }
742
+ }
743
+ return {
744
+ content,
745
+ toolCalls,
746
+ thinking: thinking || void 0,
747
+ rawResponse: response
748
+ };
749
+ } catch (error) {
750
+ throw error;
751
+ }
752
+ }
753
+ async *stream(request) {
754
+ const client = await this.getClient();
755
+ const { options } = this.buildRequestOptions(request);
756
+ const messageId = generateMessageId();
757
+ yield { type: "message:start", id: messageId };
758
+ try {
759
+ const stream = await client.messages.stream(options);
760
+ let currentToolUse = null;
761
+ let isInThinkingBlock = false;
762
+ for await (const event of stream) {
763
+ if (request.signal?.aborted) {
764
+ break;
765
+ }
766
+ switch (event.type) {
767
+ case "content_block_start":
768
+ if (event.content_block.type === "tool_use") {
769
+ currentToolUse = {
770
+ id: event.content_block.id,
771
+ name: event.content_block.name,
772
+ input: ""
773
+ };
774
+ yield {
775
+ type: "action:start",
776
+ id: currentToolUse.id,
777
+ name: currentToolUse.name
778
+ };
779
+ } else if (event.content_block.type === "thinking") {
780
+ isInThinkingBlock = true;
781
+ yield { type: "thinking:start" };
782
+ }
783
+ break;
784
+ case "content_block_delta":
785
+ if (event.delta.type === "text_delta") {
786
+ yield { type: "message:delta", content: event.delta.text };
787
+ } else if (event.delta.type === "thinking_delta") {
788
+ yield { type: "thinking:delta", content: event.delta.thinking };
789
+ } else if (event.delta.type === "input_json_delta" && currentToolUse) {
790
+ currentToolUse.input += event.delta.partial_json;
791
+ }
792
+ break;
793
+ case "content_block_stop":
794
+ if (currentToolUse) {
795
+ yield {
796
+ type: "action:args",
797
+ id: currentToolUse.id,
798
+ args: currentToolUse.input
799
+ };
800
+ currentToolUse = null;
801
+ }
802
+ if (isInThinkingBlock) {
803
+ yield { type: "thinking:end" };
804
+ isInThinkingBlock = false;
805
+ }
806
+ break;
807
+ case "message_stop":
808
+ break;
809
+ }
810
+ }
811
+ yield { type: "message:end" };
812
+ yield { type: "done" };
813
+ } catch (error) {
814
+ yield {
815
+ type: "error",
816
+ message: error instanceof Error ? error.message : "Unknown error",
817
+ code: "ANTHROPIC_ERROR"
818
+ };
819
+ }
820
+ }
821
+ };
822
+ function createAnthropicAdapter(config) {
823
+ return new AnthropicAdapter(config);
824
+ }
825
+
826
+ // src/providers/anthropic/index.ts
827
+ var ANTHROPIC_MODELS2 = {
828
+ // Claude 4 series (latest)
829
+ "claude-sonnet-4-20250514": {
830
+ vision: true,
831
+ tools: true,
832
+ thinking: true,
833
+ maxTokens: 64e3
834
+ },
835
+ "claude-opus-4-20250514": {
836
+ vision: true,
837
+ tools: true,
838
+ thinking: true,
839
+ maxTokens: 32e3
840
+ },
841
+ // Claude 3.5 series
842
+ "claude-3-5-sonnet-latest": {
843
+ vision: true,
844
+ tools: true,
845
+ thinking: true,
846
+ maxTokens: 2e5
847
+ },
848
+ "claude-3-5-sonnet-20241022": {
849
+ vision: true,
850
+ tools: true,
851
+ thinking: true,
852
+ maxTokens: 2e5
853
+ },
854
+ "claude-3-5-haiku-latest": {
855
+ vision: true,
856
+ tools: true,
857
+ thinking: false,
858
+ maxTokens: 2e5
859
+ },
860
+ "claude-3-5-haiku-20241022": {
861
+ vision: true,
862
+ tools: true,
863
+ thinking: false,
864
+ maxTokens: 2e5
865
+ },
866
+ // Claude 3 series
867
+ "claude-3-opus-latest": {
868
+ vision: true,
869
+ tools: true,
870
+ thinking: true,
871
+ maxTokens: 2e5
872
+ },
873
+ "claude-3-opus-20240229": {
874
+ vision: true,
875
+ tools: true,
876
+ thinking: true,
877
+ maxTokens: 2e5
878
+ },
879
+ "claude-3-sonnet-20240229": {
880
+ vision: true,
881
+ tools: true,
882
+ thinking: false,
883
+ maxTokens: 2e5
884
+ },
885
+ "claude-3-haiku-20240307": {
886
+ vision: true,
887
+ tools: true,
888
+ thinking: false,
889
+ maxTokens: 2e5
890
+ }
891
+ };
892
+ function createAnthropic(config = {}) {
893
+ const apiKey = config.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
894
+ return {
895
+ name: "anthropic",
896
+ supportedModels: Object.keys(ANTHROPIC_MODELS2),
897
+ languageModel(modelId) {
898
+ return createAnthropicAdapter({
899
+ apiKey,
900
+ model: modelId,
901
+ baseUrl: config.baseUrl,
902
+ thinking: config.thinkingBudget ? { type: "enabled", budgetTokens: config.thinkingBudget } : void 0
903
+ });
904
+ },
905
+ getCapabilities(modelId) {
906
+ const model = ANTHROPIC_MODELS2[modelId] ?? ANTHROPIC_MODELS2["claude-3-5-sonnet-latest"];
907
+ return {
908
+ supportsVision: model.vision,
909
+ supportsTools: model.tools,
910
+ supportsThinking: model.thinking,
911
+ supportsStreaming: true,
912
+ supportsPDF: true,
913
+ // Claude supports PDFs
914
+ supportsAudio: false,
915
+ supportsVideo: false,
916
+ maxTokens: model.maxTokens,
917
+ supportedImageTypes: [
918
+ "image/png",
919
+ "image/jpeg",
920
+ "image/gif",
921
+ "image/webp"
922
+ ],
923
+ supportsJsonMode: false,
924
+ // Anthropic doesn't have JSON mode
925
+ supportsSystemMessages: true
926
+ };
927
+ }
928
+ };
929
+ }
930
+ var createAnthropicProvider = createAnthropic;
931
+
932
+ export { anthropic, createAnthropic, anthropic as createAnthropicModel, createAnthropicProvider };
933
+ //# sourceMappingURL=index.mjs.map
934
+ //# sourceMappingURL=index.mjs.map