@providerprotocol/ai 0.0.20 → 0.0.22

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 (54) hide show
  1. package/dist/anthropic/index.d.ts +184 -14
  2. package/dist/anthropic/index.js +306 -107
  3. package/dist/anthropic/index.js.map +1 -1
  4. package/dist/{chunk-P5IRTEM5.js → chunk-7WYBJPJJ.js} +2 -2
  5. package/dist/chunk-I2VHCGQE.js +49 -0
  6. package/dist/chunk-I2VHCGQE.js.map +1 -0
  7. package/dist/{chunk-UMKWXGO3.js → chunk-M4BMM5IB.js} +86 -2
  8. package/dist/chunk-M4BMM5IB.js.map +1 -0
  9. package/dist/{chunk-SKY2JLA7.js → chunk-MKDLXV4O.js} +1 -1
  10. package/dist/chunk-MKDLXV4O.js.map +1 -0
  11. package/dist/{chunk-Z7RBRCRN.js → chunk-NWS5IKNR.js} +37 -11
  12. package/dist/chunk-NWS5IKNR.js.map +1 -0
  13. package/dist/{chunk-U3FZWV4U.js → chunk-RFWLEFAB.js} +100 -43
  14. package/dist/chunk-RFWLEFAB.js.map +1 -0
  15. package/dist/{chunk-U4JJC2YX.js → chunk-RS7C25LS.js} +36 -11
  16. package/dist/chunk-RS7C25LS.js.map +1 -0
  17. package/dist/google/index.d.ts +35 -24
  18. package/dist/google/index.js +273 -99
  19. package/dist/google/index.js.map +1 -1
  20. package/dist/http/index.d.ts +3 -3
  21. package/dist/http/index.js +4 -4
  22. package/dist/index.d.ts +103 -38
  23. package/dist/index.js +346 -153
  24. package/dist/index.js.map +1 -1
  25. package/dist/ollama/index.d.ts +14 -16
  26. package/dist/ollama/index.js +68 -16
  27. package/dist/ollama/index.js.map +1 -1
  28. package/dist/openai/index.d.ts +25 -133
  29. package/dist/openai/index.js +208 -122
  30. package/dist/openai/index.js.map +1 -1
  31. package/dist/openrouter/index.d.ts +28 -53
  32. package/dist/openrouter/index.js +179 -72
  33. package/dist/openrouter/index.js.map +1 -1
  34. package/dist/provider-DWEAzeM5.d.ts +1329 -0
  35. package/dist/proxy/index.d.ts +2 -3
  36. package/dist/proxy/index.js +174 -17
  37. package/dist/proxy/index.js.map +1 -1
  38. package/dist/{retry-DR7YRJDz.d.ts → retry-DmPmqZL6.d.ts} +12 -3
  39. package/dist/{stream-DRHy6q1a.d.ts → stream-DbkLOIbJ.d.ts} +15 -5
  40. package/dist/xai/index.d.ts +16 -88
  41. package/dist/xai/index.js +167 -86
  42. package/dist/xai/index.js.map +1 -1
  43. package/package.json +4 -1
  44. package/dist/chunk-MSR5P65T.js +0 -39
  45. package/dist/chunk-MSR5P65T.js.map +0 -1
  46. package/dist/chunk-SKY2JLA7.js.map +0 -1
  47. package/dist/chunk-U3FZWV4U.js.map +0 -1
  48. package/dist/chunk-U4JJC2YX.js.map +0 -1
  49. package/dist/chunk-UMKWXGO3.js.map +0 -1
  50. package/dist/chunk-Z7RBRCRN.js.map +0 -1
  51. package/dist/content-DEl3z_W2.d.ts +0 -276
  52. package/dist/image-Dhq-Yuq4.d.ts +0 -456
  53. package/dist/provider-BBMBZuGn.d.ts +0 -570
  54. /package/dist/{chunk-P5IRTEM5.js.map → chunk-7WYBJPJJ.js.map} +0 -0
package/dist/index.js CHANGED
@@ -2,10 +2,7 @@ import {
2
2
  aggregateUsage,
3
3
  createTurn,
4
4
  emptyUsage
5
- } from "./chunk-SKY2JLA7.js";
6
- import {
7
- createProvider
8
- } from "./chunk-MSR5P65T.js";
5
+ } from "./chunk-MKDLXV4O.js";
9
6
  import {
10
7
  Image
11
8
  } from "./chunk-WAKD3OO5.js";
@@ -14,35 +11,72 @@ import {
14
11
  Message,
15
12
  ToolResultMessage,
16
13
  UserMessage,
14
+ createProvider,
17
15
  generateId,
18
16
  isAssistantMessage,
19
17
  isToolResultMessage,
20
- isUserMessage
21
- } from "./chunk-UMKWXGO3.js";
18
+ isUserMessage,
19
+ resolveEmbeddingHandler,
20
+ resolveImageHandler,
21
+ resolveLLMHandler
22
+ } from "./chunk-M4BMM5IB.js";
22
23
  import {
23
24
  ExponentialBackoff,
24
25
  LinearBackoff,
25
26
  NoRetry,
26
27
  RetryAfterStrategy,
27
28
  TokenBucket
28
- } from "./chunk-U4JJC2YX.js";
29
- import "./chunk-Z7RBRCRN.js";
29
+ } from "./chunk-RS7C25LS.js";
30
+ import "./chunk-NWS5IKNR.js";
30
31
  import {
31
32
  DynamicKey,
32
33
  RoundRobinKeys,
33
34
  WeightedKeys
34
- } from "./chunk-P5IRTEM5.js";
35
+ } from "./chunk-7WYBJPJJ.js";
35
36
  import {
36
- UPPError
37
- } from "./chunk-U3FZWV4U.js";
37
+ UPPError,
38
+ toError
39
+ } from "./chunk-RFWLEFAB.js";
40
+
41
+ // src/types/content.ts
42
+ function text(content) {
43
+ return { type: "text", text: content };
44
+ }
45
+ function isTextBlock(block) {
46
+ return block.type === "text";
47
+ }
48
+ function isImageBlock(block) {
49
+ return block.type === "image";
50
+ }
51
+ function isAudioBlock(block) {
52
+ return block.type === "audio";
53
+ }
54
+ function isVideoBlock(block) {
55
+ return block.type === "video";
56
+ }
57
+ function isBinaryBlock(block) {
58
+ return block.type === "binary";
59
+ }
38
60
 
39
61
  // src/types/stream.ts
40
- function createStreamResult(generator, turnPromise, abortController) {
62
+ function createStreamResult(generator, turnPromiseOrFactory, abortController) {
63
+ let cachedTurn = null;
64
+ const getTurn = () => {
65
+ if (typeof turnPromiseOrFactory === "function") {
66
+ if (!cachedTurn) {
67
+ cachedTurn = turnPromiseOrFactory();
68
+ }
69
+ return cachedTurn;
70
+ }
71
+ return turnPromiseOrFactory;
72
+ };
41
73
  return {
42
74
  [Symbol.asyncIterator]() {
43
75
  return generator;
44
76
  },
45
- turn: turnPromise,
77
+ get turn() {
78
+ return getTurn();
79
+ },
46
80
  abort() {
47
81
  abortController.abort();
48
82
  }
@@ -108,9 +142,19 @@ function toolExecutionEnd(toolCallId, toolName, result, isError, timestamp, inde
108
142
  // src/core/llm.ts
109
143
  var DEFAULT_MAX_ITERATIONS = 10;
110
144
  function llm(options) {
111
- const { model: modelRef, config = {}, params, system, tools, toolStrategy, structure } = options;
145
+ const { model: modelRef, config: explicitConfig = {}, params, system, tools, toolStrategy, structure } = options;
146
+ const providerConfig = modelRef.providerConfig ?? {};
147
+ const config = {
148
+ ...providerConfig,
149
+ ...explicitConfig,
150
+ headers: {
151
+ ...providerConfig.headers,
152
+ ...explicitConfig.headers
153
+ }
154
+ };
112
155
  const provider = modelRef.provider;
113
- if (!provider.modalities.llm) {
156
+ const llmHandler = resolveLLMHandler(provider, modelRef.options);
157
+ if (!llmHandler) {
114
158
  throw new UPPError(
115
159
  `Provider '${provider.name}' does not support LLM modality`,
116
160
  "INVALID_REQUEST",
@@ -118,7 +162,6 @@ function llm(options) {
118
162
  "llm"
119
163
  );
120
164
  }
121
- const llmHandler = provider.modalities.llm;
122
165
  const boundModel = llmHandler.bind(modelRef.modelId);
123
166
  const capabilities = boundModel.capabilities;
124
167
  if (structure && !capabilities.structuredOutput) {
@@ -185,10 +228,21 @@ function isMessageInstance(value) {
185
228
  if (value instanceof Message) {
186
229
  return true;
187
230
  }
188
- if (typeof value === "object" && value !== null && "timestamp" in value && "type" in value && "id" in value) {
231
+ if (typeof value === "object" && value !== null) {
189
232
  const obj = value;
190
- const messageTypes = ["user", "assistant", "tool_result"];
191
- return messageTypes.includes(obj.type);
233
+ const type = obj.type;
234
+ const id = obj.id;
235
+ const timestamp = obj.timestamp;
236
+ const hasValidTimestamp = timestamp instanceof Date || typeof timestamp === "string" && !Number.isNaN(Date.parse(timestamp));
237
+ if (typeof id !== "string" || id.length === 0 || !hasValidTimestamp) {
238
+ return false;
239
+ }
240
+ if (type === "user" || type === "assistant") {
241
+ return Array.isArray(obj.content);
242
+ }
243
+ if (type === "tool_result") {
244
+ return Array.isArray(obj.results);
245
+ }
192
246
  }
193
247
  return false;
194
248
  }
@@ -220,11 +274,17 @@ function inputToMessage(input) {
220
274
  if ("type" in input && "id" in input && "timestamp" in input) {
221
275
  return input;
222
276
  }
277
+ if (typeof input !== "object" || input === null || !("type" in input)) {
278
+ throw new Error("Invalid inference input");
279
+ }
223
280
  const block = input;
224
- if (block.type === "text") {
281
+ if (isTextBlock(block)) {
225
282
  return new UserMessage(block.text);
226
283
  }
227
- return new UserMessage([block]);
284
+ if (isImageBlock(block) || isAudioBlock(block) || isVideoBlock(block) || isBinaryBlock(block)) {
285
+ return new UserMessage([block]);
286
+ }
287
+ throw new Error("Invalid inference input");
228
288
  }
229
289
  async function executeGenerate(model, config, system, params, tools, toolStrategy, structure, history, newMessages) {
230
290
  validateMediaCapabilities(
@@ -300,17 +360,47 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
300
360
  let cycles = 0;
301
361
  let generatorError = null;
302
362
  let structuredData;
363
+ let generatorCompleted = false;
303
364
  let resolveGenerator;
304
365
  let rejectGenerator;
366
+ let generatorSettled = false;
305
367
  const generatorDone = new Promise((resolve, reject) => {
306
- resolveGenerator = resolve;
307
- rejectGenerator = reject;
368
+ resolveGenerator = () => {
369
+ if (!generatorSettled) {
370
+ generatorSettled = true;
371
+ resolve();
372
+ }
373
+ };
374
+ rejectGenerator = (error) => {
375
+ if (!generatorSettled) {
376
+ generatorSettled = true;
377
+ reject(error);
378
+ }
379
+ };
380
+ });
381
+ void generatorDone.catch((error) => {
382
+ if (!generatorError) {
383
+ generatorError = toError(error);
384
+ }
308
385
  });
309
386
  const maxIterations = toolStrategy?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
387
+ const onAbort = () => {
388
+ const error = new UPPError("Stream cancelled", "CANCELLED", model.provider.name, "llm");
389
+ generatorError = error;
390
+ rejectGenerator(error);
391
+ };
392
+ abortController.signal.addEventListener("abort", onAbort, { once: true });
393
+ const ensureNotAborted = () => {
394
+ if (abortController.signal.aborted) {
395
+ throw new UPPError("Stream cancelled", "CANCELLED", model.provider.name, "llm");
396
+ }
397
+ };
310
398
  async function* generateStream() {
311
399
  try {
400
+ ensureNotAborted();
312
401
  while (cycles < maxIterations + 1) {
313
402
  cycles++;
403
+ ensureNotAborted();
314
404
  const request = {
315
405
  messages: allMessages,
316
406
  system,
@@ -322,6 +412,7 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
322
412
  };
323
413
  const streamResult = model.stream(request);
324
414
  for await (const event of streamResult) {
415
+ ensureNotAborted();
325
416
  yield event;
326
417
  }
327
418
  const response = await streamResult.response;
@@ -352,6 +443,7 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
352
443
  (event) => toolEvents.push(event)
353
444
  );
354
445
  for (const event of toolEvents) {
446
+ ensureNotAborted();
355
447
  yield event;
356
448
  }
357
449
  allMessages.push(new ToolResultMessage(results));
@@ -359,14 +451,26 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
359
451
  }
360
452
  break;
361
453
  }
454
+ generatorCompleted = true;
362
455
  resolveGenerator();
363
456
  } catch (error) {
364
- generatorError = error;
365
- rejectGenerator(error);
366
- throw error;
457
+ const err = toError(error);
458
+ generatorError = err;
459
+ rejectGenerator(err);
460
+ throw err;
461
+ } finally {
462
+ abortController.signal.removeEventListener("abort", onAbort);
463
+ if (!generatorCompleted && !generatorSettled) {
464
+ const error = new UPPError("Stream cancelled", "CANCELLED", model.provider.name, "llm");
465
+ generatorError = error;
466
+ if (!abortController.signal.aborted) {
467
+ abortController.abort();
468
+ }
469
+ rejectGenerator(error);
470
+ }
367
471
  }
368
472
  }
369
- const turnPromise = (async () => {
473
+ const createTurnPromise = async () => {
370
474
  await generatorDone;
371
475
  if (generatorError) {
372
476
  throw generatorError;
@@ -379,8 +483,8 @@ function executeStream(model, config, system, params, tools, toolStrategy, struc
379
483
  cycles,
380
484
  data
381
485
  );
382
- })();
383
- return createStreamResult(generateStream(), turnPromise, abortController);
486
+ };
487
+ return createStreamResult(generateStream(), createTurnPromise, abortController);
384
488
  }
385
489
  async function executeTools(message, tools, toolStrategy, executions, onEvent) {
386
490
  const toolCalls = message.toolCalls ?? [];
@@ -388,41 +492,57 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
388
492
  const toolMap = new Map(tools.map((t) => [t.name, t]));
389
493
  const promises = toolCalls.map(async (call, index) => {
390
494
  const tool = toolMap.get(call.toolName);
391
- if (!tool) {
495
+ const toolName = tool?.name ?? call.toolName;
496
+ const startTime = Date.now();
497
+ onEvent?.(toolExecutionStart(call.toolCallId, toolName, startTime, index));
498
+ let effectiveParams = call.arguments;
499
+ const endWithError = async (message2, approved2) => {
500
+ const endTime = Date.now();
501
+ if (tool) {
502
+ await toolStrategy?.onError?.(tool, effectiveParams, new Error(message2));
503
+ }
504
+ const execution = {
505
+ toolName,
506
+ toolCallId: call.toolCallId,
507
+ arguments: effectiveParams,
508
+ result: message2,
509
+ isError: true,
510
+ duration: endTime - startTime,
511
+ approved: approved2
512
+ };
513
+ executions.push(execution);
514
+ onEvent?.(toolExecutionEnd(call.toolCallId, toolName, message2, true, endTime, index));
392
515
  return {
393
516
  toolCallId: call.toolCallId,
394
- result: `Tool '${call.toolName}' not found`,
517
+ result: message2,
395
518
  isError: true
396
519
  };
520
+ };
521
+ if (!tool) {
522
+ return endWithError(`Tool '${call.toolName}' not found`);
523
+ }
524
+ try {
525
+ await toolStrategy?.onToolCall?.(tool, effectiveParams);
526
+ } catch (error) {
527
+ return endWithError(toError(error).message);
397
528
  }
398
- const startTime = Date.now();
399
- onEvent?.(toolExecutionStart(call.toolCallId, tool.name, startTime, index));
400
- let effectiveParams = call.arguments;
401
- await toolStrategy?.onToolCall?.(tool, effectiveParams);
402
529
  if (toolStrategy?.onBeforeCall) {
403
- const beforeResult = await toolStrategy.onBeforeCall(tool, effectiveParams);
530
+ let beforeResult;
531
+ try {
532
+ beforeResult = await toolStrategy.onBeforeCall(tool, effectiveParams);
533
+ } catch (error) {
534
+ return endWithError(toError(error).message);
535
+ }
404
536
  const isBeforeCallResult = (value) => typeof value === "object" && value !== null && "proceed" in value;
405
537
  if (isBeforeCallResult(beforeResult)) {
406
538
  if (!beforeResult.proceed) {
407
- const endTime = Date.now();
408
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, "Tool execution skipped", true, endTime, index));
409
- return {
410
- toolCallId: call.toolCallId,
411
- result: "Tool execution skipped",
412
- isError: true
413
- };
539
+ return endWithError("Tool execution skipped");
414
540
  }
415
541
  if (beforeResult.params !== void 0) {
416
542
  effectiveParams = beforeResult.params;
417
543
  }
418
544
  } else if (!beforeResult) {
419
- const endTime = Date.now();
420
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, "Tool execution skipped", true, endTime, index));
421
- return {
422
- toolCallId: call.toolCallId,
423
- result: "Tool execution skipped",
424
- isError: true
425
- };
545
+ return endWithError("Tool execution skipped");
426
546
  }
427
547
  }
428
548
  let approved = true;
@@ -430,13 +550,13 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
430
550
  try {
431
551
  approved = await tool.approval(effectiveParams);
432
552
  } catch (error) {
433
- throw error;
553
+ return endWithError(toError(error).message);
434
554
  }
435
555
  }
436
556
  if (!approved) {
437
557
  const endTime = Date.now();
438
558
  const execution = {
439
- toolName: tool.name,
559
+ toolName,
440
560
  toolCallId: call.toolCallId,
441
561
  arguments: effectiveParams,
442
562
  result: "Tool execution denied",
@@ -445,7 +565,7 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
445
565
  approved: false
446
566
  };
447
567
  executions.push(execution);
448
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, "Tool execution denied by approval handler", true, endTime, index));
568
+ onEvent?.(toolExecutionEnd(call.toolCallId, toolName, "Tool execution denied by approval handler", true, endTime, index));
449
569
  return {
450
570
  toolCallId: call.toolCallId,
451
571
  result: "Tool execution denied by approval handler",
@@ -463,7 +583,7 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
463
583
  }
464
584
  }
465
585
  const execution = {
466
- toolName: tool.name,
586
+ toolName,
467
587
  toolCallId: call.toolCallId,
468
588
  arguments: effectiveParams,
469
589
  result,
@@ -472,7 +592,7 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
472
592
  approved
473
593
  };
474
594
  executions.push(execution);
475
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, result, false, endTime, index));
595
+ onEvent?.(toolExecutionEnd(call.toolCallId, toolName, result, false, endTime, index));
476
596
  return {
477
597
  toolCallId: call.toolCallId,
478
598
  result,
@@ -480,22 +600,22 @@ async function executeTools(message, tools, toolStrategy, executions, onEvent) {
480
600
  };
481
601
  } catch (error) {
482
602
  const endTime = Date.now();
483
- await toolStrategy?.onError?.(tool, effectiveParams, error);
484
- const errorMessage = error instanceof Error ? error.message : String(error);
603
+ const err = toError(error);
604
+ await toolStrategy?.onError?.(tool, effectiveParams, err);
485
605
  const execution = {
486
- toolName: tool.name,
606
+ toolName,
487
607
  toolCallId: call.toolCallId,
488
608
  arguments: effectiveParams,
489
- result: errorMessage,
609
+ result: err.message,
490
610
  isError: true,
491
611
  duration: endTime - startTime,
492
612
  approved
493
613
  };
494
614
  executions.push(execution);
495
- onEvent?.(toolExecutionEnd(call.toolCallId, tool.name, errorMessage, true, endTime, index));
615
+ onEvent?.(toolExecutionEnd(call.toolCallId, toolName, err.message, true, endTime, index));
496
616
  return {
497
617
  toolCallId: call.toolCallId,
498
- result: errorMessage,
618
+ result: err.message,
499
619
  isError: true
500
620
  };
501
621
  }
@@ -537,9 +657,19 @@ function validateMediaCapabilities(messages, capabilities, providerName) {
537
657
 
538
658
  // src/core/embedding.ts
539
659
  function embedding(options) {
540
- const { model: modelRef, config = {}, params } = options;
660
+ const { model: modelRef, config: explicitConfig = {}, params } = options;
661
+ const providerConfig = modelRef.providerConfig ?? {};
662
+ const config = {
663
+ ...providerConfig,
664
+ ...explicitConfig,
665
+ headers: {
666
+ ...providerConfig.headers,
667
+ ...explicitConfig.headers
668
+ }
669
+ };
541
670
  const provider = modelRef.provider;
542
- if (!provider.modalities.embedding) {
671
+ const handler = resolveEmbeddingHandler(provider);
672
+ if (!handler) {
543
673
  throw new UPPError(
544
674
  `Provider '${provider.name}' does not support embedding modality`,
545
675
  "INVALID_REQUEST",
@@ -547,20 +677,19 @@ function embedding(options) {
547
677
  "embedding"
548
678
  );
549
679
  }
550
- const handler = provider.modalities.embedding;
551
680
  const boundModel = handler.bind(modelRef.modelId);
552
- const instance = {
681
+ function embed(input, embedOptions) {
682
+ const inputs = Array.isArray(input) ? input : [input];
683
+ if (embedOptions?.chunked) {
684
+ return createChunkedStream(boundModel, inputs, params, config, embedOptions);
685
+ }
686
+ return executeEmbed(boundModel, inputs, params, config, embedOptions?.signal);
687
+ }
688
+ return {
553
689
  model: boundModel,
554
690
  params,
555
- embed(input, embedOptions) {
556
- const inputs = Array.isArray(input) ? input : [input];
557
- if (embedOptions?.chunked) {
558
- return createChunkedStream(boundModel, inputs, params, config, embedOptions);
559
- }
560
- return executeEmbed(boundModel, inputs, params, config, embedOptions?.signal);
561
- }
691
+ embed
562
692
  };
563
- return instance;
564
693
  }
565
694
  async function executeEmbed(model, inputs, params, config, signal) {
566
695
  const response = await model.embed({
@@ -569,12 +698,12 @@ async function executeEmbed(model, inputs, params, config, signal) {
569
698
  config: config ?? {},
570
699
  signal
571
700
  });
572
- return normalizeResponse(response);
701
+ return normalizeResponse(response, model.provider.name);
573
702
  }
574
- function normalizeResponse(response) {
703
+ function normalizeResponse(response, providerName) {
575
704
  return {
576
705
  embeddings: response.embeddings.map((vec, i) => {
577
- const vector = normalizeVector(vec.vector);
706
+ const vector = normalizeVector(vec.vector, providerName);
578
707
  return {
579
708
  vector,
580
709
  dimensions: vector.length,
@@ -587,20 +716,32 @@ function normalizeResponse(response) {
587
716
  metadata: response.metadata
588
717
  };
589
718
  }
590
- function normalizeVector(vector) {
719
+ function normalizeVector(vector, providerName) {
591
720
  if (Array.isArray(vector)) {
592
721
  return vector;
593
722
  }
594
- return decodeBase64(vector);
723
+ return decodeBase64(vector, providerName);
595
724
  }
596
- function decodeBase64(b64) {
597
- const binary = atob(b64);
598
- const bytes = new Uint8Array(binary.length);
599
- for (let i = 0; i < binary.length; i++) {
600
- bytes[i] = binary.charCodeAt(i);
725
+ function decodeBase64(b64, providerName) {
726
+ try {
727
+ const binary = atob(b64);
728
+ const bytes = new Uint8Array(binary.length);
729
+ for (let i = 0; i < binary.length; i++) {
730
+ bytes[i] = binary.charCodeAt(i);
731
+ }
732
+ const floats = new Float32Array(bytes.buffer);
733
+ return Array.from(floats);
734
+ } catch (error) {
735
+ const cause = error instanceof Error ? error : new Error("Failed to decode base64 vector");
736
+ throw new UPPError(
737
+ "Invalid base64 embedding vector",
738
+ "INVALID_RESPONSE",
739
+ providerName,
740
+ "embedding",
741
+ void 0,
742
+ cause
743
+ );
601
744
  }
602
- const floats = new Float32Array(bytes.buffer);
603
- return Array.from(floats);
604
745
  }
605
746
  function createChunkedStream(model, inputs, params, config, options) {
606
747
  const abortController = new AbortController();
@@ -608,33 +749,59 @@ function createChunkedStream(model, inputs, params, config, options) {
608
749
  const concurrency = options.concurrency ?? 1;
609
750
  let resolveResult;
610
751
  let rejectResult;
752
+ let settled = false;
611
753
  const resultPromise = new Promise((resolve, reject) => {
612
- resolveResult = resolve;
613
- rejectResult = reject;
754
+ resolveResult = (result) => {
755
+ if (!settled) {
756
+ settled = true;
757
+ resolve(result);
758
+ }
759
+ };
760
+ rejectResult = (error) => {
761
+ if (!settled) {
762
+ settled = true;
763
+ reject(error);
764
+ }
765
+ };
614
766
  });
767
+ const cancelError = () => new UPPError(
768
+ "Embedding cancelled",
769
+ "CANCELLED",
770
+ model.provider.name,
771
+ "embedding"
772
+ );
773
+ const onAbort = () => {
774
+ rejectResult(cancelError());
775
+ };
776
+ abortController.signal.addEventListener("abort", onAbort, { once: true });
777
+ const onExternalAbort = () => abortController.abort();
778
+ if (options.signal) {
779
+ options.signal.addEventListener("abort", onExternalAbort, { once: true });
780
+ }
781
+ const cleanupAbortListeners = () => {
782
+ abortController.signal.removeEventListener("abort", onAbort);
783
+ if (options.signal) {
784
+ options.signal.removeEventListener("abort", onExternalAbort);
785
+ }
786
+ };
615
787
  async function* generate() {
616
788
  const total = inputs.length;
617
789
  const allEmbeddings = [];
618
790
  let totalTokens = 0;
619
791
  const batches = [];
620
792
  for (let i = 0; i < inputs.length; i += batchSize) {
621
- batches.push(inputs.slice(i, i + batchSize));
793
+ batches.push({ inputs: inputs.slice(i, i + batchSize), startIndex: i });
622
794
  }
623
795
  try {
624
796
  for (let i = 0; i < batches.length; i += concurrency) {
625
797
  if (abortController.signal.aborted || options.signal?.aborted) {
626
- throw new UPPError(
627
- "Embedding cancelled",
628
- "CANCELLED",
629
- model.provider.name,
630
- "embedding"
631
- );
798
+ throw cancelError();
632
799
  }
633
800
  const chunk = batches.slice(i, i + concurrency);
634
801
  const responses = await Promise.all(
635
802
  chunk.map(
636
803
  (batch) => model.embed({
637
- inputs: batch,
804
+ inputs: batch.inputs,
638
805
  params,
639
806
  config: config ?? {},
640
807
  signal: abortController.signal
@@ -642,13 +809,17 @@ function createChunkedStream(model, inputs, params, config, options) {
642
809
  )
643
810
  );
644
811
  const batchEmbeddings = [];
645
- for (const response of responses) {
646
- for (const vec of response.embeddings) {
647
- const vector = normalizeVector(vec.vector);
812
+ for (let responseIndex = 0; responseIndex < responses.length; responseIndex += 1) {
813
+ const response = responses[responseIndex];
814
+ const batch = chunk[responseIndex];
815
+ for (let vecIndex = 0; vecIndex < response.embeddings.length; vecIndex += 1) {
816
+ const vec = response.embeddings[vecIndex];
817
+ const vector = normalizeVector(vec.vector, model.provider.name);
818
+ const resolvedIndex = batch.startIndex + (vec.index ?? vecIndex);
648
819
  const emb = {
649
820
  vector,
650
821
  dimensions: vector.length,
651
- index: allEmbeddings.length + batchEmbeddings.length,
822
+ index: resolvedIndex,
652
823
  tokens: vec.tokens,
653
824
  metadata: vec.metadata
654
825
  };
@@ -664,13 +835,19 @@ function createChunkedStream(model, inputs, params, config, options) {
664
835
  percent: allEmbeddings.length / total * 100
665
836
  };
666
837
  }
838
+ const orderedEmbeddings = [...allEmbeddings].sort(
839
+ (left, right) => left.index - right.index
840
+ );
667
841
  resolveResult({
668
- embeddings: allEmbeddings,
842
+ embeddings: orderedEmbeddings,
669
843
  usage: { totalTokens }
670
844
  });
671
845
  } catch (error) {
672
- rejectResult(error);
673
- throw error;
846
+ const err = toError(error);
847
+ rejectResult(err);
848
+ throw err;
849
+ } finally {
850
+ cleanupAbortListeners();
674
851
  }
675
852
  }
676
853
  const generator = generate();
@@ -683,9 +860,19 @@ function createChunkedStream(model, inputs, params, config, options) {
683
860
 
684
861
  // src/core/image.ts
685
862
  function image(options) {
686
- const { model: modelRef, config = {}, params } = options;
863
+ const { model: modelRef, config: explicitConfig = {}, params } = options;
864
+ const providerConfig = modelRef.providerConfig ?? {};
865
+ const config = {
866
+ ...providerConfig,
867
+ ...explicitConfig,
868
+ headers: {
869
+ ...providerConfig.headers,
870
+ ...explicitConfig.headers
871
+ }
872
+ };
687
873
  const provider = modelRef.provider;
688
- if (!provider.modalities.image) {
874
+ const imageHandler = resolveImageHandler(provider);
875
+ if (!imageHandler) {
689
876
  throw new UPPError(
690
877
  `Provider '${provider.name}' does not support image modality`,
691
878
  "INVALID_REQUEST",
@@ -693,33 +880,44 @@ function image(options) {
693
880
  "image"
694
881
  );
695
882
  }
696
- const imageHandler = provider.modalities.image;
697
883
  const boundModel = imageHandler.bind(modelRef.modelId);
698
884
  const capabilities = boundModel.capabilities;
885
+ const normalizeImageError = (error) => {
886
+ if (error instanceof UPPError) {
887
+ return error;
888
+ }
889
+ const err = toError(error);
890
+ return new UPPError(err.message, "PROVIDER_ERROR", provider.name, "image", void 0, err);
891
+ };
699
892
  const instance = {
700
893
  model: boundModel,
701
894
  params,
702
895
  capabilities,
703
- async generate(input) {
896
+ async generate(input, options2) {
704
897
  const prompt = normalizeInput(input);
705
- const response = await boundModel.generate({
706
- prompt,
707
- params,
708
- config
709
- });
710
- return {
711
- images: response.images,
712
- metadata: response.metadata,
713
- usage: response.usage
714
- };
898
+ try {
899
+ const response = await boundModel.generate({
900
+ prompt,
901
+ params,
902
+ config,
903
+ signal: options2?.signal
904
+ });
905
+ return {
906
+ images: response.images,
907
+ metadata: response.metadata,
908
+ usage: response.usage
909
+ };
910
+ } catch (error) {
911
+ throw normalizeImageError(error);
912
+ }
715
913
  }
716
914
  };
717
915
  if (capabilities.streaming && boundModel.stream) {
718
- const boundModelWithStream = boundModel;
916
+ const stream = boundModel.stream;
719
917
  instance.stream = function(input) {
720
918
  const prompt = normalizeInput(input);
721
919
  const abortController = new AbortController();
722
- const providerStream = boundModelWithStream.stream({
920
+ const providerStream = stream({
723
921
  prompt,
724
922
  params,
725
923
  config,
@@ -729,29 +927,44 @@ function image(options) {
729
927
  images: response.images,
730
928
  metadata: response.metadata,
731
929
  usage: response.usage
732
- }));
930
+ })).catch((error) => {
931
+ throw normalizeImageError(error);
932
+ });
933
+ async function* wrappedStream() {
934
+ try {
935
+ for await (const event of providerStream) {
936
+ yield event;
937
+ }
938
+ } catch (error) {
939
+ throw normalizeImageError(error);
940
+ }
941
+ }
733
942
  return {
734
- [Symbol.asyncIterator]: () => providerStream[Symbol.asyncIterator](),
943
+ [Symbol.asyncIterator]: () => wrappedStream(),
735
944
  result: resultPromise,
736
945
  abort: () => abortController.abort()
737
946
  };
738
947
  };
739
948
  }
740
949
  if (capabilities.edit && boundModel.edit) {
741
- const boundModelWithEdit = boundModel;
950
+ const edit = boundModel.edit;
742
951
  instance.edit = async function(input) {
743
- const response = await boundModelWithEdit.edit({
744
- image: input.image,
745
- mask: input.mask,
746
- prompt: input.prompt,
747
- params,
748
- config
749
- });
750
- return {
751
- images: response.images,
752
- metadata: response.metadata,
753
- usage: response.usage
754
- };
952
+ try {
953
+ const response = await edit({
954
+ image: input.image,
955
+ mask: input.mask,
956
+ prompt: input.prompt,
957
+ params,
958
+ config
959
+ });
960
+ return {
961
+ images: response.images,
962
+ metadata: response.metadata,
963
+ usage: response.usage
964
+ };
965
+ } catch (error) {
966
+ throw normalizeImageError(error);
967
+ }
755
968
  };
756
969
  }
757
970
  return instance;
@@ -763,26 +976,6 @@ function normalizeInput(input) {
763
976
  return input.prompt;
764
977
  }
765
978
 
766
- // src/types/content.ts
767
- function text(content) {
768
- return { type: "text", text: content };
769
- }
770
- function isTextBlock(block) {
771
- return block.type === "text";
772
- }
773
- function isImageBlock(block) {
774
- return block.type === "image";
775
- }
776
- function isAudioBlock(block) {
777
- return block.type === "audio";
778
- }
779
- function isVideoBlock(block) {
780
- return block.type === "video";
781
- }
782
- function isBinaryBlock(block) {
783
- return block.type === "binary";
784
- }
785
-
786
979
  // src/types/thread.ts
787
980
  var Thread = class _Thread {
788
981
  /** Unique thread identifier */