diff --git a/readme.md b/readme.md index 26646db..7d8cb89 100644 --- a/readme.md +++ b/readme.md @@ -15,6 +15,10 @@ TODO +## TODO + +https://github.com/colinhacks/zod#writing-generic-functions + ## Use Cases https://platform.openai.com/examples diff --git a/src/llm.ts b/src/llm.ts index 24528c7..f43ceb8 100644 --- a/src/llm.ts +++ b/src/llm.ts @@ -1,4 +1,4 @@ -import type { ZodType } from 'zod' +import { ZodRawShape, ZodTypeAny, z } from 'zod' import * as types from './types' @@ -66,21 +66,33 @@ export class Agentic { } } -export abstract class BaseLLMCallBuilder { +export abstract class BaseLLMCallBuilder< + TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TOutput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TModelParams extends Record = Record +> { _options: types.BaseLLMOptions constructor(options: types.BaseLLMOptions) { this._options = options } - input(inputSchema: ZodType) { - this._options.input = inputSchema - return this + input( + inputSchema: U + ): BaseLLMCallBuilder { + ;( + this as unknown as BaseLLMCallBuilder + )._options.input = inputSchema + return this as unknown as BaseLLMCallBuilder } - output(outputSchema: ZodType) { - this._options.output = outputSchema - return this + output( + outputSchema: U + ): BaseLLMCallBuilder { + ;( + this as unknown as BaseLLMCallBuilder + )._options.output = outputSchema + return this as unknown as BaseLLMCallBuilder } examples(examples: types.LLMExample[]) { @@ -93,21 +105,21 @@ export abstract class BaseLLMCallBuilder { return this } - abstract call(input?: TInput): Promise + abstract call( + input?: types.ParsedData + ): Promise> // TODO - // abstract stream( + // abstract stream({ // input: TInput, // onProgress: types.ProgressFunction - // ): Promise - - // abstract stream(onProgress: types.ProgressFunction): Promise + // }): Promise } export abstract class ChatModelBuilder< - TInput, - TOutput, - TModelParams + TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TOutput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TModelParams extends Record = Record > extends BaseLLMCallBuilder { _messages: types.ChatMessage[] @@ -118,7 +130,10 @@ export abstract class ChatModelBuilder< } } -export class OpenAIChatModelBuilder extends ChatModelBuilder< +export class OpenAIChatModelBuilder< + TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TOutput extends ZodRawShape | ZodTypeAny = ZodTypeAny +> extends ChatModelBuilder< TInput, TOutput, Omit @@ -141,7 +156,11 @@ export class OpenAIChatModelBuilder extends ChatModelBuilder< this._client = client } - override async call(input?: TInput): Promise { + override async call( + input?: types.ParsedData + ): Promise> { + // this._options.output?.describe // TODO + return true as types.ParsedData } } diff --git a/src/temp.ts b/src/temp.ts new file mode 100644 index 0000000..c735131 --- /dev/null +++ b/src/temp.ts @@ -0,0 +1,20 @@ +import dotenv from 'dotenv-safe' +import { OpenAIClient } from 'openai-fetch' +import { z } from 'zod' + +import { Agentic } from './llm' + +dotenv.config() +async function main() { + const openai = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! }) + const $ = new Agentic(openai) + + const ex0 = await $.gpt4(`give me a single boolean value`) + .output(z.boolean()) + // .retry({ attempts: 3 }) + .call() + + console.log(ex0) +} + +main() diff --git a/src/temp2.ts b/src/temp2.ts new file mode 100644 index 0000000..9bae58e --- /dev/null +++ b/src/temp2.ts @@ -0,0 +1,28 @@ +import { ZodRawShape, ZodType, ZodTypeAny, z } from 'zod' + +import * as types from './types' + +class Test { + _schema: T + + schema(schema: U): Test { + ;(this as unknown as Test)._schema = schema + return this as unknown as Test + } + + call(value: types.ParsedData): types.ParsedData { + const finalSchema = + this._schema instanceof ZodType ? this._schema : z.object(this._schema) + return finalSchema.parse(value) + } +} + +async function main() { + const t = new Test() + const t2 = t.schema(z.string()) + const t3 = t2.call('foo') + + console.log(t3) +} + +main() diff --git a/src/types.ts b/src/types.ts index 830e13a..d0c1720 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,43 +1,67 @@ import * as openai from 'openai-fetch' -import type { ZodType } from 'zod' +import { + SafeParseReturnType, + ZodObject, + ZodRawShape, + ZodSchema, + ZodTypeAny, + output, + z +} from 'zod' export { openai } +export type ParsedData = + T extends ZodTypeAny + ? output + : T extends ZodRawShape + ? output> + : never + +export type SafeParsedData = + T extends ZodTypeAny + ? SafeParseReturnType, ParsedData> + : T extends ZodRawShape + ? SafeParseReturnType, ParsedData> + : never + export interface BaseLLMOptions< - TInput = any, - TOutput = any, - TModelParams = Record + TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TOutput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TModelParams extends Record = Record > { provider?: string model?: string modelParams?: TModelParams timeoutMs?: number - input?: ZodType - output?: ZodType + input?: TInput + output?: TOutput examples?: LLMExample[] retryConfig?: LLMRetryConfig } export interface LLMOptions< - TInput = any, - TOutput = any, - TModelParams = Record + TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TOutput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TModelParams extends Record = Record > extends BaseLLMOptions { promptTemplate?: string promptPrefix?: string promptSuffix?: string } +export type ChatMessageRole = 'user' | 'system' | 'assistant' | 'tool' + export interface ChatMessage { - role: 'user' | 'system' | 'assistant' | 'tool' + role: ChatMessageRole content: string } export interface ChatModelOptions< - TInput = any, - TOutput = any, - TModelParams = Record + TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TOutput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TModelParams extends Record = Record > extends BaseLLMOptions { messages: ChatMessage[] } @@ -51,3 +75,5 @@ export interface LLMRetryConfig { attempts: number strategy: string } + +// export type ProgressFunction = (partialResponse: ChatMessage) => void