UNPKG

@genkit-ai/ai

Version:

Genkit AI framework generative AI APIs.

267 lines 7.38 kB
import { action, assertUnstable, isAction, stripUndefinedProps, z } from "@genkit-ai/core"; import { parseSchema, toJsonSchema } from "@genkit-ai/core/schema"; import { setCustomMetadataAttributes } from "@genkit-ai/core/tracing"; import { MultipartToolResponseSchema } from "./parts.js"; import { isExecutablePrompt } from "./prompt.js"; function asTool(registry, action2) { if (action2.__action?.metadata?.type === "tool") { return action2; } const fn = (input) => { setCustomMetadataAttributes({ subtype: "tool" }); return action2(input); }; fn.__action = { ...action2.__action, metadata: { ...action2.__action.metadata, type: "tool" } }; return fn; } async function resolveTools(registry, tools) { if (!tools || tools.length === 0) { return []; } return await Promise.all( tools.map(async (ref) => { if (typeof ref === "string") { return await lookupToolByName(registry, ref); } else if (isAction(ref)) { return asTool(registry, ref); } else if (isExecutablePrompt(ref)) { return await ref.asTool(); } else if (ref.name) { return await lookupToolByName( registry, ref.metadata?.originalName || ref.name ); } throw new Error("Tools must be strings, tool definitions, or actions."); }) ); } async function lookupToolByName(registry, name) { const tool2 = await registry.lookupAction(name) || await registry.lookupAction(`/tool/${name}`) || await registry.lookupAction(`/tool.v2/${name}`) || await registry.lookupAction(`/prompt/${name}`) || await registry.lookupAction(`/dynamic-action-provider/${name}`); if (!tool2) { throw new Error(`Tool ${name} not found`); } return tool2; } function toToolDefinition(tool2) { const originalName = tool2.__action.name; let name = originalName; if (originalName.includes("/")) { name = originalName.substring(originalName.lastIndexOf("/") + 1); } const out = { name, description: tool2.__action.description || "", outputSchema: toJsonSchema({ schema: tool2.__action.outputSchema ?? z.void(), jsonSchema: tool2.__action.outputJsonSchema }), inputSchema: toJsonSchema({ schema: tool2.__action.inputSchema ?? z.void(), jsonSchema: tool2.__action.inputJsonSchema }) }; if (originalName !== name) { out.metadata = { originalName }; } return out; } function defineTool(registry, config, fn) { const a = tool(config, fn); delete a.__action.metadata.dynamic; registry.registerAction(config.multipart ? "tool.v2" : "tool", a); if (!config.multipart) { registry.registerAction("tool.v2", basicToolV2(config, fn)); } return a; } function implementTool(a, config, registry) { a.respond = (interrupt2, responseData, options) => { if (registry) { assertUnstable( registry, "beta", "The 'tool.reply' method is part of the 'interrupts' beta feature." ); } parseSchema(responseData, { jsonSchema: config.outputJsonSchema, schema: config.outputSchema }); return { toolResponse: stripUndefinedProps({ name: interrupt2.toolRequest.name, ref: interrupt2.toolRequest.ref, output: responseData }), metadata: { interruptResponse: options?.metadata || true } }; }; a.restart = (interrupt2, resumedMetadata, options) => { if (registry) { assertUnstable( registry, "beta", "The 'tool.restart' method is part of the 'interrupts' beta feature." ); } let replaceInput = options?.replaceInput; if (replaceInput) { replaceInput = parseSchema(replaceInput, { schema: config.inputSchema, jsonSchema: config.inputJsonSchema }); } return { toolRequest: stripUndefinedProps({ name: interrupt2.toolRequest.name, ref: interrupt2.toolRequest.ref, input: replaceInput || interrupt2.toolRequest.input }), metadata: stripUndefinedProps({ ...interrupt2.metadata, resumed: resumedMetadata || true, // annotate the original input if replacing it replacedInput: replaceInput ? interrupt2.toolRequest.input : void 0 }) }; }; } function isToolRequest(part) { return !!part.toolRequest; } function isToolResponse(part) { return !!part.toolResponse; } function isDynamicTool(t) { return isAction(t) && t.__action?.metadata?.dynamic === true; } function isMultipartTool(t) { return isAction(t) && t.__action?.metadata?.type === "tool.v2"; } function interrupt(config) { const { requestMetadata, ...toolConfig } = config; return tool(toolConfig, async (input, { interrupt: interrupt2 }) => { if (!config.requestMetadata) interrupt2(); else if (typeof config.requestMetadata === "object") interrupt2(config.requestMetadata); else interrupt2(await Promise.resolve(config.requestMetadata(input))); }); } function defineInterrupt(registry, config) { const i = interrupt(config); registry.registerAction("tool", i); return i; } class ToolInterruptError extends Error { constructor(metadata) { super(); this.metadata = metadata; this.name = "ToolInterruptError"; } } function interruptTool(registry) { return (metadata) => { if (registry) { assertUnstable(registry, "beta", "Tool interrupts are a beta feature."); } throw new ToolInterruptError(metadata); }; } function tool(config, fn) { return config.multipart ? multipartTool(config, fn) : basicTool(config, fn); } function basicTool(config, fn) { const a = action( { ...config, actionType: "tool", metadata: { ...config.metadata || {}, type: "tool", dynamic: true } }, (i, runOptions) => { const interrupt2 = interruptTool(runOptions.registry); if (fn) { return fn(i, { ...runOptions, context: { ...runOptions.context }, interrupt: interrupt2 }); } return interrupt2(); } ); implementTool(a, config); return a; } function basicToolV2(config, fn) { return multipartTool(config, async (input, ctx) => { if (!fn) { const interrupt2 = interruptTool(ctx.registry); return interrupt2(); } return { output: await fn(input, ctx) }; }); } function multipartTool(config, fn) { const a = action( { ...config, outputSchema: MultipartToolResponseSchema, actionType: "tool.v2", metadata: { ...config.metadata || {}, type: "tool.v2", tool: { multipart: true }, dynamic: true } }, (i, runOptions) => { const interrupt2 = interruptTool(runOptions.registry); if (fn) { return fn(i, { ...runOptions, context: { ...runOptions.context }, interrupt: interrupt2 }); } return interrupt2(); } ); implementTool(a, config); return a; } function dynamicTool(config, fn) { const t = basicTool(config, fn); t.attach = (_) => t; return t; } export { ToolInterruptError, asTool, defineInterrupt, defineTool, dynamicTool, interrupt, isDynamicTool, isMultipartTool, isToolRequest, isToolResponse, lookupToolByName, resolveTools, toToolDefinition, tool }; //# sourceMappingURL=tool.mjs.map