@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.
- package/README.md +188 -6
- package/dist/anthropic/index.d.ts +1 -1
- package/dist/anthropic/index.js +115 -39
- package/dist/anthropic/index.js.map +1 -1
- package/dist/{chunk-Y3GBJNA2.js → chunk-55X3W2MN.js} +4 -3
- package/dist/chunk-55X3W2MN.js.map +1 -0
- package/dist/chunk-73IIE3QT.js +120 -0
- package/dist/chunk-73IIE3QT.js.map +1 -0
- package/dist/{chunk-M4BMM5IB.js → chunk-MF5ETY5O.js} +13 -4
- package/dist/chunk-MF5ETY5O.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-EDENPF3E.js → chunk-QNJO7DSD.js} +152 -53
- package/dist/chunk-QNJO7DSD.js.map +1 -0
- package/dist/{chunk-Z4ILICF5.js → chunk-SBCATNHA.js} +43 -14
- package/dist/chunk-SBCATNHA.js.map +1 -0
- package/dist/chunk-Z6DKC37J.js +50 -0
- package/dist/chunk-Z6DKC37J.js.map +1 -0
- package/dist/google/index.d.ts +22 -7
- package/dist/google/index.js +286 -85
- 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 +10 -6
- package/dist/index.js +331 -204
- package/dist/index.js.map +1 -1
- package/dist/ollama/index.d.ts +5 -2
- package/dist/ollama/index.js +87 -28
- package/dist/ollama/index.js.map +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/openai/index.js +226 -81
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.d.ts +1 -1
- package/dist/openrouter/index.js +199 -64
- package/dist/openrouter/index.js.map +1 -1
- package/dist/{provider-DGQHYE6I.d.ts → provider-DR1yins0.d.ts} +159 -53
- package/dist/proxy/index.d.ts +2 -2
- package/dist/proxy/index.js +178 -17
- package/dist/proxy/index.js.map +1 -1
- package/dist/{retry-Pcs3hnbu.d.ts → retry-DJiqAslw.d.ts} +11 -2
- package/dist/{stream-Di9acos2.d.ts → stream-BuTrqt_j.d.ts} +103 -41
- package/dist/xai/index.d.ts +1 -1
- package/dist/xai/index.js +189 -75
- package/dist/xai/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-EDENPF3E.js.map +0 -1
- package/dist/chunk-M4BMM5IB.js.map +0 -1
- package/dist/chunk-SKY2JLA7.js.map +0 -1
- package/dist/chunk-Y3GBJNA2.js.map +0 -1
- package/dist/chunk-Z4ILICF5.js.map +0 -1
- 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-
|
|
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-
|
|
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-
|
|
30
|
-
import "./chunk-
|
|
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-
|
|
48
|
+
} from "./chunk-55X3W2MN.js";
|
|
36
49
|
import {
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
ErrorCode,
|
|
51
|
+
ModalityType,
|
|
52
|
+
UPPError,
|
|
53
|
+
toError
|
|
54
|
+
} from "./chunk-QNJO7DSD.js";
|
|
39
55
|
|
|
40
|
-
// src/types/
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
114
|
+
ErrorCode.InvalidRequest,
|
|
128
115
|
provider.name,
|
|
129
|
-
|
|
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
|
-
|
|
124
|
+
ErrorCode.InvalidRequest,
|
|
138
125
|
provider.name,
|
|
139
|
-
|
|
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
|
-
|
|
132
|
+
ErrorCode.InvalidRequest,
|
|
146
133
|
provider.name,
|
|
147
|
-
|
|
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
|
-
|
|
160
|
+
ErrorCode.InvalidRequest,
|
|
174
161
|
provider.name,
|
|
175
|
-
|
|
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
|
|
185
|
+
if (typeof value === "object" && value !== null) {
|
|
199
186
|
const obj = value;
|
|
200
|
-
const
|
|
201
|
-
|
|
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
|
|
235
|
+
if (isTextBlock(block)) {
|
|
235
236
|
return new UserMessage(block.text);
|
|
236
237
|
}
|
|
237
|
-
|
|
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
|
-
|
|
279
|
+
ErrorCode.InvalidRequest,
|
|
276
280
|
model.provider.name,
|
|
277
|
-
|
|
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 =
|
|
317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
386
|
+
ErrorCode.InvalidRequest,
|
|
355
387
|
model.provider.name,
|
|
356
|
-
|
|
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
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
|
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(),
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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
|
-
|
|
497
|
-
|
|
557
|
+
const err = toError(error);
|
|
558
|
+
await toolStrategy?.onError?.(tool, effectiveParams, err);
|
|
498
559
|
const execution = {
|
|
499
|
-
toolName
|
|
560
|
+
toolName,
|
|
500
561
|
toolCallId: call.toolCallId,
|
|
501
562
|
arguments: effectiveParams,
|
|
502
|
-
result:
|
|
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,
|
|
569
|
+
onEvent?.(toolExecutionEnd(call.toolCallId, toolName, err.message, true, endTime, index));
|
|
509
570
|
return {
|
|
510
571
|
toolCallId: call.toolCallId,
|
|
511
|
-
result:
|
|
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
|
-
|
|
587
|
+
ErrorCode.InvalidRequest,
|
|
527
588
|
providerName,
|
|
528
|
-
|
|
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
|
-
|
|
595
|
+
ErrorCode.InvalidRequest,
|
|
535
596
|
providerName,
|
|
536
|
-
|
|
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
|
-
|
|
603
|
+
ErrorCode.InvalidRequest,
|
|
543
604
|
providerName,
|
|
544
|
-
|
|
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
|
-
|
|
629
|
+
ErrorCode.InvalidRequest,
|
|
560
630
|
provider.name,
|
|
561
|
-
|
|
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
|
-
|
|
692
|
+
ErrorCode.InvalidResponse,
|
|
623
693
|
providerName,
|
|
624
|
-
|
|
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 =
|
|
638
|
-
|
|
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
|
|
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 (
|
|
671
|
-
|
|
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:
|
|
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:
|
|
796
|
+
embeddings: orderedEmbeddings,
|
|
694
797
|
usage: { totalTokens }
|
|
695
798
|
});
|
|
696
799
|
} catch (error) {
|
|
697
|
-
|
|
698
|
-
|
|
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
|
-
|
|
832
|
+
ErrorCode.InvalidRequest,
|
|
718
833
|
provider.name,
|
|
719
|
-
|
|
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
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
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]: () =>
|
|
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
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
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,
|