openai 4.14.2 → 4.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +114 -1
- package/core.d.ts +1 -0
- package/core.d.ts.map +1 -1
- package/core.js +5 -1
- package/core.js.map +1 -1
- package/core.mjs +5 -1
- package/core.mjs.map +1 -1
- package/index.d.mts +2 -0
- package/index.d.ts +2 -0
- package/index.d.ts.map +1 -1
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/index.mjs +2 -0
- package/index.mjs.map +1 -1
- package/lib/AbstractChatCompletionRunner.d.ts +111 -0
- package/lib/AbstractChatCompletionRunner.d.ts.map +1 -0
- package/lib/AbstractChatCompletionRunner.js +386 -0
- package/lib/AbstractChatCompletionRunner.js.map +1 -0
- package/lib/AbstractChatCompletionRunner.mjs +382 -0
- package/lib/AbstractChatCompletionRunner.mjs.map +1 -0
- package/lib/ChatCompletionRunFunctions.test.d.ts +2 -0
- package/lib/ChatCompletionRunFunctions.test.d.ts.map +1 -0
- package/lib/ChatCompletionRunFunctions.test.js +1850 -0
- package/lib/ChatCompletionRunFunctions.test.js.map +1 -0
- package/lib/ChatCompletionRunFunctions.test.mjs +1845 -0
- package/lib/ChatCompletionRunFunctions.test.mjs.map +1 -0
- package/lib/ChatCompletionRunner.d.ts +17 -0
- package/lib/ChatCompletionRunner.d.ts.map +1 -0
- package/lib/ChatCompletionRunner.js +19 -0
- package/lib/ChatCompletionRunner.js.map +1 -0
- package/lib/ChatCompletionRunner.mjs +15 -0
- package/lib/ChatCompletionRunner.mjs.map +1 -0
- package/lib/ChatCompletionStream.d.ts +111 -0
- package/lib/ChatCompletionStream.d.ts.map +1 -0
- package/lib/ChatCompletionStream.js +210 -0
- package/lib/ChatCompletionStream.js.map +1 -0
- package/lib/ChatCompletionStream.mjs +206 -0
- package/lib/ChatCompletionStream.mjs.map +1 -0
- package/lib/ChatCompletionStreamingRunner.d.ts +20 -0
- package/lib/ChatCompletionStreamingRunner.d.ts.map +1 -0
- package/lib/ChatCompletionStreamingRunner.js +18 -0
- package/lib/ChatCompletionStreamingRunner.js.map +1 -0
- package/lib/ChatCompletionStreamingRunner.mjs +14 -0
- package/lib/ChatCompletionStreamingRunner.mjs.map +1 -0
- package/lib/RunnableFunction.d.ts +70 -0
- package/lib/RunnableFunction.d.ts.map +1 -0
- package/lib/RunnableFunction.js +22 -0
- package/lib/RunnableFunction.js.map +1 -0
- package/lib/RunnableFunction.mjs +17 -0
- package/lib/RunnableFunction.mjs.map +1 -0
- package/lib/jsonschema.d.ts +106 -0
- package/lib/jsonschema.d.ts.map +1 -0
- package/lib/jsonschema.js +11 -0
- package/lib/jsonschema.js.map +1 -0
- package/lib/jsonschema.mjs +10 -0
- package/lib/jsonschema.mjs.map +1 -0
- package/package.json +1 -1
- package/resources/beta/beta.d.ts +9 -0
- package/resources/beta/beta.d.ts.map +1 -0
- package/resources/beta/beta.js +40 -0
- package/resources/beta/beta.js.map +1 -0
- package/resources/beta/beta.mjs +13 -0
- package/resources/beta/beta.mjs.map +1 -0
- package/resources/beta/chat/chat.d.ts +9 -0
- package/resources/beta/chat/chat.d.ts.map +1 -0
- package/resources/beta/chat/chat.js +40 -0
- package/resources/beta/chat/chat.js.map +1 -0
- package/resources/beta/chat/chat.mjs +13 -0
- package/resources/beta/chat/chat.mjs.map +1 -0
- package/resources/beta/chat/completions.d.ts +28 -0
- package/resources/beta/chat/completions.d.ts.map +1 -0
- package/resources/beta/chat/completions.js +32 -0
- package/resources/beta/chat/completions.js.map +1 -0
- package/resources/beta/chat/completions.mjs +24 -0
- package/resources/beta/chat/completions.mjs.map +1 -0
- package/resources/beta/chat/index.d.ts +3 -0
- package/resources/beta/chat/index.d.ts.map +1 -0
- package/resources/beta/chat/index.js +9 -0
- package/resources/beta/chat/index.js.map +1 -0
- package/resources/beta/chat/index.mjs +4 -0
- package/resources/beta/chat/index.mjs.map +1 -0
- package/resources/beta/index.d.ts +3 -0
- package/resources/beta/index.d.ts.map +1 -0
- package/resources/beta/index.js +9 -0
- package/resources/beta/index.js.map +1 -0
- package/resources/beta/index.mjs +4 -0
- package/resources/beta/index.mjs.map +1 -0
- package/resources/index.d.ts +1 -0
- package/resources/index.d.ts.map +1 -1
- package/resources/index.js +3 -1
- package/resources/index.js.map +1 -1
- package/resources/index.mjs +1 -0
- package/resources/index.mjs.map +1 -1
- package/src/core.ts +11 -2
- package/src/index.ts +3 -0
- package/src/lib/AbstractChatCompletionRunner.ts +488 -0
- package/src/lib/ChatCompletionRunFunctions.test.ts +1987 -0
- package/src/lib/ChatCompletionRunner.ts +42 -0
- package/src/lib/ChatCompletionStream.ts +327 -0
- package/src/lib/ChatCompletionStreamingRunner.ts +43 -0
- package/src/lib/RunnableFunction.ts +96 -0
- package/src/lib/jsonschema.ts +148 -0
- package/src/resources/beta/beta.ts +12 -0
- package/src/resources/beta/chat/chat.ts +12 -0
- package/src/resources/beta/chat/completions.ts +70 -0
- package/src/resources/beta/chat/index.ts +4 -0
- package/src/resources/beta/index.ts +4 -0
- package/src/resources/index.ts +1 -0
- package/src/streaming.ts +13 -4
- package/src/version.ts +1 -1
- package/streaming.d.ts +13 -0
- package/streaming.d.ts.map +1 -1
- package/streaming.js +13 -4
- package/streaming.js.map +1 -1
- package/streaming.mjs +13 -4
- package/streaming.mjs.map +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import * as Core from "../core";
|
|
2
|
+
import { type CompletionUsage } from "../resources/completions";
|
|
3
|
+
import {
|
|
4
|
+
type Completions,
|
|
5
|
+
type ChatCompletion,
|
|
6
|
+
type ChatCompletionMessage,
|
|
7
|
+
type ChatCompletionMessageParam,
|
|
8
|
+
type ChatCompletionCreateParams,
|
|
9
|
+
} from "../resources/chat/completions";
|
|
10
|
+
import { APIUserAbortError, OpenAIError } from "../error";
|
|
11
|
+
import {
|
|
12
|
+
type RunnableFunction,
|
|
13
|
+
isRunnableFunctionWithParse,
|
|
14
|
+
type BaseFunctionsArgs,
|
|
15
|
+
} from './RunnableFunction';
|
|
16
|
+
import { ChatCompletionFunctionRunnerParams } from './ChatCompletionRunner';
|
|
17
|
+
import { ChatCompletionStreamingFunctionRunnerParams } from './ChatCompletionStreamingRunner';
|
|
18
|
+
|
|
19
|
+
export abstract class AbstractChatCompletionRunner<
|
|
20
|
+
Events extends CustomEvents<any> = AbstractChatCompletionRunnerEvents,
|
|
21
|
+
> {
|
|
22
|
+
controller: AbortController = new AbortController();
|
|
23
|
+
|
|
24
|
+
#connectedPromise: Promise<void>;
|
|
25
|
+
#resolveConnectedPromise: () => void = () => {};
|
|
26
|
+
#rejectConnectedPromise: (error: OpenAIError) => void = () => {};
|
|
27
|
+
|
|
28
|
+
#endPromise: Promise<void>;
|
|
29
|
+
#resolveEndPromise: () => void = () => {};
|
|
30
|
+
#rejectEndPromise: (error: OpenAIError) => void = () => {};
|
|
31
|
+
|
|
32
|
+
#listeners: { [Event in keyof Events]?: ListenersForEvent<Events, Event> } = {};
|
|
33
|
+
|
|
34
|
+
protected _chatCompletions: ChatCompletion[] = [];
|
|
35
|
+
messages: (ChatCompletionMessage | ChatCompletionMessageParam)[] = [];
|
|
36
|
+
|
|
37
|
+
#ended = false;
|
|
38
|
+
#errored = false;
|
|
39
|
+
#aborted = false;
|
|
40
|
+
#catchingPromiseCreated = false;
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
this.#connectedPromise = new Promise<void>((resolve, reject) => {
|
|
44
|
+
this.#resolveConnectedPromise = resolve;
|
|
45
|
+
this.#rejectConnectedPromise = reject;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
this.#endPromise = new Promise<void>((resolve, reject) => {
|
|
49
|
+
this.#resolveEndPromise = resolve;
|
|
50
|
+
this.#rejectEndPromise = reject;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Don't let these promises cause unhandled rejection errors.
|
|
54
|
+
// we will manually cause an unhandled rejection error later
|
|
55
|
+
// if the user hasn't registered any error listener or called
|
|
56
|
+
// any promise-returning method.
|
|
57
|
+
this.#connectedPromise.catch(() => {});
|
|
58
|
+
this.#endPromise.catch(() => {});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected _run(executor: () => Promise<any>) {
|
|
62
|
+
// Unfortunately if we call `executor()` immediately we get runtime errors about
|
|
63
|
+
// references to `this` before the `super()` constructor call returns.
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
executor().then(() => {
|
|
66
|
+
this._emitFinal();
|
|
67
|
+
this._emit('end');
|
|
68
|
+
}, this.#handleError);
|
|
69
|
+
}, 0);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected _addChatCompletion(chatCompletion: ChatCompletion): ChatCompletion {
|
|
73
|
+
this._chatCompletions.push(chatCompletion);
|
|
74
|
+
this._emit('chatCompletion', chatCompletion);
|
|
75
|
+
const message = chatCompletion.choices[0]?.message;
|
|
76
|
+
if (message) this._addMessage(message);
|
|
77
|
+
return chatCompletion;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
protected _addMessage(message: ChatCompletionMessage | ChatCompletionMessageParam, emit = true) {
|
|
81
|
+
this.messages.push(message);
|
|
82
|
+
if (emit) {
|
|
83
|
+
this._emit('message', message);
|
|
84
|
+
if (message.role === 'function' && message.content) {
|
|
85
|
+
this._emit('functionCallResult', message.content);
|
|
86
|
+
} else if (message.function_call) {
|
|
87
|
+
this._emit('functionCall', message.function_call);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
protected _connected() {
|
|
93
|
+
if (this.ended) return;
|
|
94
|
+
this.#resolveConnectedPromise();
|
|
95
|
+
this._emit('connect');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
get ended(): boolean {
|
|
99
|
+
return this.#ended;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
get errored(): boolean {
|
|
103
|
+
return this.#errored;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get aborted(): boolean {
|
|
107
|
+
return this.#aborted;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
abort() {
|
|
111
|
+
this.controller.abort();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Adds the listener function to the end of the listeners array for the event.
|
|
116
|
+
* No checks are made to see if the listener has already been added. Multiple calls passing
|
|
117
|
+
* the same combination of event and listener will result in the listener being added, and
|
|
118
|
+
* called, multiple times.
|
|
119
|
+
* @returns this ChatCompletionStream, so that calls can be chained
|
|
120
|
+
*/
|
|
121
|
+
on<Event extends keyof Events>(event: Event, listener: ListenerForEvent<Events, Event>): this {
|
|
122
|
+
const listeners: ListenersForEvent<Events, Event> =
|
|
123
|
+
this.#listeners[event] || (this.#listeners[event] = []);
|
|
124
|
+
listeners.push({ listener });
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Removes the specified listener from the listener array for the event.
|
|
130
|
+
* off() will remove, at most, one instance of a listener from the listener array. If any single
|
|
131
|
+
* listener has been added multiple times to the listener array for the specified event, then
|
|
132
|
+
* off() must be called multiple times to remove each instance.
|
|
133
|
+
* @returns this ChatCompletionStream, so that calls can be chained
|
|
134
|
+
*/
|
|
135
|
+
off<Event extends keyof Events>(event: Event, listener: ListenerForEvent<Events, Event>): this {
|
|
136
|
+
const listeners = this.#listeners[event];
|
|
137
|
+
if (!listeners) return this;
|
|
138
|
+
const index = listeners.findIndex((l) => l.listener === listener);
|
|
139
|
+
if (index >= 0) listeners.splice(index, 1);
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Adds a one-time listener function for the event. The next time the event is triggered,
|
|
145
|
+
* this listener is removed and then invoked.
|
|
146
|
+
* @returns this ChatCompletionStream, so that calls can be chained
|
|
147
|
+
*/
|
|
148
|
+
once<Event extends keyof Events>(event: Event, listener: ListenerForEvent<Events, Event>): this {
|
|
149
|
+
const listeners: ListenersForEvent<Events, Event> =
|
|
150
|
+
this.#listeners[event] || (this.#listeners[event] = []);
|
|
151
|
+
listeners.push({ listener, once: true });
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* This is similar to `.once()`, but returns a Promise that resolves the next time
|
|
157
|
+
* the event is triggered, instead of calling a listener callback.
|
|
158
|
+
* @returns a Promise that resolves the next time given event is triggered,
|
|
159
|
+
* or rejects if an error is emitted. (If you request the 'error' event,
|
|
160
|
+
* returns a promise that resolves with the error).
|
|
161
|
+
*
|
|
162
|
+
* Example:
|
|
163
|
+
*
|
|
164
|
+
* const message = await stream.emitted('message') // rejects if the stream errors
|
|
165
|
+
*/
|
|
166
|
+
emitted<Event extends keyof Events>(
|
|
167
|
+
event: Event,
|
|
168
|
+
): Promise<
|
|
169
|
+
EventParameters<Events, Event> extends [infer Param] ? Param
|
|
170
|
+
: EventParameters<Events, Event> extends [] ? void
|
|
171
|
+
: EventParameters<Events, Event>
|
|
172
|
+
> {
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
174
|
+
this.#catchingPromiseCreated = true;
|
|
175
|
+
if (event !== 'error') this.once('error', reject);
|
|
176
|
+
this.once(event, resolve as any);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async done(): Promise<void> {
|
|
181
|
+
this.#catchingPromiseCreated = true;
|
|
182
|
+
await this.#endPromise;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @returns a promise that resolves with the final ChatCompletion, or rejects
|
|
187
|
+
* if an error occurred or the stream ended prematurely without producing a ChatCompletion.
|
|
188
|
+
*/
|
|
189
|
+
async finalChatCompletion(): Promise<ChatCompletion> {
|
|
190
|
+
await this.done();
|
|
191
|
+
const completion = this._chatCompletions[this._chatCompletions.length - 1];
|
|
192
|
+
if (!completion) throw new OpenAIError('stream ended without producing a ChatCompletion');
|
|
193
|
+
return completion;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
#getFinalContent(): string | null {
|
|
197
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
198
|
+
const message = this.messages[i];
|
|
199
|
+
if (message?.role === 'assistant') return message.content;
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @returns a promise that resolves with the content of the final ChatCompletionMessage, or rejects
|
|
206
|
+
* if an error occurred or the stream ended prematurely without producing a ChatCompletionMessage.
|
|
207
|
+
*/
|
|
208
|
+
async finalContent(): Promise<string | null> {
|
|
209
|
+
await this.done();
|
|
210
|
+
return this.#getFinalContent();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @returns a promise that resolves with the the final ChatCompletionMessage, or rejects
|
|
215
|
+
* if an error occurred or the stream ended prematurely without producing a ChatCompletionMessage.
|
|
216
|
+
*/
|
|
217
|
+
async finalMessage(): Promise<ChatCompletionMessage> {
|
|
218
|
+
await this.done();
|
|
219
|
+
const message = this.messages[this.messages.length - 1];
|
|
220
|
+
if (!message) throw new OpenAIError('stream ended without producing a ChatCompletionMessage');
|
|
221
|
+
return message;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
#getFinalFunctionCall(): ChatCompletionMessage.FunctionCall | undefined {
|
|
225
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
226
|
+
const message = this.messages[i];
|
|
227
|
+
if (message?.function_call) return message.function_call;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @returns a promise that resolves with the content of the final FunctionCall, or rejects
|
|
233
|
+
* if an error occurred or the stream ended prematurely without producing a ChatCompletionMessage.
|
|
234
|
+
*/
|
|
235
|
+
async finalFunctionCall(): Promise<ChatCompletionMessage.FunctionCall | undefined> {
|
|
236
|
+
await this.done();
|
|
237
|
+
return this.#getFinalFunctionCall();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
#getFinalFunctionCallResult(): string | undefined {
|
|
241
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
242
|
+
const message = this.messages[i];
|
|
243
|
+
if (message?.role === 'function' && message.content != null) return message.content;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async finalFunctionCallResult(): Promise<string | undefined> {
|
|
248
|
+
await this.done();
|
|
249
|
+
return this.#getFinalFunctionCallResult();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
#calculateTotalUsage(): CompletionUsage {
|
|
253
|
+
const total: CompletionUsage = {
|
|
254
|
+
completion_tokens: 0,
|
|
255
|
+
prompt_tokens: 0,
|
|
256
|
+
total_tokens: 0,
|
|
257
|
+
};
|
|
258
|
+
for (const { usage } of this._chatCompletions) {
|
|
259
|
+
if (usage) {
|
|
260
|
+
total.completion_tokens += usage.completion_tokens;
|
|
261
|
+
total.prompt_tokens += usage.prompt_tokens;
|
|
262
|
+
total.total_tokens += usage.total_tokens;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return total;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async totalUsage(): Promise<CompletionUsage> {
|
|
269
|
+
await this.done();
|
|
270
|
+
return this.#calculateTotalUsage();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
allChatCompletions(): ChatCompletion[] {
|
|
274
|
+
return [...this._chatCompletions];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
#handleError = (error: unknown) => {
|
|
278
|
+
this.#errored = true;
|
|
279
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
280
|
+
error = new APIUserAbortError();
|
|
281
|
+
}
|
|
282
|
+
if (error instanceof APIUserAbortError) {
|
|
283
|
+
this.#aborted = true;
|
|
284
|
+
this._emit('abort', error);
|
|
285
|
+
}
|
|
286
|
+
const openAIError: OpenAIError =
|
|
287
|
+
error instanceof OpenAIError ? error : (
|
|
288
|
+
new OpenAIError(error instanceof Error ? error.message : String(error))
|
|
289
|
+
);
|
|
290
|
+
this._emit('error', openAIError);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
protected _emit<Event extends keyof Events>(event: Event, ...args: EventParameters<Events, Event>) {
|
|
294
|
+
// make sure we don't emit any events after end
|
|
295
|
+
if (this.#ended) return;
|
|
296
|
+
|
|
297
|
+
if (event === 'end') {
|
|
298
|
+
this.#ended = true;
|
|
299
|
+
this.#resolveEndPromise();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const listeners: ListenersForEvent<Events, Event> | undefined = this.#listeners[event];
|
|
303
|
+
if (listeners) {
|
|
304
|
+
this.#listeners[event] = listeners.filter((l) => !l.once) as any;
|
|
305
|
+
listeners.forEach(({ listener }: any) => listener(...args));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (event === 'error') {
|
|
309
|
+
// NOTE: _emit('error', error) should only be called from #handleError().
|
|
310
|
+
|
|
311
|
+
const error = args[0] as OpenAIError;
|
|
312
|
+
if (!this.#catchingPromiseCreated && !listeners?.length) {
|
|
313
|
+
// Trigger an unhandled rejection if the user hasn't registered any error handlers.
|
|
314
|
+
// If you are seeing stack traces here, make sure to handle errors via either:
|
|
315
|
+
// - runner.on('error', () => ...)
|
|
316
|
+
// - await runner.done()
|
|
317
|
+
// - await runner.finalChatCompletion()
|
|
318
|
+
// - etc.
|
|
319
|
+
Promise.reject(error);
|
|
320
|
+
}
|
|
321
|
+
this.#rejectConnectedPromise(error);
|
|
322
|
+
this.#rejectEndPromise(error);
|
|
323
|
+
this._emit('end');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
protected _emitFinal() {
|
|
328
|
+
const completion = this._chatCompletions[this._chatCompletions.length - 1];
|
|
329
|
+
if (completion) this._emit('finalChatCompletion', completion);
|
|
330
|
+
const finalMessage = this.messages[this.messages.length - 1];
|
|
331
|
+
if (finalMessage) this._emit('finalMessage', finalMessage);
|
|
332
|
+
const finalContent = this.#getFinalContent();
|
|
333
|
+
if (finalContent) this._emit('finalContent', finalContent);
|
|
334
|
+
|
|
335
|
+
const finalFunctionCall = this.#getFinalFunctionCall();
|
|
336
|
+
if (finalFunctionCall) this._emit('finalFunctionCall', finalFunctionCall);
|
|
337
|
+
|
|
338
|
+
const finalFunctionCallResult = this.#getFinalFunctionCallResult();
|
|
339
|
+
if (finalFunctionCallResult != null) this._emit('finalFunctionCallResult', finalFunctionCallResult);
|
|
340
|
+
|
|
341
|
+
if (this._chatCompletions.some((c) => c.usage)) {
|
|
342
|
+
this._emit('totalUsage', this.#calculateTotalUsage());
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
protected async _createChatCompletion(
|
|
347
|
+
completions: Completions,
|
|
348
|
+
params: ChatCompletionCreateParams,
|
|
349
|
+
options?: Core.RequestOptions,
|
|
350
|
+
): Promise<ChatCompletion> {
|
|
351
|
+
const signal = options?.signal;
|
|
352
|
+
if (signal) {
|
|
353
|
+
if (signal.aborted) this.controller.abort();
|
|
354
|
+
signal.addEventListener('abort', () => this.controller.abort());
|
|
355
|
+
}
|
|
356
|
+
const chatCompletion = await completions.create(
|
|
357
|
+
{ ...params, stream: false },
|
|
358
|
+
{ ...options, signal: this.controller.signal },
|
|
359
|
+
);
|
|
360
|
+
this._connected();
|
|
361
|
+
return this._addChatCompletion(chatCompletion);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
protected async _runChatCompletion(
|
|
365
|
+
completions: Completions,
|
|
366
|
+
params: ChatCompletionCreateParams,
|
|
367
|
+
options?: Core.RequestOptions,
|
|
368
|
+
): Promise<ChatCompletion> {
|
|
369
|
+
for (const message of params.messages) {
|
|
370
|
+
this._addMessage(message, false);
|
|
371
|
+
}
|
|
372
|
+
return await this._createChatCompletion(completions, params, options);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
protected async _runFunctions<FunctionsArgs extends BaseFunctionsArgs>(
|
|
376
|
+
completions: Completions,
|
|
377
|
+
params:
|
|
378
|
+
| ChatCompletionFunctionRunnerParams<FunctionsArgs>
|
|
379
|
+
| ChatCompletionStreamingFunctionRunnerParams<FunctionsArgs>,
|
|
380
|
+
options?: Core.RequestOptions & { maxChatCompletions?: number },
|
|
381
|
+
) {
|
|
382
|
+
const { function_call = 'auto', stream, ...restParams } = params;
|
|
383
|
+
const isSingleFunctionCall = typeof function_call !== 'string' && function_call?.name;
|
|
384
|
+
|
|
385
|
+
const functionsByName: Record<string, RunnableFunction<any>> = {};
|
|
386
|
+
for (const f of params.functions) {
|
|
387
|
+
functionsByName[f.name || f.function.name] = f;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const functions: ChatCompletionCreateParams.Function[] = params.functions.map(
|
|
391
|
+
(f): ChatCompletionCreateParams.Function => ({
|
|
392
|
+
name: f.name || f.function.name,
|
|
393
|
+
parameters: f.parameters as Record<string, unknown>,
|
|
394
|
+
description: f.description,
|
|
395
|
+
}),
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
for (const message of params.messages) {
|
|
399
|
+
this._addMessage(message, false);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
for (let i = 0; i < (options?.maxChatCompletions ?? 5); ++i) {
|
|
403
|
+
const chatCompletion: ChatCompletion = await this._createChatCompletion(
|
|
404
|
+
completions,
|
|
405
|
+
{
|
|
406
|
+
...restParams,
|
|
407
|
+
function_call,
|
|
408
|
+
functions,
|
|
409
|
+
messages: [...this.messages],
|
|
410
|
+
},
|
|
411
|
+
options,
|
|
412
|
+
);
|
|
413
|
+
const message = chatCompletion.choices[0]?.message;
|
|
414
|
+
if (!message) {
|
|
415
|
+
throw new OpenAIError(`missing message in ChatCompletion response`);
|
|
416
|
+
}
|
|
417
|
+
if (!message.function_call) return;
|
|
418
|
+
const { name, arguments: args } = message.function_call;
|
|
419
|
+
const fn = functionsByName[name];
|
|
420
|
+
if (!fn || (typeof function_call !== 'string' && name !== function_call?.name)) {
|
|
421
|
+
this._addMessage({
|
|
422
|
+
role: 'function',
|
|
423
|
+
name,
|
|
424
|
+
content: `Invalid function_call: ${JSON.stringify(name)}. Available options are: ${functions
|
|
425
|
+
.map((f) => JSON.stringify(f.name))
|
|
426
|
+
.join(', ')}. Please try again`,
|
|
427
|
+
});
|
|
428
|
+
if (isSingleFunctionCall) return;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
let parsed;
|
|
432
|
+
try {
|
|
433
|
+
parsed = isRunnableFunctionWithParse(fn) ? await fn.parse(args) : args;
|
|
434
|
+
} catch (error) {
|
|
435
|
+
this._addMessage({
|
|
436
|
+
role: 'function',
|
|
437
|
+
name,
|
|
438
|
+
content: error instanceof Error ? error.message : String(error),
|
|
439
|
+
});
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
const rawContent = await (fn.function as any)(parsed as any, this);
|
|
443
|
+
const content =
|
|
444
|
+
typeof rawContent === 'string' ? rawContent
|
|
445
|
+
: rawContent === undefined ? 'undefined'
|
|
446
|
+
: JSON.stringify(rawContent);
|
|
447
|
+
this._addMessage({ role: 'function', name, content });
|
|
448
|
+
|
|
449
|
+
if (isSingleFunctionCall) return;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
type CustomEvents<Event extends string> = {
|
|
455
|
+
[k in Event]: k extends keyof AbstractChatCompletionRunnerEvents ? AbstractChatCompletionRunnerEvents[k]
|
|
456
|
+
: (...args: any[]) => void;
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
type ListenerForEvent<
|
|
460
|
+
Events extends CustomEvents<any>,
|
|
461
|
+
Event extends keyof Events,
|
|
462
|
+
> = Event extends keyof AbstractChatCompletionRunnerEvents ? AbstractChatCompletionRunnerEvents[Event]
|
|
463
|
+
: Events[Event];
|
|
464
|
+
|
|
465
|
+
type ListenersForEvent<Events extends CustomEvents<any>, Event extends keyof Events> = Array<{
|
|
466
|
+
listener: ListenerForEvent<Events, Event>;
|
|
467
|
+
once?: boolean;
|
|
468
|
+
}>;
|
|
469
|
+
type EventParameters<Events extends CustomEvents<any>, Event extends keyof Events> = Parameters<
|
|
470
|
+
ListenerForEvent<Events, Event>
|
|
471
|
+
>;
|
|
472
|
+
|
|
473
|
+
export interface AbstractChatCompletionRunnerEvents {
|
|
474
|
+
connect: () => void;
|
|
475
|
+
functionCall: (functionCall: ChatCompletionMessage.FunctionCall) => void;
|
|
476
|
+
message: (message: ChatCompletionMessage | ChatCompletionMessageParam) => void;
|
|
477
|
+
chatCompletion: (completion: ChatCompletion) => void;
|
|
478
|
+
finalContent: (contentSnapshot: string) => void;
|
|
479
|
+
finalMessage: (message: ChatCompletionMessage | ChatCompletionMessageParam) => void;
|
|
480
|
+
finalChatCompletion: (completion: ChatCompletion) => void;
|
|
481
|
+
finalFunctionCall: (functionCall: ChatCompletionMessage.FunctionCall) => void;
|
|
482
|
+
functionCallResult: (content: string) => void;
|
|
483
|
+
finalFunctionCallResult: (content: string) => void;
|
|
484
|
+
error: (error: OpenAIError) => void;
|
|
485
|
+
abort: (error: APIUserAbortError) => void;
|
|
486
|
+
end: () => void;
|
|
487
|
+
totalUsage: (usage: CompletionUsage) => void;
|
|
488
|
+
}
|