@dogpile/sdk 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/browser/index.js +784 -562
- package/dist/browser/index.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/runtime/broadcast.d.ts.map +1 -1
- package/dist/runtime/broadcast.js +1 -13
- package/dist/runtime/broadcast.js.map +1 -1
- package/dist/runtime/coordinator.d.ts.map +1 -1
- package/dist/runtime/coordinator.js +1 -13
- package/dist/runtime/coordinator.js.map +1 -1
- package/dist/runtime/ids.d.ts +19 -0
- package/dist/runtime/ids.d.ts.map +1 -0
- package/dist/runtime/ids.js +36 -0
- package/dist/runtime/ids.js.map +1 -0
- package/dist/runtime/logger.d.ts +61 -0
- package/dist/runtime/logger.d.ts.map +1 -0
- package/dist/runtime/logger.js +114 -0
- package/dist/runtime/logger.js.map +1 -0
- package/dist/runtime/retry.d.ts +99 -0
- package/dist/runtime/retry.d.ts.map +1 -0
- package/dist/runtime/retry.js +181 -0
- package/dist/runtime/retry.js.map +1 -0
- package/dist/runtime/sequential.d.ts.map +1 -1
- package/dist/runtime/sequential.js +1 -10
- package/dist/runtime/sequential.js.map +1 -1
- package/dist/runtime/shared.d.ts.map +1 -1
- package/dist/runtime/shared.js +1 -13
- package/dist/runtime/shared.js.map +1 -1
- package/dist/runtime/tools/built-in.d.ts +99 -0
- package/dist/runtime/tools/built-in.d.ts.map +1 -0
- package/dist/runtime/tools/built-in.js +577 -0
- package/dist/runtime/tools/built-in.js.map +1 -0
- package/dist/runtime/tools/vercel-ai.d.ts +67 -0
- package/dist/runtime/tools/vercel-ai.d.ts.map +1 -0
- package/dist/runtime/tools/vercel-ai.js +148 -0
- package/dist/runtime/tools/vercel-ai.js.map +1 -0
- package/dist/runtime/tools.d.ts +5 -268
- package/dist/runtime/tools.d.ts.map +1 -1
- package/dist/runtime/tools.js +7 -770
- package/dist/runtime/tools.js.map +1 -1
- package/dist/types/benchmark.d.ts +276 -0
- package/dist/types/benchmark.d.ts.map +1 -0
- package/dist/types/benchmark.js +2 -0
- package/dist/types/benchmark.js.map +1 -0
- package/dist/types/events.d.ts +495 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +2 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/replay.d.ts +169 -0
- package/dist/types/replay.d.ts.map +1 -0
- package/dist/types/replay.js +2 -0
- package/dist/types/replay.js.map +1 -0
- package/dist/types.d.ts +6 -935
- package/dist/types.d.ts.map +1 -1
- package/package.json +27 -1
- package/src/index.ts +4 -0
- package/src/runtime/broadcast.ts +1 -16
- package/src/runtime/coordinator.ts +1 -16
- package/src/runtime/ids.ts +41 -0
- package/src/runtime/logger.ts +152 -0
- package/src/runtime/retry.ts +270 -0
- package/src/runtime/sequential.ts +1 -12
- package/src/runtime/shared.ts +1 -16
- package/src/runtime/tools/built-in.ts +875 -0
- package/src/runtime/tools/vercel-ai.ts +269 -0
- package/src/runtime/tools.ts +60 -1255
- package/src/types/benchmark.ts +300 -0
- package/src/types/events.ts +544 -0
- package/src/types/replay.ts +201 -0
- package/src/types.ts +104 -994
package/dist/runtime/tools.js
CHANGED
|
@@ -1,81 +1,9 @@
|
|
|
1
1
|
import { validateRuntimeToolRegistrations } from "./validation.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
description: "Search the web through a caller-provided fetch-compatible search adapter."
|
|
8
|
-
};
|
|
9
|
-
const codeExecIdentity = {
|
|
10
|
-
id: "dogpile.tools.codeExec",
|
|
11
|
-
namespace: "dogpile",
|
|
12
|
-
name: "codeExec",
|
|
13
|
-
version: "1.0.0",
|
|
14
|
-
description: "Execute code through a caller-provided sandbox adapter."
|
|
15
|
-
};
|
|
16
|
-
const webSearchInputSchema = {
|
|
17
|
-
kind: "json-schema",
|
|
18
|
-
description: "Web search query and optional result cap.",
|
|
19
|
-
schema: {
|
|
20
|
-
type: "object",
|
|
21
|
-
properties: {
|
|
22
|
-
query: { type: "string" },
|
|
23
|
-
maxResults: { type: "number", minimum: 1 }
|
|
24
|
-
},
|
|
25
|
-
required: ["query"],
|
|
26
|
-
additionalProperties: false
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
const codeExecInputSchema = {
|
|
30
|
-
kind: "json-schema",
|
|
31
|
-
description: "Code snippet plus language and optional timeout.",
|
|
32
|
-
schema: {
|
|
33
|
-
type: "object",
|
|
34
|
-
properties: {
|
|
35
|
-
language: {
|
|
36
|
-
type: "string",
|
|
37
|
-
enum: ["javascript", "typescript", "python", "bash", "shell"]
|
|
38
|
-
},
|
|
39
|
-
code: { type: "string" },
|
|
40
|
-
timeoutMs: { type: "number", minimum: 1 }
|
|
41
|
-
},
|
|
42
|
-
required: ["language", "code"],
|
|
43
|
-
additionalProperties: false
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const webSearchPermissions = [
|
|
47
|
-
{
|
|
48
|
-
kind: "network",
|
|
49
|
-
allowPrivateNetwork: false
|
|
50
|
-
}
|
|
51
|
-
];
|
|
52
|
-
const codeExecPermissions = [
|
|
53
|
-
{
|
|
54
|
-
kind: "code-execution",
|
|
55
|
-
sandbox: "caller-provided",
|
|
56
|
-
languages: ["javascript", "typescript", "python", "bash", "shell"],
|
|
57
|
-
allowNetwork: false
|
|
58
|
-
}
|
|
59
|
-
];
|
|
60
|
-
const codeExecLanguages = ["javascript", "typescript", "python", "bash", "shell"];
|
|
61
|
-
export function builtInDogpileToolIdentity(name) {
|
|
62
|
-
return name === "webSearch" ? webSearchIdentity : codeExecIdentity;
|
|
63
|
-
}
|
|
64
|
-
export function builtInDogpileToolInputSchema(name) {
|
|
65
|
-
return name === "webSearch" ? webSearchInputSchema : codeExecInputSchema;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Return the default permission declarations for one built-in tool name.
|
|
69
|
-
*/
|
|
70
|
-
export function builtInDogpileToolPermissions(name) {
|
|
71
|
-
return name === "webSearch" ? webSearchPermissions : codeExecPermissions;
|
|
72
|
-
}
|
|
73
|
-
export function validateBuiltInDogpileToolInput(name, input) {
|
|
74
|
-
const issues = name === "webSearch"
|
|
75
|
-
? validateWebSearchInput(input)
|
|
76
|
-
: validateCodeExecInput(input);
|
|
77
|
-
return issues.length === 0 ? { type: "valid" } : { type: "invalid", issues };
|
|
78
|
-
}
|
|
2
|
+
import { normalizeRuntimeToolAdapterError } from "./tools/built-in.js";
|
|
3
|
+
// Re-export the public surface from the split modules so the
|
|
4
|
+
// `@dogpile/sdk/runtime/tools` subpath stays stable.
|
|
5
|
+
export { builtInDogpileToolIdentity, builtInDogpileToolInputSchema, builtInDogpileToolPermissions, createCodeExecToolAdapter, createWebSearchToolAdapter, normalizeBuiltInDogpileTool, normalizeBuiltInDogpileTools, normalizeRuntimeToolAdapterError, validateBuiltInDogpileToolInput } from "./tools/built-in.js";
|
|
6
|
+
export { normalizeVercelAITool, normalizeVercelAITools } from "./tools/vercel-ai.js";
|
|
79
7
|
/**
|
|
80
8
|
* Create the shared runtime tool executor used by every first-party protocol.
|
|
81
9
|
*
|
|
@@ -206,36 +134,6 @@ function runtimeToolPermissionManifest(permission) {
|
|
|
206
134
|
...(permission.metadata ? { metadata: permission.metadata } : {})
|
|
207
135
|
};
|
|
208
136
|
}
|
|
209
|
-
function validateCodeExecAdapterInput(input, options) {
|
|
210
|
-
const issues = [...validateCodeExecInput(input)];
|
|
211
|
-
const languages = options.languages ?? codeExecLanguages;
|
|
212
|
-
if (typeof input.language === "string" && isCodeExecLanguage(input.language) && !languages.includes(input.language)) {
|
|
213
|
-
issues.push({
|
|
214
|
-
code: "invalid-value",
|
|
215
|
-
path: "language",
|
|
216
|
-
message: "codeExec.language is not enabled for this adapter.",
|
|
217
|
-
detail: {
|
|
218
|
-
allowed: Array.from(languages)
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
const effectiveTimeoutMs = input.timeoutMs ?? options.defaultTimeoutMs;
|
|
223
|
-
if (effectiveTimeoutMs !== undefined &&
|
|
224
|
-
options.maxTimeoutMs !== undefined &&
|
|
225
|
-
Number.isFinite(effectiveTimeoutMs) &&
|
|
226
|
-
Number.isFinite(options.maxTimeoutMs) &&
|
|
227
|
-
effectiveTimeoutMs > options.maxTimeoutMs) {
|
|
228
|
-
issues.push({
|
|
229
|
-
code: "out-of-range",
|
|
230
|
-
path: input.timeoutMs === undefined ? "defaultTimeoutMs" : "timeoutMs",
|
|
231
|
-
message: `codeExec.timeoutMs must be less than or equal to ${options.maxTimeoutMs}.`,
|
|
232
|
-
detail: {
|
|
233
|
-
maximum: options.maxTimeoutMs
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
return issues.length === 0 ? { type: "valid" } : { type: "invalid", issues };
|
|
238
|
-
}
|
|
239
137
|
function createExecutionContext(options, request, toolCallId) {
|
|
240
138
|
return {
|
|
241
139
|
runId: options.runId,
|
|
@@ -263,8 +161,8 @@ async function executeRuntimeTool(tool, identity, input, context) {
|
|
|
263
161
|
}
|
|
264
162
|
};
|
|
265
163
|
}
|
|
266
|
-
const validation =
|
|
267
|
-
if (validation
|
|
164
|
+
const validation = tool.validateInput?.(input);
|
|
165
|
+
if (validation?.type === "invalid") {
|
|
268
166
|
return {
|
|
269
167
|
type: "error",
|
|
270
168
|
toolCallId: context.toolCallId,
|
|
@@ -296,12 +194,6 @@ async function executeRuntimeTool(tool, identity, input, context) {
|
|
|
296
194
|
};
|
|
297
195
|
}
|
|
298
196
|
}
|
|
299
|
-
function validateRuntimeToolInput(tool, input) {
|
|
300
|
-
if (typeof tool.validateInput !== "function") {
|
|
301
|
-
return { type: "valid" };
|
|
302
|
-
}
|
|
303
|
-
return tool.validateInput(input);
|
|
304
|
-
}
|
|
305
197
|
function mergeToolMetadata(base, request) {
|
|
306
198
|
return {
|
|
307
199
|
...(base ?? {}),
|
|
@@ -311,659 +203,4 @@ function mergeToolMetadata(base, request) {
|
|
|
311
203
|
function defaultToolCallId(runId, callIndex) {
|
|
312
204
|
return `${runId}:tool-${callIndex + 1}`;
|
|
313
205
|
}
|
|
314
|
-
/**
|
|
315
|
-
* Convert an unknown adapter failure into Dogpile's serializable error data.
|
|
316
|
-
*/
|
|
317
|
-
export function normalizeRuntimeToolAdapterError(error) {
|
|
318
|
-
if (isRuntimeToolAdapterError(error)) {
|
|
319
|
-
return error;
|
|
320
|
-
}
|
|
321
|
-
if (error instanceof DOMException && error.name === "AbortError") {
|
|
322
|
-
return {
|
|
323
|
-
code: "aborted",
|
|
324
|
-
message: error.message || "Tool execution was aborted.",
|
|
325
|
-
retryable: true,
|
|
326
|
-
detail: {
|
|
327
|
-
name: error.name
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
if (error instanceof Error) {
|
|
332
|
-
return {
|
|
333
|
-
code: "backend-error",
|
|
334
|
-
message: error.message,
|
|
335
|
-
retryable: false,
|
|
336
|
-
detail: {
|
|
337
|
-
name: error.name
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
return {
|
|
342
|
-
code: "unknown",
|
|
343
|
-
message: "Tool execution failed with a non-Error value.",
|
|
344
|
-
retryable: false,
|
|
345
|
-
detail: {
|
|
346
|
-
valueType: typeof error
|
|
347
|
-
}
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Create Dogpile's built-in fetch-based web search adapter.
|
|
352
|
-
*
|
|
353
|
-
* @remarks
|
|
354
|
-
* The adapter is backend-neutral: by default it sends a GET request with
|
|
355
|
-
* `q` and `limit` query parameters, then accepts either `{ results: [...] }`
|
|
356
|
-
* or a bare array of result objects from the response JSON. Callers can replace
|
|
357
|
-
* request construction or response parsing for a specific search API while
|
|
358
|
-
* keeping Dogpile's shared runtime tool contract, identity, permissions, input
|
|
359
|
-
* validation, and serializable errors.
|
|
360
|
-
*/
|
|
361
|
-
export function createWebSearchToolAdapter(options) {
|
|
362
|
-
const identity = mergeIdentity(webSearchIdentity, options.identity);
|
|
363
|
-
return normalizeBuiltInDogpileTool({
|
|
364
|
-
name: "webSearch",
|
|
365
|
-
...(options.identity ? { identity: options.identity } : {}),
|
|
366
|
-
...(options.permissions ? { permissions: options.permissions } : {}),
|
|
367
|
-
async execute(input, context) {
|
|
368
|
-
const fetchImplementation = options.fetch ?? globalThis.fetch;
|
|
369
|
-
if (!fetchImplementation) {
|
|
370
|
-
return {
|
|
371
|
-
type: "error",
|
|
372
|
-
toolCallId: context.toolCallId,
|
|
373
|
-
tool: identity,
|
|
374
|
-
error: {
|
|
375
|
-
code: "unavailable",
|
|
376
|
-
message: "No fetch implementation is available for webSearch.",
|
|
377
|
-
retryable: false
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
const request = options.buildRequest
|
|
382
|
-
? options.buildRequest(input, context)
|
|
383
|
-
: defaultWebSearchRequest(options, input, context);
|
|
384
|
-
const response = await fetchImplementation(request.url, {
|
|
385
|
-
...request.init,
|
|
386
|
-
...(context.abortSignal ? { signal: context.abortSignal } : {})
|
|
387
|
-
});
|
|
388
|
-
if (!response.ok) {
|
|
389
|
-
throw {
|
|
390
|
-
code: response.status >= 500 ? "unavailable" : "backend-error",
|
|
391
|
-
message: `Web search backend returned HTTP ${response.status}.`,
|
|
392
|
-
retryable: response.status === 408 || response.status === 429 || response.status >= 500,
|
|
393
|
-
detail: {
|
|
394
|
-
status: response.status,
|
|
395
|
-
statusText: response.statusText
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
const output = options.parseResponse
|
|
400
|
-
? await options.parseResponse(response, input, context)
|
|
401
|
-
: await defaultWebSearchResponseParser(response);
|
|
402
|
-
return {
|
|
403
|
-
type: "success",
|
|
404
|
-
toolCallId: context.toolCallId,
|
|
405
|
-
tool: identity,
|
|
406
|
-
output
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* Create Dogpile's built-in code execution adapter around a caller-owned sandbox.
|
|
413
|
-
*
|
|
414
|
-
* @remarks
|
|
415
|
-
* Dogpile core stays runtime-portable and never evaluates code itself. This
|
|
416
|
-
* adapter supplies the stable `codeExec` identity, schema, permissions,
|
|
417
|
-
* validation, timeout defaults, abort handling, and serializable errors while
|
|
418
|
-
* the host application owns the sandbox boundary.
|
|
419
|
-
*/
|
|
420
|
-
export function createCodeExecToolAdapter(options) {
|
|
421
|
-
const identity = mergeIdentity(codeExecIdentity, options.identity);
|
|
422
|
-
const permissions = options.permissions ??
|
|
423
|
-
codeExecPermissionsFor(options.languages ?? codeExecLanguages, options.allowNetwork ?? false);
|
|
424
|
-
const inputSchema = codeExecInputSchemaFor(options.languages ?? codeExecLanguages);
|
|
425
|
-
return {
|
|
426
|
-
identity,
|
|
427
|
-
inputSchema,
|
|
428
|
-
permissions,
|
|
429
|
-
validateInput: (input) => validateCodeExecAdapterInput(input, options),
|
|
430
|
-
async execute(input, context) {
|
|
431
|
-
const validation = validateCodeExecAdapterInput(input, options);
|
|
432
|
-
if (validation.type === "invalid") {
|
|
433
|
-
return {
|
|
434
|
-
type: "error",
|
|
435
|
-
toolCallId: context.toolCallId,
|
|
436
|
-
tool: identity,
|
|
437
|
-
error: {
|
|
438
|
-
code: "invalid-input",
|
|
439
|
-
message: "Invalid codeExec tool input.",
|
|
440
|
-
retryable: false,
|
|
441
|
-
detail: {
|
|
442
|
-
issues: validation.issues
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
const timeoutMs = input.timeoutMs ?? options.defaultTimeoutMs;
|
|
448
|
-
const executionInput = timeoutMs === undefined
|
|
449
|
-
? input
|
|
450
|
-
: {
|
|
451
|
-
...input,
|
|
452
|
-
timeoutMs
|
|
453
|
-
};
|
|
454
|
-
try {
|
|
455
|
-
const output = await executeSandboxWithPolicy(options.execute, executionInput, context, timeoutMs);
|
|
456
|
-
return {
|
|
457
|
-
type: "success",
|
|
458
|
-
toolCallId: context.toolCallId,
|
|
459
|
-
tool: identity,
|
|
460
|
-
output
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
catch (error) {
|
|
464
|
-
return {
|
|
465
|
-
type: "error",
|
|
466
|
-
toolCallId: context.toolCallId,
|
|
467
|
-
tool: identity,
|
|
468
|
-
error: normalizeRuntimeToolAdapterError(error)
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
export function normalizeBuiltInDogpileTool(definition) {
|
|
475
|
-
switch (definition.name) {
|
|
476
|
-
case "webSearch": {
|
|
477
|
-
const identity = mergeIdentity(webSearchIdentity, definition.identity);
|
|
478
|
-
const permissions = definition.permissions ?? webSearchPermissions;
|
|
479
|
-
const tool = {
|
|
480
|
-
identity,
|
|
481
|
-
inputSchema: definition.inputSchema ?? webSearchInputSchema,
|
|
482
|
-
permissions,
|
|
483
|
-
validateInput: (input) => validateBuiltInDogpileToolInput("webSearch", input),
|
|
484
|
-
execute: (input, context) => executeBuiltInTool(identity, definition.execute, input, context, "webSearch")
|
|
485
|
-
};
|
|
486
|
-
return tool;
|
|
487
|
-
}
|
|
488
|
-
case "codeExec": {
|
|
489
|
-
const identity = mergeIdentity(codeExecIdentity, definition.identity);
|
|
490
|
-
const permissions = definition.permissions ?? codeExecPermissions;
|
|
491
|
-
const tool = {
|
|
492
|
-
identity,
|
|
493
|
-
inputSchema: definition.inputSchema ?? codeExecInputSchema,
|
|
494
|
-
permissions,
|
|
495
|
-
validateInput: (input) => validateBuiltInDogpileToolInput("codeExec", input),
|
|
496
|
-
execute: (input, context) => executeBuiltInTool(identity, definition.execute, input, context, "codeExec")
|
|
497
|
-
};
|
|
498
|
-
return tool;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
/**
|
|
503
|
-
* Normalize configured built-in Dogpile tool executors into runtime tools.
|
|
504
|
-
*/
|
|
505
|
-
export function normalizeBuiltInDogpileTools(tools) {
|
|
506
|
-
const normalized = [];
|
|
507
|
-
if (tools.webSearch) {
|
|
508
|
-
normalized.push(normalizeBuiltInDogpileTool(asWebSearchDefinition(tools.webSearch)));
|
|
509
|
-
}
|
|
510
|
-
if (tools.codeExec) {
|
|
511
|
-
normalized.push(normalizeBuiltInDogpileTool(asCodeExecDefinition(tools.codeExec)));
|
|
512
|
-
}
|
|
513
|
-
return normalized;
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Normalize one Vercel AI SDK tool into Dogpile's shared runtime tool interface.
|
|
517
|
-
*/
|
|
518
|
-
export async function normalizeVercelAITool(definition) {
|
|
519
|
-
if (!definition.tool.execute) {
|
|
520
|
-
throw new Error(`Vercel AI tool "${definition.name}" must define execute() to run inside Dogpile.`);
|
|
521
|
-
}
|
|
522
|
-
const identity = vercelAIToolIdentity(definition);
|
|
523
|
-
const inputSchema = definition.inputSchema ?? (await vercelAIInputSchema(definition.tool, definition.name));
|
|
524
|
-
const execute = definition.tool.execute;
|
|
525
|
-
return {
|
|
526
|
-
identity,
|
|
527
|
-
inputSchema,
|
|
528
|
-
async execute(input, context) {
|
|
529
|
-
try {
|
|
530
|
-
const output = await resolveVercelAIToolOutput(execute(input, {
|
|
531
|
-
toolCallId: context.toolCallId,
|
|
532
|
-
messages: Array.from(definition.messages ?? []),
|
|
533
|
-
...(context.abortSignal ? { abortSignal: context.abortSignal } : {}),
|
|
534
|
-
experimental_context: context
|
|
535
|
-
}));
|
|
536
|
-
return {
|
|
537
|
-
type: "success",
|
|
538
|
-
toolCallId: context.toolCallId,
|
|
539
|
-
tool: identity,
|
|
540
|
-
output
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
catch (error) {
|
|
544
|
-
return {
|
|
545
|
-
type: "error",
|
|
546
|
-
toolCallId: context.toolCallId,
|
|
547
|
-
tool: identity,
|
|
548
|
-
error: {
|
|
549
|
-
code: "vercel-ai-tool-error",
|
|
550
|
-
message: error instanceof Error ? error.message : "Vercel AI tool execution failed.",
|
|
551
|
-
retryable: false,
|
|
552
|
-
detail: errorDetail(error)
|
|
553
|
-
}
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Normalize a Vercel AI SDK tool set into runtime tools in caller-defined key order.
|
|
561
|
-
*/
|
|
562
|
-
export async function normalizeVercelAITools(tools, options = {}) {
|
|
563
|
-
return Promise.all(Object.entries(tools).map(([name, tool]) => {
|
|
564
|
-
const identity = removeUndefinedIdentityFields({
|
|
565
|
-
...(options.namespace !== undefined ? { namespace: options.namespace } : {}),
|
|
566
|
-
...(options.version !== undefined ? { version: options.version } : {}),
|
|
567
|
-
...options.identity?.[name]
|
|
568
|
-
});
|
|
569
|
-
return normalizeVercelAITool({
|
|
570
|
-
name,
|
|
571
|
-
tool: asJsonRuntimeVercelAITool(tool),
|
|
572
|
-
...(options.messages ? { messages: options.messages } : {}),
|
|
573
|
-
...(identity ? { identity } : {})
|
|
574
|
-
});
|
|
575
|
-
}));
|
|
576
|
-
}
|
|
577
|
-
async function executeBuiltInTool(identity, execute, input, context, name) {
|
|
578
|
-
const validation = validateBuiltInDogpileToolInput(name, input);
|
|
579
|
-
if (validation.type === "invalid") {
|
|
580
|
-
return {
|
|
581
|
-
type: "error",
|
|
582
|
-
toolCallId: context.toolCallId,
|
|
583
|
-
tool: identity,
|
|
584
|
-
error: {
|
|
585
|
-
code: "invalid-input",
|
|
586
|
-
message: `Invalid ${name} tool input.`,
|
|
587
|
-
retryable: false,
|
|
588
|
-
detail: {
|
|
589
|
-
issues: validation.issues
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
try {
|
|
595
|
-
return await execute(input, context);
|
|
596
|
-
}
|
|
597
|
-
catch (error) {
|
|
598
|
-
return {
|
|
599
|
-
type: "error",
|
|
600
|
-
toolCallId: context.toolCallId,
|
|
601
|
-
tool: identity,
|
|
602
|
-
error: normalizeRuntimeToolAdapterError(error)
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
function asWebSearchDefinition(tool) {
|
|
607
|
-
return typeof tool === "function" ? { name: "webSearch", execute: tool } : tool;
|
|
608
|
-
}
|
|
609
|
-
function asCodeExecDefinition(tool) {
|
|
610
|
-
return typeof tool === "function" ? { name: "codeExec", execute: tool } : tool;
|
|
611
|
-
}
|
|
612
|
-
function mergeIdentity(defaultIdentity, options) {
|
|
613
|
-
if (!options) {
|
|
614
|
-
return defaultIdentity;
|
|
615
|
-
}
|
|
616
|
-
return {
|
|
617
|
-
...defaultIdentity,
|
|
618
|
-
...(options.namespace !== undefined ? { namespace: options.namespace } : {}),
|
|
619
|
-
...(options.version !== undefined ? { version: options.version } : {}),
|
|
620
|
-
...(options.description !== undefined ? { description: options.description } : {})
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
async function vercelAIInputSchema(tool, name) {
|
|
624
|
-
const schema = await resolveCompatibleSchema(tool.inputSchema);
|
|
625
|
-
const jsonSchema = asJsonObject(schema, `Vercel AI tool "${name}" input schema`);
|
|
626
|
-
return {
|
|
627
|
-
kind: "json-schema",
|
|
628
|
-
schema: jsonSchema,
|
|
629
|
-
...(tool.description ? { description: tool.description } : {})
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
async function resolveCompatibleSchema(schema) {
|
|
633
|
-
if (isJsonSchemaWrapper(schema)) {
|
|
634
|
-
return await schema.jsonSchema;
|
|
635
|
-
}
|
|
636
|
-
return schema;
|
|
637
|
-
}
|
|
638
|
-
function isJsonSchemaWrapper(schema) {
|
|
639
|
-
return typeof schema === "object" && schema !== null && "jsonSchema" in schema;
|
|
640
|
-
}
|
|
641
|
-
function vercelAIToolIdentity(definition) {
|
|
642
|
-
return {
|
|
643
|
-
id: definition.identity?.id ?? `vercel-ai.tools.${definition.name}`,
|
|
644
|
-
name: definition.name,
|
|
645
|
-
namespace: definition.identity?.namespace ?? "vercel-ai",
|
|
646
|
-
...(definition.identity?.version ? { version: definition.identity.version } : {}),
|
|
647
|
-
...(definition.identity?.description ?? definition.tool.description
|
|
648
|
-
? { description: definition.identity?.description ?? definition.tool.description }
|
|
649
|
-
: {})
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
|
-
async function resolveVercelAIToolOutput(output) {
|
|
653
|
-
if (isAsyncIterable(output)) {
|
|
654
|
-
let lastOutput;
|
|
655
|
-
for await (const chunk of output) {
|
|
656
|
-
lastOutput = chunk;
|
|
657
|
-
}
|
|
658
|
-
if (lastOutput === undefined) {
|
|
659
|
-
throw new Error("Vercel AI tool async iterable completed without an output.");
|
|
660
|
-
}
|
|
661
|
-
return lastOutput;
|
|
662
|
-
}
|
|
663
|
-
return await output;
|
|
664
|
-
}
|
|
665
|
-
function isAsyncIterable(value) {
|
|
666
|
-
return typeof value === "object" && value !== null && Symbol.asyncIterator in value;
|
|
667
|
-
}
|
|
668
|
-
function asJsonObject(value, label) {
|
|
669
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
670
|
-
throw new Error(`${label} must resolve to a JSON object.`);
|
|
671
|
-
}
|
|
672
|
-
return value;
|
|
673
|
-
}
|
|
674
|
-
function errorDetail(error) {
|
|
675
|
-
if (error instanceof Error) {
|
|
676
|
-
return {
|
|
677
|
-
name: error.name
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
return {
|
|
681
|
-
valueType: typeof error
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
function defaultWebSearchRequest(options, input, _context) {
|
|
685
|
-
const url = new URL(String(options.endpoint));
|
|
686
|
-
url.searchParams.set("q", input.query);
|
|
687
|
-
url.searchParams.set("limit", String(input.maxResults ?? options.defaultMaxResults ?? 10));
|
|
688
|
-
return {
|
|
689
|
-
url,
|
|
690
|
-
init: {
|
|
691
|
-
method: "GET",
|
|
692
|
-
...(options.headers ? { headers: options.headers } : {})
|
|
693
|
-
}
|
|
694
|
-
};
|
|
695
|
-
}
|
|
696
|
-
async function defaultWebSearchResponseParser(response) {
|
|
697
|
-
const payload = await response.json();
|
|
698
|
-
const resultValues = Array.isArray(payload)
|
|
699
|
-
? payload
|
|
700
|
-
: isJsonObject(payload) && Array.isArray(payload.results)
|
|
701
|
-
? payload.results
|
|
702
|
-
: undefined;
|
|
703
|
-
if (!resultValues) {
|
|
704
|
-
throw {
|
|
705
|
-
code: "backend-error",
|
|
706
|
-
message: "Web search backend response must contain a results array.",
|
|
707
|
-
retryable: false
|
|
708
|
-
};
|
|
709
|
-
}
|
|
710
|
-
return {
|
|
711
|
-
results: resultValues.map(normalizeWebSearchResult)
|
|
712
|
-
};
|
|
713
|
-
}
|
|
714
|
-
function codeExecPermissionsFor(languages, allowNetwork) {
|
|
715
|
-
return [
|
|
716
|
-
{
|
|
717
|
-
kind: "code-execution",
|
|
718
|
-
sandbox: "caller-provided",
|
|
719
|
-
languages,
|
|
720
|
-
allowNetwork
|
|
721
|
-
}
|
|
722
|
-
];
|
|
723
|
-
}
|
|
724
|
-
function codeExecInputSchemaFor(languages) {
|
|
725
|
-
return {
|
|
726
|
-
kind: "json-schema",
|
|
727
|
-
...(codeExecInputSchema.description ? { description: codeExecInputSchema.description } : {}),
|
|
728
|
-
schema: {
|
|
729
|
-
type: "object",
|
|
730
|
-
properties: {
|
|
731
|
-
language: {
|
|
732
|
-
type: "string",
|
|
733
|
-
enum: Array.from(languages)
|
|
734
|
-
},
|
|
735
|
-
code: { type: "string" },
|
|
736
|
-
timeoutMs: { type: "number", minimum: 1 }
|
|
737
|
-
},
|
|
738
|
-
required: ["language", "code"],
|
|
739
|
-
additionalProperties: false
|
|
740
|
-
}
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
async function executeSandboxWithPolicy(execute, input, context, timeoutMs) {
|
|
744
|
-
if (context.abortSignal?.aborted) {
|
|
745
|
-
throw {
|
|
746
|
-
code: "aborted",
|
|
747
|
-
message: "Code execution was aborted before the sandbox started.",
|
|
748
|
-
retryable: true
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
const execution = Promise.resolve().then(() => execute(input, context));
|
|
752
|
-
if (timeoutMs === undefined && context.abortSignal === undefined) {
|
|
753
|
-
return await execution;
|
|
754
|
-
}
|
|
755
|
-
return await new Promise((resolve, reject) => {
|
|
756
|
-
let timeoutId;
|
|
757
|
-
const cleanup = () => {
|
|
758
|
-
if (timeoutId !== undefined) {
|
|
759
|
-
clearTimeout(timeoutId);
|
|
760
|
-
}
|
|
761
|
-
context.abortSignal?.removeEventListener("abort", abortHandler);
|
|
762
|
-
};
|
|
763
|
-
const abortHandler = () => {
|
|
764
|
-
cleanup();
|
|
765
|
-
reject({
|
|
766
|
-
code: "aborted",
|
|
767
|
-
message: "Code execution was aborted.",
|
|
768
|
-
retryable: true
|
|
769
|
-
});
|
|
770
|
-
};
|
|
771
|
-
if (context.abortSignal) {
|
|
772
|
-
context.abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
773
|
-
}
|
|
774
|
-
if (timeoutMs !== undefined) {
|
|
775
|
-
timeoutId = setTimeout(() => {
|
|
776
|
-
cleanup();
|
|
777
|
-
reject({
|
|
778
|
-
code: "timeout",
|
|
779
|
-
message: `Code execution exceeded timeout of ${timeoutMs}ms.`,
|
|
780
|
-
retryable: true,
|
|
781
|
-
detail: {
|
|
782
|
-
timeoutMs
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
}, timeoutMs);
|
|
786
|
-
}
|
|
787
|
-
execution.then((output) => {
|
|
788
|
-
cleanup();
|
|
789
|
-
resolve(output);
|
|
790
|
-
}, (error) => {
|
|
791
|
-
cleanup();
|
|
792
|
-
reject(error);
|
|
793
|
-
});
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
function normalizeWebSearchResult(value) {
|
|
797
|
-
if (!isJsonObject(value)) {
|
|
798
|
-
throw {
|
|
799
|
-
code: "backend-error",
|
|
800
|
-
message: "Web search result must be a JSON object.",
|
|
801
|
-
retryable: false
|
|
802
|
-
};
|
|
803
|
-
}
|
|
804
|
-
const title = jsonString(value.title, "title");
|
|
805
|
-
const url = jsonString(value.url, "url");
|
|
806
|
-
const snippet = optionalJsonString(value.snippet, "snippet");
|
|
807
|
-
const metadata = optionalJsonObject(value.metadata, "metadata");
|
|
808
|
-
return {
|
|
809
|
-
title,
|
|
810
|
-
url,
|
|
811
|
-
...(snippet !== undefined ? { snippet } : {}),
|
|
812
|
-
...(metadata !== undefined ? { metadata } : {})
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
function jsonString(value, fieldName) {
|
|
816
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
817
|
-
throw {
|
|
818
|
-
code: "backend-error",
|
|
819
|
-
message: `Web search result ${fieldName} must be a non-empty string.`,
|
|
820
|
-
retryable: false
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
|
-
return value;
|
|
824
|
-
}
|
|
825
|
-
function optionalJsonString(value, fieldName) {
|
|
826
|
-
if (value === undefined) {
|
|
827
|
-
return undefined;
|
|
828
|
-
}
|
|
829
|
-
if (typeof value !== "string") {
|
|
830
|
-
throw {
|
|
831
|
-
code: "backend-error",
|
|
832
|
-
message: `Web search result ${fieldName} must be a string when present.`,
|
|
833
|
-
retryable: false
|
|
834
|
-
};
|
|
835
|
-
}
|
|
836
|
-
return value;
|
|
837
|
-
}
|
|
838
|
-
function optionalJsonObject(value, fieldName) {
|
|
839
|
-
if (value === undefined) {
|
|
840
|
-
return undefined;
|
|
841
|
-
}
|
|
842
|
-
if (!isJsonObject(value)) {
|
|
843
|
-
throw {
|
|
844
|
-
code: "backend-error",
|
|
845
|
-
message: `Web search result ${fieldName} must be a JSON object when present.`,
|
|
846
|
-
retryable: false
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
return value;
|
|
850
|
-
}
|
|
851
|
-
function isJsonObject(value) {
|
|
852
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
853
|
-
}
|
|
854
|
-
function validateWebSearchInput(input) {
|
|
855
|
-
const issues = [];
|
|
856
|
-
if (typeof input.query !== "string") {
|
|
857
|
-
issues.push({
|
|
858
|
-
code: input.query === undefined ? "missing-field" : "invalid-type",
|
|
859
|
-
path: "query",
|
|
860
|
-
message: "webSearch.query must be a string."
|
|
861
|
-
});
|
|
862
|
-
}
|
|
863
|
-
else if (input.query.trim().length === 0) {
|
|
864
|
-
issues.push({
|
|
865
|
-
code: "invalid-value",
|
|
866
|
-
path: "query",
|
|
867
|
-
message: "webSearch.query must not be empty."
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
|
-
if (input.maxResults !== undefined) {
|
|
871
|
-
if (typeof input.maxResults !== "number" || !Number.isFinite(input.maxResults)) {
|
|
872
|
-
issues.push({
|
|
873
|
-
code: "invalid-type",
|
|
874
|
-
path: "maxResults",
|
|
875
|
-
message: "webSearch.maxResults must be a finite number."
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
else if (input.maxResults < 1) {
|
|
879
|
-
issues.push({
|
|
880
|
-
code: "out-of-range",
|
|
881
|
-
path: "maxResults",
|
|
882
|
-
message: "webSearch.maxResults must be greater than or equal to 1.",
|
|
883
|
-
detail: {
|
|
884
|
-
minimum: 1
|
|
885
|
-
}
|
|
886
|
-
});
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
return issues;
|
|
890
|
-
}
|
|
891
|
-
function validateCodeExecInput(input) {
|
|
892
|
-
const issues = [];
|
|
893
|
-
if (typeof input.language !== "string") {
|
|
894
|
-
issues.push({
|
|
895
|
-
code: input.language === undefined ? "missing-field" : "invalid-type",
|
|
896
|
-
path: "language",
|
|
897
|
-
message: "codeExec.language must be a string."
|
|
898
|
-
});
|
|
899
|
-
}
|
|
900
|
-
else if (!isCodeExecLanguage(input.language)) {
|
|
901
|
-
issues.push({
|
|
902
|
-
code: "invalid-value",
|
|
903
|
-
path: "language",
|
|
904
|
-
message: "codeExec.language must be one of javascript, typescript, python, bash, or shell.",
|
|
905
|
-
detail: {
|
|
906
|
-
allowed: ["javascript", "typescript", "python", "bash", "shell"]
|
|
907
|
-
}
|
|
908
|
-
});
|
|
909
|
-
}
|
|
910
|
-
if (typeof input.code !== "string") {
|
|
911
|
-
issues.push({
|
|
912
|
-
code: input.code === undefined ? "missing-field" : "invalid-type",
|
|
913
|
-
path: "code",
|
|
914
|
-
message: "codeExec.code must be a string."
|
|
915
|
-
});
|
|
916
|
-
}
|
|
917
|
-
if (input.timeoutMs !== undefined) {
|
|
918
|
-
if (typeof input.timeoutMs !== "number" || !Number.isFinite(input.timeoutMs)) {
|
|
919
|
-
issues.push({
|
|
920
|
-
code: "invalid-type",
|
|
921
|
-
path: "timeoutMs",
|
|
922
|
-
message: "codeExec.timeoutMs must be a finite number."
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
else if (input.timeoutMs < 1) {
|
|
926
|
-
issues.push({
|
|
927
|
-
code: "out-of-range",
|
|
928
|
-
path: "timeoutMs",
|
|
929
|
-
message: "codeExec.timeoutMs must be greater than or equal to 1.",
|
|
930
|
-
detail: {
|
|
931
|
-
minimum: 1
|
|
932
|
-
}
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
return issues;
|
|
937
|
-
}
|
|
938
|
-
function isCodeExecLanguage(value) {
|
|
939
|
-
return value === "javascript" || value === "typescript" || value === "python" || value === "bash" || value === "shell";
|
|
940
|
-
}
|
|
941
|
-
function isRuntimeToolAdapterError(error) {
|
|
942
|
-
if (typeof error !== "object" || error === null || !("code" in error) || !("message" in error)) {
|
|
943
|
-
return false;
|
|
944
|
-
}
|
|
945
|
-
const candidate = error;
|
|
946
|
-
return isRuntimeToolAdapterErrorCode(candidate.code) && typeof candidate.message === "string";
|
|
947
|
-
}
|
|
948
|
-
function isRuntimeToolAdapterErrorCode(value) {
|
|
949
|
-
return (value === "invalid-input" ||
|
|
950
|
-
value === "permission-denied" ||
|
|
951
|
-
value === "timeout" ||
|
|
952
|
-
value === "aborted" ||
|
|
953
|
-
value === "unavailable" ||
|
|
954
|
-
value === "backend-error" ||
|
|
955
|
-
value === "unknown");
|
|
956
|
-
}
|
|
957
|
-
function removeUndefinedIdentityFields(identity) {
|
|
958
|
-
const normalized = {
|
|
959
|
-
...(identity.id !== undefined ? { id: identity.id } : {}),
|
|
960
|
-
...(identity.namespace !== undefined ? { namespace: identity.namespace } : {}),
|
|
961
|
-
...(identity.version !== undefined ? { version: identity.version } : {}),
|
|
962
|
-
...(identity.description !== undefined ? { description: identity.description } : {})
|
|
963
|
-
};
|
|
964
|
-
return Object.keys(normalized).length > 0 ? normalized : undefined;
|
|
965
|
-
}
|
|
966
|
-
function asJsonRuntimeVercelAITool(tool) {
|
|
967
|
-
return tool;
|
|
968
|
-
}
|
|
969
206
|
//# sourceMappingURL=tools.js.map
|