var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _AbstractChatCompletionRunner_instances, _AbstractChatCompletionRunner_connectedPromise, _AbstractChatCompletionRunner_resolveConnectedPromise, _AbstractChatCompletionRunner_rejectConnectedPromise, _AbstractChatCompletionRunner_endPromise, _AbstractChatCompletionRunner_resolveEndPromise, _AbstractChatCompletionRunner_rejectEndPromise, _AbstractChatCompletionRunner_listeners, _AbstractChatCompletionRunner_ended, _AbstractChatCompletionRunner_errored, _AbstractChatCompletionRunner_aborted, _AbstractChatCompletionRunner_catchingPromiseCreated, _AbstractChatCompletionRunner_getFinalContent, _AbstractChatCompletionRunner_getFinalMessage, _AbstractChatCompletionRunner_getFinalFunctionCall, _AbstractChatCompletionRunner_getFinalFunctionCallResult, _AbstractChatCompletionRunner_calculateTotalUsage, _AbstractChatCompletionRunner_handleError, _AbstractChatCompletionRunner_validateParams, _AbstractChatCompletionRunner_stringifyFunctionCallResult; import { APIUserAbortError, OpenAIError } from 'openai/error'; import { isRunnableFunctionWithParse, } from "./RunnableFunction.mjs"; import { isAssistantMessage, isFunctionMessage, isToolMessage } from "./chatCompletionUtils.mjs"; const DEFAULT_MAX_CHAT_COMPLETIONS = 10; export class AbstractChatCompletionRunner { constructor() { _AbstractChatCompletionRunner_instances.add(this); this.controller = new AbortController(); _AbstractChatCompletionRunner_connectedPromise.set(this, void 0); _AbstractChatCompletionRunner_resolveConnectedPromise.set(this, () => { }); _AbstractChatCompletionRunner_rejectConnectedPromise.set(this, () => { }); _AbstractChatCompletionRunner_endPromise.set(this, void 0); _AbstractChatCompletionRunner_resolveEndPromise.set(this, () => { }); _AbstractChatCompletionRunner_rejectEndPromise.set(this, () => { }); _AbstractChatCompletionRunner_listeners.set(this, {}); this._chatCompletions = []; this.messages = []; _AbstractChatCompletionRunner_ended.set(this, false); _AbstractChatCompletionRunner_errored.set(this, false); _AbstractChatCompletionRunner_aborted.set(this, false); _AbstractChatCompletionRunner_catchingPromiseCreated.set(this, false); _AbstractChatCompletionRunner_handleError.set(this, (error) => { __classPrivateFieldSet(this, _AbstractChatCompletionRunner_errored, true, "f"); if (error instanceof Error && error.name === 'AbortError') { error = new APIUserAbortError(); } if (error instanceof APIUserAbortError) { __classPrivateFieldSet(this, _AbstractChatCompletionRunner_aborted, true, "f"); return this._emit('abort', error); } if (error instanceof OpenAIError) { return this._emit('error', error); } if (error instanceof Error) { const openAIError = new OpenAIError(error.message); // @ts-ignore openAIError.cause = error; return this._emit('error', openAIError); } return this._emit('error', new OpenAIError(String(error))); }); __classPrivateFieldSet(this, _AbstractChatCompletionRunner_connectedPromise, new Promise((resolve, reject) => { __classPrivateFieldSet(this, _AbstractChatCompletionRunner_resolveConnectedPromise, resolve, "f"); __classPrivateFieldSet(this, _AbstractChatCompletionRunner_rejectConnectedPromise, reject, "f"); }), "f"); __classPrivateFieldSet(this, _AbstractChatCompletionRunner_endPromise, new Promise((resolve, reject) => { __classPrivateFieldSet(this, _AbstractChatCompletionRunner_resolveEndPromise, resolve, "f"); __classPrivateFieldSet(this, _AbstractChatCompletionRunner_rejectEndPromise, reject, "f"); }), "f"); // Don't let these promises cause unhandled rejection errors. // we will manually cause an unhandled rejection error later // if the user hasn't registered any error listener or called // any promise-returning method. __classPrivateFieldGet(this, _AbstractChatCompletionRunner_connectedPromise, "f").catch(() => { }); __classPrivateFieldGet(this, _AbstractChatCompletionRunner_endPromise, "f").catch(() => { }); } _run(executor) { // Unfortunately if we call `executor()` immediately we get runtime errors about // references to `this` before the `super()` constructor call returns. setTimeout(() => { executor().then(() => { this._emitFinal(); this._emit('end'); }, __classPrivateFieldGet(this, _AbstractChatCompletionRunner_handleError, "f")); }, 0); } _addChatCompletion(chatCompletion) { this._chatCompletions.push(chatCompletion); this._emit('chatCompletion', chatCompletion); const message = chatCompletion.choices[0]?.message; if (message) this._addMessage(message); return chatCompletion; } _addMessage(message, emit = true) { if (!('content' in message)) message.content = null; this.messages.push(message); if (emit) { this._emit('message', message); if ((isFunctionMessage(message) || isToolMessage(message)) && message.content) { // Note, this assumes that {role: 'tool', content: …} is always the result of a call of tool of type=function. this._emit('functionCallResult', message.content); } else if (isAssistantMessage(message) && message.function_call) { this._emit('functionCall', message.function_call); } else if (isAssistantMessage(message) && message.tool_calls) { for (const tool_call of message.tool_calls) { if (tool_call.type === 'function') { this._emit('functionCall', tool_call.function); } } } } } _connected() { if (this.ended) return; __classPrivateFieldGet(this, _AbstractChatCompletionRunner_resolveConnectedPromise, "f").call(this); this._emit('connect'); } get ended() { return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_ended, "f"); } get errored() { return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_errored, "f"); } get aborted() { return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_aborted, "f"); } abort() { this.controller.abort(); } /** * Adds the listener function to the end of the listeners array for the event. * No checks are made to see if the listener has already been added. Multiple calls passing * the same combination of event and listener will result in the listener being added, and * called, multiple times. * @returns this ChatCompletionStream, so that calls can be chained */ on(event, listener) { const listeners = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_listeners, "f")[event] || (__classPrivateFieldGet(this, _AbstractChatCompletionRunner_listeners, "f")[event] = []); listeners.push({ listener }); return this; } /** * Removes the specified listener from the listener array for the event. * off() will remove, at most, one instance of a listener from the listener array. If any single * listener has been added multiple times to the listener array for the specified event, then * off() must be called multiple times to remove each instance. * @returns this ChatCompletionStream, so that calls can be chained */ off(event, listener) { const listeners = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_listeners, "f")[event]; if (!listeners) return this; const index = listeners.findIndex((l) => l.listener === listener); if (index >= 0) listeners.splice(index, 1); return this; } /** * Adds a one-time listener function for the event. The next time the event is triggered, * this listener is removed and then invoked. * @returns this ChatCompletionStream, so that calls can be chained */ once(event, listener) { const listeners = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_listeners, "f")[event] || (__classPrivateFieldGet(this, _AbstractChatCompletionRunner_listeners, "f")[event] = []); listeners.push({ listener, once: true }); return this; } /** * This is similar to `.once()`, but returns a Promise that resolves the next time * the event is triggered, instead of calling a listener callback. * @returns a Promise that resolves the next time given event is triggered, * or rejects if an error is emitted. (If you request the 'error' event, * returns a promise that resolves with the error). * * Example: * * const message = await stream.emitted('message') // rejects if the stream errors */ emitted(event) { return new Promise((resolve, reject) => { __classPrivateFieldSet(this, _AbstractChatCompletionRunner_catchingPromiseCreated, true, "f"); if (event !== 'error') this.once('error', reject); this.once(event, resolve); }); } async done() { __classPrivateFieldSet(this, _AbstractChatCompletionRunner_catchingPromiseCreated, true, "f"); await __classPrivateFieldGet(this, _AbstractChatCompletionRunner_endPromise, "f"); } /** * @returns a promise that resolves with the final ChatCompletion, or rejects * if an error occurred or the stream ended prematurely without producing a ChatCompletion. */ async finalChatCompletion() { await this.done(); const completion = this._chatCompletions[this._chatCompletions.length - 1]; if (!completion) throw new OpenAIError('stream ended without producing a ChatCompletion'); return completion; } /** * @returns a promise that resolves with the content of the final ChatCompletionMessage, or rejects * if an error occurred or the stream ended prematurely without producing a ChatCompletionMessage. */ async finalContent() { await this.done(); return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalContent).call(this); } /** * @returns a promise that resolves with the the final assistant ChatCompletionMessage response, * or rejects if an error occurred or the stream ended prematurely without producing a ChatCompletionMessage. */ async finalMessage() { await this.done(); return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this); } /** * @returns a promise that resolves with the content of the final FunctionCall, or rejects * if an error occurred or the stream ended prematurely without producing a ChatCompletionMessage. */ async finalFunctionCall() { await this.done(); return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionCall).call(this); } async finalFunctionCallResult() { await this.done(); return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionCallResult).call(this); } async totalUsage() { await this.done(); return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_calculateTotalUsage).call(this); } allChatCompletions() { return [...this._chatCompletions]; } _emit(event, ...args) { // make sure we don't emit any events after end if (__classPrivateFieldGet(this, _AbstractChatCompletionRunner_ended, "f")) { return; } if (event === 'end') { __classPrivateFieldSet(this, _AbstractChatCompletionRunner_ended, true, "f"); __classPrivateFieldGet(this, _AbstractChatCompletionRunner_resolveEndPromise, "f").call(this); } const listeners = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_listeners, "f")[event]; if (listeners) { __classPrivateFieldGet(this, _AbstractChatCompletionRunner_listeners, "f")[event] = listeners.filter((l) => !l.once); listeners.forEach(({ listener }) => listener(...args)); } if (event === 'abort') { const error = args[0]; if (!__classPrivateFieldGet(this, _AbstractChatCompletionRunner_catchingPromiseCreated, "f") && !listeners?.length) { Promise.reject(error); } __classPrivateFieldGet(this, _AbstractChatCompletionRunner_rejectConnectedPromise, "f").call(this, error); __classPrivateFieldGet(this, _AbstractChatCompletionRunner_rejectEndPromise, "f").call(this, error); this._emit('end'); return; } if (event === 'error') { // NOTE: _emit('error', error) should only be called from #handleError(). const error = args[0]; if (!__classPrivateFieldGet(this, _AbstractChatCompletionRunner_catchingPromiseCreated, "f") && !listeners?.length) { // Trigger an unhandled rejection if the user hasn't registered any error handlers. // If you are seeing stack traces here, make sure to handle errors via either: // - runner.on('error', () => ...) // - await runner.done() // - await runner.finalChatCompletion() // - etc. Promise.reject(error); } __classPrivateFieldGet(this, _AbstractChatCompletionRunner_rejectConnectedPromise, "f").call(this, error); __classPrivateFieldGet(this, _AbstractChatCompletionRunner_rejectEndPromise, "f").call(this, error); this._emit('end'); } } _emitFinal() { const completion = this._chatCompletions[this._chatCompletions.length - 1]; if (completion) this._emit('finalChatCompletion', completion); const finalMessage = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this); if (finalMessage) this._emit('finalMessage', finalMessage); const finalContent = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalContent).call(this); if (finalContent) this._emit('finalContent', finalContent); const finalFunctionCall = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionCall).call(this); if (finalFunctionCall) this._emit('finalFunctionCall', finalFunctionCall); const finalFunctionCallResult = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionCallResult).call(this); if (finalFunctionCallResult != null) this._emit('finalFunctionCallResult', finalFunctionCallResult); if (this._chatCompletions.some((c) => c.usage)) { this._emit('totalUsage', __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_calculateTotalUsage).call(this)); } } async _createChatCompletion(completions, params, options) { const signal = options?.signal; if (signal) { if (signal.aborted) this.controller.abort(); signal.addEventListener('abort', () => this.controller.abort()); } __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_validateParams).call(this, params); const chatCompletion = await completions.create({ ...params, stream: false }, { ...options, signal: this.controller.signal }); this._connected(); return this._addChatCompletion(chatCompletion); } async _runChatCompletion(completions, params, options) { for (const message of params.messages) { this._addMessage(message, false); } return await this._createChatCompletion(completions, params, options); } async _runFunctions(completions, params, options) { const role = 'function'; const { function_call = 'auto', stream, ...restParams } = params; const singleFunctionToCall = typeof function_call !== 'string' && function_call?.name; const { maxChatCompletions = DEFAULT_MAX_CHAT_COMPLETIONS } = options || {}; const functionsByName = {}; for (const f of params.functions) { functionsByName[f.name || f.function.name] = f; } const functions = params.functions.map((f) => ({ name: f.name || f.function.name, parameters: f.parameters, description: f.description, })); for (const message of params.messages) { this._addMessage(message, false); } for (let i = 0; i < maxChatCompletions; ++i) { const chatCompletion = await this._createChatCompletion(completions, { ...restParams, function_call, functions, messages: [...this.messages], }, options); const message = chatCompletion.choices[0]?.message; if (!message) { throw new OpenAIError(`missing message in ChatCompletion response`); } if (!message.function_call) return; const { name, arguments: args } = message.function_call; const fn = functionsByName[name]; if (!fn) { const content = `Invalid function_call: ${JSON.stringify(name)}. Available options are: ${functions .map((f) => JSON.stringify(f.name)) .join(', ')}. Please try again`; this._addMessage({ role, name, content }); continue; } else if (singleFunctionToCall && singleFunctionToCall !== name) { const content = `Invalid function_call: ${JSON.stringify(name)}. ${JSON.stringify(singleFunctionToCall)} requested. Please try again`; this._addMessage({ role, name, content }); continue; } let parsed; try { parsed = isRunnableFunctionWithParse(fn) ? await fn.parse(args) : args; } catch (error) { this._addMessage({ role, name, content: error instanceof Error ? error.message : String(error), }); continue; } // @ts-expect-error it can't rule out `never` type. const rawContent = await fn.function(parsed, this); const content = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_stringifyFunctionCallResult).call(this, rawContent); this._addMessage({ role, name, content }); if (singleFunctionToCall) return; } } async _runTools(completions, params, options) { const role = 'tool'; const { tool_choice = 'auto', stream, ...restParams } = params; const singleFunctionToCall = typeof tool_choice !== 'string' && tool_choice?.function?.name; const { maxChatCompletions = DEFAULT_MAX_CHAT_COMPLETIONS } = options || {}; const functionsByName = {}; for (const f of params.tools) { if (f.type === 'function') { functionsByName[f.function.name || f.function.function.name] = f.function; } } const tools = 'tools' in params ? params.tools.map((t) => t.type === 'function' ? { type: 'function', function: { name: t.function.name || t.function.function.name, parameters: t.function.parameters, description: t.function.description, }, } : t) : undefined; for (const message of params.messages) { this._addMessage(message, false); } for (let i = 0; i < maxChatCompletions; ++i) { const chatCompletion = await this._createChatCompletion(completions, { ...restParams, tool_choice, tools, messages: [...this.messages], }, options); const message = chatCompletion.choices[0]?.message; if (!message) { throw new OpenAIError(`missing message in ChatCompletion response`); } if (!message.tool_calls) { return; } for (const tool_call of message.tool_calls) { if (tool_call.type !== 'function') continue; const tool_call_id = tool_call.id; const { name, arguments: args } = tool_call.function; const fn = functionsByName[name]; if (!fn) { const content = `Invalid tool_call: ${JSON.stringify(name)}. Available options are: ${tools .map((f) => JSON.stringify(f.function.name)) .join(', ')}. Please try again`; this._addMessage({ role, tool_call_id, content }); continue; } else if (singleFunctionToCall && singleFunctionToCall !== name) { const content = `Invalid tool_call: ${JSON.stringify(name)}. ${JSON.stringify(singleFunctionToCall)} requested. Please try again`; this._addMessage({ role, tool_call_id, content }); continue; } let parsed; try { parsed = isRunnableFunctionWithParse(fn) ? await fn.parse(args) : args; } catch (error) { const content = error instanceof Error ? error.message : String(error); this._addMessage({ role, tool_call_id, content }); continue; } // @ts-expect-error it can't rule out `never` type. const rawContent = await fn.function(parsed, this); const content = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_stringifyFunctionCallResult).call(this, rawContent); this._addMessage({ role, tool_call_id, content }); if (singleFunctionToCall) { return; } } } return; } } _AbstractChatCompletionRunner_connectedPromise = new WeakMap(), _AbstractChatCompletionRunner_resolveConnectedPromise = new WeakMap(), _AbstractChatCompletionRunner_rejectConnectedPromise = new WeakMap(), _AbstractChatCompletionRunner_endPromise = new WeakMap(), _AbstractChatCompletionRunner_resolveEndPromise = new WeakMap(), _AbstractChatCompletionRunner_rejectEndPromise = new WeakMap(), _AbstractChatCompletionRunner_listeners = new WeakMap(), _AbstractChatCompletionRunner_ended = new WeakMap(), _AbstractChatCompletionRunner_errored = new WeakMap(), _AbstractChatCompletionRunner_aborted = new WeakMap(), _AbstractChatCompletionRunner_catchingPromiseCreated = new WeakMap(), _AbstractChatCompletionRunner_handleError = new WeakMap(), _AbstractChatCompletionRunner_instances = new WeakSet(), _AbstractChatCompletionRunner_getFinalContent = function _AbstractChatCompletionRunner_getFinalContent() { return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this).content ?? null; }, _AbstractChatCompletionRunner_getFinalMessage = function _AbstractChatCompletionRunner_getFinalMessage() { let i = this.messages.length; while (i-- > 0) { const message = this.messages[i]; if (isAssistantMessage(message)) { return { ...message, content: message.content ?? null }; } } throw new OpenAIError('stream ended without producing a ChatCompletionMessage with role=assistant'); }, _AbstractChatCompletionRunner_getFinalFunctionCall = function _AbstractChatCompletionRunner_getFinalFunctionCall() { for (let i = this.messages.length - 1; i >= 0; i--) { const message = this.messages[i]; if (isAssistantMessage(message) && message?.function_call) { return message.function_call; } if (isAssistantMessage(message) && message?.tool_calls?.length) { return message.tool_calls.at(-1)?.function; } } return; }, _AbstractChatCompletionRunner_getFinalFunctionCallResult = function _AbstractChatCompletionRunner_getFinalFunctionCallResult() { for (let i = this.messages.length - 1; i >= 0; i--) { const message = this.messages[i]; if (isFunctionMessage(message) && message.content != null) { return message.content; } if (isToolMessage(message) && message.content != null && this.messages.some((x) => x.role === 'assistant' && x.tool_calls?.some((y) => y.type === 'function' && y.id === message.tool_call_id))) { return message.content; } } return; }, _AbstractChatCompletionRunner_calculateTotalUsage = function _AbstractChatCompletionRunner_calculateTotalUsage() { const total = { completion_tokens: 0, prompt_tokens: 0, total_tokens: 0, }; for (const { usage } of this._chatCompletions) { if (usage) { total.completion_tokens += usage.completion_tokens; total.prompt_tokens += usage.prompt_tokens; total.total_tokens += usage.total_tokens; } } return total; }, _AbstractChatCompletionRunner_validateParams = function _AbstractChatCompletionRunner_validateParams(params) { if (params.n != null && params.n > 1) { throw new OpenAIError('ChatCompletion convenience helpers only support n=1 at this time. To use n>1, please use chat.completions.create() directly.'); } }, _AbstractChatCompletionRunner_stringifyFunctionCallResult = function _AbstractChatCompletionRunner_stringifyFunctionCallResult(rawContent) { return (typeof rawContent === 'string' ? rawContent : rawContent === undefined ? 'undefined' : JSON.stringify(rawContent)); }; //# sourceMappingURL=AbstractChatCompletionRunner.mjs.map