@providerprotocol/ai 0.0.21 → 0.0.23

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 (53) hide show
  1. package/README.md +188 -6
  2. package/dist/anthropic/index.d.ts +1 -1
  3. package/dist/anthropic/index.js +115 -39
  4. package/dist/anthropic/index.js.map +1 -1
  5. package/dist/{chunk-Y3GBJNA2.js → chunk-55X3W2MN.js} +4 -3
  6. package/dist/chunk-55X3W2MN.js.map +1 -0
  7. package/dist/chunk-73IIE3QT.js +120 -0
  8. package/dist/chunk-73IIE3QT.js.map +1 -0
  9. package/dist/{chunk-M4BMM5IB.js → chunk-MF5ETY5O.js} +13 -4
  10. package/dist/chunk-MF5ETY5O.js.map +1 -0
  11. package/dist/{chunk-SKY2JLA7.js → chunk-MKDLXV4O.js} +1 -1
  12. package/dist/chunk-MKDLXV4O.js.map +1 -0
  13. package/dist/{chunk-Z7RBRCRN.js → chunk-NWS5IKNR.js} +37 -11
  14. package/dist/chunk-NWS5IKNR.js.map +1 -0
  15. package/dist/{chunk-EDENPF3E.js → chunk-QNJO7DSD.js} +152 -53
  16. package/dist/chunk-QNJO7DSD.js.map +1 -0
  17. package/dist/{chunk-Z4ILICF5.js → chunk-SBCATNHA.js} +43 -14
  18. package/dist/chunk-SBCATNHA.js.map +1 -0
  19. package/dist/chunk-Z6DKC37J.js +50 -0
  20. package/dist/chunk-Z6DKC37J.js.map +1 -0
  21. package/dist/google/index.d.ts +22 -7
  22. package/dist/google/index.js +286 -85
  23. package/dist/google/index.js.map +1 -1
  24. package/dist/http/index.d.ts +3 -3
  25. package/dist/http/index.js +4 -4
  26. package/dist/index.d.ts +10 -6
  27. package/dist/index.js +331 -204
  28. package/dist/index.js.map +1 -1
  29. package/dist/ollama/index.d.ts +5 -2
  30. package/dist/ollama/index.js +87 -28
  31. package/dist/ollama/index.js.map +1 -1
  32. package/dist/openai/index.d.ts +1 -1
  33. package/dist/openai/index.js +226 -81
  34. package/dist/openai/index.js.map +1 -1
  35. package/dist/openrouter/index.d.ts +1 -1
  36. package/dist/openrouter/index.js +199 -64
  37. package/dist/openrouter/index.js.map +1 -1
  38. package/dist/{provider-DGQHYE6I.d.ts → provider-DR1yins0.d.ts} +159 -53
  39. package/dist/proxy/index.d.ts +2 -2
  40. package/dist/proxy/index.js +178 -17
  41. package/dist/proxy/index.js.map +1 -1
  42. package/dist/{retry-Pcs3hnbu.d.ts → retry-DJiqAslw.d.ts} +11 -2
  43. package/dist/{stream-Di9acos2.d.ts → stream-BuTrqt_j.d.ts} +103 -41
  44. package/dist/xai/index.d.ts +1 -1
  45. package/dist/xai/index.js +189 -75
  46. package/dist/xai/index.js.map +1 -1
  47. package/package.json +1 -1
  48. package/dist/chunk-EDENPF3E.js.map +0 -1
  49. package/dist/chunk-M4BMM5IB.js.map +0 -1
  50. package/dist/chunk-SKY2JLA7.js.map +0 -1
  51. package/dist/chunk-Y3GBJNA2.js.map +0 -1
  52. package/dist/chunk-Z4ILICF5.js.map +0 -1
  53. package/dist/chunk-Z7RBRCRN.js.map +0 -1
package/dist/index.js CHANGED
@@ -2,13 +2,26 @@ import {
2
2
  aggregateUsage,
3
3
  createTurn,
4
4
  emptyUsage
5
- } from "./chunk-SKY2JLA7.js";
5
+ } from "./chunk-MKDLXV4O.js";
6
6
  import {
7
7
  Image
8
8
  } from "./chunk-WAKD3OO5.js";
9
+ import {
10
+ StreamEventType,
11
+ contentBlockStart,
12
+ contentBlockStop,
13
+ createStreamResult,
14
+ messageStart,
15
+ messageStop,
16
+ textDelta,
17
+ toolCallDelta,
18
+ toolExecutionEnd,
19
+ toolExecutionStart
20
+ } from "./chunk-73IIE3QT.js";
9
21
  import {
10
22
  AssistantMessage,
11
23
  Message,
24
+ MessageRole,
12
25
  ToolResultMessage,
13
26
  UserMessage,
14
27
  createProvider,
@@ -19,91 +32,65 @@ import {
19
32
  resolveEmbeddingHandler,
20
33
  resolveImageHandler,
21
34
  resolveLLMHandler
22
- } from "./chunk-M4BMM5IB.js";
35
+ } from "./chunk-MF5ETY5O.js";
23
36
  import {
24
37
  ExponentialBackoff,
25
38
  LinearBackoff,
26
39
  NoRetry,
27
40
  RetryAfterStrategy,
28
41
  TokenBucket
29
- } from "./chunk-Z4ILICF5.js";
30
- import "./chunk-Z7RBRCRN.js";
42
+ } from "./chunk-SBCATNHA.js";
43
+ import "./chunk-NWS5IKNR.js";
31
44
  import {
32
45
  DynamicKey,
33
46
  RoundRobinKeys,
34
47
  WeightedKeys
35
- } from "./chunk-Y3GBJNA2.js";
48
+ } from "./chunk-55X3W2MN.js";
36
49
  import {
37
- UPPError
38
- } from "./chunk-EDENPF3E.js";
50
+ ErrorCode,
51
+ ModalityType,
52
+ UPPError,
53
+ toError
54
+ } from "./chunk-QNJO7DSD.js";
39
55
 
40
- // src/types/stream.ts
41
- function createStreamResult(generator, turnPromise, abortController) {
42
- return {
43
- [Symbol.asyncIterator]() {
44
- return generator;
45
- },
46
- turn: turnPromise,
47
- abort() {
48
- abortController.abort();
49
- }
50
- };
51
- }
52
- function textDelta(text2, index = 0) {
53
- return {
54
- type: "text_delta",
55
- index,
56
- delta: { text: text2 }
57
- };
58
- }
59
- function toolCallDelta(toolCallId, toolName, argumentsJson, index = 0) {
60
- return {
61
- type: "tool_call_delta",
62
- index,
63
- delta: { toolCallId, toolName, argumentsJson }
64
- };
65
- }
66
- function messageStart() {
67
- return {
68
- type: "message_start",
69
- index: 0,
70
- delta: {}
71
- };
56
+ // src/types/content.ts
57
+ var ContentBlockType = {
58
+ /** Text content */
59
+ Text: "text",
60
+ /** Image content */
61
+ Image: "image",
62
+ /** Audio content */
63
+ Audio: "audio",
64
+ /** Video content */
65
+ Video: "video",
66
+ /** Binary/arbitrary data content */
67
+ Binary: "binary"
68
+ };
69
+ var ImageSourceType = {
70
+ /** Base64-encoded image data */
71
+ Base64: "base64",
72
+ /** URL reference to image */
73
+ Url: "url",
74
+ /** Raw bytes image data */
75
+ Bytes: "bytes"
76
+ };
77
+ function text(content) {
78
+ return { type: ContentBlockType.Text, text: content };
72
79
  }
73
- function messageStop() {
74
- return {
75
- type: "message_stop",
76
- index: 0,
77
- delta: {}
78
- };
80
+ function isTextBlock(block) {
81
+ return block.type === ContentBlockType.Text;
79
82
  }
80
- function contentBlockStart(index) {
81
- return {
82
- type: "content_block_start",
83
- index,
84
- delta: {}
85
- };
83
+ function isImageBlock(block) {
84
+ return block.type === ContentBlockType.Image;
86
85
  }
87
- function contentBlockStop(index) {
88
- return {
89
- type: "content_block_stop",
90
- index,
91
- delta: {}
92
- };
86
+ function isAudioBlock(block) {
87
+ return block.type === ContentBlockType.Audio;
93
88
  }
94
- function toolExecutionStart(toolCallId, toolName, timestamp, index = 0) {
95
- return {
96
- type: "tool_execution_start",
97
- index,
98
- delta: { toolCallId, toolName, timestamp }
99
- };
89
+ function isVideoBlock(block) {
90
+ return block.type === ContentBlockType.Video;
100
91
  }
101
- function toolExecutionEnd(toolCallId, toolName, result, isError, timestamp, index = 0) {
102
- return {
103
- type: "tool_execution_end",
104
- index,
105
- delta: { toolCallId, toolName, result, isError, timestamp }
106
- };
92
+ function isBinaryBlock(block) {
93
+ return block.type === ContentBlockType.Binary;
107
94
  }
108
95
 
109
96
  // src/core/llm.ts
@@ -124,9 +111,9 @@ function llm(options) {
124
111
  if (!llmHandler) {
125
112
  throw new UPPError(
126
113
  `Provider '${provider.name}' does not support LLM modality`,
127
- "INVALID_REQUEST",
114
+ ErrorCode.InvalidRequest,
128
115
  provider.name,
129
- "llm"
116
+ ModalityType.LLM
130
117
  );
131
118
  }
132
119
  const boundModel = llmHandler.bind(modelRef.modelId);
@@ -134,17 +121,17 @@ function llm(options) {
134
121
  if (structure && !capabilities.structuredOutput) {
135
122
  throw new UPPError(
136
123
  `Provider '${provider.name}' does not support structured output`,
137
- "INVALID_REQUEST",
124
+ ErrorCode.InvalidRequest,
138
125
  provider.name,
139
- "llm"
126
+ ModalityType.LLM
140
127
  );
141
128
  }
142
129
  if (tools && tools.length > 0 && !capabilities.tools) {
143
130
  throw new UPPError(
144
131
  `Provider '${provider.name}' does not support tools`,
145
- "INVALID_REQUEST",
132
+ ErrorCode.InvalidRequest,
146
133
  provider.name,
147
- "llm"
134
+ ModalityType.LLM
148
135
  );
149
136
  }
150
137
  const instance = {
@@ -170,9 +157,9 @@ function llm(options) {
170
157
  if (!capabilities.streaming) {
171
158
  throw new UPPError(
172
159
  `Provider '${provider.name}' does not support streaming`,
173
- "INVALID_REQUEST",
160
+ ErrorCode.InvalidRequest,
174
161
  provider.name,
175
- "llm"
162
+ ModalityType.LLM
176
163
  );
177
164
  }
178
165
  const { history, messages } = parseInputs(historyOrInput, inputs);
@@ -195,10 +182,21 @@ function isMessageInstance(value) {
195
182
  if (value instanceof Message) {
196
183
  return true;
197
184
  }
198
- if (typeof value === "object" && value !== null && "timestamp" in value && "type" in value && "id" in value) {
185
+ if (typeof value === "object" && value !== null) {
199
186
  const obj = value;
200
- const messageTypes = ["user", "assistant", "tool_result"];
201
- return messageTypes.includes(obj.type);
187
+ const type = obj.type;
188
+ const id = obj.id;
189
+ const timestamp = obj.timestamp;
190
+ const hasValidTimestamp = timestamp instanceof Date || typeof timestamp === "string" && !Number.isNaN(Date.parse(timestamp));
191
+ if (typeof id !== "string" || id.length === 0 || !hasValidTimestamp) {
192
+ return false;
193
+ }
194
+ if (type === "user" || type === "assistant") {
195
+ return Array.isArray(obj.content);
196
+ }
197
+ if (type === "tool_result") {
198
+ return Array.isArray(obj.results);
199
+ }
202
200
  }
203
201
  return false;
204
202
  }
@@ -230,11 +228,17 @@ function inputToMessage(input) {
230
228
  if ("type" in input && "id" in input && "timestamp" in input) {
231
229
  return input;
232
230
  }
231
+ if (typeof input !== "object" || input === null || !("type" in input)) {
232
+ throw new Error("Invalid inference input");
233
+ }
233
234
  const block = input;
234
- if (block.type === "text") {
235
+ if (isTextBlock(block)) {
235
236
  return new UserMessage(block.text);
236
237
  }
237
- return new UserMessage([block]);
238
+ if (isImageBlock(block) || isAudioBlock(block) || isVideoBlock(block) || isBinaryBlock(block)) {
239
+ return new UserMessage([block]);
240
+ }
241
+ throw new Error("Invalid inference input");
238
242
  }
239
243
  async function executeGenerate(model, config, system, params, tools, toolStrategy, structure, history, newMessages) {
240
244
  validateMediaCapabilities(
@@ -272,9 +276,9 @@ async function executeGenerate(model, config, system, params, tools, toolStrateg
272
276
  await toolStrategy?.onMaxIterations?.(maxIterations);
273
277
  throw new UPPError(
274
278
  `Tool execution exceeded maximum iterations (${maxIterations})`,
275
- "INVALID_REQUEST",
279
+ ErrorCode.InvalidRequest,
276
280
  model.provider.name,
277
- "llm"
281
+ ModalityType.LLM
278
282
  );
279
283
  }
280
284
  const results = await executeTools(
@@ -310,20 +314,47 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
310
314
  let cycles = 0;
311
315
  let generatorError = null;
312
316
  let structuredData;
317
+ let generatorCompleted = false;
313
318
  let resolveGenerator;
314
319
  let rejectGenerator;
320
+ let generatorSettled = false;
315
321
  const generatorDone = new Promise((resolve, reject) => {
316
- resolveGenerator = resolve;
317
- rejectGenerator = reject;
322
+ resolveGenerator = () => {
323
+ if (!generatorSettled) {
324
+ generatorSettled = true;
325
+ resolve();
326
+ }
327
+ };
328
+ rejectGenerator = (error) => {
329
+ if (!generatorSettled) {
330
+ generatorSettled = true;
331
+ reject(error);
332
+ }
333
+ };
334
+ });
335
+ void generatorDone.catch((error) => {
336
+ if (!generatorError) {
337
+ generatorError = toError(error);
338
+ }
318
339
  });
319
340
  const maxIterations = toolStrategy?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
341
+ const onAbort = () => {
342
+ const error = new UPPError("Stream cancelled", ErrorCode.Cancelled, model.provider.name, ModalityType.LLM);
343
+ generatorError = error;
344
+ rejectGenerator(error);
345
+ };
346
+ abortController.signal.addEventListener("abort", onAbort, { once: true });
347
+ const ensureNotAborted = () => {
348
+ if (abortController.signal.aborted) {
349
+ throw new UPPError("Stream cancelled", ErrorCode.Cancelled, model.provider.name, ModalityType.LLM);
350
+ }
351
+ };
320
352
  async function* generateStream() {
321
353
  try {
322
- if (abortController.signal.aborted) {
323
- throw new UPPError("Stream cancelled", "CANCELLED", model.provider.name, "llm");
324
- }
354
+ ensureNotAborted();
325
355
  while (cycles < maxIterations + 1) {
326
356
  cycles++;
357
+ ensureNotAborted();
327
358
  const request = {
328
359
  messages: allMessages,
329
360
  system,
@@ -335,6 +366,7 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
335
366
  };
336
367
  const streamResult = model.stream(request);
337
368
  for await (const event of streamResult) {
369
+ ensureNotAborted();
338
370
  yield event;
339
371
  }
340
372
  const response = await streamResult.response;
@@ -351,9 +383,9 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
351
383
  await toolStrategy?.onMaxIterations?.(maxIterations);
352
384
  throw new UPPError(
353
385
  `Tool execution exceeded maximum iterations (${maxIterations})`,
354
- "INVALID_REQUEST",
386
+ ErrorCode.InvalidRequest,
355
387
  model.provider.name,
356
- "llm"
388
+ ModalityType.LLM
357
389
  );
358
390
  }
359
391
  const toolEvents = [];
@@ -365,6 +397,7 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
365
397
  (event) => toolEvents.push(event)
366
398
  );
367
399
  for (const event of toolEvents) {
400
+ ensureNotAborted();
368
401
  yield event;
369
402
  }
370
403
  allMessages.push(new ToolResultMessage(results));
@@ -372,14 +405,26 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
372
405
  }
373
406
  break;
374
407
  }
408
+ generatorCompleted = true;
375
409
  resolveGenerator();
376
410
  } catch (error) {
377
- generatorError = error;
378
- rejectGenerator(error);
379
- throw error;
411
+ const err = toError(error);
412
+ generatorError = err;
413
+ rejectGenerator(err);
414
+ throw err;
415
+ } finally {
416
+ abortController.signal.removeEventListener("abort", onAbort);
417
+ if (!generatorCompleted && !generatorSettled) {
418
+ const error = new UPPError("Stream cancelled", ErrorCode.Cancelled, model.provider.name, ModalityType.LLM);
419
+ generatorError = error;
420
+ if (!abortController.signal.aborted) {
421
+ abortController.abort();
422
+ }
423
+ rejectGenerator(error);
424
+ }
380
425
  }
381
426
  }
382
- const turnPromise = (async () => {
427
+ const createTurnPromise = async () => {
383
428
  await generatorDone;
384
429
  if (generatorError) {
385
430
  throw generatorError;
@@ -392,8 +437,8 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
392
437
  cycles,
393
438
  data
394
439
  );
395
- })();
396
- return createStreamResult(generateStream(), turnPromise, abortController);
440
+ };
441
+ return createStreamResult(generateStream(), createTurnPromise, abortController);
397
442
  }
398
443
  async function executeTools(message, tools, toolStrategy, executions, onEvent) {
399
444
  const toolCalls = message.toolCalls ?? [];
@@ -401,41 +446,57 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
401
446
  const toolMap = new Map(tools.map((t) => [t.name, t]));
402
447
  const promises = toolCalls.map(async (call, index) => {
403
448
  const tool = toolMap.get(call.toolName);
404
- if (!tool) {
449
+ const toolName = tool?.name ?? call.toolName;
450
+ const startTime = Date.now();
451
+ onEvent?.(toolExecutionStart(call.toolCallId, toolName, startTime, index));
452
+ let effectiveParams = call.arguments;
453
+ const endWithError = async (message2, approved2) => {
454
+ const endTime = Date.now();
455
+ if (tool) {
456
+ await toolStrategy?.onError?.(tool, effectiveParams, new Error(message2));
457
+ }
458
+ const execution = {
459
+ toolName,
460
+ toolCallId: call.toolCallId,
461
+ arguments: effectiveParams,
462
+ result: message2,
463
+ isError: true,
464
+ duration: endTime - startTime,
465
+ approved: approved2
466
+ };
467
+ executions.push(execution);
468
+ onEvent?.(toolExecutionEnd(call.toolCallId, toolName, message2, true, endTime, index));
405
469
  return {
406
470
  toolCallId: call.toolCallId,
407
- result: `Tool '${call.toolName}' not found`,
471
+ result: message2,
408
472
  isError: true
409
473
  };
474
+ };
475
+ if (!tool) {
476
+ return endWithError(`Tool '${call.toolName}' not found`);
477
+ }
478
+ try {
479
+ await toolStrategy?.onToolCall?.(tool, effectiveParams);
480
+ } catch (error) {
481
+ return endWithError(toError(error).message);
410
482
  }
411
- const startTime = Date.now();
412
- onEvent?.(toolExecutionStart(call.toolCallId, tool.name, startTime, index));
413
- let effectiveParams = call.arguments;
414
- await toolStrategy?.onToolCall?.(tool, effectiveParams);
415
483
  if (toolStrategy?.onBeforeCall) {
416
- const beforeResult = await toolStrategy.onBeforeCall(tool, effectiveParams);
484
+ let beforeResult;
485
+ try {
486
+ beforeResult = await toolStrategy.onBeforeCall(tool, effectiveParams);
487
+ } catch (error) {
488
+ return endWithError(toError(error).message);
489
+ }
417
490
  const isBeforeCallResult = (value) => typeof value === "object" && value !== null && "proceed" in value;
418
491
  if (isBeforeCallResult(beforeResult)) {
419
492
  if (!beforeResult.proceed) {
420
- const endTime = Date.now();
421
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, "Tool execution skipped", true, endTime, index));
422
- return {
423
- toolCallId: call.toolCallId,
424
- result: "Tool execution skipped",
425
- isError: true
426
- };
493
+ return endWithError("Tool execution skipped");
427
494
  }
428
495
  if (beforeResult.params !== void 0) {
429
496
  effectiveParams = beforeResult.params;
430
497
  }
431
498
  } else if (!beforeResult) {
432
- const endTime = Date.now();
433
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, "Tool execution skipped", true, endTime, index));
434
- return {
435
- toolCallId: call.toolCallId,
436
- result: "Tool execution skipped",
437
- isError: true
438
- };
499
+ return endWithError("Tool execution skipped");
439
500
  }
440
501
  }
441
502
  let approved = true;
@@ -443,13 +504,13 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
443
504
  try {
444
505
  approved = await tool.approval(effectiveParams);
445
506
  } catch (error) {
446
- throw error;
507
+ return endWithError(toError(error).message);
447
508
  }
448
509
  }
449
510
  if (!approved) {
450
511
  const endTime = Date.now();
451
512
  const execution = {
452
- toolName: tool.name,
513
+ toolName,
453
514
  toolCallId: call.toolCallId,
454
515
  arguments: effectiveParams,
455
516
  result: "Tool execution denied",
@@ -458,7 +519,7 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
458
519
  approved: false
459
520
  };
460
521
  executions.push(execution);
461
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, "Tool execution denied by approval handler", true, endTime, index));
522
+ onEvent?.(toolExecutionEnd(call.toolCallId, toolName, "Tool execution denied by approval handler", true, endTime, index));
462
523
  return {
463
524
  toolCallId: call.toolCallId,
464
525
  result: "Tool execution denied by approval handler",
@@ -476,7 +537,7 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
476
537
  }
477
538
  }
478
539
  const execution = {
479
- toolName: tool.name,
540
+ toolName,
480
541
  toolCallId: call.toolCallId,
481
542
  arguments: effectiveParams,
482
543
  result,
@@ -485,7 +546,7 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
485
546
  approved
486
547
  };
487
548
  executions.push(execution);
488
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, result, false, endTime, index));
549
+ onEvent?.(toolExecutionEnd(call.toolCallId, toolName, result, false, endTime, index));
489
550
  return {
490
551
  toolCallId: call.toolCallId,
491
552
  result,
@@ -493,22 +554,22 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
493
554
  };
494
555
  } catch (error) {
495
556
  const endTime = Date.now();
496
- await toolStrategy?.onError?.(tool, effectiveParams, error);
497
- const errorMessage = error instanceof Error ? error.message : String(error);
557
+ const err = toError(error);
558
+ await toolStrategy?.onError?.(tool, effectiveParams, err);
498
559
  const execution = {
499
- toolName: tool.name,
560
+ toolName,
500
561
  toolCallId: call.toolCallId,
501
562
  arguments: effectiveParams,
502
- result: errorMessage,
563
+ result: err.message,
503
564
  isError: true,
504
565
  duration: endTime - startTime,
505
566
  approved
506
567
  };
507
568
  executions.push(execution);
508
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, errorMessage, true, endTime, index));
569
+ onEvent?.(toolExecutionEnd(call.toolCallId, toolName, err.message, true, endTime, index));
509
570
  return {
510
571
  toolCallId: call.toolCallId,
511
- result: errorMessage,
572
+ result: err.message,
512
573
  isError: true
513
574
  };
514
575
  }
@@ -523,25 +584,25 @@ function validateMediaCapabilities(messages, capabilities, providerName) {
523
584
  if (block.type === "image" && !capabilities.imageInput) {
524
585
  throw new UPPError(
525
586
  `Provider '${providerName}' does not support image input`,
526
- "INVALID_REQUEST",
587
+ ErrorCode.InvalidRequest,
527
588
  providerName,
528
- "llm"
589
+ ModalityType.LLM
529
590
  );
530
591
  }
531
592
  if (block.type === "video" && !capabilities.videoInput) {
532
593
  throw new UPPError(
533
594
  `Provider '${providerName}' does not support video input`,
534
- "INVALID_REQUEST",
595
+ ErrorCode.InvalidRequest,
535
596
  providerName,
536
- "llm"
597
+ ModalityType.LLM
537
598
  );
538
599
  }
539
600
  if (block.type === "audio" && !capabilities.audioInput) {
540
601
  throw new UPPError(
541
602
  `Provider '${providerName}' does not support audio input`,
542
- "INVALID_REQUEST",
603
+ ErrorCode.InvalidRequest,
543
604
  providerName,
544
- "llm"
605
+ ModalityType.LLM
545
606
  );
546
607
  }
547
608
  }
@@ -550,15 +611,24 @@ function validateMediaCapabilities(messages, capabilities, providerName) {
550
611
 
551
612
  // src/core/embedding.ts
552
613
  function embedding(options) {
553
- const { model: modelRef, config = {}, params } = options;
614
+ const { model: modelRef, config: explicitConfig = {}, params } = options;
615
+ const providerConfig = modelRef.providerConfig ?? {};
616
+ const config = {
617
+ ...providerConfig,
618
+ ...explicitConfig,
619
+ headers: {
620
+ ...providerConfig.headers,
621
+ ...explicitConfig.headers
622
+ }
623
+ };
554
624
  const provider = modelRef.provider;
555
625
  const handler = resolveEmbeddingHandler(provider);
556
626
  if (!handler) {
557
627
  throw new UPPError(
558
628
  `Provider '${provider.name}' does not support embedding modality`,
559
- "INVALID_REQUEST",
629
+ ErrorCode.InvalidRequest,
560
630
  provider.name,
561
- "embedding"
631
+ ModalityType.Embedding
562
632
  );
563
633
  }
564
634
  const boundModel = handler.bind(modelRef.modelId);
@@ -619,9 +689,9 @@ function decodeBase64(b64, providerName) {
619
689
  const cause = error instanceof Error ? error : new Error("Failed to decode base64 vector");
620
690
  throw new UPPError(
621
691
  "Invalid base64 embedding vector",
622
- "INVALID_RESPONSE",
692
+ ErrorCode.InvalidResponse,
623
693
  providerName,
624
- "embedding",
694
+ ModalityType.Embedding,
625
695
  void 0,
626
696
  cause
627
697
  );
@@ -633,33 +703,59 @@ function createChunkedStream(model, inputs, params, config, options) {
633
703
  const concurrency = options.concurrency ?? 1;
634
704
  let resolveResult;
635
705
  let rejectResult;
706
+ let settled = false;
636
707
  const resultPromise = new Promise((resolve, reject) => {
637
- resolveResult = resolve;
638
- rejectResult = reject;
708
+ resolveResult = (result) => {
709
+ if (!settled) {
710
+ settled = true;
711
+ resolve(result);
712
+ }
713
+ };
714
+ rejectResult = (error) => {
715
+ if (!settled) {
716
+ settled = true;
717
+ reject(error);
718
+ }
719
+ };
639
720
  });
721
+ const cancelError = () => new UPPError(
722
+ "Embedding cancelled",
723
+ ErrorCode.Cancelled,
724
+ model.provider.name,
725
+ ModalityType.Embedding
726
+ );
727
+ const onAbort = () => {
728
+ rejectResult(cancelError());
729
+ };
730
+ abortController.signal.addEventListener("abort", onAbort, { once: true });
731
+ const onExternalAbort = () => abortController.abort();
732
+ if (options.signal) {
733
+ options.signal.addEventListener("abort", onExternalAbort, { once: true });
734
+ }
735
+ const cleanupAbortListeners = () => {
736
+ abortController.signal.removeEventListener("abort", onAbort);
737
+ if (options.signal) {
738
+ options.signal.removeEventListener("abort", onExternalAbort);
739
+ }
740
+ };
640
741
  async function* generate() {
641
742
  const total = inputs.length;
642
743
  const allEmbeddings = [];
643
744
  let totalTokens = 0;
644
745
  const batches = [];
645
746
  for (let i = 0; i < inputs.length; i += batchSize) {
646
- batches.push(inputs.slice(i, i + batchSize));
747
+ batches.push({ inputs: inputs.slice(i, i + batchSize), startIndex: i });
647
748
  }
648
749
  try {
649
750
  for (let i = 0; i < batches.length; i += concurrency) {
650
751
  if (abortController.signal.aborted || options.signal?.aborted) {
651
- throw new UPPError(
652
- "Embedding cancelled",
653
- "CANCELLED",
654
- model.provider.name,
655
- "embedding"
656
- );
752
+ throw cancelError();
657
753
  }
658
754
  const chunk = batches.slice(i, i + concurrency);
659
755
  const responses = await Promise.all(
660
756
  chunk.map(
661
757
  (batch) => model.embed({
662
- inputs: batch,
758
+ inputs: batch.inputs,
663
759
  params,
664
760
  config: config ?? {},
665
761
  signal: abortController.signal
@@ -667,13 +763,17 @@ function createChunkedStream(model, inputs, params, config, options) {
667
763
  )
668
764
  );
669
765
  const batchEmbeddings = [];
670
- for (const response of responses) {
671
- for (const vec of response.embeddings) {
766
+ for (let responseIndex = 0; responseIndex < responses.length; responseIndex += 1) {
767
+ const response = responses[responseIndex];
768
+ const batch = chunk[responseIndex];
769
+ for (let vecIndex = 0; vecIndex < response.embeddings.length; vecIndex += 1) {
770
+ const vec = response.embeddings[vecIndex];
672
771
  const vector = normalizeVector(vec.vector, model.provider.name);
772
+ const resolvedIndex = batch.startIndex + (vec.index ?? vecIndex);
673
773
  const emb = {
674
774
  vector,
675
775
  dimensions: vector.length,
676
- index: allEmbeddings.length + batchEmbeddings.length,
776
+ index: resolvedIndex,
677
777
  tokens: vec.tokens,
678
778
  metadata: vec.metadata
679
779
  };
@@ -689,13 +789,19 @@ function createChunkedStream(model, inputs, params, config, options) {
689
789
  percent: allEmbeddings.length / total * 100
690
790
  };
691
791
  }
792
+ const orderedEmbeddings = [...allEmbeddings].sort(
793
+ (left, right) => left.index - right.index
794
+ );
692
795
  resolveResult({
693
- embeddings: allEmbeddings,
796
+ embeddings: orderedEmbeddings,
694
797
  usage: { totalTokens }
695
798
  });
696
799
  } catch (error) {
697
- rejectResult(error);
698
- throw error;
800
+ const err = toError(error);
801
+ rejectResult(err);
802
+ throw err;
803
+ } finally {
804
+ cleanupAbortListeners();
699
805
  }
700
806
  }
701
807
  const generator = generate();
@@ -708,36 +814,56 @@ function createChunkedStream(model, inputs, params, config, options) {
708
814
 
709
815
  // src/core/image.ts
710
816
  function image(options) {
711
- const { model: modelRef, config = {}, params } = options;
817
+ const { model: modelRef, config: explicitConfig = {}, params } = options;
818
+ const providerConfig = modelRef.providerConfig ?? {};
819
+ const config = {
820
+ ...providerConfig,
821
+ ...explicitConfig,
822
+ headers: {
823
+ ...providerConfig.headers,
824
+ ...explicitConfig.headers
825
+ }
826
+ };
712
827
  const provider = modelRef.provider;
713
828
  const imageHandler = resolveImageHandler(provider);
714
829
  if (!imageHandler) {
715
830
  throw new UPPError(
716
831
  `Provider '${provider.name}' does not support image modality`,
717
- "INVALID_REQUEST",
832
+ ErrorCode.InvalidRequest,
718
833
  provider.name,
719
- "image"
834
+ ModalityType.Image
720
835
  );
721
836
  }
722
837
  const boundModel = imageHandler.bind(modelRef.modelId);
723
838
  const capabilities = boundModel.capabilities;
839
+ const normalizeImageError = (error) => {
840
+ if (error instanceof UPPError) {
841
+ return error;
842
+ }
843
+ const err = toError(error);
844
+ return new UPPError(err.message, ErrorCode.ProviderError, provider.name, ModalityType.Image, void 0, err);
845
+ };
724
846
  const instance = {
725
847
  model: boundModel,
726
848
  params,
727
849
  capabilities,
728
850
  async generate(input, options2) {
729
851
  const prompt = normalizeInput(input);
730
- const response = await boundModel.generate({
731
- prompt,
732
- params,
733
- config,
734
- signal: options2?.signal
735
- });
736
- return {
737
- images: response.images,
738
- metadata: response.metadata,
739
- usage: response.usage
740
- };
852
+ try {
853
+ const response = await boundModel.generate({
854
+ prompt,
855
+ params,
856
+ config,
857
+ signal: options2?.signal
858
+ });
859
+ return {
860
+ images: response.images,
861
+ metadata: response.metadata,
862
+ usage: response.usage
863
+ };
864
+ } catch (error) {
865
+ throw normalizeImageError(error);
866
+ }
741
867
  }
742
868
  };
743
869
  if (capabilities.streaming && boundModel.stream) {
@@ -755,9 +881,20 @@ function image(options) {
755
881
  images: response.images,
756
882
  metadata: response.metadata,
757
883
  usage: response.usage
758
- }));
884
+ })).catch((error) => {
885
+ throw normalizeImageError(error);
886
+ });
887
+ async function* wrappedStream() {
888
+ try {
889
+ for await (const event of providerStream) {
890
+ yield event;
891
+ }
892
+ } catch (error) {
893
+ throw normalizeImageError(error);
894
+ }
895
+ }
759
896
  return {
760
- [Symbol.asyncIterator]: () => providerStream[Symbol.asyncIterator](),
897
+ [Symbol.asyncIterator]: () => wrappedStream(),
761
898
  result: resultPromise,
762
899
  abort: () => abortController.abort()
763
900
  };
@@ -766,18 +903,22 @@ function image(options) {
766
903
  if (capabilities.edit && boundModel.edit) {
767
904
  const edit = boundModel.edit;
768
905
  instance.edit = async function(input) {
769
- const response = await edit({
770
- image: input.image,
771
- mask: input.mask,
772
- prompt: input.prompt,
773
- params,
774
- config
775
- });
776
- return {
777
- images: response.images,
778
- metadata: response.metadata,
779
- usage: response.usage
780
- };
906
+ try {
907
+ const response = await edit({
908
+ image: input.image,
909
+ mask: input.mask,
910
+ prompt: input.prompt,
911
+ params,
912
+ config
913
+ });
914
+ return {
915
+ images: response.images,
916
+ metadata: response.metadata,
917
+ usage: response.usage
918
+ };
919
+ } catch (error) {
920
+ throw normalizeImageError(error);
921
+ }
781
922
  };
782
923
  }
783
924
  return instance;
@@ -789,26 +930,6 @@ function normalizeInput(input) {
789
930
  return input.prompt;
790
931
  }
791
932
 
792
- // src/types/content.ts
793
- function text(content) {
794
- return { type: "text", text: content };
795
- }
796
- function isTextBlock(block) {
797
- return block.type === "text";
798
- }
799
- function isImageBlock(block) {
800
- return block.type === "image";
801
- }
802
- function isAudioBlock(block) {
803
- return block.type === "audio";
804
- }
805
- function isVideoBlock(block) {
806
- return block.type === "video";
807
- }
808
- function isBinaryBlock(block) {
809
- return block.type === "binary";
810
- }
811
-
812
933
  // src/types/thread.ts
813
934
  var Thread = class _Thread {
814
935
  /** Unique thread identifier */
@@ -1073,14 +1194,20 @@ var ai = {
1073
1194
  };
1074
1195
  export {
1075
1196
  AssistantMessage,
1197
+ ContentBlockType,
1076
1198
  DynamicKey,
1199
+ ErrorCode,
1077
1200
  ExponentialBackoff,
1078
1201
  Image,
1202
+ ImageSourceType,
1079
1203
  LinearBackoff,
1080
1204
  Message,
1205
+ MessageRole,
1206
+ ModalityType,
1081
1207
  NoRetry,
1082
1208
  RetryAfterStrategy,
1083
1209
  RoundRobinKeys,
1210
+ StreamEventType,
1084
1211
  Thread,
1085
1212
  TokenBucket,
1086
1213
  ToolResultMessage,