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.
Files changed (95) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +3 -3
  3. package/error.d.ts.map +1 -1
  4. package/error.js +2 -1
  5. package/error.js.map +1 -1
  6. package/error.mjs +2 -1
  7. package/error.mjs.map +1 -1
  8. package/index.d.mts +7 -5
  9. package/index.d.ts +7 -5
  10. package/index.d.ts.map +1 -1
  11. package/index.js +5 -5
  12. package/index.js.map +1 -1
  13. package/index.mjs +5 -5
  14. package/index.mjs.map +1 -1
  15. package/lib/AbstractChatCompletionRunner.d.ts +1 -1
  16. package/lib/AbstractChatCompletionRunner.d.ts.map +1 -1
  17. package/lib/AbstractChatCompletionRunner.js +21 -6
  18. package/lib/AbstractChatCompletionRunner.js.map +1 -1
  19. package/lib/AbstractChatCompletionRunner.mjs +21 -6
  20. package/lib/AbstractChatCompletionRunner.mjs.map +1 -1
  21. package/lib/ChatCompletionRunFunctions.test.js +823 -549
  22. package/lib/ChatCompletionRunFunctions.test.js.map +1 -1
  23. package/lib/ChatCompletionRunFunctions.test.mjs +824 -550
  24. package/lib/ChatCompletionRunFunctions.test.mjs.map +1 -1
  25. package/lib/ChatCompletionRunner.d.ts +1 -0
  26. package/lib/ChatCompletionRunner.d.ts.map +1 -1
  27. package/lib/ChatCompletionRunner.js +11 -2
  28. package/lib/ChatCompletionRunner.js.map +1 -1
  29. package/lib/ChatCompletionRunner.mjs +11 -2
  30. package/lib/ChatCompletionRunner.mjs.map +1 -1
  31. package/lib/ChatCompletionStreamingRunner.d.ts +1 -0
  32. package/lib/ChatCompletionStreamingRunner.d.ts.map +1 -1
  33. package/lib/ChatCompletionStreamingRunner.js +7 -4
  34. package/lib/ChatCompletionStreamingRunner.js.map +1 -1
  35. package/lib/ChatCompletionStreamingRunner.mjs +7 -4
  36. package/lib/ChatCompletionStreamingRunner.mjs.map +1 -1
  37. package/lib/RunnableFunction.d.ts +19 -3
  38. package/lib/RunnableFunction.d.ts.map +1 -1
  39. package/lib/RunnableFunction.js +14 -1
  40. package/lib/RunnableFunction.js.map +1 -1
  41. package/lib/RunnableFunction.mjs +12 -0
  42. package/lib/RunnableFunction.mjs.map +1 -1
  43. package/package.json +3 -2
  44. package/resources/audio/speech.d.ts +3 -1
  45. package/resources/audio/speech.d.ts.map +1 -1
  46. package/resources/audio/speech.js.map +1 -1
  47. package/resources/audio/speech.mjs.map +1 -1
  48. package/resources/beta/chat/completions.d.ts +2 -8
  49. package/resources/beta/chat/completions.d.ts.map +1 -1
  50. package/resources/beta/chat/completions.js +2 -1
  51. package/resources/beta/chat/completions.js.map +1 -1
  52. package/resources/beta/chat/completions.mjs +1 -1
  53. package/resources/beta/chat/completions.mjs.map +1 -1
  54. package/resources/chat/completions.d.ts +52 -34
  55. package/resources/chat/completions.d.ts.map +1 -1
  56. package/resources/chat/completions.js.map +1 -1
  57. package/resources/chat/completions.mjs.map +1 -1
  58. package/resources/completions.d.ts +2 -2
  59. package/resources/embeddings.d.ts +2 -1
  60. package/resources/embeddings.d.ts.map +1 -1
  61. package/resources/embeddings.js.map +1 -1
  62. package/resources/embeddings.mjs.map +1 -1
  63. package/resources/files.d.ts +3 -3
  64. package/resources/files.js +3 -3
  65. package/resources/files.mjs +3 -3
  66. package/resources/shared.d.ts +12 -14
  67. package/resources/shared.d.ts.map +1 -1
  68. package/src/error.ts +2 -1
  69. package/src/index.ts +8 -5
  70. package/src/lib/AbstractChatCompletionRunner.ts +37 -13
  71. package/src/lib/ChatCompletionRunFunctions.test.ts +828 -558
  72. package/src/lib/ChatCompletionRunner.ts +11 -2
  73. package/src/lib/ChatCompletionStreamingRunner.ts +11 -12
  74. package/src/lib/RunnableFunction.ts +33 -7
  75. package/src/resources/audio/speech.ts +3 -1
  76. package/src/resources/beta/chat/completions.ts +2 -7
  77. package/src/resources/chat/completions.ts +56 -35
  78. package/src/resources/completions.ts +2 -2
  79. package/src/resources/embeddings.ts +2 -1
  80. package/src/resources/files.ts +3 -3
  81. package/src/resources/shared.ts +13 -15
  82. package/src/streaming.ts +4 -1
  83. package/src/uploads.ts +2 -3
  84. package/src/version.ts +1 -1
  85. package/streaming.d.ts.map +1 -1
  86. package/streaming.js.map +1 -1
  87. package/streaming.mjs.map +1 -1
  88. package/uploads.d.ts.map +1 -1
  89. package/uploads.js +2 -1
  90. package/uploads.js.map +1 -1
  91. package/uploads.mjs +2 -1
  92. package/uploads.mjs.map +1 -1
  93. package/version.d.ts +1 -1
  94. package/version.js +1 -1
  95. package/version.mjs +1 -1
@@ -1,6 +1,6 @@
1
1
  import OpenAI from 'openai';
2
2
  import { PassThrough } from 'stream';
3
- import { ParsingFunction, ChatCompletionStreamingRunner, } from 'openai/resources/beta/chat/completions';
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
- function_call: {
133
- arguments: `${deltas[i] || ''}${i === deltas.length - 1 ? '' : ' '}`,
134
- ...(i === deltas.length - 1 ? { name } : null),
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(this.messages[this.messages.length - 1]);
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(this.eventMessages[this.eventMessages.length - 1]);
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.runFunctions({
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
- functions: [
347
+ tools: [
336
348
  {
337
- name: 'numProperties',
338
- function: (obj) => String(Object.keys(obj).length),
339
- parameters: { type: 'object' },
340
- parse: (str) => {
341
- const result = JSON.parse(str);
342
- if (!(result instanceof Object) || Array.isArray(result)) {
343
- throw new Error('must be an object');
344
- }
345
- return result;
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
- function: (str) => String(str.length),
351
- parameters: { type: 'string' },
352
- description: 'gets the length of a string',
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
- function: (obj) => String(Object.keys(obj).length),
357
- parameters: { type: 'object' },
358
- description: 'gets the number of properties on an object',
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.runFunctions({
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
- functions: [
368
- new ParsingFunction({
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.runFunctions({
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
- functions: [
384
- new ParsingFunction({
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 ParsingFunction({
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 ParsingFunction({
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.runFunctions({
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
- functions: [
447
+ tools: [
427
448
  {
428
- name: 'numProperties',
429
- parse: (str) => {
430
- const result = JSON.parse(str);
431
- if (!(result instanceof Object) || Array.isArray(result)) {
432
- throw new Error('must be an object');
433
- }
434
- return result;
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
- name: 'keys',
442
- parse: (str) => {
443
- const result = JSON.parse(str);
444
- if (!(result instanceof Object)) {
445
- throw new Error('must be an Object');
446
- }
447
- return result;
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
- name: 'len2',
455
- parse: (str) => str,
456
- // @ts-ignore error occurs here in TS 5
457
- // function input doesn't match parse output
458
- function: (obj) => String(Object.keys(obj).length),
459
- parameters: { type: 'object' },
460
- description: 'gets the number of properties on an object',
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
- // TODO: re-enable
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.runFunctions({
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
- functions: [
503
+ tools: [
475
504
  {
476
- function: function getWeather() {
477
- return `it's raining`;
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 Promise.all([
486
- handleRequest(async (request) => {
487
- expect(request.messages).toEqual([{ role: 'user', content: 'tell me what the weather is like' }]);
488
- return {
489
- id: '1',
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
- role: 'assistant',
514
- content: null,
515
- function_call: {
516
- arguments: '',
517
- name: 'getWeather',
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
- role: 'function',
522
- content: `it's raining`,
523
- name: 'getWeather',
524
- },
525
- ]);
526
- return {
527
- id: '2',
528
- choices: [
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
- index: 0,
531
- finish_reason: 'stop',
532
- message: {
533
- role: 'assistant',
534
- content: `it's raining`,
554
+ type: 'function',
555
+ id: '123',
556
+ function: {
557
+ arguments: '',
558
+ name: 'getWeather',
535
559
  },
536
560
  },
537
561
  ],
538
- created: Math.floor(Date.now() / 1000),
539
- model: 'gpt-3.5-turbo',
540
- object: 'chat.completion',
541
- };
542
- }),
543
- runner.done(),
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
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
548
- { role: 'function', content: `it's raining`, name: 'getWeather' },
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.runFunctions({
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
- functions: [
616
+ tools: [
562
617
  {
563
- function: function getWeather() {
564
- return `it's raining`;
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
- function_call: {
584
- arguments: '',
585
- name: 'getWeather',
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
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
600
- { role: 'function', content: `it's raining`, name: 'getWeather' },
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.runFunctions({
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
- functions: [
618
- new ParsingFunction({
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 Promise.all([
635
- handleRequest(async (request) => {
636
- expect(request.messages).toEqual([
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
- role: 'user',
639
- content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
640
- },
641
- ]);
642
- return {
643
- id: '1',
644
- choices: [
645
- {
646
- index: 0,
647
- finish_reason: 'function_call',
648
- message: {
649
- role: 'assistant',
650
- content: null,
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
- role: 'function',
684
- content: '3',
685
- name: 'numProperties',
686
- },
687
- ]);
688
- return {
689
- id: '2',
690
- choices: [
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
- index: 0,
693
- finish_reason: 'stop',
694
- message: {
695
- role: 'assistant',
696
- content: `there are 3 properties in {"a": 1, "b": 2, "c": 3}`,
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
- created: Math.floor(Date.now() / 1000),
701
- model: 'gpt-3.5-turbo',
702
- object: 'chat.completion',
703
- usage: {
704
- completion_tokens: 10,
705
- prompt_tokens: 25,
706
- total_tokens: 35,
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
- runner.done(),
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
- function_call: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
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: 'function', content: '3', name: 'numProperties' },
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.runFunctions({
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
- functions: [
740
- new ParsingFunction({
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
- function_call: {
774
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
775
- name: 'numProperties',
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
- function_call: {
795
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
796
- name: 'numProperties',
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: 'function',
905
+ role: 'tool',
801
906
  content: `must be an object`,
802
- name: 'numProperties',
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
- function_call: {
815
- arguments: '{"a": 1, "b": 2, "c": 3}',
816
- name: 'numProperties',
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
- function_call: {
836
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
837
- name: 'numProperties',
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: 'function',
958
+ role: 'tool',
842
959
  content: `must be an object`,
843
- name: 'numProperties',
960
+ tool_call_id: '123',
844
961
  },
845
962
  {
846
963
  role: 'assistant',
847
964
  content: null,
848
- function_call: {
849
- arguments: '{"a": 1, "b": 2, "c": 3}',
850
- name: 'numProperties',
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: 'function',
977
+ role: 'tool',
855
978
  content: '3',
856
- name: 'numProperties',
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
- function_call: { name: 'numProperties', arguments: '[{"a": 1, "b": 2, "c": 3}]' },
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: 'function', content: `must be an object`, name: 'numProperties' },
1017
+ { role: 'tool', content: `must be an object`, tool_call_id: '123' },
889
1018
  {
890
1019
  role: 'assistant',
891
1020
  content: null,
892
- function_call: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
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: 'function', content: '3', name: 'numProperties' },
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.runFunctions({
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
- function_call: {
907
- name: 'getWeather',
1041
+ tool_choice: {
1042
+ type: 'function',
1043
+ function: {
1044
+ name: 'getWeather',
1045
+ },
908
1046
  },
909
- functions: [
1047
+ tools: [
910
1048
  {
911
- function: function getWeather() {
912
- return `it's raining`;
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
- function_call: {
933
- arguments: '',
934
- name: 'getWeather',
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
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
949
- { role: 'function', content: `it's raining`, name: 'getWeather' },
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.runFunctions({
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
- functions: [
1120
+ tools: [
961
1121
  {
962
- function: function getWeather() {
963
- return `it's raining`;
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
- function_call: {
984
- arguments: '',
985
- name: 'get_weather',
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
- function_call: {
1002
- arguments: '',
1003
- name: 'get_weather',
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: 'function',
1008
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1009
- name: 'get_weather',
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
- function_call: {
1022
- arguments: '',
1023
- name: 'getWeather',
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
- function_call: {
1040
- arguments: '',
1041
- name: 'get_weather',
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: 'function',
1046
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1047
- name: 'get_weather',
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
- function_call: {
1053
- arguments: '',
1054
- name: 'getWeather',
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: 'function',
1251
+ role: 'tool',
1059
1252
  content: `it's raining`,
1060
- name: 'getWeather',
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: 'function',
1087
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
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
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1091
- { role: 'function', content: `it's raining`, name: 'getWeather' },
1092
- { role: 'assistant', content: "it's raining" },
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: 'function',
1151
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1152
- name: 'get_weather',
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 function_call: "get_weather". Available options are: "getWeather". Please try again`,
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
- // TODO: re-enable
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.runFunctions({
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
- functions: [
1310
+ tools: [
1171
1311
  {
1172
- function: function getWeather() {
1173
- return `it's raining`;
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
- function_call: {
1194
- arguments: '',
1195
- name: 'getWeather',
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
- function_call: {
1212
- arguments: '',
1213
- name: 'getWeather',
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: 'function',
1373
+ role: 'tool',
1218
1374
  content: `it's raining`,
1219
- name: 'getWeather',
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
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1236
- { role: 'function', content: `it's raining`, name: 'getWeather' },
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.runFunctions({
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
- functions: [
1419
+ tools: [
1251
1420
  {
1252
- function: function getWeather() {
1253
- return `it's raining`;
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
- function_call: {
1274
- arguments: '',
1275
- name: 'getWeather',
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
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1288
- { role: 'function', content: `it's raining`, name: 'getWeather' },
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.runFunctions({
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
- functions: [
1307
- new ParsingFunction({
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
- function_call: {
1341
- arguments: '{"a": 1, "b": 2, "c": 3}',
1342
- name: 'numProperties',
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
- function_call: {
1362
- arguments: '{"a": 1, "b": 2, "c": 3}',
1363
- name: 'numProperties',
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: 'function',
1572
+ role: 'tool',
1368
1573
  content: '3',
1369
- name: 'numProperties',
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
- function_call: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
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: 'function', content: '3', name: 'numProperties' },
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.runFunctions({
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
- functions: [
1409
- new ParsingFunction({
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}]', { name: 'numProperties' })) {
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
- function_call: {
1453
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
1454
- name: 'numProperties',
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: 'function',
1678
+ role: 'tool',
1459
1679
  content: `must be an object`,
1460
- name: 'numProperties',
1680
+ tool_call_id: '123',
1461
1681
  },
1462
1682
  ]);
1463
- for (const choice of functionCallDeltas('{"a": 1, "b": 2, "c": 3}', { name: 'numProperties' })) {
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
- function_call: {
1483
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
1484
- name: 'numProperties',
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: 'function',
1717
+ role: 'tool',
1489
1718
  content: `must be an object`,
1490
- name: 'numProperties',
1719
+ tool_call_id: '123',
1491
1720
  },
1492
1721
  {
1493
1722
  role: 'assistant',
1494
1723
  content: null,
1495
- function_call: {
1496
- arguments: '{"a": 1, "b": 2, "c": 3}',
1497
- name: 'numProperties',
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: 'function',
1736
+ role: 'tool',
1502
1737
  content: '3',
1503
- name: 'numProperties',
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
- function_call: { name: 'numProperties', arguments: '[{"a": 1, "b": 2, "c": 3}]' },
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: 'function', content: `must be an object`, name: 'numProperties' },
1765
+ { role: 'tool', content: `must be an object`, tool_call_id: '123' },
1525
1766
  {
1526
1767
  role: 'assistant',
1527
1768
  content: null,
1528
- function_call: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
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: 'function', content: '3', name: 'numProperties' },
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.runFunctions({
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
- function_call: {
1544
- name: 'getWeather',
1790
+ tool_choice: {
1791
+ type: 'function',
1792
+ function: {
1793
+ name: 'getWeather',
1794
+ },
1545
1795
  },
1546
- functions: [
1796
+ tools: [
1547
1797
  {
1548
- function: function getWeather() {
1549
- return `it's raining`;
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
- function_call: {
1570
- arguments: '',
1571
- name: 'getWeather',
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
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1585
- { role: 'function', content: `it's raining`, name: 'getWeather' },
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.runFunctions({
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
- functions: [
1870
+ tools: [
1598
1871
  {
1599
- function: function getWeather() {
1600
- return `it's raining`;
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
- function_call: {
1621
- arguments: '',
1622
- name: 'get_weather',
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
- function_call: {
1639
- arguments: '',
1640
- name: 'get_weather',
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: 'function',
1645
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1646
- name: 'get_weather',
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
- function_call: {
1659
- arguments: '',
1660
- name: 'getWeather',
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
- function_call: {
1677
- arguments: '',
1678
- name: 'get_weather',
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: 'function',
1683
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1684
- name: 'get_weather',
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
- function_call: {
1690
- arguments: '',
1691
- name: 'getWeather',
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: 'function',
2003
+ role: 'tool',
1696
2004
  content: `it's raining`,
1697
- name: 'getWeather',
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: 'function',
1716
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1717
- name: 'get_weather',
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
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1720
- { role: 'function', content: `it's raining`, name: 'getWeather' },
1721
- { role: 'assistant', content: "it's raining" },
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: 'function',
1780
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1781
- name: 'get_weather',
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 function_call: "get_weather". Available options are: "getWeather". Please try again`,
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
  });