openai 4.20.1 → 4.22.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 +37 -0
- package/README.md +3 -3
- package/error.d.ts.map +1 -1
- package/error.js +2 -1
- package/error.js.map +1 -1
- package/error.mjs +2 -1
- package/error.mjs.map +1 -1
- package/index.d.mts +7 -5
- package/index.d.ts +7 -5
- package/index.d.ts.map +1 -1
- package/index.js +5 -5
- package/index.js.map +1 -1
- package/index.mjs +5 -5
- package/index.mjs.map +1 -1
- package/lib/AbstractChatCompletionRunner.d.ts +1 -1
- package/lib/AbstractChatCompletionRunner.d.ts.map +1 -1
- package/lib/AbstractChatCompletionRunner.js +21 -6
- package/lib/AbstractChatCompletionRunner.js.map +1 -1
- package/lib/AbstractChatCompletionRunner.mjs +21 -6
- package/lib/AbstractChatCompletionRunner.mjs.map +1 -1
- package/lib/ChatCompletionRunFunctions.test.js +823 -549
- package/lib/ChatCompletionRunFunctions.test.js.map +1 -1
- package/lib/ChatCompletionRunFunctions.test.mjs +824 -550
- package/lib/ChatCompletionRunFunctions.test.mjs.map +1 -1
- package/lib/ChatCompletionRunner.d.ts +1 -0
- package/lib/ChatCompletionRunner.d.ts.map +1 -1
- package/lib/ChatCompletionRunner.js +11 -2
- package/lib/ChatCompletionRunner.js.map +1 -1
- package/lib/ChatCompletionRunner.mjs +11 -2
- package/lib/ChatCompletionRunner.mjs.map +1 -1
- package/lib/ChatCompletionStreamingRunner.d.ts +1 -0
- package/lib/ChatCompletionStreamingRunner.d.ts.map +1 -1
- package/lib/ChatCompletionStreamingRunner.js +7 -4
- package/lib/ChatCompletionStreamingRunner.js.map +1 -1
- package/lib/ChatCompletionStreamingRunner.mjs +7 -4
- package/lib/ChatCompletionStreamingRunner.mjs.map +1 -1
- package/lib/RunnableFunction.d.ts +19 -3
- package/lib/RunnableFunction.d.ts.map +1 -1
- package/lib/RunnableFunction.js +14 -1
- package/lib/RunnableFunction.js.map +1 -1
- package/lib/RunnableFunction.mjs +12 -0
- package/lib/RunnableFunction.mjs.map +1 -1
- package/package.json +3 -2
- package/resources/audio/speech.d.ts +3 -1
- package/resources/audio/speech.d.ts.map +1 -1
- package/resources/audio/speech.js.map +1 -1
- package/resources/audio/speech.mjs.map +1 -1
- package/resources/beta/chat/completions.d.ts +2 -8
- package/resources/beta/chat/completions.d.ts.map +1 -1
- package/resources/beta/chat/completions.js +2 -1
- package/resources/beta/chat/completions.js.map +1 -1
- package/resources/beta/chat/completions.mjs +1 -1
- package/resources/beta/chat/completions.mjs.map +1 -1
- package/resources/chat/completions.d.ts +52 -34
- package/resources/chat/completions.d.ts.map +1 -1
- package/resources/chat/completions.js.map +1 -1
- package/resources/chat/completions.mjs.map +1 -1
- package/resources/completions.d.ts +2 -2
- package/resources/embeddings.d.ts +2 -1
- package/resources/embeddings.d.ts.map +1 -1
- package/resources/embeddings.js.map +1 -1
- package/resources/embeddings.mjs.map +1 -1
- package/resources/files.d.ts +3 -3
- package/resources/files.js +3 -3
- package/resources/files.mjs +3 -3
- package/resources/shared.d.ts +12 -14
- package/resources/shared.d.ts.map +1 -1
- package/src/error.ts +2 -1
- package/src/index.ts +8 -5
- package/src/lib/AbstractChatCompletionRunner.ts +37 -13
- package/src/lib/ChatCompletionRunFunctions.test.ts +828 -558
- package/src/lib/ChatCompletionRunner.ts +11 -2
- package/src/lib/ChatCompletionStreamingRunner.ts +11 -12
- package/src/lib/RunnableFunction.ts +33 -7
- package/src/resources/audio/speech.ts +3 -1
- package/src/resources/beta/chat/completions.ts +2 -7
- package/src/resources/chat/completions.ts +56 -35
- package/src/resources/completions.ts +2 -2
- package/src/resources/embeddings.ts +2 -1
- package/src/resources/files.ts +3 -3
- package/src/resources/shared.ts +13 -15
- package/src/streaming.ts +4 -1
- package/src/uploads.ts +2 -3
- package/src/version.ts +1 -1
- package/streaming.d.ts.map +1 -1
- package/streaming.js.map +1 -1
- package/streaming.mjs.map +1 -1
- package/uploads.d.ts.map +1 -1
- package/uploads.js +2 -1
- package/uploads.js.map +1 -1
- package/uploads.mjs +2 -1
- package/uploads.mjs.map +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
2
|
import { PassThrough } from 'stream';
|
|
3
|
-
import {
|
|
3
|
+
import { ParsingToolFunction, ChatCompletionStreamingRunner, } from 'openai/resources/beta/chat/completions';
|
|
4
4
|
import { Response } from 'node-fetch';
|
|
5
5
|
import { isAssistantMessage } from "./chatCompletionUtils.mjs";
|
|
6
6
|
/**
|
|
@@ -47,11 +47,15 @@ function mockFetch() {
|
|
|
47
47
|
]);
|
|
48
48
|
}
|
|
49
49
|
function handleRequest(handle) {
|
|
50
|
-
return new Promise((resolve) => {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
51
|
fetchQueue.shift()?.(async (req, init) => {
|
|
52
52
|
try {
|
|
53
53
|
return await handle(req, init);
|
|
54
54
|
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
reject(err);
|
|
57
|
+
return err;
|
|
58
|
+
}
|
|
55
59
|
finally {
|
|
56
60
|
resolve();
|
|
57
61
|
}
|
|
@@ -121,7 +125,7 @@ function* contentChoiceDeltas(content, { index = 0, role = 'assistant', } = {})
|
|
|
121
125
|
}
|
|
122
126
|
// functionCallDeltas returns an async iterator which mocks a delta stream of a functionCall by splitting
|
|
123
127
|
// the argument into chunks separated by whitespace.
|
|
124
|
-
function* functionCallDeltas(args, { index = 0, name, role = 'assistant', }) {
|
|
128
|
+
function* functionCallDeltas(args, { index = 0, id = '123', name, role = 'assistant', }) {
|
|
125
129
|
const deltas = args.split(/\s+/g);
|
|
126
130
|
for (let i = 0; i < deltas.length; i++) {
|
|
127
131
|
yield {
|
|
@@ -129,10 +133,17 @@ function* functionCallDeltas(args, { index = 0, name, role = 'assistant', }) {
|
|
|
129
133
|
finish_reason: i === deltas.length - 1 ? 'function_call' : null,
|
|
130
134
|
delta: {
|
|
131
135
|
role,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
tool_calls: [
|
|
137
|
+
{
|
|
138
|
+
type: 'function',
|
|
139
|
+
index: 0,
|
|
140
|
+
id,
|
|
141
|
+
function: {
|
|
142
|
+
arguments: `${deltas[i] || ''}${i === deltas.length - 1 ? '' : ' '}`,
|
|
143
|
+
...(i === deltas.length - 1 ? { name } : null),
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
],
|
|
136
147
|
},
|
|
137
148
|
};
|
|
138
149
|
}
|
|
@@ -164,7 +175,7 @@ class RunnerListener {
|
|
|
164
175
|
.on('finalFunctionCallResult', (result) => (this.finalFunctionCallResult = result))
|
|
165
176
|
.on('totalUsage', (usage) => (this.totalUsage = usage))
|
|
166
177
|
.on('error', (error) => (this.error = error))
|
|
167
|
-
.on('abort', () => (this.gotAbort = true))
|
|
178
|
+
.on('abort', (error) => ((this.error = error), (this.gotAbort = true)))
|
|
168
179
|
.on('end', () => (this.gotEnd = true))
|
|
169
180
|
.once('message', () => this.onceMessageCallCount++);
|
|
170
181
|
}
|
|
@@ -210,7 +221,7 @@ class RunnerListener {
|
|
|
210
221
|
.map((m) => m.content)
|
|
211
222
|
.filter(Boolean);
|
|
212
223
|
expect(this.contents).toEqual(expectedContents);
|
|
213
|
-
expect(this.finalMessage).toEqual(
|
|
224
|
+
expect(this.finalMessage).toEqual([...this.messages].reverse().find((x) => x.role === 'assistant'));
|
|
214
225
|
expect(await this.runner.finalMessage()).toEqual(this.finalMessage);
|
|
215
226
|
expect(this.finalContent).toEqual(expectedContents[expectedContents.length - 1] ?? null);
|
|
216
227
|
expect(await this.runner.finalContent()).toEqual(this.finalContent);
|
|
@@ -267,6 +278,7 @@ class StreamingRunnerListener {
|
|
|
267
278
|
.on('finalFunctionCall', (functionCall) => (this.finalFunctionCall = functionCall))
|
|
268
279
|
.on('finalFunctionCallResult', (result) => (this.finalFunctionCallResult = result))
|
|
269
280
|
.on('error', (error) => (this.error = error))
|
|
281
|
+
.on('abort', (abort) => (this.error = abort))
|
|
270
282
|
.on('end', () => (this.gotEnd = true));
|
|
271
283
|
}
|
|
272
284
|
async sanityCheck({ error } = {}) {
|
|
@@ -302,7 +314,7 @@ class StreamingRunnerListener {
|
|
|
302
314
|
return;
|
|
303
315
|
if (this.eventContents.length)
|
|
304
316
|
expect(this.eventChunks.length).toBeGreaterThan(0);
|
|
305
|
-
expect(this.finalMessage).toEqual(
|
|
317
|
+
expect(this.finalMessage).toEqual([...this.eventMessages].reverse().find((x) => x.role === 'assistant'));
|
|
306
318
|
expect(await this.runner.finalMessage()).toEqual(this.finalMessage);
|
|
307
319
|
expect(this.finalContent).toEqual(this.eventContents[this.eventContents.length - 1]?.[1] ?? null);
|
|
308
320
|
expect(await this.runner.finalContent()).toEqual(this.finalContent);
|
|
@@ -327,45 +339,54 @@ class StreamingRunnerListener {
|
|
|
327
339
|
}
|
|
328
340
|
function _typeTests() {
|
|
329
341
|
const openai = new OpenAI();
|
|
330
|
-
openai.beta.chat.completions.
|
|
342
|
+
openai.beta.chat.completions.runTools({
|
|
331
343
|
messages: [
|
|
332
344
|
{ role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' },
|
|
333
345
|
],
|
|
334
346
|
model: 'gpt-3.5-turbo',
|
|
335
|
-
|
|
347
|
+
tools: [
|
|
336
348
|
{
|
|
337
|
-
|
|
338
|
-
function:
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
349
|
+
type: 'function',
|
|
350
|
+
function: {
|
|
351
|
+
name: 'numProperties',
|
|
352
|
+
function: (obj) => String(Object.keys(obj).length),
|
|
353
|
+
parameters: { type: 'object' },
|
|
354
|
+
parse: (str) => {
|
|
355
|
+
const result = JSON.parse(str);
|
|
356
|
+
if (!(result instanceof Object) || Array.isArray(result)) {
|
|
357
|
+
throw new Error('must be an object');
|
|
358
|
+
}
|
|
359
|
+
return result;
|
|
360
|
+
},
|
|
361
|
+
description: 'gets the number of properties on an object',
|
|
346
362
|
},
|
|
347
|
-
description: 'gets the number of properties on an object',
|
|
348
363
|
},
|
|
349
364
|
{
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
365
|
+
type: 'function',
|
|
366
|
+
function: {
|
|
367
|
+
function: (str) => String(str.length),
|
|
368
|
+
parameters: { type: 'string' },
|
|
369
|
+
description: 'gets the length of a string',
|
|
370
|
+
},
|
|
353
371
|
},
|
|
354
|
-
// @ts-expect-error function must accept string if parse is omitted
|
|
355
372
|
{
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
373
|
+
type: 'function',
|
|
374
|
+
// @ts-expect-error function must accept string if parse is omitted
|
|
375
|
+
function: {
|
|
376
|
+
function: (obj) => String(Object.keys(obj).length),
|
|
377
|
+
parameters: { type: 'object' },
|
|
378
|
+
description: 'gets the number of properties on an object',
|
|
379
|
+
},
|
|
359
380
|
},
|
|
360
381
|
],
|
|
361
382
|
});
|
|
362
|
-
openai.beta.chat.completions.
|
|
383
|
+
openai.beta.chat.completions.runTools({
|
|
363
384
|
messages: [
|
|
364
385
|
{ role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' },
|
|
365
386
|
],
|
|
366
387
|
model: 'gpt-3.5-turbo',
|
|
367
|
-
|
|
368
|
-
new
|
|
388
|
+
tools: [
|
|
389
|
+
new ParsingToolFunction({
|
|
369
390
|
name: 'numProperties',
|
|
370
391
|
// @ts-expect-error parse and function don't match
|
|
371
392
|
parse: (str) => str,
|
|
@@ -375,13 +396,13 @@ function _typeTests() {
|
|
|
375
396
|
}),
|
|
376
397
|
],
|
|
377
398
|
});
|
|
378
|
-
openai.beta.chat.completions.
|
|
399
|
+
openai.beta.chat.completions.runTools({
|
|
379
400
|
messages: [
|
|
380
401
|
{ role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' },
|
|
381
402
|
],
|
|
382
403
|
model: 'gpt-3.5-turbo',
|
|
383
|
-
|
|
384
|
-
new
|
|
404
|
+
tools: [
|
|
405
|
+
new ParsingToolFunction({
|
|
385
406
|
name: 'numProperties',
|
|
386
407
|
parse: (str) => {
|
|
387
408
|
const result = JSON.parse(str);
|
|
@@ -394,7 +415,7 @@ function _typeTests() {
|
|
|
394
415
|
parameters: { type: 'object' },
|
|
395
416
|
description: 'gets the number of properties on an object',
|
|
396
417
|
}),
|
|
397
|
-
new
|
|
418
|
+
new ParsingToolFunction({
|
|
398
419
|
name: 'keys',
|
|
399
420
|
parse: (str) => {
|
|
400
421
|
const result = JSON.parse(str);
|
|
@@ -407,7 +428,7 @@ function _typeTests() {
|
|
|
407
428
|
parameters: { type: 'object' },
|
|
408
429
|
description: 'gets the number of properties on an object',
|
|
409
430
|
}),
|
|
410
|
-
new
|
|
431
|
+
new ParsingToolFunction({
|
|
411
432
|
name: 'len2',
|
|
412
433
|
// @ts-expect-error parse and function don't match
|
|
413
434
|
parse: (str) => str,
|
|
@@ -417,135 +438,169 @@ function _typeTests() {
|
|
|
417
438
|
}),
|
|
418
439
|
],
|
|
419
440
|
});
|
|
420
|
-
openai.beta.chat.completions.
|
|
441
|
+
openai.beta.chat.completions.runTools({
|
|
421
442
|
messages: [
|
|
422
443
|
{ role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' },
|
|
423
444
|
],
|
|
424
445
|
model: 'gpt-3.5-turbo',
|
|
425
446
|
// @ts-ignore error occurs here in TS 4
|
|
426
|
-
|
|
447
|
+
tools: [
|
|
427
448
|
{
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
449
|
+
type: 'function',
|
|
450
|
+
function: {
|
|
451
|
+
name: 'numProperties',
|
|
452
|
+
parse: (str) => {
|
|
453
|
+
const result = JSON.parse(str);
|
|
454
|
+
if (!(result instanceof Object) || Array.isArray(result)) {
|
|
455
|
+
throw new Error('must be an object');
|
|
456
|
+
}
|
|
457
|
+
return result;
|
|
458
|
+
},
|
|
459
|
+
function: (obj) => String(Object.keys(obj).length),
|
|
460
|
+
parameters: { type: 'object' },
|
|
461
|
+
description: 'gets the number of properties on an object',
|
|
435
462
|
},
|
|
436
|
-
function: (obj) => String(Object.keys(obj).length),
|
|
437
|
-
parameters: { type: 'object' },
|
|
438
|
-
description: 'gets the number of properties on an object',
|
|
439
463
|
},
|
|
440
464
|
{
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
465
|
+
type: 'function',
|
|
466
|
+
function: {
|
|
467
|
+
name: 'keys',
|
|
468
|
+
parse: (str) => {
|
|
469
|
+
const result = JSON.parse(str);
|
|
470
|
+
if (!(result instanceof Object)) {
|
|
471
|
+
throw new Error('must be an Object');
|
|
472
|
+
}
|
|
473
|
+
return result;
|
|
474
|
+
},
|
|
475
|
+
function: (obj) => Object.keys(obj).join(', '),
|
|
476
|
+
parameters: { type: 'object' },
|
|
477
|
+
description: 'gets the number of properties on an object',
|
|
448
478
|
},
|
|
449
|
-
function: (obj) => Object.keys(obj).join(', '),
|
|
450
|
-
parameters: { type: 'object' },
|
|
451
|
-
description: 'gets the number of properties on an object',
|
|
452
479
|
},
|
|
453
480
|
{
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
481
|
+
type: 'function',
|
|
482
|
+
function: {
|
|
483
|
+
name: 'len2',
|
|
484
|
+
parse: (str) => str,
|
|
485
|
+
// @ts-ignore error occurs here in TS 5
|
|
486
|
+
// function input doesn't match parse output
|
|
487
|
+
function: (obj) => String(Object.keys(obj).length),
|
|
488
|
+
parameters: { type: 'object' },
|
|
489
|
+
description: 'gets the number of properties on an object',
|
|
490
|
+
},
|
|
461
491
|
},
|
|
462
492
|
],
|
|
463
493
|
});
|
|
464
494
|
}
|
|
465
495
|
describe('resource completions', () => {
|
|
466
|
-
|
|
467
|
-
describe.skip('runFunctions with stream: false', () => {
|
|
496
|
+
describe('runTools with stream: false', () => {
|
|
468
497
|
test('successful flow', async () => {
|
|
469
498
|
const { fetch, handleRequest } = mockChatCompletionFetch();
|
|
470
499
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
471
|
-
const runner = openai.beta.chat.completions.
|
|
500
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
472
501
|
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
473
502
|
model: 'gpt-3.5-turbo',
|
|
474
|
-
|
|
503
|
+
tools: [
|
|
475
504
|
{
|
|
476
|
-
|
|
477
|
-
|
|
505
|
+
type: 'function',
|
|
506
|
+
function: {
|
|
507
|
+
function: function getWeather() {
|
|
508
|
+
return `it's raining`;
|
|
509
|
+
},
|
|
510
|
+
parameters: {},
|
|
511
|
+
description: 'gets the weather',
|
|
478
512
|
},
|
|
479
|
-
parameters: {},
|
|
480
|
-
description: 'gets the weather',
|
|
481
513
|
},
|
|
482
514
|
],
|
|
483
515
|
});
|
|
484
516
|
const listener = new RunnerListener(runner);
|
|
485
|
-
await
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
choices: [
|
|
491
|
-
{
|
|
492
|
-
index: 0,
|
|
493
|
-
finish_reason: 'function_call',
|
|
494
|
-
message: {
|
|
495
|
-
role: 'assistant',
|
|
496
|
-
content: null,
|
|
497
|
-
function_call: {
|
|
498
|
-
arguments: '',
|
|
499
|
-
name: 'getWeather',
|
|
500
|
-
},
|
|
501
|
-
},
|
|
502
|
-
},
|
|
503
|
-
],
|
|
504
|
-
created: Math.floor(Date.now() / 1000),
|
|
505
|
-
model: 'gpt-3.5-turbo',
|
|
506
|
-
object: 'chat.completion',
|
|
507
|
-
};
|
|
508
|
-
}),
|
|
509
|
-
handleRequest(async (request) => {
|
|
510
|
-
expect(request.messages).toEqual([
|
|
511
|
-
{ role: 'user', content: 'tell me what the weather is like' },
|
|
517
|
+
await handleRequest(async (request) => {
|
|
518
|
+
expect(request.messages).toEqual([{ role: 'user', content: 'tell me what the weather is like' }]);
|
|
519
|
+
return {
|
|
520
|
+
id: '1',
|
|
521
|
+
choices: [
|
|
512
522
|
{
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
523
|
+
index: 0,
|
|
524
|
+
finish_reason: 'function_call',
|
|
525
|
+
message: {
|
|
526
|
+
role: 'assistant',
|
|
527
|
+
content: null,
|
|
528
|
+
tool_calls: [
|
|
529
|
+
{
|
|
530
|
+
type: 'function',
|
|
531
|
+
id: '123',
|
|
532
|
+
function: {
|
|
533
|
+
arguments: '',
|
|
534
|
+
name: 'getWeather',
|
|
535
|
+
},
|
|
536
|
+
},
|
|
537
|
+
],
|
|
518
538
|
},
|
|
519
539
|
},
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
540
|
+
],
|
|
541
|
+
created: Math.floor(Date.now() / 1000),
|
|
542
|
+
model: 'gpt-3.5-turbo',
|
|
543
|
+
object: 'chat.completion',
|
|
544
|
+
};
|
|
545
|
+
});
|
|
546
|
+
await handleRequest(async (request) => {
|
|
547
|
+
expect(request.messages).toEqual([
|
|
548
|
+
{ role: 'user', content: 'tell me what the weather is like' },
|
|
549
|
+
{
|
|
550
|
+
role: 'assistant',
|
|
551
|
+
content: null,
|
|
552
|
+
tool_calls: [
|
|
529
553
|
{
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
554
|
+
type: 'function',
|
|
555
|
+
id: '123',
|
|
556
|
+
function: {
|
|
557
|
+
arguments: '',
|
|
558
|
+
name: 'getWeather',
|
|
535
559
|
},
|
|
536
560
|
},
|
|
537
561
|
],
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
role: 'tool',
|
|
565
|
+
content: `it's raining`,
|
|
566
|
+
tool_call_id: '123',
|
|
567
|
+
},
|
|
568
|
+
]);
|
|
569
|
+
return {
|
|
570
|
+
id: '2',
|
|
571
|
+
choices: [
|
|
572
|
+
{
|
|
573
|
+
index: 0,
|
|
574
|
+
finish_reason: 'stop',
|
|
575
|
+
message: {
|
|
576
|
+
role: 'assistant',
|
|
577
|
+
content: `it's raining`,
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
],
|
|
581
|
+
created: Math.floor(Date.now() / 1000),
|
|
582
|
+
model: 'gpt-3.5-turbo',
|
|
583
|
+
object: 'chat.completion',
|
|
584
|
+
};
|
|
585
|
+
});
|
|
586
|
+
await runner.done();
|
|
545
587
|
expect(listener.messages).toEqual([
|
|
546
588
|
{ role: 'user', content: 'tell me what the weather is like' },
|
|
547
|
-
{
|
|
548
|
-
|
|
589
|
+
{
|
|
590
|
+
role: 'assistant',
|
|
591
|
+
content: null,
|
|
592
|
+
tool_calls: [
|
|
593
|
+
{
|
|
594
|
+
type: 'function',
|
|
595
|
+
id: '123',
|
|
596
|
+
function: {
|
|
597
|
+
arguments: '',
|
|
598
|
+
name: 'getWeather',
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
],
|
|
602
|
+
},
|
|
603
|
+
{ role: 'tool', content: `it's raining`, tool_call_id: '123' },
|
|
549
604
|
{ role: 'assistant', content: "it's raining" },
|
|
550
605
|
]);
|
|
551
606
|
expect(listener.functionCallResults).toEqual([`it's raining`]);
|
|
@@ -555,16 +610,19 @@ describe('resource completions', () => {
|
|
|
555
610
|
const { fetch, handleRequest } = mockChatCompletionFetch();
|
|
556
611
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
557
612
|
const controller = new AbortController();
|
|
558
|
-
const runner = openai.beta.chat.completions.
|
|
613
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
559
614
|
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
560
615
|
model: 'gpt-3.5-turbo',
|
|
561
|
-
|
|
616
|
+
tools: [
|
|
562
617
|
{
|
|
563
|
-
|
|
564
|
-
|
|
618
|
+
type: 'function',
|
|
619
|
+
function: {
|
|
620
|
+
function: function getWeather() {
|
|
621
|
+
return `it's raining`;
|
|
622
|
+
},
|
|
623
|
+
parameters: {},
|
|
624
|
+
description: 'gets the weather',
|
|
565
625
|
},
|
|
566
|
-
parameters: {},
|
|
567
|
-
description: 'gets the weather',
|
|
568
626
|
},
|
|
569
627
|
],
|
|
570
628
|
}, { signal: controller.signal });
|
|
@@ -580,10 +638,16 @@ describe('resource completions', () => {
|
|
|
580
638
|
message: {
|
|
581
639
|
role: 'assistant',
|
|
582
640
|
content: null,
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
641
|
+
tool_calls: [
|
|
642
|
+
{
|
|
643
|
+
type: 'function',
|
|
644
|
+
id: '123',
|
|
645
|
+
function: {
|
|
646
|
+
arguments: '',
|
|
647
|
+
name: 'getWeather',
|
|
648
|
+
},
|
|
649
|
+
},
|
|
650
|
+
],
|
|
587
651
|
},
|
|
588
652
|
},
|
|
589
653
|
],
|
|
@@ -596,8 +660,21 @@ describe('resource completions', () => {
|
|
|
596
660
|
await runner.done().catch(() => { });
|
|
597
661
|
expect(listener.messages).toEqual([
|
|
598
662
|
{ role: 'user', content: 'tell me what the weather is like' },
|
|
599
|
-
{
|
|
600
|
-
|
|
663
|
+
{
|
|
664
|
+
role: 'assistant',
|
|
665
|
+
content: null,
|
|
666
|
+
tool_calls: [
|
|
667
|
+
{
|
|
668
|
+
type: 'function',
|
|
669
|
+
id: '123',
|
|
670
|
+
function: {
|
|
671
|
+
arguments: '',
|
|
672
|
+
name: 'getWeather',
|
|
673
|
+
},
|
|
674
|
+
},
|
|
675
|
+
],
|
|
676
|
+
},
|
|
677
|
+
{ role: 'tool', content: `it's raining`, tool_call_id: '123' },
|
|
601
678
|
]);
|
|
602
679
|
expect(listener.functionCallResults).toEqual([`it's raining`]);
|
|
603
680
|
await listener.sanityCheck({ error: 'Request was aborted.' });
|
|
@@ -606,7 +683,7 @@ describe('resource completions', () => {
|
|
|
606
683
|
test('successful flow with parse', async () => {
|
|
607
684
|
const { fetch, handleRequest } = mockChatCompletionFetch();
|
|
608
685
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
609
|
-
const runner = openai.beta.chat.completions.
|
|
686
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
610
687
|
messages: [
|
|
611
688
|
{
|
|
612
689
|
role: 'user',
|
|
@@ -614,8 +691,8 @@ describe('resource completions', () => {
|
|
|
614
691
|
},
|
|
615
692
|
],
|
|
616
693
|
model: 'gpt-3.5-turbo',
|
|
617
|
-
|
|
618
|
-
new
|
|
694
|
+
tools: [
|
|
695
|
+
new ParsingToolFunction({
|
|
619
696
|
name: 'numProperties',
|
|
620
697
|
function: (obj) => String(Object.keys(obj).length),
|
|
621
698
|
parameters: { type: 'object' },
|
|
@@ -631,84 +708,94 @@ describe('resource completions', () => {
|
|
|
631
708
|
],
|
|
632
709
|
});
|
|
633
710
|
const listener = new RunnerListener(runner);
|
|
634
|
-
await
|
|
635
|
-
|
|
636
|
-
|
|
711
|
+
await handleRequest(async (request) => {
|
|
712
|
+
expect(request.messages).toEqual([
|
|
713
|
+
{
|
|
714
|
+
role: 'user',
|
|
715
|
+
content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
|
|
716
|
+
},
|
|
717
|
+
]);
|
|
718
|
+
return {
|
|
719
|
+
id: '1',
|
|
720
|
+
choices: [
|
|
637
721
|
{
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
function_call: {
|
|
652
|
-
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
653
|
-
name: 'numProperties',
|
|
722
|
+
index: 0,
|
|
723
|
+
finish_reason: 'function_call',
|
|
724
|
+
message: {
|
|
725
|
+
role: 'assistant',
|
|
726
|
+
content: null,
|
|
727
|
+
tool_calls: [
|
|
728
|
+
{
|
|
729
|
+
type: 'function',
|
|
730
|
+
id: '123',
|
|
731
|
+
function: {
|
|
732
|
+
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
733
|
+
name: 'numProperties',
|
|
734
|
+
},
|
|
654
735
|
},
|
|
655
|
-
|
|
656
|
-
},
|
|
657
|
-
],
|
|
658
|
-
created: Math.floor(Date.now() / 1000),
|
|
659
|
-
model: 'gpt-3.5-turbo',
|
|
660
|
-
object: 'chat.completion',
|
|
661
|
-
usage: {
|
|
662
|
-
completion_tokens: 5,
|
|
663
|
-
prompt_tokens: 20,
|
|
664
|
-
total_tokens: 25,
|
|
665
|
-
},
|
|
666
|
-
};
|
|
667
|
-
}),
|
|
668
|
-
handleRequest(async (request) => {
|
|
669
|
-
expect(request.messages).toEqual([
|
|
670
|
-
{
|
|
671
|
-
role: 'user',
|
|
672
|
-
content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
|
|
673
|
-
},
|
|
674
|
-
{
|
|
675
|
-
role: 'assistant',
|
|
676
|
-
content: null,
|
|
677
|
-
function_call: {
|
|
678
|
-
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
679
|
-
name: 'numProperties',
|
|
736
|
+
],
|
|
680
737
|
},
|
|
681
738
|
},
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
739
|
+
],
|
|
740
|
+
created: Math.floor(Date.now() / 1000),
|
|
741
|
+
model: 'gpt-3.5-turbo',
|
|
742
|
+
object: 'chat.completion',
|
|
743
|
+
usage: {
|
|
744
|
+
completion_tokens: 5,
|
|
745
|
+
prompt_tokens: 20,
|
|
746
|
+
total_tokens: 25,
|
|
747
|
+
},
|
|
748
|
+
};
|
|
749
|
+
});
|
|
750
|
+
await handleRequest(async (request) => {
|
|
751
|
+
expect(request.messages).toEqual([
|
|
752
|
+
{
|
|
753
|
+
role: 'user',
|
|
754
|
+
content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
|
|
755
|
+
},
|
|
756
|
+
{
|
|
757
|
+
role: 'assistant',
|
|
758
|
+
content: null,
|
|
759
|
+
tool_calls: [
|
|
691
760
|
{
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
761
|
+
type: 'function',
|
|
762
|
+
id: '123',
|
|
763
|
+
function: {
|
|
764
|
+
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
765
|
+
name: 'numProperties',
|
|
697
766
|
},
|
|
698
767
|
},
|
|
699
768
|
],
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
role: 'tool',
|
|
772
|
+
content: '3',
|
|
773
|
+
tool_call_id: '123',
|
|
774
|
+
},
|
|
775
|
+
]);
|
|
776
|
+
return {
|
|
777
|
+
id: '2',
|
|
778
|
+
choices: [
|
|
779
|
+
{
|
|
780
|
+
index: 0,
|
|
781
|
+
finish_reason: 'stop',
|
|
782
|
+
message: {
|
|
783
|
+
role: 'assistant',
|
|
784
|
+
content: `there are 3 properties in {"a": 1, "b": 2, "c": 3}`,
|
|
785
|
+
},
|
|
707
786
|
},
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
787
|
+
],
|
|
788
|
+
created: Math.floor(Date.now() / 1000),
|
|
789
|
+
model: 'gpt-3.5-turbo',
|
|
790
|
+
object: 'chat.completion',
|
|
791
|
+
usage: {
|
|
792
|
+
completion_tokens: 10,
|
|
793
|
+
prompt_tokens: 25,
|
|
794
|
+
total_tokens: 35,
|
|
795
|
+
},
|
|
796
|
+
};
|
|
797
|
+
});
|
|
798
|
+
await runner.done();
|
|
712
799
|
expect(listener.messages).toEqual([
|
|
713
800
|
{
|
|
714
801
|
role: 'user',
|
|
@@ -717,9 +804,15 @@ describe('resource completions', () => {
|
|
|
717
804
|
{
|
|
718
805
|
role: 'assistant',
|
|
719
806
|
content: null,
|
|
720
|
-
|
|
807
|
+
tool_calls: [
|
|
808
|
+
{
|
|
809
|
+
type: 'function',
|
|
810
|
+
id: '123',
|
|
811
|
+
function: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
|
|
812
|
+
},
|
|
813
|
+
],
|
|
721
814
|
},
|
|
722
|
-
{ role: '
|
|
815
|
+
{ role: 'tool', content: '3', tool_call_id: '123' },
|
|
723
816
|
{ role: 'assistant', content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}' },
|
|
724
817
|
]);
|
|
725
818
|
expect(listener.functionCallResults).toEqual(['3']);
|
|
@@ -728,7 +821,7 @@ describe('resource completions', () => {
|
|
|
728
821
|
test('flow with parse error', async () => {
|
|
729
822
|
const { fetch, handleRequest } = mockChatCompletionFetch();
|
|
730
823
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
731
|
-
const runner = openai.beta.chat.completions.
|
|
824
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
732
825
|
messages: [
|
|
733
826
|
{
|
|
734
827
|
role: 'user',
|
|
@@ -736,8 +829,8 @@ describe('resource completions', () => {
|
|
|
736
829
|
},
|
|
737
830
|
],
|
|
738
831
|
model: 'gpt-3.5-turbo',
|
|
739
|
-
|
|
740
|
-
new
|
|
832
|
+
tools: [
|
|
833
|
+
new ParsingToolFunction({
|
|
741
834
|
name: 'numProperties',
|
|
742
835
|
function: (obj) => String(Object.keys(obj).length),
|
|
743
836
|
parameters: { type: 'object' },
|
|
@@ -770,10 +863,16 @@ describe('resource completions', () => {
|
|
|
770
863
|
message: {
|
|
771
864
|
role: 'assistant',
|
|
772
865
|
content: null,
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
866
|
+
tool_calls: [
|
|
867
|
+
{
|
|
868
|
+
type: 'function',
|
|
869
|
+
id: '123',
|
|
870
|
+
function: {
|
|
871
|
+
arguments: '[{"a": 1, "b": 2, "c": 3}]',
|
|
872
|
+
name: 'numProperties',
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
],
|
|
777
876
|
},
|
|
778
877
|
},
|
|
779
878
|
],
|
|
@@ -791,15 +890,21 @@ describe('resource completions', () => {
|
|
|
791
890
|
{
|
|
792
891
|
role: 'assistant',
|
|
793
892
|
content: null,
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
893
|
+
tool_calls: [
|
|
894
|
+
{
|
|
895
|
+
type: 'function',
|
|
896
|
+
id: '123',
|
|
897
|
+
function: {
|
|
898
|
+
arguments: '[{"a": 1, "b": 2, "c": 3}]',
|
|
899
|
+
name: 'numProperties',
|
|
900
|
+
},
|
|
901
|
+
},
|
|
902
|
+
],
|
|
798
903
|
},
|
|
799
904
|
{
|
|
800
|
-
role: '
|
|
905
|
+
role: 'tool',
|
|
801
906
|
content: `must be an object`,
|
|
802
|
-
|
|
907
|
+
tool_call_id: '123',
|
|
803
908
|
},
|
|
804
909
|
]);
|
|
805
910
|
return {
|
|
@@ -811,10 +916,16 @@ describe('resource completions', () => {
|
|
|
811
916
|
message: {
|
|
812
917
|
role: 'assistant',
|
|
813
918
|
content: null,
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
919
|
+
tool_calls: [
|
|
920
|
+
{
|
|
921
|
+
type: 'function',
|
|
922
|
+
id: '1234',
|
|
923
|
+
function: {
|
|
924
|
+
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
925
|
+
name: 'numProperties',
|
|
926
|
+
},
|
|
927
|
+
},
|
|
928
|
+
],
|
|
818
929
|
},
|
|
819
930
|
},
|
|
820
931
|
],
|
|
@@ -832,28 +943,40 @@ describe('resource completions', () => {
|
|
|
832
943
|
{
|
|
833
944
|
role: 'assistant',
|
|
834
945
|
content: null,
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
946
|
+
tool_calls: [
|
|
947
|
+
{
|
|
948
|
+
type: 'function',
|
|
949
|
+
id: '123',
|
|
950
|
+
function: {
|
|
951
|
+
arguments: '[{"a": 1, "b": 2, "c": 3}]',
|
|
952
|
+
name: 'numProperties',
|
|
953
|
+
},
|
|
954
|
+
},
|
|
955
|
+
],
|
|
839
956
|
},
|
|
840
957
|
{
|
|
841
|
-
role: '
|
|
958
|
+
role: 'tool',
|
|
842
959
|
content: `must be an object`,
|
|
843
|
-
|
|
960
|
+
tool_call_id: '123',
|
|
844
961
|
},
|
|
845
962
|
{
|
|
846
963
|
role: 'assistant',
|
|
847
964
|
content: null,
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
965
|
+
tool_calls: [
|
|
966
|
+
{
|
|
967
|
+
type: 'function',
|
|
968
|
+
id: '1234',
|
|
969
|
+
function: {
|
|
970
|
+
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
971
|
+
name: 'numProperties',
|
|
972
|
+
},
|
|
973
|
+
},
|
|
974
|
+
],
|
|
852
975
|
},
|
|
853
976
|
{
|
|
854
|
-
role: '
|
|
977
|
+
role: 'tool',
|
|
855
978
|
content: '3',
|
|
856
|
-
|
|
979
|
+
tool_call_id: '1234',
|
|
857
980
|
},
|
|
858
981
|
]);
|
|
859
982
|
return {
|
|
@@ -883,15 +1006,27 @@ describe('resource completions', () => {
|
|
|
883
1006
|
{
|
|
884
1007
|
role: 'assistant',
|
|
885
1008
|
content: null,
|
|
886
|
-
|
|
1009
|
+
tool_calls: [
|
|
1010
|
+
{
|
|
1011
|
+
type: 'function',
|
|
1012
|
+
id: '123',
|
|
1013
|
+
function: { name: 'numProperties', arguments: '[{"a": 1, "b": 2, "c": 3}]' },
|
|
1014
|
+
},
|
|
1015
|
+
],
|
|
887
1016
|
},
|
|
888
|
-
{ role: '
|
|
1017
|
+
{ role: 'tool', content: `must be an object`, tool_call_id: '123' },
|
|
889
1018
|
{
|
|
890
1019
|
role: 'assistant',
|
|
891
1020
|
content: null,
|
|
892
|
-
|
|
1021
|
+
tool_calls: [
|
|
1022
|
+
{
|
|
1023
|
+
type: 'function',
|
|
1024
|
+
id: '1234',
|
|
1025
|
+
function: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
|
|
1026
|
+
},
|
|
1027
|
+
],
|
|
893
1028
|
},
|
|
894
|
-
{ role: '
|
|
1029
|
+
{ role: 'tool', content: '3', tool_call_id: '1234' },
|
|
895
1030
|
{ role: 'assistant', content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}' },
|
|
896
1031
|
]);
|
|
897
1032
|
expect(listener.functionCallResults).toEqual([`must be an object`, '3']);
|
|
@@ -900,19 +1035,25 @@ describe('resource completions', () => {
|
|
|
900
1035
|
test('single function call', async () => {
|
|
901
1036
|
const { fetch, handleRequest } = mockChatCompletionFetch();
|
|
902
1037
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
903
|
-
const runner = openai.beta.chat.completions.
|
|
1038
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
904
1039
|
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
905
1040
|
model: 'gpt-3.5-turbo',
|
|
906
|
-
|
|
907
|
-
|
|
1041
|
+
tool_choice: {
|
|
1042
|
+
type: 'function',
|
|
1043
|
+
function: {
|
|
1044
|
+
name: 'getWeather',
|
|
1045
|
+
},
|
|
908
1046
|
},
|
|
909
|
-
|
|
1047
|
+
tools: [
|
|
910
1048
|
{
|
|
911
|
-
|
|
912
|
-
|
|
1049
|
+
type: 'function',
|
|
1050
|
+
function: {
|
|
1051
|
+
function: function getWeather() {
|
|
1052
|
+
return `it's raining`;
|
|
1053
|
+
},
|
|
1054
|
+
parameters: {},
|
|
1055
|
+
description: 'gets the weather',
|
|
913
1056
|
},
|
|
914
|
-
parameters: {},
|
|
915
|
-
description: 'gets the weather',
|
|
916
1057
|
},
|
|
917
1058
|
],
|
|
918
1059
|
});
|
|
@@ -929,10 +1070,16 @@ describe('resource completions', () => {
|
|
|
929
1070
|
message: {
|
|
930
1071
|
role: 'assistant',
|
|
931
1072
|
content: null,
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1073
|
+
tool_calls: [
|
|
1074
|
+
{
|
|
1075
|
+
type: 'function',
|
|
1076
|
+
id: '123',
|
|
1077
|
+
function: {
|
|
1078
|
+
arguments: '',
|
|
1079
|
+
name: 'getWeather',
|
|
1080
|
+
},
|
|
1081
|
+
},
|
|
1082
|
+
],
|
|
936
1083
|
},
|
|
937
1084
|
},
|
|
938
1085
|
],
|
|
@@ -945,8 +1092,21 @@ describe('resource completions', () => {
|
|
|
945
1092
|
]);
|
|
946
1093
|
expect(listener.messages).toEqual([
|
|
947
1094
|
{ role: 'user', content: 'tell me what the weather is like' },
|
|
948
|
-
{
|
|
949
|
-
|
|
1095
|
+
{
|
|
1096
|
+
role: 'assistant',
|
|
1097
|
+
content: null,
|
|
1098
|
+
tool_calls: [
|
|
1099
|
+
{
|
|
1100
|
+
type: 'function',
|
|
1101
|
+
id: '123',
|
|
1102
|
+
function: {
|
|
1103
|
+
arguments: '',
|
|
1104
|
+
name: 'getWeather',
|
|
1105
|
+
},
|
|
1106
|
+
},
|
|
1107
|
+
],
|
|
1108
|
+
},
|
|
1109
|
+
{ role: 'tool', content: `it's raining`, tool_call_id: '123' },
|
|
950
1110
|
]);
|
|
951
1111
|
expect(listener.functionCallResults).toEqual([`it's raining`]);
|
|
952
1112
|
await listener.sanityCheck();
|
|
@@ -954,16 +1114,19 @@ describe('resource completions', () => {
|
|
|
954
1114
|
test('wrong function name', async () => {
|
|
955
1115
|
const { fetch, handleRequest } = mockChatCompletionFetch();
|
|
956
1116
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
957
|
-
const runner = openai.beta.chat.completions.
|
|
1117
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
958
1118
|
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
959
1119
|
model: 'gpt-3.5-turbo',
|
|
960
|
-
|
|
1120
|
+
tools: [
|
|
961
1121
|
{
|
|
962
|
-
|
|
963
|
-
|
|
1122
|
+
type: 'function',
|
|
1123
|
+
function: {
|
|
1124
|
+
function: function getWeather() {
|
|
1125
|
+
return `it's raining`;
|
|
1126
|
+
},
|
|
1127
|
+
parameters: {},
|
|
1128
|
+
description: 'gets the weather',
|
|
964
1129
|
},
|
|
965
|
-
parameters: {},
|
|
966
|
-
description: 'gets the weather',
|
|
967
1130
|
},
|
|
968
1131
|
],
|
|
969
1132
|
});
|
|
@@ -980,10 +1143,16 @@ describe('resource completions', () => {
|
|
|
980
1143
|
message: {
|
|
981
1144
|
role: 'assistant',
|
|
982
1145
|
content: null,
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1146
|
+
tool_calls: [
|
|
1147
|
+
{
|
|
1148
|
+
type: 'function',
|
|
1149
|
+
id: '123',
|
|
1150
|
+
function: {
|
|
1151
|
+
arguments: '',
|
|
1152
|
+
name: 'get_weather',
|
|
1153
|
+
},
|
|
1154
|
+
},
|
|
1155
|
+
],
|
|
987
1156
|
},
|
|
988
1157
|
},
|
|
989
1158
|
],
|
|
@@ -998,15 +1167,21 @@ describe('resource completions', () => {
|
|
|
998
1167
|
{
|
|
999
1168
|
role: 'assistant',
|
|
1000
1169
|
content: null,
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1170
|
+
tool_calls: [
|
|
1171
|
+
{
|
|
1172
|
+
type: 'function',
|
|
1173
|
+
id: '123',
|
|
1174
|
+
function: {
|
|
1175
|
+
arguments: '',
|
|
1176
|
+
name: 'get_weather',
|
|
1177
|
+
},
|
|
1178
|
+
},
|
|
1179
|
+
],
|
|
1005
1180
|
},
|
|
1006
1181
|
{
|
|
1007
|
-
role: '
|
|
1008
|
-
content: `Invalid
|
|
1009
|
-
|
|
1182
|
+
role: 'tool',
|
|
1183
|
+
content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
1184
|
+
tool_call_id: '123',
|
|
1010
1185
|
},
|
|
1011
1186
|
]);
|
|
1012
1187
|
return {
|
|
@@ -1018,10 +1193,16 @@ describe('resource completions', () => {
|
|
|
1018
1193
|
message: {
|
|
1019
1194
|
role: 'assistant',
|
|
1020
1195
|
content: null,
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1196
|
+
tool_calls: [
|
|
1197
|
+
{
|
|
1198
|
+
type: 'function',
|
|
1199
|
+
id: '1234',
|
|
1200
|
+
function: {
|
|
1201
|
+
arguments: '',
|
|
1202
|
+
name: 'getWeather',
|
|
1203
|
+
},
|
|
1204
|
+
},
|
|
1205
|
+
],
|
|
1025
1206
|
},
|
|
1026
1207
|
},
|
|
1027
1208
|
],
|
|
@@ -1036,28 +1217,40 @@ describe('resource completions', () => {
|
|
|
1036
1217
|
{
|
|
1037
1218
|
role: 'assistant',
|
|
1038
1219
|
content: null,
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1220
|
+
tool_calls: [
|
|
1221
|
+
{
|
|
1222
|
+
type: 'function',
|
|
1223
|
+
id: '123',
|
|
1224
|
+
function: {
|
|
1225
|
+
arguments: '',
|
|
1226
|
+
name: 'get_weather',
|
|
1227
|
+
},
|
|
1228
|
+
},
|
|
1229
|
+
],
|
|
1043
1230
|
},
|
|
1044
1231
|
{
|
|
1045
|
-
role: '
|
|
1046
|
-
content: `Invalid
|
|
1047
|
-
|
|
1232
|
+
role: 'tool',
|
|
1233
|
+
content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
1234
|
+
tool_call_id: '123',
|
|
1048
1235
|
},
|
|
1049
1236
|
{
|
|
1050
1237
|
role: 'assistant',
|
|
1051
1238
|
content: null,
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1239
|
+
tool_calls: [
|
|
1240
|
+
{
|
|
1241
|
+
type: 'function',
|
|
1242
|
+
id: '1234',
|
|
1243
|
+
function: {
|
|
1244
|
+
arguments: '',
|
|
1245
|
+
name: 'getWeather',
|
|
1246
|
+
},
|
|
1247
|
+
},
|
|
1248
|
+
],
|
|
1056
1249
|
},
|
|
1057
1250
|
{
|
|
1058
|
-
role: '
|
|
1251
|
+
role: 'tool',
|
|
1059
1252
|
content: `it's raining`,
|
|
1060
|
-
|
|
1253
|
+
tool_call_id: '1234',
|
|
1061
1254
|
},
|
|
1062
1255
|
]);
|
|
1063
1256
|
return {
|
|
@@ -1081,99 +1274,49 @@ describe('resource completions', () => {
|
|
|
1081
1274
|
]);
|
|
1082
1275
|
expect(listener.messages).toEqual([
|
|
1083
1276
|
{ role: 'user', content: 'tell me what the weather is like' },
|
|
1084
|
-
{ role: 'assistant', content: null, function_call: { name: 'get_weather', arguments: '' } },
|
|
1085
1277
|
{
|
|
1086
|
-
role: '
|
|
1087
|
-
content:
|
|
1088
|
-
name: 'get_weather',
|
|
1278
|
+
role: 'assistant',
|
|
1279
|
+
content: null,
|
|
1280
|
+
tool_calls: [{ type: 'function', id: '123', function: { name: 'get_weather', arguments: '' } }],
|
|
1089
1281
|
},
|
|
1090
|
-
{
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
expect(listener.functionCallResults).toEqual([
|
|
1095
|
-
`Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
1096
|
-
`it's raining`,
|
|
1097
|
-
]);
|
|
1098
|
-
await listener.sanityCheck();
|
|
1099
|
-
});
|
|
1100
|
-
test('wrong function name with single function call', async () => {
|
|
1101
|
-
const { fetch, handleRequest } = mockChatCompletionFetch();
|
|
1102
|
-
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
1103
|
-
const runner = openai.beta.chat.completions.runFunctions({
|
|
1104
|
-
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
1105
|
-
model: 'gpt-3.5-turbo',
|
|
1106
|
-
function_call: {
|
|
1107
|
-
name: 'getWeather',
|
|
1282
|
+
{
|
|
1283
|
+
role: 'tool',
|
|
1284
|
+
content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
1285
|
+
tool_call_id: '123',
|
|
1108
1286
|
},
|
|
1109
|
-
functions: [
|
|
1110
|
-
{
|
|
1111
|
-
function: function getWeather() {
|
|
1112
|
-
return `it's raining`;
|
|
1113
|
-
},
|
|
1114
|
-
parameters: {},
|
|
1115
|
-
description: 'gets the weather',
|
|
1116
|
-
},
|
|
1117
|
-
],
|
|
1118
|
-
});
|
|
1119
|
-
const listener = new RunnerListener(runner);
|
|
1120
|
-
await Promise.all([
|
|
1121
|
-
handleRequest(async (request) => {
|
|
1122
|
-
expect(request.messages).toEqual([{ role: 'user', content: 'tell me what the weather is like' }]);
|
|
1123
|
-
return {
|
|
1124
|
-
id: '1',
|
|
1125
|
-
choices: [
|
|
1126
|
-
{
|
|
1127
|
-
index: 0,
|
|
1128
|
-
finish_reason: 'function_call',
|
|
1129
|
-
message: {
|
|
1130
|
-
role: 'assistant',
|
|
1131
|
-
content: null,
|
|
1132
|
-
function_call: {
|
|
1133
|
-
arguments: '',
|
|
1134
|
-
name: 'get_weather',
|
|
1135
|
-
},
|
|
1136
|
-
},
|
|
1137
|
-
},
|
|
1138
|
-
],
|
|
1139
|
-
created: Math.floor(Date.now() / 1000),
|
|
1140
|
-
model: 'gpt-3.5-turbo',
|
|
1141
|
-
object: 'chat.completion',
|
|
1142
|
-
};
|
|
1143
|
-
}),
|
|
1144
|
-
runner.done(),
|
|
1145
|
-
]);
|
|
1146
|
-
expect(listener.messages).toEqual([
|
|
1147
|
-
{ role: 'user', content: 'tell me what the weather is like' },
|
|
1148
|
-
{ role: 'assistant', content: null, function_call: { name: 'get_weather', arguments: '' } },
|
|
1149
1287
|
{
|
|
1150
|
-
role: '
|
|
1151
|
-
content:
|
|
1152
|
-
name: '
|
|
1288
|
+
role: 'assistant',
|
|
1289
|
+
content: null,
|
|
1290
|
+
tool_calls: [{ type: 'function', id: '1234', function: { name: 'getWeather', arguments: '' } }],
|
|
1153
1291
|
},
|
|
1292
|
+
{ role: 'tool', content: `it's raining`, tool_call_id: '1234' },
|
|
1293
|
+
{ role: 'assistant', content: "it's raining" },
|
|
1154
1294
|
]);
|
|
1155
1295
|
expect(listener.functionCallResults).toEqual([
|
|
1156
|
-
`Invalid
|
|
1296
|
+
`Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
1297
|
+
`it's raining`,
|
|
1157
1298
|
]);
|
|
1158
1299
|
await listener.sanityCheck();
|
|
1159
1300
|
});
|
|
1160
1301
|
});
|
|
1161
|
-
|
|
1162
|
-
describe.skip('runFunctions with stream: true', () => {
|
|
1302
|
+
describe('runTools with stream: true', () => {
|
|
1163
1303
|
test('successful flow', async () => {
|
|
1164
1304
|
const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
|
|
1165
1305
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
1166
|
-
const runner = openai.beta.chat.completions.
|
|
1306
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
1167
1307
|
stream: true,
|
|
1168
1308
|
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
1169
1309
|
model: 'gpt-3.5-turbo',
|
|
1170
|
-
|
|
1310
|
+
tools: [
|
|
1171
1311
|
{
|
|
1172
|
-
|
|
1173
|
-
|
|
1312
|
+
type: 'function',
|
|
1313
|
+
function: {
|
|
1314
|
+
function: function getWeather() {
|
|
1315
|
+
return `it's raining`;
|
|
1316
|
+
},
|
|
1317
|
+
parameters: {},
|
|
1318
|
+
description: 'gets the weather',
|
|
1174
1319
|
},
|
|
1175
|
-
parameters: {},
|
|
1176
|
-
description: 'gets the weather',
|
|
1177
1320
|
},
|
|
1178
1321
|
],
|
|
1179
1322
|
});
|
|
@@ -1190,10 +1333,17 @@ describe('resource completions', () => {
|
|
|
1190
1333
|
delta: {
|
|
1191
1334
|
role: 'assistant',
|
|
1192
1335
|
content: null,
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1336
|
+
tool_calls: [
|
|
1337
|
+
{
|
|
1338
|
+
type: 'function',
|
|
1339
|
+
index: 0,
|
|
1340
|
+
id: '123',
|
|
1341
|
+
function: {
|
|
1342
|
+
arguments: '',
|
|
1343
|
+
name: 'getWeather',
|
|
1344
|
+
},
|
|
1345
|
+
},
|
|
1346
|
+
],
|
|
1197
1347
|
},
|
|
1198
1348
|
},
|
|
1199
1349
|
],
|
|
@@ -1208,15 +1358,21 @@ describe('resource completions', () => {
|
|
|
1208
1358
|
{
|
|
1209
1359
|
role: 'assistant',
|
|
1210
1360
|
content: null,
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1361
|
+
tool_calls: [
|
|
1362
|
+
{
|
|
1363
|
+
type: 'function',
|
|
1364
|
+
id: '123',
|
|
1365
|
+
function: {
|
|
1366
|
+
arguments: '',
|
|
1367
|
+
name: 'getWeather',
|
|
1368
|
+
},
|
|
1369
|
+
},
|
|
1370
|
+
],
|
|
1215
1371
|
},
|
|
1216
1372
|
{
|
|
1217
|
-
role: '
|
|
1373
|
+
role: 'tool',
|
|
1218
1374
|
content: `it's raining`,
|
|
1219
|
-
|
|
1375
|
+
tool_call_id: '123',
|
|
1220
1376
|
},
|
|
1221
1377
|
]);
|
|
1222
1378
|
for (const choice of contentChoiceDeltas(`it's raining`)) {
|
|
@@ -1232,8 +1388,21 @@ describe('resource completions', () => {
|
|
|
1232
1388
|
runner.done(),
|
|
1233
1389
|
]);
|
|
1234
1390
|
expect(listener.eventMessages).toEqual([
|
|
1235
|
-
{
|
|
1236
|
-
|
|
1391
|
+
{
|
|
1392
|
+
role: 'assistant',
|
|
1393
|
+
content: null,
|
|
1394
|
+
tool_calls: [
|
|
1395
|
+
{
|
|
1396
|
+
type: 'function',
|
|
1397
|
+
id: '123',
|
|
1398
|
+
function: {
|
|
1399
|
+
arguments: '',
|
|
1400
|
+
name: 'getWeather',
|
|
1401
|
+
},
|
|
1402
|
+
},
|
|
1403
|
+
],
|
|
1404
|
+
},
|
|
1405
|
+
{ role: 'tool', content: `it's raining`, tool_call_id: '123' },
|
|
1237
1406
|
{ role: 'assistant', content: "it's raining" },
|
|
1238
1407
|
]);
|
|
1239
1408
|
expect(listener.eventFunctionCallResults).toEqual([`it's raining`]);
|
|
@@ -1243,17 +1412,20 @@ describe('resource completions', () => {
|
|
|
1243
1412
|
const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
|
|
1244
1413
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
1245
1414
|
const controller = new AbortController();
|
|
1246
|
-
const runner = openai.beta.chat.completions.
|
|
1415
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
1247
1416
|
stream: true,
|
|
1248
1417
|
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
1249
1418
|
model: 'gpt-3.5-turbo',
|
|
1250
|
-
|
|
1419
|
+
tools: [
|
|
1251
1420
|
{
|
|
1252
|
-
|
|
1253
|
-
|
|
1421
|
+
type: 'function',
|
|
1422
|
+
function: {
|
|
1423
|
+
function: function getWeather() {
|
|
1424
|
+
return `it's raining`;
|
|
1425
|
+
},
|
|
1426
|
+
parameters: {},
|
|
1427
|
+
description: 'gets the weather',
|
|
1254
1428
|
},
|
|
1255
|
-
parameters: {},
|
|
1256
|
-
description: 'gets the weather',
|
|
1257
1429
|
},
|
|
1258
1430
|
],
|
|
1259
1431
|
}, { signal: controller.signal });
|
|
@@ -1270,10 +1442,17 @@ describe('resource completions', () => {
|
|
|
1270
1442
|
delta: {
|
|
1271
1443
|
role: 'assistant',
|
|
1272
1444
|
content: null,
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1445
|
+
tool_calls: [
|
|
1446
|
+
{
|
|
1447
|
+
type: 'function',
|
|
1448
|
+
index: 0,
|
|
1449
|
+
id: '123',
|
|
1450
|
+
function: {
|
|
1451
|
+
arguments: '',
|
|
1452
|
+
name: 'getWeather',
|
|
1453
|
+
},
|
|
1454
|
+
},
|
|
1455
|
+
],
|
|
1277
1456
|
},
|
|
1278
1457
|
},
|
|
1279
1458
|
],
|
|
@@ -1284,8 +1463,21 @@ describe('resource completions', () => {
|
|
|
1284
1463
|
});
|
|
1285
1464
|
await runner.done().catch(() => { });
|
|
1286
1465
|
expect(listener.eventMessages).toEqual([
|
|
1287
|
-
{
|
|
1288
|
-
|
|
1466
|
+
{
|
|
1467
|
+
role: 'assistant',
|
|
1468
|
+
content: null,
|
|
1469
|
+
tool_calls: [
|
|
1470
|
+
{
|
|
1471
|
+
type: 'function',
|
|
1472
|
+
id: '123',
|
|
1473
|
+
function: {
|
|
1474
|
+
arguments: '',
|
|
1475
|
+
name: 'getWeather',
|
|
1476
|
+
},
|
|
1477
|
+
},
|
|
1478
|
+
],
|
|
1479
|
+
},
|
|
1480
|
+
{ role: 'tool', content: `it's raining`, tool_call_id: '123' },
|
|
1289
1481
|
]);
|
|
1290
1482
|
expect(listener.eventFunctionCallResults).toEqual([`it's raining`]);
|
|
1291
1483
|
await listener.sanityCheck({ error: 'Request was aborted.' });
|
|
@@ -1294,7 +1486,7 @@ describe('resource completions', () => {
|
|
|
1294
1486
|
test('successful flow with parse', async () => {
|
|
1295
1487
|
const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
|
|
1296
1488
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
1297
|
-
const runner = openai.beta.chat.completions.
|
|
1489
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
1298
1490
|
stream: true,
|
|
1299
1491
|
messages: [
|
|
1300
1492
|
{
|
|
@@ -1303,8 +1495,8 @@ describe('resource completions', () => {
|
|
|
1303
1495
|
},
|
|
1304
1496
|
],
|
|
1305
1497
|
model: 'gpt-3.5-turbo',
|
|
1306
|
-
|
|
1307
|
-
new
|
|
1498
|
+
tools: [
|
|
1499
|
+
new ParsingToolFunction({
|
|
1308
1500
|
name: 'numProperties',
|
|
1309
1501
|
function: (obj) => String(Object.keys(obj).length),
|
|
1310
1502
|
parameters: { type: 'object' },
|
|
@@ -1337,10 +1529,17 @@ describe('resource completions', () => {
|
|
|
1337
1529
|
delta: {
|
|
1338
1530
|
role: 'assistant',
|
|
1339
1531
|
content: null,
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1532
|
+
tool_calls: [
|
|
1533
|
+
{
|
|
1534
|
+
type: 'function',
|
|
1535
|
+
id: '123',
|
|
1536
|
+
index: 0,
|
|
1537
|
+
function: {
|
|
1538
|
+
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
1539
|
+
name: 'numProperties',
|
|
1540
|
+
},
|
|
1541
|
+
},
|
|
1542
|
+
],
|
|
1344
1543
|
},
|
|
1345
1544
|
},
|
|
1346
1545
|
],
|
|
@@ -1358,15 +1557,21 @@ describe('resource completions', () => {
|
|
|
1358
1557
|
{
|
|
1359
1558
|
role: 'assistant',
|
|
1360
1559
|
content: null,
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1560
|
+
tool_calls: [
|
|
1561
|
+
{
|
|
1562
|
+
type: 'function',
|
|
1563
|
+
id: '123',
|
|
1564
|
+
function: {
|
|
1565
|
+
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
1566
|
+
name: 'numProperties',
|
|
1567
|
+
},
|
|
1568
|
+
},
|
|
1569
|
+
],
|
|
1365
1570
|
},
|
|
1366
1571
|
{
|
|
1367
|
-
role: '
|
|
1572
|
+
role: 'tool',
|
|
1368
1573
|
content: '3',
|
|
1369
|
-
|
|
1574
|
+
tool_call_id: '123',
|
|
1370
1575
|
},
|
|
1371
1576
|
]);
|
|
1372
1577
|
for (const choice of contentChoiceDeltas(`there are 3 properties in {"a": 1, "b": 2, "c": 3}`)) {
|
|
@@ -1385,9 +1590,15 @@ describe('resource completions', () => {
|
|
|
1385
1590
|
{
|
|
1386
1591
|
role: 'assistant',
|
|
1387
1592
|
content: null,
|
|
1388
|
-
|
|
1593
|
+
tool_calls: [
|
|
1594
|
+
{
|
|
1595
|
+
type: 'function',
|
|
1596
|
+
id: '123',
|
|
1597
|
+
function: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
|
|
1598
|
+
},
|
|
1599
|
+
],
|
|
1389
1600
|
},
|
|
1390
|
-
{ role: '
|
|
1601
|
+
{ role: 'tool', content: '3', tool_call_id: '123' },
|
|
1391
1602
|
{ role: 'assistant', content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}' },
|
|
1392
1603
|
]);
|
|
1393
1604
|
expect(listener.eventFunctionCallResults).toEqual(['3']);
|
|
@@ -1396,7 +1607,7 @@ describe('resource completions', () => {
|
|
|
1396
1607
|
test('flow with parse error', async () => {
|
|
1397
1608
|
const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
|
|
1398
1609
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
1399
|
-
const runner = openai.beta.chat.completions.
|
|
1610
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
1400
1611
|
stream: true,
|
|
1401
1612
|
messages: [
|
|
1402
1613
|
{
|
|
@@ -1405,8 +1616,8 @@ describe('resource completions', () => {
|
|
|
1405
1616
|
},
|
|
1406
1617
|
],
|
|
1407
1618
|
model: 'gpt-3.5-turbo',
|
|
1408
|
-
|
|
1409
|
-
new
|
|
1619
|
+
tools: [
|
|
1620
|
+
new ParsingToolFunction({
|
|
1410
1621
|
name: 'numProperties',
|
|
1411
1622
|
function: (obj) => String(Object.keys(obj).length),
|
|
1412
1623
|
parameters: { type: 'object' },
|
|
@@ -1430,7 +1641,10 @@ describe('resource completions', () => {
|
|
|
1430
1641
|
content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
|
|
1431
1642
|
},
|
|
1432
1643
|
]);
|
|
1433
|
-
for (const choice of functionCallDeltas('[{"a": 1, "b": 2, "c": 3}]', {
|
|
1644
|
+
for (const choice of functionCallDeltas('[{"a": 1, "b": 2, "c": 3}]', {
|
|
1645
|
+
name: 'numProperties',
|
|
1646
|
+
id: '123',
|
|
1647
|
+
})) {
|
|
1434
1648
|
yield {
|
|
1435
1649
|
id: '1',
|
|
1436
1650
|
choices: [choice],
|
|
@@ -1449,18 +1663,27 @@ describe('resource completions', () => {
|
|
|
1449
1663
|
{
|
|
1450
1664
|
role: 'assistant',
|
|
1451
1665
|
content: null,
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1666
|
+
tool_calls: [
|
|
1667
|
+
{
|
|
1668
|
+
type: 'function',
|
|
1669
|
+
id: '123',
|
|
1670
|
+
function: {
|
|
1671
|
+
arguments: '[{"a": 1, "b": 2, "c": 3}]',
|
|
1672
|
+
name: 'numProperties',
|
|
1673
|
+
},
|
|
1674
|
+
},
|
|
1675
|
+
],
|
|
1456
1676
|
},
|
|
1457
1677
|
{
|
|
1458
|
-
role: '
|
|
1678
|
+
role: 'tool',
|
|
1459
1679
|
content: `must be an object`,
|
|
1460
|
-
|
|
1680
|
+
tool_call_id: '123',
|
|
1461
1681
|
},
|
|
1462
1682
|
]);
|
|
1463
|
-
for (const choice of functionCallDeltas('{"a": 1, "b": 2, "c": 3}', {
|
|
1683
|
+
for (const choice of functionCallDeltas('{"a": 1, "b": 2, "c": 3}', {
|
|
1684
|
+
name: 'numProperties',
|
|
1685
|
+
id: '1234',
|
|
1686
|
+
})) {
|
|
1464
1687
|
yield {
|
|
1465
1688
|
id: '2',
|
|
1466
1689
|
choices: [choice],
|
|
@@ -1479,28 +1702,40 @@ describe('resource completions', () => {
|
|
|
1479
1702
|
{
|
|
1480
1703
|
role: 'assistant',
|
|
1481
1704
|
content: null,
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1705
|
+
tool_calls: [
|
|
1706
|
+
{
|
|
1707
|
+
type: 'function',
|
|
1708
|
+
id: '123',
|
|
1709
|
+
function: {
|
|
1710
|
+
arguments: '[{"a": 1, "b": 2, "c": 3}]',
|
|
1711
|
+
name: 'numProperties',
|
|
1712
|
+
},
|
|
1713
|
+
},
|
|
1714
|
+
],
|
|
1486
1715
|
},
|
|
1487
1716
|
{
|
|
1488
|
-
role: '
|
|
1717
|
+
role: 'tool',
|
|
1489
1718
|
content: `must be an object`,
|
|
1490
|
-
|
|
1719
|
+
tool_call_id: '123',
|
|
1491
1720
|
},
|
|
1492
1721
|
{
|
|
1493
1722
|
role: 'assistant',
|
|
1494
1723
|
content: null,
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1724
|
+
tool_calls: [
|
|
1725
|
+
{
|
|
1726
|
+
type: 'function',
|
|
1727
|
+
id: '1234',
|
|
1728
|
+
function: {
|
|
1729
|
+
arguments: '{"a": 1, "b": 2, "c": 3}',
|
|
1730
|
+
name: 'numProperties',
|
|
1731
|
+
},
|
|
1732
|
+
},
|
|
1733
|
+
],
|
|
1499
1734
|
},
|
|
1500
1735
|
{
|
|
1501
|
-
role: '
|
|
1736
|
+
role: 'tool',
|
|
1502
1737
|
content: '3',
|
|
1503
|
-
|
|
1738
|
+
tool_call_id: '1234',
|
|
1504
1739
|
},
|
|
1505
1740
|
]);
|
|
1506
1741
|
for (const choice of contentChoiceDeltas(`there are 3 properties in {"a": 1, "b": 2, "c": 3}`)) {
|
|
@@ -1519,15 +1754,27 @@ describe('resource completions', () => {
|
|
|
1519
1754
|
{
|
|
1520
1755
|
role: 'assistant',
|
|
1521
1756
|
content: null,
|
|
1522
|
-
|
|
1757
|
+
tool_calls: [
|
|
1758
|
+
{
|
|
1759
|
+
type: 'function',
|
|
1760
|
+
id: '123',
|
|
1761
|
+
function: { name: 'numProperties', arguments: '[{"a": 1, "b": 2, "c": 3}]' },
|
|
1762
|
+
},
|
|
1763
|
+
],
|
|
1523
1764
|
},
|
|
1524
|
-
{ role: '
|
|
1765
|
+
{ role: 'tool', content: `must be an object`, tool_call_id: '123' },
|
|
1525
1766
|
{
|
|
1526
1767
|
role: 'assistant',
|
|
1527
1768
|
content: null,
|
|
1528
|
-
|
|
1769
|
+
tool_calls: [
|
|
1770
|
+
{
|
|
1771
|
+
type: 'function',
|
|
1772
|
+
id: '1234',
|
|
1773
|
+
function: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
|
|
1774
|
+
},
|
|
1775
|
+
],
|
|
1529
1776
|
},
|
|
1530
|
-
{ role: '
|
|
1777
|
+
{ role: 'tool', content: '3', tool_call_id: '1234' },
|
|
1531
1778
|
{ role: 'assistant', content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}' },
|
|
1532
1779
|
]);
|
|
1533
1780
|
expect(listener.eventFunctionCallResults).toEqual([`must be an object`, '3']);
|
|
@@ -1536,20 +1783,26 @@ describe('resource completions', () => {
|
|
|
1536
1783
|
test('single function call', async () => {
|
|
1537
1784
|
const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
|
|
1538
1785
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
1539
|
-
const runner = openai.beta.chat.completions.
|
|
1786
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
1540
1787
|
stream: true,
|
|
1541
1788
|
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
1542
1789
|
model: 'gpt-3.5-turbo',
|
|
1543
|
-
|
|
1544
|
-
|
|
1790
|
+
tool_choice: {
|
|
1791
|
+
type: 'function',
|
|
1792
|
+
function: {
|
|
1793
|
+
name: 'getWeather',
|
|
1794
|
+
},
|
|
1545
1795
|
},
|
|
1546
|
-
|
|
1796
|
+
tools: [
|
|
1547
1797
|
{
|
|
1548
|
-
|
|
1549
|
-
|
|
1798
|
+
type: 'function',
|
|
1799
|
+
function: {
|
|
1800
|
+
function: function getWeather() {
|
|
1801
|
+
return `it's raining`;
|
|
1802
|
+
},
|
|
1803
|
+
parameters: {},
|
|
1804
|
+
description: 'gets the weather',
|
|
1550
1805
|
},
|
|
1551
|
-
parameters: {},
|
|
1552
|
-
description: 'gets the weather',
|
|
1553
1806
|
},
|
|
1554
1807
|
],
|
|
1555
1808
|
});
|
|
@@ -1566,10 +1819,17 @@ describe('resource completions', () => {
|
|
|
1566
1819
|
delta: {
|
|
1567
1820
|
role: 'assistant',
|
|
1568
1821
|
content: null,
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1822
|
+
tool_calls: [
|
|
1823
|
+
{
|
|
1824
|
+
type: 'function',
|
|
1825
|
+
index: 0,
|
|
1826
|
+
id: '123',
|
|
1827
|
+
function: {
|
|
1828
|
+
arguments: '',
|
|
1829
|
+
name: 'getWeather',
|
|
1830
|
+
},
|
|
1831
|
+
},
|
|
1832
|
+
],
|
|
1573
1833
|
},
|
|
1574
1834
|
},
|
|
1575
1835
|
],
|
|
@@ -1581,8 +1841,21 @@ describe('resource completions', () => {
|
|
|
1581
1841
|
runner.done(),
|
|
1582
1842
|
]);
|
|
1583
1843
|
expect(listener.eventMessages).toEqual([
|
|
1584
|
-
{
|
|
1585
|
-
|
|
1844
|
+
{
|
|
1845
|
+
role: 'assistant',
|
|
1846
|
+
content: null,
|
|
1847
|
+
tool_calls: [
|
|
1848
|
+
{
|
|
1849
|
+
type: 'function',
|
|
1850
|
+
id: '123',
|
|
1851
|
+
function: {
|
|
1852
|
+
arguments: '',
|
|
1853
|
+
name: 'getWeather',
|
|
1854
|
+
},
|
|
1855
|
+
},
|
|
1856
|
+
],
|
|
1857
|
+
},
|
|
1858
|
+
{ role: 'tool', tool_call_id: '123', content: `it's raining` },
|
|
1586
1859
|
]);
|
|
1587
1860
|
expect(listener.eventFunctionCallResults).toEqual([`it's raining`]);
|
|
1588
1861
|
await listener.sanityCheck();
|
|
@@ -1590,17 +1863,20 @@ describe('resource completions', () => {
|
|
|
1590
1863
|
test('wrong function name', async () => {
|
|
1591
1864
|
const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
|
|
1592
1865
|
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
1593
|
-
const runner = openai.beta.chat.completions.
|
|
1866
|
+
const runner = openai.beta.chat.completions.runTools({
|
|
1594
1867
|
stream: true,
|
|
1595
1868
|
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
1596
1869
|
model: 'gpt-3.5-turbo',
|
|
1597
|
-
|
|
1870
|
+
tools: [
|
|
1598
1871
|
{
|
|
1599
|
-
|
|
1600
|
-
|
|
1872
|
+
type: 'function',
|
|
1873
|
+
function: {
|
|
1874
|
+
function: function getWeather() {
|
|
1875
|
+
return `it's raining`;
|
|
1876
|
+
},
|
|
1877
|
+
parameters: {},
|
|
1878
|
+
description: 'gets the weather',
|
|
1601
1879
|
},
|
|
1602
|
-
parameters: {},
|
|
1603
|
-
description: 'gets the weather',
|
|
1604
1880
|
},
|
|
1605
1881
|
],
|
|
1606
1882
|
});
|
|
@@ -1617,10 +1893,17 @@ describe('resource completions', () => {
|
|
|
1617
1893
|
delta: {
|
|
1618
1894
|
role: 'assistant',
|
|
1619
1895
|
content: null,
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1896
|
+
tool_calls: [
|
|
1897
|
+
{
|
|
1898
|
+
type: 'function',
|
|
1899
|
+
index: 0,
|
|
1900
|
+
id: '123',
|
|
1901
|
+
function: {
|
|
1902
|
+
arguments: '',
|
|
1903
|
+
name: 'get_weather',
|
|
1904
|
+
},
|
|
1905
|
+
},
|
|
1906
|
+
],
|
|
1624
1907
|
},
|
|
1625
1908
|
},
|
|
1626
1909
|
],
|
|
@@ -1635,15 +1918,21 @@ describe('resource completions', () => {
|
|
|
1635
1918
|
{
|
|
1636
1919
|
role: 'assistant',
|
|
1637
1920
|
content: null,
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1921
|
+
tool_calls: [
|
|
1922
|
+
{
|
|
1923
|
+
type: 'function',
|
|
1924
|
+
id: '123',
|
|
1925
|
+
function: {
|
|
1926
|
+
arguments: '',
|
|
1927
|
+
name: 'get_weather',
|
|
1928
|
+
},
|
|
1929
|
+
},
|
|
1930
|
+
],
|
|
1642
1931
|
},
|
|
1643
1932
|
{
|
|
1644
|
-
role: '
|
|
1645
|
-
content: `Invalid
|
|
1646
|
-
|
|
1933
|
+
role: 'tool',
|
|
1934
|
+
content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
1935
|
+
tool_call_id: '123',
|
|
1647
1936
|
},
|
|
1648
1937
|
]);
|
|
1649
1938
|
yield {
|
|
@@ -1655,10 +1944,17 @@ describe('resource completions', () => {
|
|
|
1655
1944
|
delta: {
|
|
1656
1945
|
role: 'assistant',
|
|
1657
1946
|
content: null,
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1947
|
+
tool_calls: [
|
|
1948
|
+
{
|
|
1949
|
+
type: 'function',
|
|
1950
|
+
index: 0,
|
|
1951
|
+
id: '1234',
|
|
1952
|
+
function: {
|
|
1953
|
+
arguments: '',
|
|
1954
|
+
name: 'getWeather',
|
|
1955
|
+
},
|
|
1956
|
+
},
|
|
1957
|
+
],
|
|
1662
1958
|
},
|
|
1663
1959
|
},
|
|
1664
1960
|
],
|
|
@@ -1673,28 +1969,40 @@ describe('resource completions', () => {
|
|
|
1673
1969
|
{
|
|
1674
1970
|
role: 'assistant',
|
|
1675
1971
|
content: null,
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1972
|
+
tool_calls: [
|
|
1973
|
+
{
|
|
1974
|
+
type: 'function',
|
|
1975
|
+
id: '123',
|
|
1976
|
+
function: {
|
|
1977
|
+
arguments: '',
|
|
1978
|
+
name: 'get_weather',
|
|
1979
|
+
},
|
|
1980
|
+
},
|
|
1981
|
+
],
|
|
1680
1982
|
},
|
|
1681
1983
|
{
|
|
1682
|
-
role: '
|
|
1683
|
-
content: `Invalid
|
|
1684
|
-
|
|
1984
|
+
role: 'tool',
|
|
1985
|
+
content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
1986
|
+
tool_call_id: '123',
|
|
1685
1987
|
},
|
|
1686
1988
|
{
|
|
1687
1989
|
role: 'assistant',
|
|
1688
1990
|
content: null,
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1991
|
+
tool_calls: [
|
|
1992
|
+
{
|
|
1993
|
+
type: 'function',
|
|
1994
|
+
id: '1234',
|
|
1995
|
+
function: {
|
|
1996
|
+
arguments: '',
|
|
1997
|
+
name: 'getWeather',
|
|
1998
|
+
},
|
|
1999
|
+
},
|
|
2000
|
+
],
|
|
1693
2001
|
},
|
|
1694
2002
|
{
|
|
1695
|
-
role: '
|
|
2003
|
+
role: 'tool',
|
|
1696
2004
|
content: `it's raining`,
|
|
1697
|
-
|
|
2005
|
+
tool_call_id: '1234',
|
|
1698
2006
|
},
|
|
1699
2007
|
]);
|
|
1700
2008
|
for (const choice of contentChoiceDeltas(`it's raining`)) {
|
|
@@ -1710,79 +2018,45 @@ describe('resource completions', () => {
|
|
|
1710
2018
|
runner.done(),
|
|
1711
2019
|
]);
|
|
1712
2020
|
expect(listener.eventMessages).toEqual([
|
|
1713
|
-
{ role: 'assistant', content: null, function_call: { name: 'get_weather', arguments: '' } },
|
|
1714
2021
|
{
|
|
1715
|
-
role: '
|
|
1716
|
-
content:
|
|
1717
|
-
|
|
2022
|
+
role: 'assistant',
|
|
2023
|
+
content: null,
|
|
2024
|
+
tool_calls: [
|
|
2025
|
+
{
|
|
2026
|
+
type: 'function',
|
|
2027
|
+
id: '123',
|
|
2028
|
+
function: {
|
|
2029
|
+
arguments: '',
|
|
2030
|
+
name: 'get_weather',
|
|
2031
|
+
},
|
|
2032
|
+
},
|
|
2033
|
+
],
|
|
1718
2034
|
},
|
|
1719
|
-
{
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
expect(listener.eventFunctionCallResults).toEqual([
|
|
1724
|
-
`Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
1725
|
-
`it's raining`,
|
|
1726
|
-
]);
|
|
1727
|
-
await listener.sanityCheck();
|
|
1728
|
-
});
|
|
1729
|
-
test('wrong function name with single function call', async () => {
|
|
1730
|
-
const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
|
|
1731
|
-
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
|
|
1732
|
-
const runner = openai.beta.chat.completions.runFunctions({
|
|
1733
|
-
stream: true,
|
|
1734
|
-
messages: [{ role: 'user', content: 'tell me what the weather is like' }],
|
|
1735
|
-
model: 'gpt-3.5-turbo',
|
|
1736
|
-
function_call: {
|
|
1737
|
-
name: 'getWeather',
|
|
2035
|
+
{
|
|
2036
|
+
role: 'tool',
|
|
2037
|
+
content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
2038
|
+
tool_call_id: '123',
|
|
1738
2039
|
},
|
|
1739
|
-
functions: [
|
|
1740
|
-
{
|
|
1741
|
-
function: function getWeather() {
|
|
1742
|
-
return `it's raining`;
|
|
1743
|
-
},
|
|
1744
|
-
parameters: {},
|
|
1745
|
-
description: 'gets the weather',
|
|
1746
|
-
},
|
|
1747
|
-
],
|
|
1748
|
-
});
|
|
1749
|
-
const listener = new StreamingRunnerListener(runner);
|
|
1750
|
-
await Promise.all([
|
|
1751
|
-
handleRequest(async function* (request) {
|
|
1752
|
-
expect(request.messages).toEqual([{ role: 'user', content: 'tell me what the weather is like' }]);
|
|
1753
|
-
yield {
|
|
1754
|
-
id: '1',
|
|
1755
|
-
choices: [
|
|
1756
|
-
{
|
|
1757
|
-
index: 0,
|
|
1758
|
-
finish_reason: 'function_call',
|
|
1759
|
-
delta: {
|
|
1760
|
-
role: 'assistant',
|
|
1761
|
-
content: null,
|
|
1762
|
-
function_call: {
|
|
1763
|
-
arguments: '',
|
|
1764
|
-
name: 'get_weather',
|
|
1765
|
-
},
|
|
1766
|
-
},
|
|
1767
|
-
},
|
|
1768
|
-
],
|
|
1769
|
-
created: Math.floor(Date.now() / 1000),
|
|
1770
|
-
model: 'gpt-3.5-turbo',
|
|
1771
|
-
object: 'chat.completion.chunk',
|
|
1772
|
-
};
|
|
1773
|
-
}),
|
|
1774
|
-
runner.done(),
|
|
1775
|
-
]);
|
|
1776
|
-
expect(listener.eventMessages).toEqual([
|
|
1777
|
-
{ role: 'assistant', content: null, function_call: { name: 'get_weather', arguments: '' } },
|
|
1778
2040
|
{
|
|
1779
|
-
role: '
|
|
1780
|
-
content:
|
|
1781
|
-
|
|
2041
|
+
role: 'assistant',
|
|
2042
|
+
content: null,
|
|
2043
|
+
tool_calls: [
|
|
2044
|
+
{
|
|
2045
|
+
type: 'function',
|
|
2046
|
+
id: '1234',
|
|
2047
|
+
function: {
|
|
2048
|
+
arguments: '',
|
|
2049
|
+
name: 'getWeather',
|
|
2050
|
+
},
|
|
2051
|
+
},
|
|
2052
|
+
],
|
|
1782
2053
|
},
|
|
2054
|
+
{ role: 'tool', content: `it's raining`, tool_call_id: '1234' },
|
|
2055
|
+
{ role: 'assistant', content: "it's raining" },
|
|
1783
2056
|
]);
|
|
1784
2057
|
expect(listener.eventFunctionCallResults).toEqual([
|
|
1785
|
-
`Invalid
|
|
2058
|
+
`Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
|
|
2059
|
+
`it's raining`,
|
|
1786
2060
|
]);
|
|
1787
2061
|
await listener.sanityCheck();
|
|
1788
2062
|
});
|