diff --git a/js/ai/src/index.ts b/js/ai/src/index.ts index f87fcbfe7e..3f80d093d4 100644 --- a/js/ai/src/index.ts +++ b/js/ai/src/index.ts @@ -116,6 +116,7 @@ export { defineResource, dynamicResource, isDynamicResourceAction, + resource, type DynamicResourceAction, type ResourceAction, type ResourceFn, @@ -144,6 +145,7 @@ export { asTool, defineInterrupt, defineTool, + interrupt, type InterruptConfig, type ToolAction, type ToolArgument, diff --git a/js/ai/src/resource.ts b/js/ai/src/resource.ts index 4a93497166..1257a2ee75 100644 --- a/js/ai/src/resource.ts +++ b/js/ai/src/resource.ts @@ -154,6 +154,8 @@ export function resource( /** * Defines a dynamic resource. Dynamic resources are just like regular resources but will not be * registered in the Genkit registry and can be defined dynamically at runtime. + * + * @deprecated renamed to {@link resource}. */ export function dynamicResource( opts: ResourceOptions, diff --git a/js/ai/src/tool.ts b/js/ai/src/tool.ts index 3ae475e100..6d6b4d3eeb 100644 --- a/js/ai/src/tool.ts +++ b/js/ai/src/tool.ts @@ -386,22 +386,26 @@ export function isDynamicTool(t: unknown): t is ToolAction { return isAction(t) && !t.__registry; } -export function defineInterrupt( - registry: Registry, +export function interrupt( config: InterruptConfig ): ToolAction { const { requestMetadata, ...toolConfig } = config; - return defineTool( - registry, - toolConfig, - async (input, { interrupt }) => { - if (!config.requestMetadata) interrupt(); - else if (typeof config.requestMetadata === 'object') - interrupt(config.requestMetadata); - else interrupt(await Promise.resolve(config.requestMetadata(input))); - } - ); + return tool(toolConfig, async (input, { interrupt }) => { + if (!config.requestMetadata) interrupt(); + else if (typeof config.requestMetadata === 'object') + interrupt(config.requestMetadata); + else interrupt(await Promise.resolve(config.requestMetadata(input))); + }); +} + +export function defineInterrupt( + registry: Registry, + config: InterruptConfig +): ToolAction { + const i = interrupt(config); + registry.registerAction('tool', i); + return i; } /** @@ -441,6 +445,8 @@ export function tool( /** * Defines a dynamic tool. Dynamic tools are just like regular tools but will not be registered in the * Genkit registry and can be defined dynamically at runtime. + * + * @deprecated renamed to {@link tool}. */ export function dynamicTool( config: ToolConfig, diff --git a/js/genkit/src/common.ts b/js/genkit/src/common.ts index 267f2f8a13..241e000d56 100644 --- a/js/genkit/src/common.ts +++ b/js/genkit/src/common.ts @@ -43,6 +43,7 @@ export { modelActionMetadata, modelRef, rerankerRef, + resource, retrieverRef, type DocumentData, type DynamicResourceAction, @@ -116,7 +117,7 @@ export { type SessionData, type SessionStore, } from '@genkit-ai/ai/session'; -export { dynamicTool } from '@genkit-ai/ai/tool'; +export { dynamicTool, tool } from '@genkit-ai/ai/tool'; export { GENKIT_CLIENT_HEADER, GENKIT_VERSION, diff --git a/js/genkit/src/tool.ts b/js/genkit/src/tool.ts index c49061ba36..7034c3457d 100644 --- a/js/genkit/src/tool.ts +++ b/js/genkit/src/tool.ts @@ -17,7 +17,9 @@ export { asTool, dynamicTool, + interrupt, toToolDefinition, + tool, type ToolAction, type ToolArgument, type ToolConfig, diff --git a/js/genkit/tests/generate_test.ts b/js/genkit/tests/generate_test.ts index e61f5930da..9244851fa6 100644 --- a/js/genkit/tests/generate_test.ts +++ b/js/genkit/tests/generate_test.ts @@ -20,6 +20,7 @@ import { Operation, z, type JSONSchema7 } from '@genkit-ai/core'; import * as assert from 'assert'; import { beforeEach, describe, it } from 'node:test'; import { modelRef } from '../../ai/src/model'; +import { interrupt } from '../../ai/src/tool'; import { dynamicResource, dynamicTool, @@ -956,6 +957,10 @@ describe('generate', () => { return interrupt(); } ); + const dynamicInterrupt = interrupt({ + name: 'dynamicInterrupt', + description: 'description', + }); // first response is a tool call, the subsequent responses are just text response from agent b. let reqCounter = 0; @@ -990,6 +995,13 @@ describe('generate', () => { ref: 'ref789', }, }, + { + toolRequest: { + name: 'dynamicInterrupt', + input: { doIt: true }, + ref: 'ref890', + }, + }, ] : [{ text: 'done' }], }, @@ -998,7 +1010,12 @@ describe('generate', () => { const response = await ai.generate({ prompt: 'call the tool', - tools: ['interruptingTool', 'simpleTool', 'resumableTool'], + tools: [ + 'interruptingTool', + 'simpleTool', + 'resumableTool', + dynamicInterrupt, + ], }); assert.strictEqual(reqCounter, 1); @@ -1039,6 +1056,16 @@ describe('generate', () => { }, }, }, + { + metadata: { interrupt: true }, + toolRequest: { + input: { + doIt: true, + }, + name: 'dynamicInterrupt', + ref: 'ref890', + }, + }, ]); assert.deepStrictEqual(response.message?.toJSON(), { role: 'model', @@ -1082,6 +1109,16 @@ describe('generate', () => { }, }, }, + { + metadata: { interrupt: true }, + toolRequest: { + input: { + doIt: true, + }, + name: 'dynamicInterrupt', + ref: 'ref890', + }, + }, ], }); assert.deepStrictEqual(pm.lastRequest, { @@ -1124,6 +1161,16 @@ describe('generate', () => { $schema: 'http://json-schema.org/draft-07/schema#', }, }, + { + description: 'description', + inputSchema: { + $schema: 'http://json-schema.org/draft-07/schema#', + }, + name: 'dynamicInterrupt', + outputSchema: { + $schema: 'http://json-schema.org/draft-07/schema#', + }, + }, ], }); });