15
15
*/
16
16
17
17
import {
18
- action ,
19
18
assertUnstable ,
20
19
defineAction ,
20
+ detachedAction ,
21
+ isAction ,
22
+ isDetachedAction ,
21
23
stripUndefinedProps ,
22
24
z ,
23
25
type Action ,
24
26
type ActionContext ,
25
27
type ActionRunOptions ,
28
+ type DetachedAction ,
26
29
type JSONSchema7 ,
27
30
} from '@genkit-ai/core' ;
28
- import type { HasRegistry , Registry } from '@genkit-ai/core/registry' ;
31
+ import type { Registry } from '@genkit-ai/core/registry' ;
29
32
import { parseSchema , toJsonSchema } from '@genkit-ai/core/schema' ;
30
33
import { setCustomMetadataAttributes } from '@genkit-ai/core/tracing' ;
31
34
import type {
@@ -34,20 +37,12 @@ import type {
34
37
ToolRequestPart ,
35
38
ToolResponsePart ,
36
39
} from './model.js' ;
37
- import type { ExecutablePrompt } from './prompt.js' ;
40
+ import { isExecutablePrompt , type ExecutablePrompt } from './prompt.js' ;
38
41
39
- /**
40
- * An action with a `tool` type.
41
- */
42
- export type ToolAction <
42
+ export interface Resumable <
43
43
I extends z . ZodTypeAny = z . ZodTypeAny ,
44
44
O extends z . ZodTypeAny = z . ZodTypeAny ,
45
- > = Action < I , O , z . ZodTypeAny , ToolRunOptions > & {
46
- __action : {
47
- metadata : {
48
- type : 'tool' ;
49
- } ;
50
- } ;
45
+ > {
51
46
/**
52
47
* respond constructs a tool response corresponding to the provided interrupt tool request
53
48
* using the provided reply data, validating it against the output schema of the tool if
@@ -90,7 +85,37 @@ export type ToolAction<
90
85
replaceInput ?: z . infer < I > ;
91
86
}
92
87
) : ToolRequestPart ;
93
- } ;
88
+ }
89
+
90
+ /**
91
+ * An action with a `tool` type.
92
+ */
93
+ export type ToolAction <
94
+ I extends z . ZodTypeAny = z . ZodTypeAny ,
95
+ O extends z . ZodTypeAny = z . ZodTypeAny ,
96
+ > = Action < I , O , z . ZodTypeAny , ToolRunOptions > &
97
+ Resumable < I , O > & {
98
+ __action : {
99
+ metadata : {
100
+ type : 'tool' ;
101
+ } ;
102
+ } ;
103
+ } ;
104
+
105
+ /**
106
+ * A dynamic action with a `tool` type. Dynamic tools are detached actions -- not associated with any registry.
107
+ */
108
+ export type DynamicToolAction <
109
+ I extends z . ZodTypeAny = z . ZodTypeAny ,
110
+ O extends z . ZodTypeAny = z . ZodTypeAny ,
111
+ > = DetachedAction < I , O , z . ZodTypeAny , ToolRunOptions > &
112
+ Resumable < I , O > & {
113
+ __action : {
114
+ metadata : {
115
+ type : 'tool' ;
116
+ } ;
117
+ } ;
118
+ } ;
94
119
95
120
export interface ToolRunOptions extends ActionRunOptions < z . ZodTypeAny > {
96
121
/**
@@ -128,7 +153,12 @@ export interface ToolConfig<I extends z.ZodTypeAny, O extends z.ZodTypeAny> {
128
153
export type ToolArgument <
129
154
I extends z . ZodTypeAny = z . ZodTypeAny ,
130
155
O extends z . ZodTypeAny = z . ZodTypeAny ,
131
- > = string | ToolAction < I , O > | Action < I , O > | ExecutablePrompt < any , any , any > ;
156
+ > =
157
+ | string
158
+ | ToolAction < I , O >
159
+ | DynamicToolAction < I , O >
160
+ | Action < I , O >
161
+ | ExecutablePrompt < any , any , any > ;
132
162
133
163
/**
134
164
* Converts an action to a tool action by setting the appropriate metadata.
@@ -170,14 +200,15 @@ export async function resolveTools<
170
200
tools . map ( async ( ref ) : Promise < ToolAction > => {
171
201
if ( typeof ref === 'string' ) {
172
202
return await lookupToolByName ( registry , ref ) ;
173
- } else if ( ( ref as Action ) . __action ) {
174
- return asTool ( registry , ref as Action ) ;
175
- } else if ( typeof ( ref as ExecutablePrompt ) . asTool === 'function' ) {
176
- return await ( ref as ExecutablePrompt ) . asTool ( ) ;
177
- } else if ( ref . name ) {
203
+ } else if ( isAction ( ref ) ) {
204
+ return asTool ( registry , ref ) ;
205
+ } else if ( isExecutablePrompt ( ref ) ) {
206
+ return await ref . asTool ( ) ;
207
+ } else if ( ( ref as ToolDefinition ) . name ) {
178
208
return await lookupToolByName (
179
209
registry ,
180
- ( ref as ToolDefinition ) . metadata ?. originalName || ref . name
210
+ ( ref as ToolDefinition ) . metadata ?. originalName ||
211
+ ( ref as ToolDefinition ) . name
181
212
) ;
182
213
}
183
214
throw new Error ( 'Tools must be strings, tool definitions, or actions.' ) ;
@@ -278,14 +309,16 @@ export function defineTool<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(
278
309
function implementTool < I extends z . ZodTypeAny , O extends z . ZodTypeAny > (
279
310
a : ToolAction < I , O > ,
280
311
config : ToolConfig < I , O > ,
281
- registry : Registry
312
+ registry ? : Registry
282
313
) {
283
314
( a as ToolAction < I , O > ) . respond = ( interrupt , responseData , options ) => {
284
- assertUnstable (
285
- registry ,
286
- 'beta' ,
287
- "The 'tool.reply' method is part of the 'interrupts' beta feature."
288
- ) ;
315
+ if ( registry ) {
316
+ assertUnstable (
317
+ registry ,
318
+ 'beta' ,
319
+ "The 'tool.reply' method is part of the 'interrupts' beta feature."
320
+ ) ;
321
+ }
289
322
parseSchema ( responseData , {
290
323
jsonSchema : config . outputJsonSchema ,
291
324
schema : config . outputSchema ,
@@ -303,11 +336,13 @@ function implementTool<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(
303
336
} ;
304
337
305
338
( a as ToolAction < I , O > ) . restart = ( interrupt , resumedMetadata , options ) => {
306
- assertUnstable (
307
- registry ,
308
- 'beta' ,
309
- "The 'tool.restart' method is part of the 'interrupts' beta feature."
310
- ) ;
339
+ if ( registry ) {
340
+ assertUnstable (
341
+ registry ,
342
+ 'beta' ,
343
+ "The 'tool.restart' method is part of the 'interrupts' beta feature."
344
+ ) ;
345
+ }
311
346
let replaceInput = options ?. replaceInput ;
312
347
if ( replaceInput ) {
313
348
replaceInput = parseSchema ( replaceInput , {
@@ -352,6 +387,14 @@ export function isToolResponse(part: Part): part is ToolResponsePart {
352
387
return ! ! part . toolResponse ;
353
388
}
354
389
390
+ export function isDynamicTool ( t : unknown ) : t is DynamicToolAction {
391
+ return (
392
+ ( isDetachedAction ( t ) || isAction ( t ) ) &&
393
+ t . __action . metadata ?. type === 'tool' &&
394
+ t . __action . metadata ?. dynamic
395
+ ) ;
396
+ }
397
+
355
398
export function defineInterrupt < I extends z . ZodTypeAny , O extends z . ZodTypeAny > (
356
399
registry : Registry ,
357
400
config : InterruptConfig < I , O >
@@ -396,19 +439,17 @@ function interruptTool(registry: Registry) {
396
439
* Genkit registry and can be defined dynamically at runtime.
397
440
*/
398
441
export function dynamicTool < I extends z . ZodTypeAny , O extends z . ZodTypeAny > (
399
- ai : HasRegistry ,
400
442
config : ToolConfig < I , O > ,
401
443
fn ?: ToolFn < I , O >
402
- ) : ToolAction < I , O > {
403
- const a = action (
404
- ai . registry ,
444
+ ) : DynamicToolAction < I , O > {
445
+ const a = detachedAction (
405
446
{
406
447
...config ,
407
448
actionType : 'tool' ,
408
449
metadata : { ...( config . metadata || { } ) , type : 'tool' , dynamic : true } ,
409
450
} ,
410
451
( i , runOptions ) => {
411
- const interrupt = interruptTool ( ai . registry ) ;
452
+ const interrupt = interruptTool ( runOptions . registry ) ;
412
453
if ( fn ) {
413
454
return fn ( i , {
414
455
...runOptions ,
@@ -419,6 +460,19 @@ export function dynamicTool<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(
419
460
return interrupt ( ) ;
420
461
}
421
462
) ;
422
- implementTool ( a as ToolAction < I , O > , config , ai . registry ) ;
423
- return a as ToolAction < I , O > ;
463
+ implementTool ( a as any , config ) ;
464
+ return {
465
+ __action : {
466
+ ...a . __action ,
467
+ metadata : {
468
+ ...a . __action . metadata ,
469
+ type : 'tool' ,
470
+ } ,
471
+ } ,
472
+ attach ( registry ) {
473
+ const bound = a . attach ( registry ) ;
474
+ implementTool ( bound as ToolAction < I , O > , config ) ;
475
+ return bound ;
476
+ } ,
477
+ } as DynamicToolAction < I , O > ;
424
478
}
0 commit comments