diff --git a/packages/ai/core/generate-code/generate-code.test.ts b/packages/ai/core/generate-code/generate-code.test.ts index 70249b080419..a60049c46a39 100644 --- a/packages/ai/core/generate-code/generate-code.test.ts +++ b/packages/ai/core/generate-code/generate-code.test.ts @@ -59,7 +59,7 @@ describe('result.code', () => { return { ...dummyResponseValues, - text: `\`\`\`ts + text: `\`\`\`js let balance = listOfFunctions.getBalance({}); return balance \`\`\` diff --git a/packages/ai/core/generate-code/prompt.ts b/packages/ai/core/generate-code/prompt.ts index 1f1319a1fa41..0222fee6e93d 100644 --- a/packages/ai/core/generate-code/prompt.ts +++ b/packages/ai/core/generate-code/prompt.ts @@ -3,34 +3,41 @@ import { generateZodTypeString } from "./type-zod"; type AnyFunction = (...args: any[]) => any; -function isAsync(fn: AnyFunction): boolean { +function checkAsync(fn: AnyFunction): boolean { return fn.constructor.name === 'AsyncFunction'; } type TOOLS = Record -const displayToolsToType = (tools: TOOLS) => - Object.entries(tools) - .map(([key, value]) => { - const async = isAsync(value.execute) - return `type ${key} = (data:${generateZodTypeString(value.parameters, "data")}) => ${async ? "Promise<" : ""}${generateZodTypeString(value.returns, "returns")}${async ? ">" : ""}` - } - ).join("\n") +const functionDefinition = (tool: TOOLS[string], isAsync:boolean) => { + const type = generateZodTypeString(tool.returns, "returns") + + const returnType = isAsync ? `Promise<${type}>` : type + const paramType = generateZodTypeString(tool.parameters, "data") + + return `${isAsync ? "async" : ""} (data:${paramType}): ${returnType} => {\n\t// ${tool?.description ?? "Does something"}\n\treturn // something\n}` +} const displayToolsToCode = (tools: TOOLS) => Object.entries(tools) - .map(([key, value]) => `const ${key} = ${isAsync(value.execute) ? "async" : ""}(data:${generateZodTypeString(value.parameters, "data")}):${generateZodTypeString(value.returns, "returns")} => {\n // ${value?.description ?? "Does something"}\n return // something\n}`) + .map(([toolName, toolObject]) => { + if (!toolObject.execute) + throw new Error(`Execute function is required for tool ${toolName}`); + + const isAsync = checkAsync(toolObject.execute) + + return `const ${toolName} = ${functionDefinition(toolObject, isAsync)}` + }) .join("\n\n") export const newSystemPrompt = (text: string, tools: TOOLS, thisKeyWord: string) => `Your Persona: ${text} Instructions: - write pure javascript code -- only use functions from the "Tools" list +- only use functions from the ${thisKeyWord} object - functions are already defined -- don't imported or redifined +- don't imported any external libraries - nested functions are allowed -- don't use any external libraries - don't use console.log - don't wrap code in a function - use let to declare variables @@ -38,7 +45,7 @@ Instructions: - wrap the entire Javascript code in \`\`\`js ... \`\`\` code block - also write the JSON schema for the return value of the code in \`\`\`json ... \`\`\` code block -if function name is build(), then use it as ${thisKeyWord}.build() +eg: if function name is build(), then use it as ${thisKeyWord}.build() Tools: diff --git a/packages/ai/core/tool/tool.ts b/packages/ai/core/tool/tool.ts index fb82bc1cdf08..5ea14f2fddc3 100644 --- a/packages/ai/core/tool/tool.ts +++ b/packages/ai/core/tool/tool.ts @@ -4,6 +4,7 @@ import { ToolResultContent } from '../prompt/tool-result-content'; import { CoreMessage } from '../prompt/message'; type Parameters = z.ZodTypeAny | Schema; +type Returns = Parameters; export type inferParameters = PARAMETERS extends Schema @@ -36,7 +37,7 @@ This enables the language model to generate the input. The tool can also contain an optional execute function for the actual execution function of the tool. */ -export type CoreTool = { +export type CoreTool = { /** The schema of the input that the tool expects. The language model will use this to generate the input. It is also used to validate the output of the language model. @@ -44,12 +45,12 @@ Use descriptions to make the input understandable for the language model. */ parameters: PARAMETERS; - returns: RESULT; + returns: RETURNS; /** An optional description of what the tool does. Will be used by the language model to decide whether to use the tool. */ -description?: string; + description?: string; /** Optional conversion function that maps the tool result to multi-part tool content for LLMs. @@ -63,10 +64,10 @@ If not provided, the tool will not be executed automatically. @args is the input of the tool call. @options.abortSignal is a signal that can be used to abort the tool call. */ - execute: ( + execute?: ( args: inferParameters, options: ToolExecutionOptions, - ) => PromiseLike>; + ) => PromiseLike>; } & ( | { /** @@ -96,28 +97,28 @@ The arguments for configuring the tool. Must match the expected arguments define Helper function for inferring the execute args of a tool. */ // Note: special type inference is needed for the execute function args to make sure they are inferred correctly. -export function tool( - tool: CoreTool & { +export function tool( + tool: CoreTool & { execute: ( args: inferParameters, options: ToolExecutionOptions, - ) => PromiseLike>; + ) => PromiseLike>; }, -): CoreTool & { +): CoreTool & { execute: ( args: inferParameters, options: ToolExecutionOptions, - ) => PromiseLike>; + ) => PromiseLike>; }; -export function tool( - tool: CoreTool & { +export function tool( + tool: CoreTool & { execute?: undefined; }, -): CoreTool & { +): CoreTool & { execute: undefined; }; -export function tool( - tool: CoreTool, -): CoreTool { +export function tool( + tool: CoreTool, +): CoreTool { return tool; } \ No newline at end of file