Skip to content

Commit 9ca643d

Browse files
authored
feat(js/ai/tools): added dynamic version of the interrupt (#3570)
1 parent 54ab8eb commit 9ca643d

File tree

6 files changed

+74
-14
lines changed

6 files changed

+74
-14
lines changed

js/ai/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ export {
116116
defineResource,
117117
dynamicResource,
118118
isDynamicResourceAction,
119+
resource,
119120
type DynamicResourceAction,
120121
type ResourceAction,
121122
type ResourceFn,
@@ -144,6 +145,7 @@ export {
144145
asTool,
145146
defineInterrupt,
146147
defineTool,
148+
interrupt,
147149
type InterruptConfig,
148150
type ToolAction,
149151
type ToolArgument,

js/ai/src/resource.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ export function resource(
154154
/**
155155
* Defines a dynamic resource. Dynamic resources are just like regular resources but will not be
156156
* registered in the Genkit registry and can be defined dynamically at runtime.
157+
*
158+
* @deprecated renamed to {@link resource}.
157159
*/
158160
export function dynamicResource(
159161
opts: ResourceOptions,

js/ai/src/tool.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -386,22 +386,26 @@ export function isDynamicTool(t: unknown): t is ToolAction {
386386
return isAction(t) && !t.__registry;
387387
}
388388

389-
export function defineInterrupt<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(
390-
registry: Registry,
389+
export function interrupt<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(
391390
config: InterruptConfig<I, O>
392391
): ToolAction<I, O> {
393392
const { requestMetadata, ...toolConfig } = config;
394393

395-
return defineTool<I, O>(
396-
registry,
397-
toolConfig,
398-
async (input, { interrupt }) => {
399-
if (!config.requestMetadata) interrupt();
400-
else if (typeof config.requestMetadata === 'object')
401-
interrupt(config.requestMetadata);
402-
else interrupt(await Promise.resolve(config.requestMetadata(input)));
403-
}
404-
);
394+
return tool<I, O>(toolConfig, async (input, { interrupt }) => {
395+
if (!config.requestMetadata) interrupt();
396+
else if (typeof config.requestMetadata === 'object')
397+
interrupt(config.requestMetadata);
398+
else interrupt(await Promise.resolve(config.requestMetadata(input)));
399+
});
400+
}
401+
402+
export function defineInterrupt<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(
403+
registry: Registry,
404+
config: InterruptConfig<I, O>
405+
): ToolAction<I, O> {
406+
const i = interrupt(config);
407+
registry.registerAction('tool', i);
408+
return i;
405409
}
406410

407411
/**
@@ -441,6 +445,8 @@ export function tool<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(
441445
/**
442446
* Defines a dynamic tool. Dynamic tools are just like regular tools but will not be registered in the
443447
* Genkit registry and can be defined dynamically at runtime.
448+
*
449+
* @deprecated renamed to {@link tool}.
444450
*/
445451
export function dynamicTool<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(
446452
config: ToolConfig<I, O>,

js/genkit/src/common.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export {
4343
modelActionMetadata,
4444
modelRef,
4545
rerankerRef,
46+
resource,
4647
retrieverRef,
4748
type DocumentData,
4849
type DynamicResourceAction,
@@ -116,7 +117,7 @@ export {
116117
type SessionData,
117118
type SessionStore,
118119
} from '@genkit-ai/ai/session';
119-
export { dynamicTool } from '@genkit-ai/ai/tool';
120+
export { dynamicTool, tool } from '@genkit-ai/ai/tool';
120121
export {
121122
GENKIT_CLIENT_HEADER,
122123
GENKIT_VERSION,

js/genkit/src/tool.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
export {
1818
asTool,
1919
dynamicTool,
20+
interrupt,
2021
toToolDefinition,
22+
tool,
2123
type ToolAction,
2224
type ToolArgument,
2325
type ToolConfig,

js/genkit/tests/generate_test.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { Operation, z, type JSONSchema7 } from '@genkit-ai/core';
2020
import * as assert from 'assert';
2121
import { beforeEach, describe, it } from 'node:test';
2222
import { modelRef } from '../../ai/src/model';
23+
import { interrupt } from '../../ai/src/tool';
2324
import {
2425
dynamicResource,
2526
dynamicTool,
@@ -956,6 +957,10 @@ describe('generate', () => {
956957
return interrupt();
957958
}
958959
);
960+
const dynamicInterrupt = interrupt({
961+
name: 'dynamicInterrupt',
962+
description: 'description',
963+
});
959964

960965
// first response is a tool call, the subsequent responses are just text response from agent b.
961966
let reqCounter = 0;
@@ -990,6 +995,13 @@ describe('generate', () => {
990995
ref: 'ref789',
991996
},
992997
},
998+
{
999+
toolRequest: {
1000+
name: 'dynamicInterrupt',
1001+
input: { doIt: true },
1002+
ref: 'ref890',
1003+
},
1004+
},
9931005
]
9941006
: [{ text: 'done' }],
9951007
},
@@ -998,7 +1010,12 @@ describe('generate', () => {
9981010

9991011
const response = await ai.generate({
10001012
prompt: 'call the tool',
1001-
tools: ['interruptingTool', 'simpleTool', 'resumableTool'],
1013+
tools: [
1014+
'interruptingTool',
1015+
'simpleTool',
1016+
'resumableTool',
1017+
dynamicInterrupt,
1018+
],
10021019
});
10031020

10041021
assert.strictEqual(reqCounter, 1);
@@ -1039,6 +1056,16 @@ describe('generate', () => {
10391056
},
10401057
},
10411058
},
1059+
{
1060+
metadata: { interrupt: true },
1061+
toolRequest: {
1062+
input: {
1063+
doIt: true,
1064+
},
1065+
name: 'dynamicInterrupt',
1066+
ref: 'ref890',
1067+
},
1068+
},
10421069
]);
10431070
assert.deepStrictEqual(response.message?.toJSON(), {
10441071
role: 'model',
@@ -1082,6 +1109,16 @@ describe('generate', () => {
10821109
},
10831110
},
10841111
},
1112+
{
1113+
metadata: { interrupt: true },
1114+
toolRequest: {
1115+
input: {
1116+
doIt: true,
1117+
},
1118+
name: 'dynamicInterrupt',
1119+
ref: 'ref890',
1120+
},
1121+
},
10851122
],
10861123
});
10871124
assert.deepStrictEqual(pm.lastRequest, {
@@ -1124,6 +1161,16 @@ describe('generate', () => {
11241161
$schema: 'http://json-schema.org/draft-07/schema#',
11251162
},
11261163
},
1164+
{
1165+
description: 'description',
1166+
inputSchema: {
1167+
$schema: 'http://json-schema.org/draft-07/schema#',
1168+
},
1169+
name: 'dynamicInterrupt',
1170+
outputSchema: {
1171+
$schema: 'http://json-schema.org/draft-07/schema#',
1172+
},
1173+
},
11271174
],
11281175
});
11291176
});

0 commit comments

Comments
 (0)