From 65e2e73a00e35eadac9f1e3ae06ea1288a90b241 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Sun, 2 Jun 2024 18:13:24 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/openai/weather.ts | 66 ++++++++++--------- src/{ai-function.ts => create-ai-function.ts} | 11 ++-- src/fns.ts | 11 ++-- src/index.ts | 2 +- 4 files changed, 50 insertions(+), 40 deletions(-) rename src/{ai-function.ts => create-ai-function.ts} (87%) diff --git a/examples/openai/weather.ts b/examples/openai/weather.ts index 39ac02d..7c86588 100644 --- a/examples/openai/weather.ts +++ b/examples/openai/weather.ts @@ -18,40 +18,46 @@ async function main() { { role: 'user', content: 'What is the weather in San Francisco?' } ] - const res0 = await openai.chat.completions.create({ - messages, - model: 'gpt-4o', - temperature: 0, - tools: weather.tools.specs, - tool_choice: 'required' - }) - const message0 = res0.choices[0]?.message! - console.log(JSON.stringify(message0, null, 2)) - assert(message0.role === 'assistant') - assert(message0.tool_calls?.[0]?.function?.name === 'get_current_weather') + const tools = weather.tools - const getCurrentWeather = weather.tools.get('get_current_weather')!.function - assert(getCurrentWeather) + { + // First call to OpenAI to invoke the weather tool + const res = await openai.chat.completions.create({ + messages, + model: 'gpt-4o', + temperature: 0, + tools: tools.specs, + tool_choice: 'required' + }) + const message = res.choices[0]?.message! + console.log(JSON.stringify(message, null, 2)) + assert(message.tool_calls?.[0]?.function?.name === 'get_current_weather') - const toolParams = message0.tool_calls[0].function.arguments - assert(typeof toolParams === 'string') - const toolResult = await getCurrentWeather(toolParams) + const fn = tools.get('get_current_weather')!.function + assert(fn) - messages.push(message0) - messages.push({ - role: 'tool', - tool_call_id: message0.tool_calls[0].id, - content: JSON.stringify(toolResult) - }) + const toolParams = message.tool_calls[0].function.arguments + const toolResult = await fn(toolParams) - const res1 = await openai.chat.completions.create({ - messages, - model: 'gpt-4o', - temperature: 0, - tools: weather.tools.specs - }) - const message1 = res1.choices[0].message - console.log(JSON.stringify(message1, null, 2)) + messages.push(message) + messages.push({ + role: 'tool', + tool_call_id: message.tool_calls[0].id, + content: JSON.stringify(toolResult) + }) + } + + { + // Second call to OpenAI to generate a text response + const res = await openai.chat.completions.create({ + messages, + model: 'gpt-4o', + temperature: 0, + tools: tools.specs + }) + const message = res.choices[0].message + console.log(JSON.stringify(message, null, 2)) + } } await main() diff --git a/src/ai-function.ts b/src/create-ai-function.ts similarity index 87% rename from src/ai-function.ts rename to src/create-ai-function.ts index 6c8fd1e..c298882 100644 --- a/src/ai-function.ts +++ b/src/create-ai-function.ts @@ -26,12 +26,15 @@ export function createAIFunction, Return>( /** Implementation of the function to call with the parsed arguments. */ implementation: (params: z.infer) => types.MaybePromise ): types.AIFunction { - assert(spec.name, 'Missing required AIFunction "spec.name"') - assert(spec.inputSchema, 'Missing required AIFunction "spec.inputSchema"') - assert(implementation, 'Missing required AIFunction "implementation"') + assert(spec.name, 'createAIFunction missing required "spec.name"') + assert( + spec.inputSchema, + 'createAIFunction missing required "spec.inputSchema"' + ) + assert(implementation, 'createAIFunction missing required "implementation"') assert( typeof implementation === 'function', - 'Required AIFunction "implementation" must be a function' + 'createAIFunction "implementation" must be a function' ) /** Parse the arguments string, optionally reading from a message. */ diff --git a/src/fns.ts b/src/fns.ts index dbea51a..cd8d2ef 100644 --- a/src/fns.ts +++ b/src/fns.ts @@ -3,9 +3,9 @@ import './symbol-polyfill.js' import type { z } from 'zod' import type * as types from './types.js' -import { createAIFunction } from './ai-function.js' import { AIFunctionSet } from './ai-function-set.js' import { AIToolSet } from './ai-tool-set.js' +import { createAIFunction } from './create-ai-function.js' import { assert } from './utils.js' export interface Invocable { @@ -35,7 +35,7 @@ export abstract class AIToolsProvider { // console.log({ metadata, invocables }) const aiFunctions = invocables.map((invocable) => { - const impl = (this as any)[invocable.methodName]?.bind(this) + const impl = (this as any)[invocable.methodName] assert(impl) return createAIFunction(invocable, impl) @@ -87,14 +87,15 @@ export function aiFunction< inputSchema, methodName }) + // console.log({ // name, // methodName, // context // }) - // context.addInitializer(function () { - // ;(this as any)[methodName] = (this as any)[methodName].bind(this) - // }) + context.addInitializer(function () { + ;(this as any)[methodName] = (this as any)[methodName].bind(this) + }) } } diff --git a/src/index.ts b/src/index.ts index 2cfdd4c..2032dad 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ -export * from './ai-function.js' export * from './ai-function-set.js' export * from './ai-tool-set.js' +export * from './create-ai-function.js' export * from './errors.js' export * from './fns.js' export * from './parse-structured-output.js'