diff --git a/good-fences/src/model.ts b/good-fences/src/model.ts new file mode 100644 index 0000000..739fee9 --- /dev/null +++ b/good-fences/src/model.ts @@ -0,0 +1,24 @@ +/** @file The model behind `complete(messages)`: Workers AI, through its binding. */ + +/** a Workers AI text-generation model with no paid-plan requirement */ +export const MODEL = "@cf/openai/gpt-oss-120b"; + +export type Message = Readonly<{ role: "system" | "user" | "assistant"; content: string }>; + +/** the reply text from an OpenAI-style chat completion */ +const replyText = (output: unknown): string => { + const { choices } = (output ?? {}) as { choices?: { message?: { content?: unknown } }[] }; + const text = choices?.[0]?.message?.content; + if (typeof text !== "string") { + throw Error(`no reply text in model output with keys: ${Object.keys(output ?? {}).join(", ")}`); + } + return text; +}; + +/** `complete(messages)` on a Workers AI model; `ai` is the AI binding */ +export const makeWorkersAiModel = (ai: Ai, model: string) => ({ + async complete(messages: readonly Message[]): Promise { + const output = await ai.run(model as Parameters[0], { messages: [...messages] }); + return replyText(output); + }, +});