| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- "use strict";
- 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_getFinalContent, _AbstractChatCompletionRunner_getFinalMessage, _AbstractChatCompletionRunner_getFinalFunctionCall, _AbstractChatCompletionRunner_getFinalFunctionCallResult, _AbstractChatCompletionRunner_calculateTotalUsage, _AbstractChatCompletionRunner_validateParams, _AbstractChatCompletionRunner_stringifyFunctionCallResult;
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.AbstractChatCompletionRunner = void 0;
- const error_1 = require("../error.js");
- const RunnableFunction_1 = require("./RunnableFunction.js");
- const chatCompletionUtils_1 = require("./chatCompletionUtils.js");
- const EventStream_1 = require("./EventStream.js");
- const parser_1 = require("../lib/parser.js");
- const DEFAULT_MAX_CHAT_COMPLETIONS = 10;
- class AbstractChatCompletionRunner extends EventStream_1.EventStream {
- constructor() {
- super(...arguments);
- _AbstractChatCompletionRunner_instances.add(this);
- this._chatCompletions = [];
- this.messages = [];
- }
- _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 (((0, chatCompletionUtils_1.isFunctionMessage)(message) || (0, chatCompletionUtils_1.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 ((0, chatCompletionUtils_1.isAssistantMessage)(message) && message.function_call) {
- this._emit('functionCall', message.function_call);
- }
- else if ((0, chatCompletionUtils_1.isAssistantMessage)(message) && message.tool_calls) {
- for (const tool_call of message.tool_calls) {
- if (tool_call.type === 'function') {
- this._emit('functionCall', tool_call.function);
- }
- }
- }
- }
- }
- /**
- * @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 error_1.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];
- }
- _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(client, 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 client.chat.completions.create({ ...params, stream: false }, { ...options, signal: this.controller.signal });
- this._connected();
- return this._addChatCompletion((0, parser_1.parseChatCompletion)(chatCompletion, params));
- }
- async _runChatCompletion(client, params, options) {
- for (const message of params.messages) {
- this._addMessage(message, false);
- }
- return await this._createChatCompletion(client, params, options);
- }
- async _runFunctions(client, 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(client, {
- ...restParams,
- function_call,
- functions,
- messages: [...this.messages],
- }, options);
- const message = chatCompletion.choices[0]?.message;
- if (!message) {
- throw new error_1.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 = (0, RunnableFunction_1.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(client, 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 || {};
- // TODO(someday): clean this logic up
- const inputTools = params.tools.map((tool) => {
- if ((0, parser_1.isAutoParsableTool)(tool)) {
- if (!tool.$callback) {
- throw new error_1.OpenAIError('Tool given to `.runTools()` that does not have an associated function');
- }
- return {
- type: 'function',
- function: {
- function: tool.$callback,
- name: tool.function.name,
- description: tool.function.description || '',
- parameters: tool.function.parameters,
- parse: tool.$parseRaw,
- strict: true,
- },
- };
- }
- return tool;
- });
- const functionsByName = {};
- for (const f of inputTools) {
- if (f.type === 'function') {
- functionsByName[f.function.name || f.function.function.name] = f.function;
- }
- }
- const tools = 'tools' in params ?
- inputTools.map((t) => t.type === 'function' ?
- {
- type: 'function',
- function: {
- name: t.function.name || t.function.function.name,
- parameters: t.function.parameters,
- description: t.function.description,
- strict: t.function.strict,
- },
- }
- : t)
- : undefined;
- for (const message of params.messages) {
- this._addMessage(message, false);
- }
- for (let i = 0; i < maxChatCompletions; ++i) {
- const chatCompletion = await this._createChatCompletion(client, {
- ...restParams,
- tool_choice,
- tools,
- messages: [...this.messages],
- }, options);
- const message = chatCompletion.choices[0]?.message;
- if (!message) {
- throw new error_1.OpenAIError(`missing message in ChatCompletion response`);
- }
- if (!message.tool_calls?.length) {
- 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: ${Object.keys(functionsByName)
- .map((name) => JSON.stringify(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 = (0, RunnableFunction_1.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;
- }
- }
- exports.AbstractChatCompletionRunner = AbstractChatCompletionRunner;
- _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 ((0, chatCompletionUtils_1.isAssistantMessage)(message)) {
- const { function_call, ...rest } = message;
- // TODO: support audio here
- const ret = {
- ...rest,
- content: message.content ?? null,
- refusal: message.refusal ?? null,
- };
- if (function_call) {
- ret.function_call = function_call;
- }
- return ret;
- }
- }
- throw new error_1.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 ((0, chatCompletionUtils_1.isAssistantMessage)(message) && message?.function_call) {
- return message.function_call;
- }
- if ((0, chatCompletionUtils_1.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 ((0, chatCompletionUtils_1.isFunctionMessage)(message) && message.content != null) {
- return message.content;
- }
- if ((0, chatCompletionUtils_1.isToolMessage)(message) &&
- message.content != null &&
- typeof message.content === 'string' &&
- 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 error_1.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.js.map
|