diff --git a/packages/core/src/apis/google/mapGeminiResponseToToolInvocations.ts b/packages/core/src/apis/google/mapGeminiResponseToToolInvocations.ts index 350ac7d..707b697 100644 --- a/packages/core/src/apis/google/mapGeminiResponseToToolInvocations.ts +++ b/packages/core/src/apis/google/mapGeminiResponseToToolInvocations.ts @@ -1,4 +1,4 @@ -import { ConvertParamMapToArgs, Tool, ToolParamMap } from "../shared"; +import { ConvertParamMapToArgs, Tool, ToolParamMap } from "../../utils/Tool"; import type { GoogleGeminiResponse } from "./gemini"; diff --git a/packages/core/src/apis/shared/ToolUseRequestOptions.ts b/packages/core/src/apis/shared/ToolUseRequestOptions.ts index 95e02af..7c6ad5b 100644 --- a/packages/core/src/apis/shared/ToolUseRequestOptions.ts +++ b/packages/core/src/apis/shared/ToolUseRequestOptions.ts @@ -1,94 +1,4 @@ -type ToolParameterTypes = "STR" | "NUM" | "BOOL"; - -export type ToolParamMap = { - [key: string]: { - description: string; - type: ToolParameterTypes; - required: boolean; - }; -}; - -type ExtractArgumentType = T extends "STR" - ? string - : T extends "NUM" - ? number - : T extends "BOOL" - ? boolean - : never; - -export type ConvertParamMapToArgs = { - [K in keyof TParamMap as TParamMap[K]["required"] extends true - ? K - : never]: ExtractArgumentType; -} & { - [K in keyof TParamMap as TParamMap[K]["required"] extends false | undefined - ? K - : never]?: ExtractArgumentType; -}; - -/* - * Ifaces - */ -interface ToolParam { - name: string; - description: string; - type: ToolParameterTypes; - required: boolean; -} - -interface ToolInvocation { - arguments: TArgs; - returned?: unknown; -} - -interface ToolDescriptor { - name: string; - description: string; - parameters: ToolParam[]; - invocations: ToolInvocation[]; -} - -export class Tool { - private invokeFn: (args: ConvertParamMapToArgs) => TReturns; - - public descriptor: ToolDescriptor; - - constructor( - name: string, - description: string, - paramMap: TParamMap, - invokeFn: (args: ConvertParamMapToArgs) => TReturns, - ) { - this.invokeFn = invokeFn; - this.descriptor = { - name, - description, - parameters: this.createParameters(paramMap), - invocations: [], - }; - } - - // eslint-disable-next-line class-methods-use-this - private createParameters(paramMap: TParamMap): ToolParam[] { - return Object.entries(paramMap).map(([name, paramInfo]) => ({ - name, - description: paramInfo.description, - type: paramInfo.type, - required: paramInfo.required, - })); - } - - public invoke(args: ConvertParamMapToArgs): TReturns { - const returned = this.invokeFn(args); - - this.descriptor.invocations.push({ - arguments: args, - returned, - }); - - return returned; - } -} +import { ToolDescriptor } from "@typeDefs"; /** * @category Core Interfaces diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 89c60a3..da336ca 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -91,6 +91,7 @@ export { * Public API - Utils */ export { FnTemplate } from "./utils"; +// TODO export Tool /* * Public API - TypeDefs diff --git a/packages/core/src/typeDefs.ts b/packages/core/src/typeDefs.ts index 4c35b13..7890491 100644 --- a/packages/core/src/typeDefs.ts +++ b/packages/core/src/typeDefs.ts @@ -71,3 +71,24 @@ export type InferRequestOptions = T extends ModelApi ? U : never; export type InferResponse = T extends ModelApi ? V : never; + +export type ToolParameterTypes = "STR" | "NUM" | "BOOL"; + +export interface ToolParam { + name: string; + description: string; + type: ToolParameterTypes; + required: boolean; +} + +export interface ToolInvocation { + arguments: TArgs; + returned?: unknown; +} + +export interface ToolDescriptor { + name: string; + description: string; + parameters: ToolParam[]; + invocations: ToolInvocation[]; +} diff --git a/packages/core/src/utils/Tool.ts b/packages/core/src/utils/Tool.ts new file mode 100644 index 0000000..37bf65e --- /dev/null +++ b/packages/core/src/utils/Tool.ts @@ -0,0 +1,144 @@ +import { ToolDescriptor, ToolParam, ToolParameterTypes } from "@typeDefs"; + +export type ToolParamMap = { + [key: string]: { + description: string; + type: ToolParameterTypes; + required: boolean; + }; +}; + +type ExtractArgumentType = T extends "STR" + ? string + : T extends "NUM" + ? number + : T extends "BOOL" + ? boolean + : never; + +export type ConvertParamMapToArgs = { + [K in keyof TParamMap as TParamMap[K]["required"] extends true + ? K + : never]: ExtractArgumentType; +} & { + [K in keyof TParamMap as TParamMap[K]["required"] extends false | undefined + ? K + : never]?: ExtractArgumentType; +}; + +export class Tool { + private invokeFn: (args: ConvertParamMapToArgs) => TReturns; + + public descriptor: ToolDescriptor; + + constructor( + name: string, + description: string, + paramMap: TParamMap, + invokeFn: (args: ConvertParamMapToArgs) => TReturns, + ) { + this.invokeFn = invokeFn; + this.descriptor = { + name, + description, + parameters: this.createParameters(paramMap), + invocations: [], + }; + } + + // eslint-disable-next-line class-methods-use-this + private createParameters(paramMap: TParamMap): ToolParam[] { + return Object.entries(paramMap).map(([name, paramInfo]) => ({ + name, + description: paramInfo.description, + type: paramInfo.type, + required: paramInfo.required, + })); + } + + public invoke(args: ConvertParamMapToArgs): TReturns { + const returned = this.invokeFn(args); + + this.descriptor.invocations.push({ + arguments: args, + returned, + }); + + return returned; + } +} + +export const a = new Tool( + "get_current_weather", + "Get the current weather for a given location", + { + city: { + description: "The city name", + type: "STR", + required: true, + }, + state: { + description: "The state name", + type: "STR", + required: true, + }, + zipcode: { + description: "An optional zipcode", + type: "NUM", + required: false, + }, + }, + // should work: + ({ city, state, zipcode }) => { + console.log("Invoking get_current_weather tool...", { + city, + state, + zipcode, + }); + return { + temperature: "70", + }; + }, +); + +a.invoke({ city: "San Francisco", state: "CA" }); +a.invoke({ city: "San Francisco", state: "CA", zipcode: 94105 }); + +// bad: +// a.invoke({ city: "San Francisco" }); +// a.invoke({ city: "San Francisco", state: "CA", zipcode: 94105, xxx: "yyy" }); +// a.invoke({ city: "San Francisco", state: 123 }); + +// export const x1 = new Tool( +// "get_current_weather", +// "Get the current weather for a given location", +// { +// city: { +// description: "The city name", +// type: "STR", +// required: true, +// }, +// state: { +// description: "The state name", +// type: "STR", +// required: true, +// }, +// zipcode: { +// description: "An optional zipcode", +// type: "NUM", +// required: false, +// }, +// }, +// // should break, prop not defined: +// ({ city, state, zipcode, xxx }) => { +// console.log("Invoking get_current_weather tool...", { +// city, +// state, +// zipcode, +// xxx, +// }); +// return { +// temperature: "70", +// }; +// }, +// ); diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index c676e80..404cf23 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -1 +1,2 @@ export * from "./Template"; +export * from "./Tool"; diff --git a/tests/integration/vertexai-tools.test.ts b/tests/integration/vertexai-tools.test.ts index bd7b879..6efc159 100644 --- a/tests/integration/vertexai-tools.test.ts +++ b/tests/integration/vertexai-tools.test.ts @@ -1,7 +1,8 @@ /* eslint-disable import/no-relative-packages */ import { createVertexAiModelProvider } from "@packages/gcloud-vertex-ai"; +// TODO decide on these import/exports as part of public API import { mapGeminiResponseToToolInvocations } from "../../packages/core/src/apis/google/mapGeminiResponseToToolInvocations"; -import { Tool } from "../../packages/core/src/apis/shared/ToolUseRequestOptions"; +import { Tool } from "../../packages/core/src/utils/Tool"; xtest("VertexAI - Google Gemini (Tools)", async () => { // arrange