@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.
- package/dist/anthropic/index.d.ts +184 -14
- package/dist/anthropic/index.js +306 -107
- package/dist/anthropic/index.js.map +1 -1
- package/dist/{chunk-P5IRTEM5.js → chunk-7WYBJPJJ.js} +2 -2
- package/dist/chunk-I2VHCGQE.js +49 -0
- package/dist/chunk-I2VHCGQE.js.map +1 -0
- package/dist/{chunk-UMKWXGO3.js → chunk-M4BMM5IB.js} +86 -2
- package/dist/chunk-M4BMM5IB.js.map +1 -0
- package/dist/{chunk-SKY2JLA7.js → chunk-MKDLXV4O.js} +1 -1
- package/dist/chunk-MKDLXV4O.js.map +1 -0
- package/dist/{chunk-Z7RBRCRN.js → chunk-NWS5IKNR.js} +37 -11
- package/dist/chunk-NWS5IKNR.js.map +1 -0
- package/dist/{chunk-U3FZWV4U.js → chunk-RFWLEFAB.js} +100 -43
- package/dist/chunk-RFWLEFAB.js.map +1 -0
- package/dist/{chunk-U4JJC2YX.js → chunk-RS7C25LS.js} +36 -11
- package/dist/chunk-RS7C25LS.js.map +1 -0
- package/dist/google/index.d.ts +35 -24
- package/dist/google/index.js +273 -99
- package/dist/google/index.js.map +1 -1
- package/dist/http/index.d.ts +3 -3
- package/dist/http/index.js +4 -4
- package/dist/index.d.ts +103 -38
- package/dist/index.js +346 -153
- package/dist/index.js.map +1 -1
- package/dist/ollama/index.d.ts +14 -16
- package/dist/ollama/index.js +68 -16
- package/dist/ollama/index.js.map +1 -1
- package/dist/openai/index.d.ts +25 -133
- package/dist/openai/index.js +208 -122
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.d.ts +28 -53
- package/dist/openrouter/index.js +179 -72
- package/dist/openrouter/index.js.map +1 -1
- package/dist/provider-DWEAzeM5.d.ts +1329 -0
- package/dist/proxy/index.d.ts +2 -3
- package/dist/proxy/index.js +174 -17
- package/dist/proxy/index.js.map +1 -1
- package/dist/{retry-DR7YRJDz.d.ts → retry-DmPmqZL6.d.ts} +12 -3
- package/dist/{stream-DRHy6q1a.d.ts → stream-DbkLOIbJ.d.ts} +15 -5
- package/dist/xai/index.d.ts +16 -88
- package/dist/xai/index.js +167 -86
- package/dist/xai/index.js.map +1 -1
- package/package.json +4 -1
- package/dist/chunk-MSR5P65T.js +0 -39
- package/dist/chunk-MSR5P65T.js.map +0 -1
- package/dist/chunk-SKY2JLA7.js.map +0 -1
- package/dist/chunk-U3FZWV4U.js.map +0 -1
- package/dist/chunk-U4JJC2YX.js.map +0 -1
- package/dist/chunk-UMKWXGO3.js.map +0 -1
- package/dist/chunk-Z7RBRCRN.js.map +0 -1
- package/dist/content-DEl3z_W2.d.ts +0 -276
- package/dist/image-Dhq-Yuq4.d.ts +0 -456
- package/dist/provider-BBMBZuGn.d.ts +0 -570
- /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-
|
|
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
|
-
|
|
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-
|
|
29
|
-
import "./chunk-
|
|
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-
|
|
35
|
+
} from "./chunk-7WYBJPJJ.js";
|
|
35
36
|
import {
|
|
36
|
-
UPPError
|
|
37
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
|
231
|
+
if (typeof value === "object" && value !== null) {
|
|
189
232
|
const obj = value;
|
|
190
|
-
const
|
|
191
|
-
|
|
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
|
|
281
|
+
if (isTextBlock(block)) {
|
|
225
282
|
return new UserMessage(block.text);
|
|
226
283
|
}
|
|
227
|
-
|
|
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 =
|
|
307
|
-
|
|
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
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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
|
|
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(),
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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
|
-
|
|
484
|
-
|
|
603
|
+
const err = toError(error);
|
|
604
|
+
await toolStrategy?.onError?.(tool, effectiveParams, err);
|
|
485
605
|
const execution = {
|
|
486
|
-
toolName
|
|
606
|
+
toolName,
|
|
487
607
|
toolCallId: call.toolCallId,
|
|
488
608
|
arguments: effectiveParams,
|
|
489
|
-
result:
|
|
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,
|
|
615
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, toolName, err.message, true, endTime, index));
|
|
496
616
|
return {
|
|
497
617
|
toolCallId: call.toolCallId,
|
|
498
|
-
result:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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 =
|
|
613
|
-
|
|
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
|
|
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 (
|
|
646
|
-
|
|
647
|
-
|
|
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:
|
|
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:
|
|
842
|
+
embeddings: orderedEmbeddings,
|
|
669
843
|
usage: { totalTokens }
|
|
670
844
|
});
|
|
671
845
|
} catch (error) {
|
|
672
|
-
|
|
673
|
-
|
|
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
|
-
|
|
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
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
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
|
|
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 =
|
|
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]: () =>
|
|
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
|
|
950
|
+
const edit = boundModel.edit;
|
|
742
951
|
instance.edit = async function(input) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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 */
|