import { Component } from "./component.js"; import { getCurrentContext } from "./context.js"; import { JsonValue } from "./workflow-state.js"; import { InferZodType, toJsonSchema, ZodTypeAny, zodValidate } from "./zod.js"; export interface ToolDefinition< TParamsSchema extends ZodTypeAny, TResultSchema extends ZodTypeAny, > { description?: string; params: TParamsSchema; result: TResultSchema; } // Tool box type export type ToolBox = Record>; // Extract param/result types automatically export type InferToolParams = // eslint-disable-next-line @typescript-eslint/no-explicit-any T[K] extends ToolDefinition ? InferZodType

: never; export type InferToolResult = // eslint-disable-next-line @typescript-eslint/no-explicit-any T[K] extends ToolDefinition ? InferZodType : never; // Tool implementations for frontend export type ToolImplementations = { [K in keyof T]: { execute: ( params: InferToolParams, ) => InferToolResult | Promise>; }; }; // Helper to create tool box export function createToolBox(definitions: T): T { return definitions; } export async function executeExternalTool( toolBox: T, toolName: K, params: InferToolParams, ): Promise> { const toolDef = toolBox[toolName] as ToolDefinition; const validatedParams = zodValidate(toolDef.params, params); const paramsJsonSchema = toJsonSchema(toolDef.params); const resultJsonSchema = toJsonSchema(toolDef.result); const component = Component( "ExternalTool", async ({ toolName, validatedParams, }: { toolName: string; validatedParams: Record; }) => { const context = getCurrentContext(); const workflowContext = context.getWorkflowContext(); const currentNode = context.getCurrentNode(); if (!currentNode) { throw new Error("No current node ID found"); } // Send external tool call message workflowContext.sendWorkflowMessage({ type: "external-tool", toolName: String(toolName), params: validatedParams as JsonValue, paramsSchema: paramsJsonSchema, resultSchema: resultJsonSchema, nodeId: currentNode.id, }); const result = await workflowContext.onRequestInput({ type: "external-tool", toolName: String(toolName), nodeId: currentNode.id, params: validatedParams as JsonValue, paramsSchema: paramsJsonSchema, resultSchema: resultJsonSchema, }); if ( typeof result === "object" && result !== null && "__gensxMissingToolImplementation" in result ) { throw new Error(`Tool implementation not found: ${String(toolName)}`); } return result as InferToolResult; }, ); return await component({ toolName: String(toolName), validatedParams: validatedParams as Record, }); }