import { SSESession } from '../utils/sse-session.js'; import { EventEmitter } from '../utils/event-emitter.js'; import { GPTResponseIterator, type ToolCall, type ToolDefinition } from './gpt-response.js'; export type GPTEventMap = { /** * Emitted when a message is sent */ messageSent: { mesasge: string }; /** * Emitted when a message chunk is received */ messageChunkReceived: { chunk: string }; /** * Emitted when a response is received */ responseReceived: { response: string }; /** * Emitted when a tool is called */ toolCalled: { toolName: string; arguments: Record; result: unknown }; } export type GPTConfig = { /** * The API key to use for the GPT API */ apiKey: string; /** * The API URL to use for the GPT API */ apiUrl: string; /** * The model to use for the GPT API */ model: string; } /** * Message types that can be sent to the GPT API */ export type Message = | { role: 'user' | 'system'; content: string; } | { role: 'assistant'; content: string | null; tool_calls?: ToolCall[]; } | { role: 'tool'; tool_call_id: string; name: string; content: string; }; /** * Request configuration for GPT API calls */ export type GPTRequest = { /** * The messages to send to the GPT API */ messages: Message[]; /** * Optional tool definitions for function calling */ tools?: ToolDefinition[]; /** * Controls which (if any) tool is called by the model * - 'auto' (default): model decides whether to call a tool * - 'none': model will not call any tools * - { type: 'function', function: { name: 'tool_name' } }: forces a specific tool call */ tool_choice?: 'auto' | 'none' | { type: 'function'; function: { name: string } }; } export class GPT extends EventEmitter { constructor(public config: GPTConfig) { super(); } /** * Sends a message to the GPT API * @param message - The message to send * @returns The response from the GPT API */ send(request: GPTRequest): GPTResponseIterator { const config = this.config; const lazyIterator = (async function* () { // Build the API request body const requestBody: Record = { model: config.model, messages: request.messages, stream: true, }; // Add tools if provided if (request.tools && request.tools.length > 0) { requestBody.tools = request.tools; } // Add tool_choice if provided if (request.tool_choice) { requestBody.tool_choice = request.tool_choice; } const session = await SSESession.from(config.apiUrl, { headers: { Authorization: `Bearer ${config.apiKey}`, }, method: 'POST', body: JSON.stringify(requestBody), }); if (!session.messages) { throw new Error('Failed to create SSE session'); } yield* session.messages; })(); return new GPTResponseIterator(lazyIterator); } }