@providerprotocol/ai 0.0.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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/dist/anthropic/index.d.ts +41 -0
  4. package/dist/anthropic/index.js +500 -0
  5. package/dist/anthropic/index.js.map +1 -0
  6. package/dist/chunk-CUCRF5W6.js +136 -0
  7. package/dist/chunk-CUCRF5W6.js.map +1 -0
  8. package/dist/chunk-FTFX2VET.js +424 -0
  9. package/dist/chunk-FTFX2VET.js.map +1 -0
  10. package/dist/chunk-QUUX4G7U.js +117 -0
  11. package/dist/chunk-QUUX4G7U.js.map +1 -0
  12. package/dist/chunk-Y6Q7JCNP.js +39 -0
  13. package/dist/chunk-Y6Q7JCNP.js.map +1 -0
  14. package/dist/google/index.d.ts +69 -0
  15. package/dist/google/index.js +517 -0
  16. package/dist/google/index.js.map +1 -0
  17. package/dist/http/index.d.ts +61 -0
  18. package/dist/http/index.js +43 -0
  19. package/dist/http/index.js.map +1 -0
  20. package/dist/index.d.ts +792 -0
  21. package/dist/index.js +898 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/openai/index.d.ts +204 -0
  24. package/dist/openai/index.js +1340 -0
  25. package/dist/openai/index.js.map +1 -0
  26. package/dist/provider-CUJWjgNl.d.ts +192 -0
  27. package/dist/retry-I2661_rv.d.ts +118 -0
  28. package/package.json +88 -0
  29. package/src/anthropic/index.ts +3 -0
  30. package/src/core/image.ts +188 -0
  31. package/src/core/llm.ts +619 -0
  32. package/src/core/provider.ts +92 -0
  33. package/src/google/index.ts +3 -0
  34. package/src/http/errors.ts +112 -0
  35. package/src/http/fetch.ts +210 -0
  36. package/src/http/index.ts +31 -0
  37. package/src/http/keys.ts +136 -0
  38. package/src/http/retry.ts +205 -0
  39. package/src/http/sse.ts +136 -0
  40. package/src/index.ts +32 -0
  41. package/src/openai/index.ts +9 -0
  42. package/src/providers/anthropic/index.ts +17 -0
  43. package/src/providers/anthropic/llm.ts +196 -0
  44. package/src/providers/anthropic/transform.ts +452 -0
  45. package/src/providers/anthropic/types.ts +213 -0
  46. package/src/providers/google/index.ts +17 -0
  47. package/src/providers/google/llm.ts +203 -0
  48. package/src/providers/google/transform.ts +487 -0
  49. package/src/providers/google/types.ts +214 -0
  50. package/src/providers/openai/index.ts +151 -0
  51. package/src/providers/openai/llm.completions.ts +201 -0
  52. package/src/providers/openai/llm.responses.ts +211 -0
  53. package/src/providers/openai/transform.completions.ts +628 -0
  54. package/src/providers/openai/transform.responses.ts +718 -0
  55. package/src/providers/openai/types.ts +711 -0
  56. package/src/types/content.ts +133 -0
  57. package/src/types/errors.ts +85 -0
  58. package/src/types/index.ts +105 -0
  59. package/src/types/llm.ts +211 -0
  60. package/src/types/messages.ts +182 -0
  61. package/src/types/provider.ts +195 -0
  62. package/src/types/schema.ts +58 -0
  63. package/src/types/stream.ts +146 -0
  64. package/src/types/thread.ts +226 -0
  65. package/src/types/tool.ts +88 -0
  66. package/src/types/turn.ts +118 -0
  67. package/src/utils/id.ts +28 -0
package/dist/index.js ADDED
@@ -0,0 +1,898 @@
1
+ import {
2
+ createProvider
3
+ } from "./chunk-Y6Q7JCNP.js";
4
+ import {
5
+ AssistantMessage,
6
+ Message,
7
+ ToolResultMessage,
8
+ UserMessage,
9
+ generateId,
10
+ isAssistantMessage,
11
+ isToolResultMessage,
12
+ isUserMessage
13
+ } from "./chunk-QUUX4G7U.js";
14
+ import {
15
+ ExponentialBackoff,
16
+ LinearBackoff,
17
+ NoRetry,
18
+ RetryAfterStrategy,
19
+ TokenBucket
20
+ } from "./chunk-CUCRF5W6.js";
21
+ import {
22
+ DynamicKey,
23
+ RoundRobinKeys,
24
+ UPPError,
25
+ WeightedKeys
26
+ } from "./chunk-FTFX2VET.js";
27
+
28
+ // src/types/turn.ts
29
+ function createTurn(messages, toolExecutions, usage, cycles, data) {
30
+ const response = messages.filter((m) => m.type === "assistant").pop();
31
+ if (!response) {
32
+ throw new Error("Turn must contain at least one assistant message");
33
+ }
34
+ return {
35
+ messages,
36
+ response,
37
+ toolExecutions,
38
+ usage,
39
+ cycles,
40
+ data
41
+ };
42
+ }
43
+ function emptyUsage() {
44
+ return {
45
+ inputTokens: 0,
46
+ outputTokens: 0,
47
+ totalTokens: 0,
48
+ cycles: []
49
+ };
50
+ }
51
+ function aggregateUsage(usages) {
52
+ const cycles = [];
53
+ let inputTokens = 0;
54
+ let outputTokens = 0;
55
+ for (const usage of usages) {
56
+ inputTokens += usage.inputTokens;
57
+ outputTokens += usage.outputTokens;
58
+ cycles.push({
59
+ inputTokens: usage.inputTokens,
60
+ outputTokens: usage.outputTokens
61
+ });
62
+ }
63
+ return {
64
+ inputTokens,
65
+ outputTokens,
66
+ totalTokens: inputTokens + outputTokens,
67
+ cycles
68
+ };
69
+ }
70
+
71
+ // src/types/stream.ts
72
+ function createStreamResult(generator, turnPromise, abortController) {
73
+ return {
74
+ [Symbol.asyncIterator]() {
75
+ return generator;
76
+ },
77
+ turn: turnPromise,
78
+ abort() {
79
+ abortController.abort();
80
+ }
81
+ };
82
+ }
83
+ function textDelta(text2, index = 0) {
84
+ return {
85
+ type: "text_delta",
86
+ index,
87
+ delta: { text: text2 }
88
+ };
89
+ }
90
+ function toolCallDelta(toolCallId, toolName, argumentsJson, index = 0) {
91
+ return {
92
+ type: "tool_call_delta",
93
+ index,
94
+ delta: { toolCallId, toolName, argumentsJson }
95
+ };
96
+ }
97
+ function messageStart() {
98
+ return {
99
+ type: "message_start",
100
+ index: 0,
101
+ delta: {}
102
+ };
103
+ }
104
+ function messageStop() {
105
+ return {
106
+ type: "message_stop",
107
+ index: 0,
108
+ delta: {}
109
+ };
110
+ }
111
+ function contentBlockStart(index) {
112
+ return {
113
+ type: "content_block_start",
114
+ index,
115
+ delta: {}
116
+ };
117
+ }
118
+ function contentBlockStop(index) {
119
+ return {
120
+ type: "content_block_stop",
121
+ index,
122
+ delta: {}
123
+ };
124
+ }
125
+
126
+ // src/core/llm.ts
127
+ var DEFAULT_MAX_ITERATIONS = 10;
128
+ function llm(options) {
129
+ const { model: modelRef, config = {}, params, system, tools, toolStrategy, structure } = options;
130
+ const provider = modelRef.provider;
131
+ if (!provider.modalities.llm) {
132
+ throw new UPPError(
133
+ `Provider '${provider.name}' does not support LLM modality`,
134
+ "INVALID_REQUEST",
135
+ provider.name,
136
+ "llm"
137
+ );
138
+ }
139
+ const boundModel = provider.modalities.llm.bind(modelRef.modelId);
140
+ const capabilities = boundModel.capabilities;
141
+ if (structure && !capabilities.structuredOutput) {
142
+ throw new UPPError(
143
+ `Provider '${provider.name}' does not support structured output`,
144
+ "INVALID_REQUEST",
145
+ provider.name,
146
+ "llm"
147
+ );
148
+ }
149
+ if (tools && tools.length > 0 && !capabilities.tools) {
150
+ throw new UPPError(
151
+ `Provider '${provider.name}' does not support tools`,
152
+ "INVALID_REQUEST",
153
+ provider.name,
154
+ "llm"
155
+ );
156
+ }
157
+ const instance = {
158
+ model: boundModel,
159
+ system,
160
+ params,
161
+ capabilities,
162
+ async generate(historyOrInput, ...inputs) {
163
+ const { history, messages } = parseInputs(historyOrInput, inputs);
164
+ return executeGenerate(
165
+ boundModel,
166
+ config,
167
+ system,
168
+ params,
169
+ tools,
170
+ toolStrategy,
171
+ structure,
172
+ history,
173
+ messages
174
+ );
175
+ },
176
+ stream(historyOrInput, ...inputs) {
177
+ if (!capabilities.streaming) {
178
+ throw new UPPError(
179
+ `Provider '${provider.name}' does not support streaming`,
180
+ "INVALID_REQUEST",
181
+ provider.name,
182
+ "llm"
183
+ );
184
+ }
185
+ const { history, messages } = parseInputs(historyOrInput, inputs);
186
+ return executeStream(
187
+ boundModel,
188
+ config,
189
+ system,
190
+ params,
191
+ tools,
192
+ toolStrategy,
193
+ structure,
194
+ history,
195
+ messages
196
+ );
197
+ }
198
+ };
199
+ return instance;
200
+ }
201
+ function isMessageInstance(value) {
202
+ if (value instanceof Message) {
203
+ return true;
204
+ }
205
+ if (typeof value === "object" && value !== null && "timestamp" in value && "type" in value && "id" in value) {
206
+ const obj = value;
207
+ const messageTypes = ["user", "assistant", "tool_result"];
208
+ return messageTypes.includes(obj.type);
209
+ }
210
+ return false;
211
+ }
212
+ function parseInputs(historyOrInput, inputs) {
213
+ if (typeof historyOrInput === "object" && historyOrInput !== null && "messages" in historyOrInput && Array.isArray(historyOrInput.messages)) {
214
+ const thread = historyOrInput;
215
+ const newMessages2 = inputs.map(inputToMessage);
216
+ return { history: [...thread.messages], messages: newMessages2 };
217
+ }
218
+ if (Array.isArray(historyOrInput) && historyOrInput.length > 0) {
219
+ const first = historyOrInput[0];
220
+ if (isMessageInstance(first)) {
221
+ const newMessages2 = inputs.map(inputToMessage);
222
+ return { history: historyOrInput, messages: newMessages2 };
223
+ }
224
+ }
225
+ const allInputs = [historyOrInput, ...inputs];
226
+ const newMessages = allInputs.map(inputToMessage);
227
+ return { history: [], messages: newMessages };
228
+ }
229
+ function inputToMessage(input) {
230
+ if (typeof input === "string") {
231
+ return new UserMessage(input);
232
+ }
233
+ if ("type" in input && "id" in input && "timestamp" in input) {
234
+ return input;
235
+ }
236
+ const block = input;
237
+ if (block.type === "text") {
238
+ return new UserMessage(block.text);
239
+ }
240
+ return new UserMessage([block]);
241
+ }
242
+ async function executeGenerate(model, config, system, params, tools, toolStrategy, structure, history, newMessages) {
243
+ validateMediaCapabilities(
244
+ [...history, ...newMessages],
245
+ model.capabilities,
246
+ model.provider.name
247
+ );
248
+ const maxIterations = toolStrategy?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
249
+ const allMessages = [...history, ...newMessages];
250
+ const toolExecutions = [];
251
+ const usages = [];
252
+ let cycles = 0;
253
+ let structuredData;
254
+ while (cycles < maxIterations + 1) {
255
+ cycles++;
256
+ const request = {
257
+ messages: allMessages,
258
+ system,
259
+ params,
260
+ tools,
261
+ structure,
262
+ config
263
+ };
264
+ const response = await model.complete(request);
265
+ usages.push(response.usage);
266
+ allMessages.push(response.message);
267
+ if (response.data !== void 0) {
268
+ structuredData = response.data;
269
+ }
270
+ if (response.message.hasToolCalls && tools && tools.length > 0) {
271
+ if (response.data !== void 0) {
272
+ break;
273
+ }
274
+ if (cycles >= maxIterations) {
275
+ await toolStrategy?.onMaxIterations?.(maxIterations);
276
+ throw new UPPError(
277
+ `Tool execution exceeded maximum iterations (${maxIterations})`,
278
+ "INVALID_REQUEST",
279
+ model.provider.name,
280
+ "llm"
281
+ );
282
+ }
283
+ const results = await executeTools(
284
+ response.message,
285
+ tools,
286
+ toolStrategy,
287
+ toolExecutions
288
+ );
289
+ allMessages.push(new ToolResultMessage(results));
290
+ continue;
291
+ }
292
+ break;
293
+ }
294
+ const data = structure ? structuredData : void 0;
295
+ return createTurn(
296
+ allMessages.slice(history.length),
297
+ // Only messages from this turn
298
+ toolExecutions,
299
+ aggregateUsage(usages),
300
+ cycles,
301
+ data
302
+ );
303
+ }
304
+ function executeStream(model, config, system, params, tools, toolStrategy, structure, history, newMessages) {
305
+ validateMediaCapabilities(
306
+ [...history, ...newMessages],
307
+ model.capabilities,
308
+ model.provider.name
309
+ );
310
+ const abortController = new AbortController();
311
+ const allMessages = [...history, ...newMessages];
312
+ const toolExecutions = [];
313
+ const usages = [];
314
+ let cycles = 0;
315
+ let generatorError = null;
316
+ let structuredData;
317
+ let resolveGenerator;
318
+ let rejectGenerator;
319
+ const generatorDone = new Promise((resolve, reject) => {
320
+ resolveGenerator = resolve;
321
+ rejectGenerator = reject;
322
+ });
323
+ const maxIterations = toolStrategy?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
324
+ async function* generateStream() {
325
+ try {
326
+ while (cycles < maxIterations + 1) {
327
+ cycles++;
328
+ const request = {
329
+ messages: allMessages,
330
+ system,
331
+ params,
332
+ tools,
333
+ structure,
334
+ config,
335
+ signal: abortController.signal
336
+ };
337
+ const streamResult = model.stream(request);
338
+ for await (const event of streamResult) {
339
+ yield event;
340
+ }
341
+ const response = await streamResult.response;
342
+ usages.push(response.usage);
343
+ allMessages.push(response.message);
344
+ if (response.data !== void 0) {
345
+ structuredData = response.data;
346
+ }
347
+ if (response.message.hasToolCalls && tools && tools.length > 0) {
348
+ if (response.data !== void 0) {
349
+ break;
350
+ }
351
+ if (cycles >= maxIterations) {
352
+ await toolStrategy?.onMaxIterations?.(maxIterations);
353
+ throw new UPPError(
354
+ `Tool execution exceeded maximum iterations (${maxIterations})`,
355
+ "INVALID_REQUEST",
356
+ model.provider.name,
357
+ "llm"
358
+ );
359
+ }
360
+ const results = await executeTools(
361
+ response.message,
362
+ tools,
363
+ toolStrategy,
364
+ toolExecutions
365
+ );
366
+ allMessages.push(new ToolResultMessage(results));
367
+ continue;
368
+ }
369
+ break;
370
+ }
371
+ resolveGenerator();
372
+ } catch (error) {
373
+ generatorError = error;
374
+ rejectGenerator(error);
375
+ throw error;
376
+ }
377
+ }
378
+ const turnPromise = (async () => {
379
+ await generatorDone;
380
+ if (generatorError) {
381
+ throw generatorError;
382
+ }
383
+ const data = structure ? structuredData : void 0;
384
+ return createTurn(
385
+ allMessages.slice(history.length),
386
+ toolExecutions,
387
+ aggregateUsage(usages),
388
+ cycles,
389
+ data
390
+ );
391
+ })();
392
+ return createStreamResult(generateStream(), turnPromise, abortController);
393
+ }
394
+ async function executeTools(message, tools, toolStrategy, executions) {
395
+ const toolCalls = message.toolCalls ?? [];
396
+ const results = [];
397
+ const toolMap = new Map(tools.map((t) => [t.name, t]));
398
+ const promises = toolCalls.map(async (call) => {
399
+ const tool = toolMap.get(call.toolName);
400
+ if (!tool) {
401
+ return {
402
+ toolCallId: call.toolCallId,
403
+ result: `Tool '${call.toolName}' not found`,
404
+ isError: true
405
+ };
406
+ }
407
+ const startTime = Date.now();
408
+ await toolStrategy?.onToolCall?.(tool, call.arguments);
409
+ if (toolStrategy?.onBeforeCall) {
410
+ const shouldRun = await toolStrategy.onBeforeCall(tool, call.arguments);
411
+ if (!shouldRun) {
412
+ return {
413
+ toolCallId: call.toolCallId,
414
+ result: "Tool execution skipped",
415
+ isError: true
416
+ };
417
+ }
418
+ }
419
+ let approved = true;
420
+ if (tool.approval) {
421
+ try {
422
+ approved = await tool.approval(call.arguments);
423
+ } catch (error) {
424
+ throw error;
425
+ }
426
+ }
427
+ if (!approved) {
428
+ const execution = {
429
+ toolName: tool.name,
430
+ toolCallId: call.toolCallId,
431
+ arguments: call.arguments,
432
+ result: "Tool execution denied",
433
+ isError: true,
434
+ duration: Date.now() - startTime,
435
+ approved: false
436
+ };
437
+ executions.push(execution);
438
+ return {
439
+ toolCallId: call.toolCallId,
440
+ result: "Tool execution denied by approval handler",
441
+ isError: true
442
+ };
443
+ }
444
+ try {
445
+ const result = await tool.run(call.arguments);
446
+ await toolStrategy?.onAfterCall?.(tool, call.arguments, result);
447
+ const execution = {
448
+ toolName: tool.name,
449
+ toolCallId: call.toolCallId,
450
+ arguments: call.arguments,
451
+ result,
452
+ isError: false,
453
+ duration: Date.now() - startTime,
454
+ approved
455
+ };
456
+ executions.push(execution);
457
+ return {
458
+ toolCallId: call.toolCallId,
459
+ result,
460
+ isError: false
461
+ };
462
+ } catch (error) {
463
+ await toolStrategy?.onError?.(tool, call.arguments, error);
464
+ const errorMessage = error instanceof Error ? error.message : String(error);
465
+ const execution = {
466
+ toolName: tool.name,
467
+ toolCallId: call.toolCallId,
468
+ arguments: call.arguments,
469
+ result: errorMessage,
470
+ isError: true,
471
+ duration: Date.now() - startTime,
472
+ approved
473
+ };
474
+ executions.push(execution);
475
+ return {
476
+ toolCallId: call.toolCallId,
477
+ result: errorMessage,
478
+ isError: true
479
+ };
480
+ }
481
+ });
482
+ results.push(...await Promise.all(promises));
483
+ return results;
484
+ }
485
+ function validateMediaCapabilities(messages, capabilities, providerName) {
486
+ for (const msg of messages) {
487
+ if (!isUserMessage(msg)) continue;
488
+ for (const block of msg.content) {
489
+ if (block.type === "image" && !capabilities.imageInput) {
490
+ throw new UPPError(
491
+ `Provider '${providerName}' does not support image input`,
492
+ "INVALID_REQUEST",
493
+ providerName,
494
+ "llm"
495
+ );
496
+ }
497
+ if (block.type === "video" && !capabilities.videoInput) {
498
+ throw new UPPError(
499
+ `Provider '${providerName}' does not support video input`,
500
+ "INVALID_REQUEST",
501
+ providerName,
502
+ "llm"
503
+ );
504
+ }
505
+ if (block.type === "audio" && !capabilities.audioInput) {
506
+ throw new UPPError(
507
+ `Provider '${providerName}' does not support audio input`,
508
+ "INVALID_REQUEST",
509
+ providerName,
510
+ "llm"
511
+ );
512
+ }
513
+ }
514
+ }
515
+ }
516
+
517
+ // src/core/image.ts
518
+ var Image = class _Image {
519
+ source;
520
+ mimeType;
521
+ width;
522
+ height;
523
+ constructor(source, mimeType, width, height) {
524
+ this.source = source;
525
+ this.mimeType = mimeType;
526
+ this.width = width;
527
+ this.height = height;
528
+ }
529
+ /**
530
+ * Check if this image has data loaded (false for URL sources)
531
+ */
532
+ get hasData() {
533
+ return this.source.type !== "url";
534
+ }
535
+ /**
536
+ * Convert to base64 string (throws if source is URL)
537
+ */
538
+ toBase64() {
539
+ if (this.source.type === "base64") {
540
+ return this.source.data;
541
+ }
542
+ if (this.source.type === "bytes") {
543
+ return btoa(
544
+ Array.from(this.source.data).map((b) => String.fromCharCode(b)).join("")
545
+ );
546
+ }
547
+ throw new Error("Cannot convert URL image to base64. Fetch the image first.");
548
+ }
549
+ /**
550
+ * Convert to data URL (throws if source is URL)
551
+ */
552
+ toDataUrl() {
553
+ const base64 = this.toBase64();
554
+ return `data:${this.mimeType};base64,${base64}`;
555
+ }
556
+ /**
557
+ * Get raw bytes (throws if source is URL)
558
+ */
559
+ toBytes() {
560
+ if (this.source.type === "bytes") {
561
+ return this.source.data;
562
+ }
563
+ if (this.source.type === "base64") {
564
+ const binaryString = atob(this.source.data);
565
+ const bytes = new Uint8Array(binaryString.length);
566
+ for (let i = 0; i < binaryString.length; i++) {
567
+ bytes[i] = binaryString.charCodeAt(i);
568
+ }
569
+ return bytes;
570
+ }
571
+ throw new Error("Cannot get bytes from URL image. Fetch the image first.");
572
+ }
573
+ /**
574
+ * Get the URL (only for URL sources)
575
+ */
576
+ toUrl() {
577
+ if (this.source.type === "url") {
578
+ return this.source.url;
579
+ }
580
+ throw new Error("This image does not have a URL source.");
581
+ }
582
+ /**
583
+ * Convert to ImageBlock for use in messages
584
+ */
585
+ toBlock() {
586
+ return {
587
+ type: "image",
588
+ source: this.source,
589
+ mimeType: this.mimeType,
590
+ width: this.width,
591
+ height: this.height
592
+ };
593
+ }
594
+ /**
595
+ * Create from file path (reads file into memory)
596
+ */
597
+ static async fromPath(path) {
598
+ const file = Bun.file(path);
599
+ const data = await file.arrayBuffer();
600
+ const mimeType = file.type || detectMimeType(path);
601
+ return new _Image(
602
+ { type: "bytes", data: new Uint8Array(data) },
603
+ mimeType
604
+ );
605
+ }
606
+ /**
607
+ * Create from URL reference (does not fetch - providers handle URL conversion)
608
+ */
609
+ static fromUrl(url, mimeType) {
610
+ const detected = mimeType || detectMimeTypeFromUrl(url);
611
+ return new _Image({ type: "url", url }, detected);
612
+ }
613
+ /**
614
+ * Create from raw bytes
615
+ */
616
+ static fromBytes(data, mimeType) {
617
+ return new _Image({ type: "bytes", data }, mimeType);
618
+ }
619
+ /**
620
+ * Create from base64 string
621
+ */
622
+ static fromBase64(base64, mimeType) {
623
+ return new _Image({ type: "base64", data: base64 }, mimeType);
624
+ }
625
+ /**
626
+ * Create from an existing ImageBlock
627
+ */
628
+ static fromBlock(block) {
629
+ return new _Image(
630
+ block.source,
631
+ block.mimeType,
632
+ block.width,
633
+ block.height
634
+ );
635
+ }
636
+ };
637
+ function detectMimeType(path) {
638
+ const ext = path.split(".").pop()?.toLowerCase();
639
+ switch (ext) {
640
+ case "jpg":
641
+ case "jpeg":
642
+ return "image/jpeg";
643
+ case "png":
644
+ return "image/png";
645
+ case "gif":
646
+ return "image/gif";
647
+ case "webp":
648
+ return "image/webp";
649
+ case "svg":
650
+ return "image/svg+xml";
651
+ case "bmp":
652
+ return "image/bmp";
653
+ case "ico":
654
+ return "image/x-icon";
655
+ default:
656
+ return "application/octet-stream";
657
+ }
658
+ }
659
+ function detectMimeTypeFromUrl(url) {
660
+ try {
661
+ const pathname = new URL(url).pathname;
662
+ return detectMimeType(pathname);
663
+ } catch {
664
+ return "application/octet-stream";
665
+ }
666
+ }
667
+
668
+ // src/types/content.ts
669
+ function text(content) {
670
+ return { type: "text", text: content };
671
+ }
672
+ function isTextBlock(block) {
673
+ return block.type === "text";
674
+ }
675
+ function isImageBlock(block) {
676
+ return block.type === "image";
677
+ }
678
+ function isAudioBlock(block) {
679
+ return block.type === "audio";
680
+ }
681
+ function isVideoBlock(block) {
682
+ return block.type === "video";
683
+ }
684
+ function isBinaryBlock(block) {
685
+ return block.type === "binary";
686
+ }
687
+
688
+ // src/types/thread.ts
689
+ var Thread = class _Thread {
690
+ /** Unique thread identifier */
691
+ id;
692
+ /** Internal message storage */
693
+ _messages;
694
+ /** Creation timestamp */
695
+ _createdAt;
696
+ /** Last update timestamp */
697
+ _updatedAt;
698
+ /**
699
+ * Create a new thread, optionally with initial messages
700
+ */
701
+ constructor(messages) {
702
+ this.id = generateId();
703
+ this._messages = messages ? [...messages] : [];
704
+ this._createdAt = /* @__PURE__ */ new Date();
705
+ this._updatedAt = /* @__PURE__ */ new Date();
706
+ }
707
+ /** All messages in the thread (readonly) */
708
+ get messages() {
709
+ return this._messages;
710
+ }
711
+ /** Number of messages */
712
+ get length() {
713
+ return this._messages.length;
714
+ }
715
+ /**
716
+ * Append messages from a turn
717
+ */
718
+ append(turn) {
719
+ this._messages.push(...turn.messages);
720
+ this._updatedAt = /* @__PURE__ */ new Date();
721
+ return this;
722
+ }
723
+ /**
724
+ * Add raw messages
725
+ */
726
+ push(...messages) {
727
+ this._messages.push(...messages);
728
+ this._updatedAt = /* @__PURE__ */ new Date();
729
+ return this;
730
+ }
731
+ /**
732
+ * Add a user message
733
+ */
734
+ user(content) {
735
+ this._messages.push(new UserMessage(content));
736
+ this._updatedAt = /* @__PURE__ */ new Date();
737
+ return this;
738
+ }
739
+ /**
740
+ * Add an assistant message
741
+ */
742
+ assistant(content) {
743
+ this._messages.push(new AssistantMessage(content));
744
+ this._updatedAt = /* @__PURE__ */ new Date();
745
+ return this;
746
+ }
747
+ /**
748
+ * Get messages by type
749
+ */
750
+ filter(type) {
751
+ return this._messages.filter((m) => m.type === type);
752
+ }
753
+ /**
754
+ * Get the last N messages
755
+ */
756
+ tail(count) {
757
+ return this._messages.slice(-count);
758
+ }
759
+ /**
760
+ * Create a new thread with a subset of messages
761
+ */
762
+ slice(start, end) {
763
+ return new _Thread(this._messages.slice(start, end));
764
+ }
765
+ /**
766
+ * Clear all messages
767
+ */
768
+ clear() {
769
+ this._messages = [];
770
+ this._updatedAt = /* @__PURE__ */ new Date();
771
+ return this;
772
+ }
773
+ /**
774
+ * Convert to plain message array
775
+ */
776
+ toMessages() {
777
+ return [...this._messages];
778
+ }
779
+ /**
780
+ * Serialize to JSON
781
+ */
782
+ toJSON() {
783
+ return {
784
+ id: this.id,
785
+ messages: this._messages.map((m) => this.messageToJSON(m)),
786
+ createdAt: this._createdAt.toISOString(),
787
+ updatedAt: this._updatedAt.toISOString()
788
+ };
789
+ }
790
+ /**
791
+ * Deserialize from JSON
792
+ */
793
+ static fromJSON(json) {
794
+ const messages = json.messages.map((m) => _Thread.messageFromJSON(m));
795
+ const thread = new _Thread(messages);
796
+ thread.id = json.id;
797
+ thread._createdAt = new Date(json.createdAt);
798
+ thread._updatedAt = new Date(json.updatedAt);
799
+ return thread;
800
+ }
801
+ /**
802
+ * Iterate over messages
803
+ */
804
+ [Symbol.iterator]() {
805
+ return this._messages[Symbol.iterator]();
806
+ }
807
+ /**
808
+ * Convert a message to JSON
809
+ */
810
+ messageToJSON(m) {
811
+ const base = {
812
+ id: m.id,
813
+ type: m.type,
814
+ content: [],
815
+ metadata: m.metadata,
816
+ timestamp: m.timestamp.toISOString()
817
+ };
818
+ if (m instanceof UserMessage) {
819
+ base.content = m.content;
820
+ } else if (m instanceof AssistantMessage) {
821
+ base.content = m.content;
822
+ base.toolCalls = m.toolCalls;
823
+ } else if (m instanceof ToolResultMessage) {
824
+ base.results = m.results;
825
+ }
826
+ return base;
827
+ }
828
+ /**
829
+ * Reconstruct a message from JSON
830
+ */
831
+ static messageFromJSON(json) {
832
+ const options = {
833
+ id: json.id,
834
+ metadata: json.metadata
835
+ };
836
+ switch (json.type) {
837
+ case "user":
838
+ return new UserMessage(json.content, options);
839
+ case "assistant":
840
+ return new AssistantMessage(
841
+ json.content,
842
+ json.toolCalls,
843
+ options
844
+ );
845
+ case "tool_result":
846
+ return new ToolResultMessage(json.results ?? [], options);
847
+ default:
848
+ throw new Error(`Unknown message type: ${json.type}`);
849
+ }
850
+ }
851
+ };
852
+
853
+ // src/index.ts
854
+ var ai = {
855
+ llm
856
+ // embedding, // Coming soon
857
+ // image, // Coming soon
858
+ };
859
+ export {
860
+ AssistantMessage,
861
+ DynamicKey,
862
+ ExponentialBackoff,
863
+ Image,
864
+ LinearBackoff,
865
+ Message,
866
+ NoRetry,
867
+ RetryAfterStrategy,
868
+ RoundRobinKeys,
869
+ Thread,
870
+ TokenBucket,
871
+ ToolResultMessage,
872
+ UPPError,
873
+ UserMessage,
874
+ WeightedKeys,
875
+ aggregateUsage,
876
+ ai,
877
+ contentBlockStart,
878
+ contentBlockStop,
879
+ createProvider,
880
+ createStreamResult,
881
+ createTurn,
882
+ emptyUsage,
883
+ isAssistantMessage,
884
+ isAudioBlock,
885
+ isBinaryBlock,
886
+ isImageBlock,
887
+ isTextBlock,
888
+ isToolResultMessage,
889
+ isUserMessage,
890
+ isVideoBlock,
891
+ llm,
892
+ messageStart,
893
+ messageStop,
894
+ text,
895
+ textDelta,
896
+ toolCallDelta
897
+ };
898
+ //# sourceMappingURL=index.js.map