@ai-sdk/workflow 2.0.20 → 2.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/CHANGELOG.md +19 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.js +480 -106
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/do-stream-step.ts +165 -12
- package/src/resolve-tool-context.ts +28 -0
- package/src/serializable-schema.ts +99 -30
- package/src/stream-text-iterator.ts +273 -51
- package/src/workflow-agent.ts +153 -78
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/workflow",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "WorkflowAgent for building AI agents with AI SDK",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@ai-sdk/provider": "4.0.10",
|
|
35
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
36
|
-
"ai": "7.0.
|
|
35
|
+
"@ai-sdk/provider-utils": "5.0.36",
|
|
36
|
+
"ai": "7.0.91",
|
|
37
37
|
"ajv": "^8.20.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
package/src/do-stream-step.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
JSONObject,
|
|
2
3
|
LanguageModelV4CallOptions,
|
|
3
4
|
LanguageModelV4Prompt,
|
|
5
|
+
LanguageModelV4Source,
|
|
6
|
+
SharedV4ProviderMetadata,
|
|
4
7
|
} from '@ai-sdk/provider';
|
|
5
8
|
import { isAbortError } from '@ai-sdk/provider-utils';
|
|
6
9
|
import {
|
|
@@ -78,7 +81,9 @@ export interface ParsedToolCall {
|
|
|
78
81
|
toolName: string;
|
|
79
82
|
input: unknown;
|
|
80
83
|
providerExecuted?: boolean;
|
|
81
|
-
providerMetadata?:
|
|
84
|
+
providerMetadata?: SharedV4ProviderMetadata;
|
|
85
|
+
title?: string;
|
|
86
|
+
toolMetadata?: JSONObject;
|
|
82
87
|
dynamic?: boolean;
|
|
83
88
|
invalid?: boolean;
|
|
84
89
|
error?: unknown;
|
|
@@ -94,18 +99,46 @@ export interface StreamFinish {
|
|
|
94
99
|
providerMetadata?: Record<string, unknown>;
|
|
95
100
|
}
|
|
96
101
|
|
|
102
|
+
export type DoStreamStepRawContentPart =
|
|
103
|
+
| {
|
|
104
|
+
type: 'text';
|
|
105
|
+
text: string;
|
|
106
|
+
providerMetadata?: SharedV4ProviderMetadata;
|
|
107
|
+
}
|
|
108
|
+
| {
|
|
109
|
+
type: 'file';
|
|
110
|
+
data: string;
|
|
111
|
+
mediaType: string;
|
|
112
|
+
providerMetadata?: SharedV4ProviderMetadata;
|
|
113
|
+
}
|
|
114
|
+
| LanguageModelV4Source
|
|
115
|
+
| {
|
|
116
|
+
type: 'tool-call';
|
|
117
|
+
toolCallIndex: number;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Compact callback replay data. The start event establishes the tool name for
|
|
122
|
+
* a call, so delta events do not repeat it and available events reuse the
|
|
123
|
+
* parsed input already present in `toolCalls`.
|
|
124
|
+
*/
|
|
125
|
+
export type ToolInputLifecycleEvent =
|
|
126
|
+
| ['start', toolCallId: string, toolName: string]
|
|
127
|
+
| ['delta', toolCallId: string, inputTextDelta: string]
|
|
128
|
+
| ['available', toolCallId: string];
|
|
129
|
+
|
|
97
130
|
/**
|
|
98
131
|
* Minimal aggregates needed to reconstruct a `StepResult` outside the step
|
|
99
132
|
* boundary. By returning only these fields (instead of a fully-populated
|
|
100
133
|
* StepResult plus the raw `chunks[]` array), the durable event log doesn't
|
|
101
|
-
* carry StepResult's redundant
|
|
102
|
-
* `
|
|
103
|
-
*
|
|
104
|
-
* never reads. The caller reconstructs the full StepResult via
|
|
134
|
+
* carry StepResult's redundant derived fields — duplicate tool-call lists,
|
|
135
|
+
* `text`, `files`, `sources`, `reasoningText`, or the tool-result arrays
|
|
136
|
+
* populated after execution. It also avoids the per-chunk `chunks[]` snapshot
|
|
137
|
+
* the iterator never reads. The caller reconstructs the full StepResult via
|
|
105
138
|
* `buildStepResult`.
|
|
106
139
|
*/
|
|
107
140
|
export interface DoStreamStepRawResult {
|
|
108
|
-
|
|
141
|
+
content: DoStreamStepRawContentPart[];
|
|
109
142
|
reasoning: Array<{ text: string }>;
|
|
110
143
|
responseMetadata?: { id?: string; timestamp?: Date; modelId?: string };
|
|
111
144
|
warnings?: unknown[];
|
|
@@ -119,6 +152,11 @@ export type DoStreamStepResult =
|
|
|
119
152
|
finish: StreamFinish | undefined;
|
|
120
153
|
raw: DoStreamStepRawResult;
|
|
121
154
|
providerExecutedToolResults: Map<string, ProviderExecutedToolResult>;
|
|
155
|
+
/**
|
|
156
|
+
* Optional for compatibility with model-step results persisted before
|
|
157
|
+
* tool input lifecycle callback replay was added.
|
|
158
|
+
*/
|
|
159
|
+
toolInputLifecycleEvents?: ToolInputLifecycleEvent[];
|
|
122
160
|
/** Present when the model stream emitted an error part. */
|
|
123
161
|
terminalError?: unknown;
|
|
124
162
|
};
|
|
@@ -158,6 +196,7 @@ export async function doStreamStep(
|
|
|
158
196
|
// Reconstruct tools from serializable definitions with Ajv validation.
|
|
159
197
|
// Tools are serialized before crossing the step boundary because zod schemas
|
|
160
198
|
// contain functions that can't be serialized by the workflow runtime.
|
|
199
|
+
const toolInputLifecycleEvents: ToolInputLifecycleEvent[] = [];
|
|
161
200
|
const tools = serializedTools
|
|
162
201
|
? resolveSerializableTools(serializedTools)
|
|
163
202
|
: undefined;
|
|
@@ -244,7 +283,8 @@ export async function doStreamStep(
|
|
|
244
283
|
let finish: StreamFinish | undefined;
|
|
245
284
|
|
|
246
285
|
// Minimal aggregation — only what buildStepResult needs outside the step.
|
|
247
|
-
|
|
286
|
+
const content: DoStreamStepRawContentPart[] = [];
|
|
287
|
+
const textPartIndexes = new Map<string, number>();
|
|
248
288
|
const reasoningParts: Array<{ text: string }> = [];
|
|
249
289
|
let responseMetadata:
|
|
250
290
|
| { id?: string; timestamp?: Date; modelId?: string }
|
|
@@ -252,6 +292,7 @@ export async function doStreamStep(
|
|
|
252
292
|
let warnings: unknown[] | undefined;
|
|
253
293
|
let terminalError: unknown;
|
|
254
294
|
let hasTerminalError = false;
|
|
295
|
+
const ongoingToolCallToolNames = new Map<string, string>();
|
|
255
296
|
|
|
256
297
|
// Acquire writer once before the loop to avoid per-chunk lock overhead
|
|
257
298
|
const writer = writable?.getWriter();
|
|
@@ -264,28 +305,99 @@ export async function doStreamStep(
|
|
|
264
305
|
|
|
265
306
|
for await (const part of modelStream) {
|
|
266
307
|
switch (part.type) {
|
|
308
|
+
case 'tool-input-start':
|
|
309
|
+
ongoingToolCallToolNames.set(part.id, part.toolName);
|
|
310
|
+
if (
|
|
311
|
+
serializedTools?.[part.toolName]?.hasOnInputStart ||
|
|
312
|
+
serializedTools?.[part.toolName]?.hasOnInputDelta ||
|
|
313
|
+
serializedTools?.[part.toolName]?.hasOnInputAvailable
|
|
314
|
+
) {
|
|
315
|
+
toolInputLifecycleEvents.push(['start', part.id, part.toolName]);
|
|
316
|
+
}
|
|
317
|
+
break;
|
|
318
|
+
case 'tool-input-delta': {
|
|
319
|
+
const toolName = ongoingToolCallToolNames.get(part.id);
|
|
320
|
+
if (
|
|
321
|
+
toolName != null &&
|
|
322
|
+
serializedTools?.[toolName]?.hasOnInputDelta
|
|
323
|
+
) {
|
|
324
|
+
toolInputLifecycleEvents.push(['delta', part.id, part.delta]);
|
|
325
|
+
}
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
case 'text-start':
|
|
329
|
+
upsertTextContentPart({
|
|
330
|
+
content,
|
|
331
|
+
textPartIndexes,
|
|
332
|
+
id: part.id,
|
|
333
|
+
providerMetadata: part.providerMetadata,
|
|
334
|
+
});
|
|
335
|
+
break;
|
|
267
336
|
case 'text-delta':
|
|
268
|
-
|
|
337
|
+
upsertTextContentPart({
|
|
338
|
+
content,
|
|
339
|
+
textPartIndexes,
|
|
340
|
+
id: part.id,
|
|
341
|
+
textDelta: part.text,
|
|
342
|
+
providerMetadata: part.providerMetadata,
|
|
343
|
+
});
|
|
344
|
+
break;
|
|
345
|
+
case 'text-end':
|
|
346
|
+
upsertTextContentPart({
|
|
347
|
+
content,
|
|
348
|
+
textPartIndexes,
|
|
349
|
+
id: part.id,
|
|
350
|
+
providerMetadata: part.providerMetadata,
|
|
351
|
+
});
|
|
352
|
+
textPartIndexes.delete(part.id);
|
|
269
353
|
break;
|
|
270
354
|
case 'reasoning-delta':
|
|
271
355
|
reasoningParts.push({ text: part.text });
|
|
272
356
|
break;
|
|
357
|
+
case 'file':
|
|
358
|
+
content.push({
|
|
359
|
+
type: 'file',
|
|
360
|
+
data: part.file.base64,
|
|
361
|
+
mediaType: part.file.mediaType,
|
|
362
|
+
...(part.providerMetadata != null
|
|
363
|
+
? { providerMetadata: part.providerMetadata }
|
|
364
|
+
: {}),
|
|
365
|
+
});
|
|
366
|
+
break;
|
|
367
|
+
case 'source':
|
|
368
|
+
content.push(part);
|
|
369
|
+
break;
|
|
273
370
|
case 'tool-call': {
|
|
274
371
|
// parseToolCall adds dynamic/invalid/error at runtime
|
|
275
372
|
const toolCallPart = part as typeof part & Partial<ParsedToolCall>;
|
|
373
|
+
const toolCallIndex = toolCalls.length;
|
|
374
|
+
const lifecycleToolName = ongoingToolCallToolNames.get(
|
|
375
|
+
toolCallPart.toolCallId,
|
|
376
|
+
);
|
|
377
|
+
ongoingToolCallToolNames.delete(toolCallPart.toolCallId);
|
|
378
|
+
if (
|
|
379
|
+
lifecycleToolName != null &&
|
|
380
|
+
serializedTools?.[lifecycleToolName]?.hasOnInputAvailable
|
|
381
|
+
) {
|
|
382
|
+
toolInputLifecycleEvents.push([
|
|
383
|
+
'available',
|
|
384
|
+
toolCallPart.toolCallId,
|
|
385
|
+
]);
|
|
386
|
+
}
|
|
276
387
|
toolCalls.push({
|
|
277
388
|
type: 'tool-call',
|
|
278
389
|
toolCallId: toolCallPart.toolCallId,
|
|
279
390
|
toolName: toolCallPart.toolName,
|
|
280
391
|
input: toolCallPart.input,
|
|
281
392
|
providerExecuted: toolCallPart.providerExecuted,
|
|
282
|
-
providerMetadata: toolCallPart.providerMetadata
|
|
283
|
-
|
|
284
|
-
|
|
393
|
+
providerMetadata: toolCallPart.providerMetadata,
|
|
394
|
+
title: toolCallPart.title,
|
|
395
|
+
toolMetadata: toolCallPart.toolMetadata,
|
|
285
396
|
dynamic: toolCallPart.dynamic,
|
|
286
397
|
invalid: toolCallPart.invalid,
|
|
287
398
|
error: toolCallPart.error,
|
|
288
399
|
});
|
|
400
|
+
content.push({ type: 'tool-call', toolCallIndex });
|
|
289
401
|
break;
|
|
290
402
|
}
|
|
291
403
|
case 'tool-result':
|
|
@@ -374,12 +486,13 @@ export async function doStreamStep(
|
|
|
374
486
|
toolCalls,
|
|
375
487
|
finish,
|
|
376
488
|
raw: {
|
|
377
|
-
|
|
489
|
+
content,
|
|
378
490
|
reasoning: reasoningParts,
|
|
379
491
|
responseMetadata,
|
|
380
492
|
warnings,
|
|
381
493
|
},
|
|
382
494
|
providerExecutedToolResults,
|
|
495
|
+
toolInputLifecycleEvents,
|
|
383
496
|
...(hasTerminalError ? { terminalError } : {}),
|
|
384
497
|
};
|
|
385
498
|
}
|
|
@@ -387,3 +500,43 @@ export async function doStreamStep(
|
|
|
387
500
|
// Model-call retries are handled above so the workflow runtime must not add
|
|
388
501
|
// another retry layer around the durable step.
|
|
389
502
|
doStreamStep.maxRetries = 0;
|
|
503
|
+
|
|
504
|
+
function upsertTextContentPart({
|
|
505
|
+
content,
|
|
506
|
+
textPartIndexes,
|
|
507
|
+
id,
|
|
508
|
+
textDelta,
|
|
509
|
+
providerMetadata,
|
|
510
|
+
}: {
|
|
511
|
+
content: DoStreamStepRawContentPart[];
|
|
512
|
+
textPartIndexes: Map<string, number>;
|
|
513
|
+
id: string;
|
|
514
|
+
textDelta?: string;
|
|
515
|
+
providerMetadata?: SharedV4ProviderMetadata;
|
|
516
|
+
}) {
|
|
517
|
+
let partIndex = textPartIndexes.get(id);
|
|
518
|
+
|
|
519
|
+
if (partIndex == null) {
|
|
520
|
+
partIndex =
|
|
521
|
+
content.push({
|
|
522
|
+
type: 'text',
|
|
523
|
+
text: '',
|
|
524
|
+
...(providerMetadata != null ? { providerMetadata } : {}),
|
|
525
|
+
}) - 1;
|
|
526
|
+
textPartIndexes.set(id, partIndex);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const part = content[partIndex];
|
|
530
|
+
|
|
531
|
+
if (part.type !== 'text') {
|
|
532
|
+
throw new Error(`Expected text content at index ${partIndex}.`);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (textDelta != null) {
|
|
536
|
+
part.text += textDelta;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (providerMetadata != null) {
|
|
540
|
+
part.providerMetadata = providerMetadata;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { validateTypes, type Context, type Tool } from '@ai-sdk/provider-utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the per-tool context passed to tool callbacks and execution.
|
|
5
|
+
* Context schemas validate and normalize the value before any tool-owned
|
|
6
|
+
* callback observes it.
|
|
7
|
+
*/
|
|
8
|
+
export async function resolveToolContext({
|
|
9
|
+
toolName,
|
|
10
|
+
tool,
|
|
11
|
+
toolsContext,
|
|
12
|
+
}: {
|
|
13
|
+
toolName: string;
|
|
14
|
+
tool: Tool;
|
|
15
|
+
toolsContext: Record<string, Context | undefined> | undefined;
|
|
16
|
+
}): Promise<unknown> {
|
|
17
|
+
const contextSchema = tool.contextSchema;
|
|
18
|
+
const entry = toolsContext?.[toolName];
|
|
19
|
+
if (contextSchema == null) {
|
|
20
|
+
return entry;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return await validateTypes({
|
|
24
|
+
value: entry,
|
|
25
|
+
schema: contextSchema,
|
|
26
|
+
context: { field: 'tool context', entityName: toolName },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* `~standard.jsonSchema` (Standard Schema v2), extraction can be simplified
|
|
11
11
|
* to use that interface directly.
|
|
12
12
|
*/
|
|
13
|
-
import type { JSONSchema7 } from '@ai-sdk/provider';
|
|
13
|
+
import type { JSONObject, JSONSchema7 } from '@ai-sdk/provider';
|
|
14
14
|
import {
|
|
15
15
|
asSchema,
|
|
16
16
|
type Experimental_SandboxSession as SandboxSession,
|
|
@@ -18,23 +18,33 @@ import {
|
|
|
18
18
|
jsonSchema,
|
|
19
19
|
type Tool,
|
|
20
20
|
} from '@ai-sdk/provider-utils';
|
|
21
|
-
import { tool, type ToolSet } from 'ai';
|
|
21
|
+
import { dynamicTool, tool, type ToolSet } from 'ai';
|
|
22
22
|
import Ajv from 'ajv';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Serializable tool definition — plain objects only, safe for workflow steps.
|
|
26
26
|
*/
|
|
27
27
|
export type SerializableToolDef = {
|
|
28
|
+
title?: string;
|
|
29
|
+
metadata?: JSONObject;
|
|
28
30
|
description?: string;
|
|
29
31
|
inputSchema: JSONSchema7;
|
|
32
|
+
/** Whether providers should enforce strict tool input generation. */
|
|
33
|
+
strict?: boolean;
|
|
30
34
|
/** Input examples forwarded to providers that support them. */
|
|
31
35
|
inputExamples?: Array<{ input: unknown }>;
|
|
32
36
|
/** Provider-specific options attached to the tool definition. */
|
|
33
37
|
providerOptions?: Tool['providerOptions'];
|
|
34
|
-
/**
|
|
35
|
-
|
|
38
|
+
/** Input lifecycle callbacks that must be invoked outside the step. */
|
|
39
|
+
hasOnInputStart?: boolean;
|
|
40
|
+
hasOnInputDelta?: boolean;
|
|
41
|
+
hasOnInputAvailable?: boolean;
|
|
42
|
+
/** Present on dynamic and provider tools. */
|
|
43
|
+
type?: 'dynamic' | 'provider';
|
|
36
44
|
/** Provider tool is executed by the provider. */
|
|
37
45
|
isProviderExecuted?: boolean;
|
|
46
|
+
/** Provider tool results may arrive in a later model response. */
|
|
47
|
+
supportsDeferredResults?: boolean;
|
|
38
48
|
/** Provider tool ID, e.g. 'anthropic.web_search_20250305'. */
|
|
39
49
|
id?: `${string}.${string}`;
|
|
40
50
|
/** Provider tool configuration args (maxUses, allowedDomains, etc.). */
|
|
@@ -59,6 +69,8 @@ export function serializeToolSet<TOOLS extends ToolSet>(
|
|
|
59
69
|
return Object.fromEntries(
|
|
60
70
|
Object.entries(tools).map(([name, t]) => {
|
|
61
71
|
const def: SerializableToolDef = {
|
|
72
|
+
title: t.title,
|
|
73
|
+
metadata: t.metadata,
|
|
62
74
|
description: resolveToolDescription({
|
|
63
75
|
tool: t,
|
|
64
76
|
toolName: name,
|
|
@@ -66,17 +78,32 @@ export function serializeToolSet<TOOLS extends ToolSet>(
|
|
|
66
78
|
experimental_sandbox: sandbox,
|
|
67
79
|
}),
|
|
68
80
|
inputSchema: asSchema(t.inputSchema).jsonSchema as JSONSchema7,
|
|
81
|
+
strict: t.strict,
|
|
69
82
|
inputExamples: t.inputExamples,
|
|
70
83
|
providerOptions: t.providerOptions,
|
|
71
84
|
};
|
|
72
85
|
|
|
86
|
+
if (t.type === 'dynamic') {
|
|
87
|
+
def.type = 'dynamic';
|
|
88
|
+
}
|
|
89
|
+
if (t.onInputStart != null) {
|
|
90
|
+
def.hasOnInputStart = true;
|
|
91
|
+
}
|
|
92
|
+
if (t.onInputDelta != null) {
|
|
93
|
+
def.hasOnInputDelta = true;
|
|
94
|
+
}
|
|
95
|
+
if (t.onInputAvailable != null) {
|
|
96
|
+
def.hasOnInputAvailable = true;
|
|
97
|
+
}
|
|
98
|
+
|
|
73
99
|
// Preserve provider tool identity so the Gateway can recognize
|
|
74
100
|
// them as provider-executed tools (e.g. anthropic webSearch).
|
|
75
|
-
if (
|
|
101
|
+
if (t.type === 'provider') {
|
|
76
102
|
def.type = 'provider';
|
|
77
|
-
def.isProviderExecuted =
|
|
78
|
-
def.
|
|
79
|
-
def.
|
|
103
|
+
def.isProviderExecuted = t.isProviderExecuted ?? false;
|
|
104
|
+
def.supportsDeferredResults = t.supportsDeferredResults;
|
|
105
|
+
def.id = t.id;
|
|
106
|
+
def.args = t.args;
|
|
80
107
|
}
|
|
81
108
|
|
|
82
109
|
return [name, def];
|
|
@@ -122,39 +149,81 @@ export function resolveSerializableTools(
|
|
|
122
149
|
// Provider tools are executed server-side — pass them through
|
|
123
150
|
// with their identity intact, no client-side validation needed.
|
|
124
151
|
if (t.type === 'provider') {
|
|
152
|
+
const providerTool = {
|
|
153
|
+
type: 'provider' as const,
|
|
154
|
+
title: t.title,
|
|
155
|
+
metadata: t.metadata,
|
|
156
|
+
id: t.id!,
|
|
157
|
+
args: t.args ?? {},
|
|
158
|
+
inputSchema: jsonSchema(t.inputSchema),
|
|
159
|
+
providerOptions: t.providerOptions,
|
|
160
|
+
};
|
|
161
|
+
|
|
125
162
|
return [
|
|
126
163
|
name,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
164
|
+
t.isProviderExecuted
|
|
165
|
+
? tool({
|
|
166
|
+
...providerTool,
|
|
167
|
+
isProviderExecuted: true,
|
|
168
|
+
supportsDeferredResults: t.supportsDeferredResults,
|
|
169
|
+
})
|
|
170
|
+
: tool({
|
|
171
|
+
...providerTool,
|
|
172
|
+
isProviderExecuted: false,
|
|
173
|
+
}),
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (t.type === 'dynamic') {
|
|
178
|
+
const validateFn = ajv.compile(t.inputSchema);
|
|
179
|
+
|
|
180
|
+
return [
|
|
181
|
+
name,
|
|
182
|
+
dynamicTool({
|
|
183
|
+
description: t.description,
|
|
184
|
+
inputExamples: t.inputExamples,
|
|
133
185
|
providerOptions: t.providerOptions,
|
|
186
|
+
inputSchema: jsonSchema(t.inputSchema, {
|
|
187
|
+
validate: value => {
|
|
188
|
+
if (validateFn(value)) {
|
|
189
|
+
return { success: true, value };
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
success: false,
|
|
193
|
+
error: new Error(ajv.errorsText(validateFn.errors)),
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
}),
|
|
134
197
|
}),
|
|
135
198
|
];
|
|
136
199
|
}
|
|
137
200
|
|
|
138
201
|
const validateFn = ajv.compile(t.inputSchema);
|
|
202
|
+
const functionTool = {
|
|
203
|
+
title: t.title,
|
|
204
|
+
metadata: t.metadata,
|
|
205
|
+
description: t.description,
|
|
206
|
+
strict: t.strict,
|
|
207
|
+
inputExamples: t.inputExamples,
|
|
208
|
+
providerOptions: t.providerOptions,
|
|
209
|
+
inputSchema: jsonSchema(t.inputSchema, {
|
|
210
|
+
validate: value => {
|
|
211
|
+
if (validateFn(value)) {
|
|
212
|
+
return { success: true, value: value as any };
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
success: false,
|
|
216
|
+
error: new Error(ajv.errorsText(validateFn.errors)),
|
|
217
|
+
};
|
|
218
|
+
},
|
|
219
|
+
}),
|
|
220
|
+
};
|
|
139
221
|
|
|
140
222
|
return [
|
|
141
223
|
name,
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
providerOptions: t.providerOptions,
|
|
146
|
-
inputSchema: jsonSchema(t.inputSchema, {
|
|
147
|
-
validate: value => {
|
|
148
|
-
if (validateFn(value)) {
|
|
149
|
-
return { success: true, value: value as any };
|
|
150
|
-
}
|
|
151
|
-
return {
|
|
152
|
-
success: false,
|
|
153
|
-
error: new Error(ajv.errorsText(validateFn.errors)),
|
|
154
|
-
};
|
|
155
|
-
},
|
|
156
|
-
}),
|
|
157
|
-
}),
|
|
224
|
+
t.type === 'dynamic'
|
|
225
|
+
? tool({ ...functionTool, type: 'dynamic' })
|
|
226
|
+
: tool(functionTool),
|
|
158
227
|
];
|
|
159
228
|
}),
|
|
160
229
|
);
|