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