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
@@ -2,7 +2,7 @@ import OpenAI from 'openai';
2
2
  import { OpenAIError } from "../error";
3
3
  import { PassThrough } from 'stream';
4
4
  import {
5
- ParsingFunction,
5
+ ParsingToolFunction,
6
6
  type ChatCompletionRunner,
7
7
  type ChatCompletionFunctionRunnerParams,
8
8
  ChatCompletionStreamingRunner,
@@ -63,10 +63,13 @@ function mockFetch(): { fetch: Fetch; handleRequest: (handle: Fetch) => Promise<
63
63
  }
64
64
 
65
65
  function handleRequest(handle: typeof fetch): Promise<void> {
66
- return new Promise<void>((resolve) => {
66
+ return new Promise<void>((resolve, reject) => {
67
67
  fetchQueue.shift()?.(async (req, init) => {
68
68
  try {
69
69
  return await handle(req, init);
70
+ } catch (err) {
71
+ reject(err);
72
+ return err as any;
70
73
  } finally {
71
74
  resolve();
72
75
  }
@@ -157,10 +160,12 @@ function* functionCallDeltas(
157
160
  args: string,
158
161
  {
159
162
  index = 0,
163
+ id = '123',
160
164
  name,
161
165
  role = 'assistant',
162
166
  }: {
163
167
  name: string;
168
+ id?: string;
164
169
  index?: number;
165
170
  role?: NonNullable<OpenAI.Chat.ChatCompletionChunk.Choice.Delta['role']>;
166
171
  },
@@ -172,10 +177,17 @@ function* functionCallDeltas(
172
177
  finish_reason: i === deltas.length - 1 ? 'function_call' : null,
173
178
  delta: {
174
179
  role,
175
- function_call: {
176
- arguments: `${deltas[i] || ''}${i === deltas.length - 1 ? '' : ' '}`,
177
- ...(i === deltas.length - 1 ? { name } : null),
178
- },
180
+ tool_calls: [
181
+ {
182
+ type: 'function',
183
+ index: 0,
184
+ id,
185
+ function: {
186
+ arguments: `${deltas[i] || ''}${i === deltas.length - 1 ? '' : ' '}`,
187
+ ...(i === deltas.length - 1 ? { name } : null),
188
+ },
189
+ },
190
+ ],
179
191
  },
180
192
  };
181
193
  }
@@ -215,7 +227,7 @@ class RunnerListener {
215
227
  .on('finalFunctionCallResult', (result) => (this.finalFunctionCallResult = result))
216
228
  .on('totalUsage', (usage) => (this.totalUsage = usage))
217
229
  .on('error', (error) => (this.error = error))
218
- .on('abort', () => (this.gotAbort = true))
230
+ .on('abort', (error) => ((this.error = error), (this.gotAbort = true)))
219
231
  .on('end', () => (this.gotEnd = true))
220
232
  .once('message', () => this.onceMessageCallCount++);
221
233
  }
@@ -262,7 +274,7 @@ class RunnerListener {
262
274
  .map((m) => m.content as string)
263
275
  .filter(Boolean);
264
276
  expect(this.contents).toEqual(expectedContents);
265
- expect(this.finalMessage).toEqual(this.messages[this.messages.length - 1]);
277
+ expect(this.finalMessage).toEqual([...this.messages].reverse().find((x) => x.role === 'assistant'));
266
278
  expect(await this.runner.finalMessage()).toEqual(this.finalMessage);
267
279
  expect(this.finalContent).toEqual(expectedContents[expectedContents.length - 1] ?? null);
268
280
  expect(await this.runner.finalContent()).toEqual(this.finalContent);
@@ -329,6 +341,7 @@ class StreamingRunnerListener {
329
341
  .on('finalFunctionCall', (functionCall) => (this.finalFunctionCall = functionCall))
330
342
  .on('finalFunctionCallResult', (result) => (this.finalFunctionCallResult = result))
331
343
  .on('error', (error) => (this.error = error))
344
+ .on('abort', (abort) => (this.error = abort))
332
345
  .on('end', () => (this.gotEnd = true));
333
346
  }
334
347
 
@@ -365,7 +378,7 @@ class StreamingRunnerListener {
365
378
  if (error) return;
366
379
 
367
380
  if (this.eventContents.length) expect(this.eventChunks.length).toBeGreaterThan(0);
368
- expect(this.finalMessage).toEqual(this.eventMessages[this.eventMessages.length - 1]);
381
+ expect(this.finalMessage).toEqual([...this.eventMessages].reverse().find((x) => x.role === 'assistant'));
369
382
  expect(await this.runner.finalMessage()).toEqual(this.finalMessage);
370
383
  expect(this.finalContent).toEqual(this.eventContents[this.eventContents.length - 1]?.[1] ?? null);
371
384
  expect(await this.runner.finalContent()).toEqual(this.finalContent);
@@ -393,45 +406,54 @@ class StreamingRunnerListener {
393
406
  function _typeTests() {
394
407
  const openai = new OpenAI();
395
408
 
396
- openai.beta.chat.completions.runFunctions({
409
+ openai.beta.chat.completions.runTools({
397
410
  messages: [
398
411
  { role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' },
399
412
  ],
400
413
  model: 'gpt-3.5-turbo',
401
- functions: [
414
+ tools: [
402
415
  {
403
- name: 'numProperties',
404
- function: (obj: object) => String(Object.keys(obj).length),
405
- parameters: { type: 'object' },
406
- parse: (str: string): object => {
407
- const result = JSON.parse(str);
408
- if (!(result instanceof Object) || Array.isArray(result)) {
409
- throw new Error('must be an object');
410
- }
411
- return result;
416
+ type: 'function',
417
+ function: {
418
+ name: 'numProperties',
419
+ function: (obj: object) => String(Object.keys(obj).length),
420
+ parameters: { type: 'object' },
421
+ parse: (str: string): object => {
422
+ const result = JSON.parse(str);
423
+ if (!(result instanceof Object) || Array.isArray(result)) {
424
+ throw new Error('must be an object');
425
+ }
426
+ return result;
427
+ },
428
+ description: 'gets the number of properties on an object',
412
429
  },
413
- description: 'gets the number of properties on an object',
414
430
  },
415
431
  {
416
- function: (str: string) => String(str.length),
417
- parameters: { type: 'string' },
418
- description: 'gets the length of a string',
432
+ type: 'function',
433
+ function: {
434
+ function: (str: string) => String(str.length),
435
+ parameters: { type: 'string' },
436
+ description: 'gets the length of a string',
437
+ },
419
438
  },
420
- // @ts-expect-error function must accept string if parse is omitted
421
439
  {
422
- function: (obj: object) => String(Object.keys(obj).length),
423
- parameters: { type: 'object' },
424
- description: 'gets the number of properties on an object',
440
+ type: 'function',
441
+ // @ts-expect-error function must accept string if parse is omitted
442
+ function: {
443
+ function: (obj: object) => String(Object.keys(obj).length),
444
+ parameters: { type: 'object' },
445
+ description: 'gets the number of properties on an object',
446
+ },
425
447
  },
426
448
  ],
427
449
  });
428
- openai.beta.chat.completions.runFunctions({
450
+ openai.beta.chat.completions.runTools({
429
451
  messages: [
430
452
  { role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' },
431
453
  ],
432
454
  model: 'gpt-3.5-turbo',
433
- functions: [
434
- new ParsingFunction({
455
+ tools: [
456
+ new ParsingToolFunction({
435
457
  name: 'numProperties',
436
458
  // @ts-expect-error parse and function don't match
437
459
  parse: (str: string) => str,
@@ -441,13 +463,13 @@ function _typeTests() {
441
463
  }),
442
464
  ],
443
465
  });
444
- openai.beta.chat.completions.runFunctions({
466
+ openai.beta.chat.completions.runTools({
445
467
  messages: [
446
468
  { role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' },
447
469
  ],
448
470
  model: 'gpt-3.5-turbo',
449
- functions: [
450
- new ParsingFunction({
471
+ tools: [
472
+ new ParsingToolFunction({
451
473
  name: 'numProperties',
452
474
  parse: (str: string): object => {
453
475
  const result = JSON.parse(str);
@@ -460,7 +482,7 @@ function _typeTests() {
460
482
  parameters: { type: 'object' },
461
483
  description: 'gets the number of properties on an object',
462
484
  }),
463
- new ParsingFunction({
485
+ new ParsingToolFunction({
464
486
  name: 'keys',
465
487
  parse: (str: string): object => {
466
488
  const result = JSON.parse(str);
@@ -473,7 +495,7 @@ function _typeTests() {
473
495
  parameters: { type: 'object' },
474
496
  description: 'gets the number of properties on an object',
475
497
  }),
476
- new ParsingFunction({
498
+ new ParsingToolFunction({
477
499
  name: 'len2',
478
500
  // @ts-expect-error parse and function don't match
479
501
  parse: (str: string) => str,
@@ -483,140 +505,177 @@ function _typeTests() {
483
505
  }),
484
506
  ],
485
507
  });
486
- openai.beta.chat.completions.runFunctions({
508
+ openai.beta.chat.completions.runTools({
487
509
  messages: [
488
510
  { role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' },
489
511
  ],
490
512
  model: 'gpt-3.5-turbo',
491
513
  // @ts-ignore error occurs here in TS 4
492
- functions: [
514
+ tools: [
493
515
  {
494
- name: 'numProperties',
495
- parse: (str: string): object => {
496
- const result = JSON.parse(str);
497
- if (!(result instanceof Object) || Array.isArray(result)) {
498
- throw new Error('must be an object');
499
- }
500
- return result;
516
+ type: 'function',
517
+ function: {
518
+ name: 'numProperties',
519
+ parse: (str: string): object => {
520
+ const result = JSON.parse(str);
521
+ if (!(result instanceof Object) || Array.isArray(result)) {
522
+ throw new Error('must be an object');
523
+ }
524
+ return result;
525
+ },
526
+ function: (obj: object) => String(Object.keys(obj).length),
527
+ parameters: { type: 'object' },
528
+ description: 'gets the number of properties on an object',
501
529
  },
502
- function: (obj: object) => String(Object.keys(obj).length),
503
- parameters: { type: 'object' },
504
- description: 'gets the number of properties on an object',
505
530
  },
506
531
  {
507
- name: 'keys',
508
- parse: (str: string): object => {
509
- const result = JSON.parse(str);
510
- if (!(result instanceof Object)) {
511
- throw new Error('must be an Object');
512
- }
513
- return result;
532
+ type: 'function',
533
+ function: {
534
+ name: 'keys',
535
+ parse: (str: string): object => {
536
+ const result = JSON.parse(str);
537
+ if (!(result instanceof Object)) {
538
+ throw new Error('must be an Object');
539
+ }
540
+ return result;
541
+ },
542
+ function: (obj: object) => Object.keys(obj).join(', '),
543
+ parameters: { type: 'object' },
544
+ description: 'gets the number of properties on an object',
514
545
  },
515
- function: (obj: object) => Object.keys(obj).join(', '),
516
- parameters: { type: 'object' },
517
- description: 'gets the number of properties on an object',
518
546
  },
519
547
  {
520
- name: 'len2',
521
- parse: (str: string) => str,
522
- // @ts-ignore error occurs here in TS 5
523
- // function input doesn't match parse output
524
- function: (obj: object) => String(Object.keys(obj).length),
525
- parameters: { type: 'object' },
526
- description: 'gets the number of properties on an object',
548
+ type: 'function',
549
+ function: {
550
+ name: 'len2',
551
+ parse: (str: string) => str,
552
+ // @ts-ignore error occurs here in TS 5
553
+ // function input doesn't match parse output
554
+ function: (obj: object) => String(Object.keys(obj).length),
555
+ parameters: { type: 'object' },
556
+ description: 'gets the number of properties on an object',
557
+ },
527
558
  },
528
559
  ] as const,
529
560
  });
530
561
  }
531
562
 
532
563
  describe('resource completions', () => {
533
- // TODO: re-enable
534
- describe.skip('runFunctions with stream: false', () => {
564
+ describe('runTools with stream: false', () => {
535
565
  test('successful flow', async () => {
536
566
  const { fetch, handleRequest } = mockChatCompletionFetch();
537
567
 
538
568
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
539
569
 
540
- const runner = openai.beta.chat.completions.runFunctions({
570
+ const runner = openai.beta.chat.completions.runTools({
541
571
  messages: [{ role: 'user', content: 'tell me what the weather is like' }],
542
572
  model: 'gpt-3.5-turbo',
543
- functions: [
573
+ tools: [
544
574
  {
545
- function: function getWeather() {
546
- return `it's raining`;
575
+ type: 'function',
576
+ function: {
577
+ function: function getWeather() {
578
+ return `it's raining`;
579
+ },
580
+ parameters: {},
581
+ description: 'gets the weather',
547
582
  },
548
- parameters: {},
549
- description: 'gets the weather',
550
583
  },
551
584
  ],
552
585
  });
553
586
  const listener = new RunnerListener(runner);
554
587
 
555
- await Promise.all([
556
- handleRequest(async (request) => {
557
- expect(request.messages).toEqual([{ role: 'user', content: 'tell me what the weather is like' }]);
558
- return {
559
- id: '1',
560
- choices: [
561
- {
562
- index: 0,
563
- finish_reason: 'function_call',
564
- message: {
565
- role: 'assistant',
566
- content: null,
567
- function_call: {
568
- arguments: '',
569
- name: 'getWeather',
570
- },
571
- },
572
- },
573
- ],
574
- created: Math.floor(Date.now() / 1000),
575
- model: 'gpt-3.5-turbo',
576
- object: 'chat.completion',
577
- };
578
- }),
579
- handleRequest(async (request) => {
580
- expect(request.messages).toEqual([
581
- { role: 'user', content: 'tell me what the weather is like' },
588
+ await handleRequest(async (request) => {
589
+ expect(request.messages).toEqual([{ role: 'user', content: 'tell me what the weather is like' }]);
590
+ return {
591
+ id: '1',
592
+ choices: [
582
593
  {
583
- role: 'assistant',
584
- content: null,
585
- function_call: {
586
- arguments: '',
587
- name: 'getWeather',
594
+ index: 0,
595
+ finish_reason: 'function_call',
596
+ message: {
597
+ role: 'assistant',
598
+ content: null,
599
+ tool_calls: [
600
+ {
601
+ type: 'function',
602
+ id: '123',
603
+ function: {
604
+ arguments: '',
605
+ name: 'getWeather',
606
+ },
607
+ },
608
+ ],
588
609
  },
589
610
  },
590
- {
591
- role: 'function',
592
- content: `it's raining`,
593
- name: 'getWeather',
594
- },
595
- ]);
596
- return {
597
- id: '2',
598
- choices: [
611
+ ],
612
+ created: Math.floor(Date.now() / 1000),
613
+ model: 'gpt-3.5-turbo',
614
+ object: 'chat.completion',
615
+ };
616
+ });
617
+
618
+ await handleRequest(async (request) => {
619
+ expect(request.messages).toEqual([
620
+ { role: 'user', content: 'tell me what the weather is like' },
621
+ {
622
+ role: 'assistant',
623
+ content: null,
624
+ tool_calls: [
599
625
  {
600
- index: 0,
601
- finish_reason: 'stop',
602
- message: {
603
- role: 'assistant',
604
- content: `it's raining`,
626
+ type: 'function',
627
+ id: '123',
628
+ function: {
629
+ arguments: '',
630
+ name: 'getWeather',
605
631
  },
606
632
  },
607
633
  ],
608
- created: Math.floor(Date.now() / 1000),
609
- model: 'gpt-3.5-turbo',
610
- object: 'chat.completion',
611
- };
612
- }),
613
- runner.done(),
614
- ]);
634
+ },
635
+ {
636
+ role: 'tool',
637
+ content: `it's raining`,
638
+ tool_call_id: '123',
639
+ },
640
+ ]);
641
+
642
+ return {
643
+ id: '2',
644
+ choices: [
645
+ {
646
+ index: 0,
647
+ finish_reason: 'stop',
648
+ message: {
649
+ role: 'assistant',
650
+ content: `it's raining`,
651
+ },
652
+ },
653
+ ],
654
+ created: Math.floor(Date.now() / 1000),
655
+ model: 'gpt-3.5-turbo',
656
+ object: 'chat.completion',
657
+ };
658
+ });
659
+
660
+ await runner.done();
615
661
 
616
662
  expect(listener.messages).toEqual([
617
663
  { role: 'user', content: 'tell me what the weather is like' },
618
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
619
- { role: 'function', content: `it's raining`, name: 'getWeather' },
664
+ {
665
+ role: 'assistant',
666
+ content: null,
667
+ tool_calls: [
668
+ {
669
+ type: 'function',
670
+ id: '123',
671
+ function: {
672
+ arguments: '',
673
+ name: 'getWeather',
674
+ },
675
+ },
676
+ ],
677
+ },
678
+ { role: 'tool', content: `it's raining`, tool_call_id: '123' },
620
679
  { role: 'assistant', content: "it's raining" },
621
680
  ]);
622
681
  expect(listener.functionCallResults).toEqual([`it's raining`]);
@@ -628,17 +687,20 @@ describe('resource completions', () => {
628
687
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
629
688
 
630
689
  const controller = new AbortController();
631
- const runner = openai.beta.chat.completions.runFunctions(
690
+ const runner = openai.beta.chat.completions.runTools(
632
691
  {
633
692
  messages: [{ role: 'user', content: 'tell me what the weather is like' }],
634
693
  model: 'gpt-3.5-turbo',
635
- functions: [
694
+ tools: [
636
695
  {
637
- function: function getWeather() {
638
- return `it's raining`;
696
+ type: 'function',
697
+ function: {
698
+ function: function getWeather() {
699
+ return `it's raining`;
700
+ },
701
+ parameters: {},
702
+ description: 'gets the weather',
639
703
  },
640
- parameters: {},
641
- description: 'gets the weather',
642
704
  },
643
705
  ],
644
706
  },
@@ -657,10 +719,16 @@ describe('resource completions', () => {
657
719
  message: {
658
720
  role: 'assistant',
659
721
  content: null,
660
- function_call: {
661
- arguments: '',
662
- name: 'getWeather',
663
- },
722
+ tool_calls: [
723
+ {
724
+ type: 'function',
725
+ id: '123',
726
+ function: {
727
+ arguments: '',
728
+ name: 'getWeather',
729
+ },
730
+ },
731
+ ],
664
732
  },
665
733
  },
666
734
  ],
@@ -676,8 +744,21 @@ describe('resource completions', () => {
676
744
 
677
745
  expect(listener.messages).toEqual([
678
746
  { role: 'user', content: 'tell me what the weather is like' },
679
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
680
- { role: 'function', content: `it's raining`, name: 'getWeather' },
747
+ {
748
+ role: 'assistant',
749
+ content: null,
750
+ tool_calls: [
751
+ {
752
+ type: 'function',
753
+ id: '123',
754
+ function: {
755
+ arguments: '',
756
+ name: 'getWeather',
757
+ },
758
+ },
759
+ ],
760
+ },
761
+ { role: 'tool', content: `it's raining`, tool_call_id: '123' },
681
762
  ]);
682
763
  expect(listener.functionCallResults).toEqual([`it's raining`]);
683
764
  await listener.sanityCheck({ error: 'Request was aborted.' });
@@ -688,7 +769,7 @@ describe('resource completions', () => {
688
769
 
689
770
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
690
771
 
691
- const runner = openai.beta.chat.completions.runFunctions({
772
+ const runner = openai.beta.chat.completions.runTools({
692
773
  messages: [
693
774
  {
694
775
  role: 'user',
@@ -696,8 +777,8 @@ describe('resource completions', () => {
696
777
  },
697
778
  ],
698
779
  model: 'gpt-3.5-turbo',
699
- functions: [
700
- new ParsingFunction({
780
+ tools: [
781
+ new ParsingToolFunction({
701
782
  name: 'numProperties',
702
783
  function: (obj: object) => String(Object.keys(obj).length),
703
784
  parameters: { type: 'object' },
@@ -714,86 +795,96 @@ describe('resource completions', () => {
714
795
  });
715
796
  const listener = new RunnerListener(runner);
716
797
 
717
- await Promise.all([
718
- handleRequest(async (request) => {
719
- expect(request.messages).toEqual([
798
+ await handleRequest(async (request) => {
799
+ expect(request.messages).toEqual([
800
+ {
801
+ role: 'user',
802
+ content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
803
+ },
804
+ ]);
805
+ return {
806
+ id: '1',
807
+ choices: [
720
808
  {
721
- role: 'user',
722
- content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
723
- },
724
- ]);
725
- return {
726
- id: '1',
727
- choices: [
728
- {
729
- index: 0,
730
- finish_reason: 'function_call',
731
- message: {
732
- role: 'assistant',
733
- content: null,
734
- function_call: {
735
- arguments: '{"a": 1, "b": 2, "c": 3}',
736
- name: 'numProperties',
809
+ index: 0,
810
+ finish_reason: 'function_call',
811
+ message: {
812
+ role: 'assistant',
813
+ content: null,
814
+ tool_calls: [
815
+ {
816
+ type: 'function',
817
+ id: '123',
818
+ function: {
819
+ arguments: '{"a": 1, "b": 2, "c": 3}',
820
+ name: 'numProperties',
821
+ },
737
822
  },
738
- },
823
+ ],
739
824
  },
740
- ],
741
- created: Math.floor(Date.now() / 1000),
742
- model: 'gpt-3.5-turbo',
743
- object: 'chat.completion',
744
- usage: {
745
- completion_tokens: 5,
746
- prompt_tokens: 20,
747
- total_tokens: 25,
748
825
  },
749
- };
750
- }),
826
+ ],
827
+ created: Math.floor(Date.now() / 1000),
828
+ model: 'gpt-3.5-turbo',
829
+ object: 'chat.completion',
830
+ usage: {
831
+ completion_tokens: 5,
832
+ prompt_tokens: 20,
833
+ total_tokens: 25,
834
+ },
835
+ };
836
+ });
751
837
 
752
- handleRequest(async (request) => {
753
- expect(request.messages).toEqual([
754
- {
755
- role: 'user',
756
- content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
757
- },
758
- {
759
- role: 'assistant',
760
- content: null,
761
- function_call: {
762
- arguments: '{"a": 1, "b": 2, "c": 3}',
763
- name: 'numProperties',
764
- },
765
- },
766
- {
767
- role: 'function',
768
- content: '3',
769
- name: 'numProperties',
770
- },
771
- ]);
772
- return {
773
- id: '2',
774
- choices: [
838
+ await handleRequest(async (request) => {
839
+ expect(request.messages).toEqual([
840
+ {
841
+ role: 'user',
842
+ content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
843
+ },
844
+ {
845
+ role: 'assistant',
846
+ content: null,
847
+ tool_calls: [
775
848
  {
776
- index: 0,
777
- finish_reason: 'stop',
778
- message: {
779
- role: 'assistant',
780
- content: `there are 3 properties in {"a": 1, "b": 2, "c": 3}`,
849
+ type: 'function',
850
+ id: '123',
851
+ function: {
852
+ arguments: '{"a": 1, "b": 2, "c": 3}',
853
+ name: 'numProperties',
781
854
  },
782
855
  },
783
856
  ],
784
- created: Math.floor(Date.now() / 1000),
785
- model: 'gpt-3.5-turbo',
786
- object: 'chat.completion',
787
- usage: {
788
- completion_tokens: 10,
789
- prompt_tokens: 25,
790
- total_tokens: 35,
857
+ },
858
+ {
859
+ role: 'tool',
860
+ content: '3',
861
+ tool_call_id: '123',
862
+ },
863
+ ]);
864
+ return {
865
+ id: '2',
866
+ choices: [
867
+ {
868
+ index: 0,
869
+ finish_reason: 'stop',
870
+ message: {
871
+ role: 'assistant',
872
+ content: `there are 3 properties in {"a": 1, "b": 2, "c": 3}`,
873
+ },
791
874
  },
792
- };
793
- }),
875
+ ],
876
+ created: Math.floor(Date.now() / 1000),
877
+ model: 'gpt-3.5-turbo',
878
+ object: 'chat.completion',
879
+ usage: {
880
+ completion_tokens: 10,
881
+ prompt_tokens: 25,
882
+ total_tokens: 35,
883
+ },
884
+ };
885
+ });
794
886
 
795
- runner.done(),
796
- ]);
887
+ await runner.done();
797
888
 
798
889
  expect(listener.messages).toEqual([
799
890
  {
@@ -803,9 +894,15 @@ describe('resource completions', () => {
803
894
  {
804
895
  role: 'assistant',
805
896
  content: null,
806
- function_call: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
897
+ tool_calls: [
898
+ {
899
+ type: 'function',
900
+ id: '123',
901
+ function: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
902
+ },
903
+ ],
807
904
  },
808
- { role: 'function', content: '3', name: 'numProperties' },
905
+ { role: 'tool', content: '3', tool_call_id: '123' },
809
906
  { role: 'assistant', content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}' },
810
907
  ]);
811
908
  expect(listener.functionCallResults).toEqual(['3']);
@@ -816,7 +913,7 @@ describe('resource completions', () => {
816
913
 
817
914
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
818
915
 
819
- const runner = openai.beta.chat.completions.runFunctions({
916
+ const runner = openai.beta.chat.completions.runTools({
820
917
  messages: [
821
918
  {
822
919
  role: 'user',
@@ -824,8 +921,8 @@ describe('resource completions', () => {
824
921
  },
825
922
  ],
826
923
  model: 'gpt-3.5-turbo',
827
- functions: [
828
- new ParsingFunction({
924
+ tools: [
925
+ new ParsingToolFunction({
829
926
  name: 'numProperties',
830
927
  function: (obj: object) => String(Object.keys(obj).length),
831
928
  parameters: { type: 'object' },
@@ -859,10 +956,16 @@ describe('resource completions', () => {
859
956
  message: {
860
957
  role: 'assistant',
861
958
  content: null,
862
- function_call: {
863
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
864
- name: 'numProperties',
865
- },
959
+ tool_calls: [
960
+ {
961
+ type: 'function',
962
+ id: '123',
963
+ function: {
964
+ arguments: '[{"a": 1, "b": 2, "c": 3}]',
965
+ name: 'numProperties',
966
+ },
967
+ },
968
+ ],
866
969
  },
867
970
  },
868
971
  ],
@@ -880,15 +983,21 @@ describe('resource completions', () => {
880
983
  {
881
984
  role: 'assistant',
882
985
  content: null,
883
- function_call: {
884
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
885
- name: 'numProperties',
886
- },
986
+ tool_calls: [
987
+ {
988
+ type: 'function',
989
+ id: '123',
990
+ function: {
991
+ arguments: '[{"a": 1, "b": 2, "c": 3}]',
992
+ name: 'numProperties',
993
+ },
994
+ },
995
+ ],
887
996
  },
888
997
  {
889
- role: 'function',
998
+ role: 'tool',
890
999
  content: `must be an object`,
891
- name: 'numProperties',
1000
+ tool_call_id: '123',
892
1001
  },
893
1002
  ]);
894
1003
  return {
@@ -900,10 +1009,16 @@ describe('resource completions', () => {
900
1009
  message: {
901
1010
  role: 'assistant',
902
1011
  content: null,
903
- function_call: {
904
- arguments: '{"a": 1, "b": 2, "c": 3}',
905
- name: 'numProperties',
906
- },
1012
+ tool_calls: [
1013
+ {
1014
+ type: 'function',
1015
+ id: '1234',
1016
+ function: {
1017
+ arguments: '{"a": 1, "b": 2, "c": 3}',
1018
+ name: 'numProperties',
1019
+ },
1020
+ },
1021
+ ],
907
1022
  },
908
1023
  },
909
1024
  ],
@@ -921,28 +1036,40 @@ describe('resource completions', () => {
921
1036
  {
922
1037
  role: 'assistant',
923
1038
  content: null,
924
- function_call: {
925
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
926
- name: 'numProperties',
927
- },
1039
+ tool_calls: [
1040
+ {
1041
+ type: 'function',
1042
+ id: '123',
1043
+ function: {
1044
+ arguments: '[{"a": 1, "b": 2, "c": 3}]',
1045
+ name: 'numProperties',
1046
+ },
1047
+ },
1048
+ ],
928
1049
  },
929
1050
  {
930
- role: 'function',
1051
+ role: 'tool',
931
1052
  content: `must be an object`,
932
- name: 'numProperties',
1053
+ tool_call_id: '123',
933
1054
  },
934
1055
  {
935
1056
  role: 'assistant',
936
1057
  content: null,
937
- function_call: {
938
- arguments: '{"a": 1, "b": 2, "c": 3}',
939
- name: 'numProperties',
940
- },
1058
+ tool_calls: [
1059
+ {
1060
+ type: 'function',
1061
+ id: '1234',
1062
+ function: {
1063
+ arguments: '{"a": 1, "b": 2, "c": 3}',
1064
+ name: 'numProperties',
1065
+ },
1066
+ },
1067
+ ],
941
1068
  },
942
1069
  {
943
- role: 'function',
1070
+ role: 'tool',
944
1071
  content: '3',
945
- name: 'numProperties',
1072
+ tool_call_id: '1234',
946
1073
  },
947
1074
  ]);
948
1075
  return {
@@ -973,15 +1100,27 @@ describe('resource completions', () => {
973
1100
  {
974
1101
  role: 'assistant',
975
1102
  content: null,
976
- function_call: { name: 'numProperties', arguments: '[{"a": 1, "b": 2, "c": 3}]' },
1103
+ tool_calls: [
1104
+ {
1105
+ type: 'function',
1106
+ id: '123',
1107
+ function: { name: 'numProperties', arguments: '[{"a": 1, "b": 2, "c": 3}]' },
1108
+ },
1109
+ ],
977
1110
  },
978
- { role: 'function', content: `must be an object`, name: 'numProperties' },
1111
+ { role: 'tool', content: `must be an object`, tool_call_id: '123' },
979
1112
  {
980
1113
  role: 'assistant',
981
1114
  content: null,
982
- function_call: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
1115
+ tool_calls: [
1116
+ {
1117
+ type: 'function',
1118
+ id: '1234',
1119
+ function: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
1120
+ },
1121
+ ],
983
1122
  },
984
- { role: 'function', content: '3', name: 'numProperties' },
1123
+ { role: 'tool', content: '3', tool_call_id: '1234' },
985
1124
  { role: 'assistant', content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}' },
986
1125
  ]);
987
1126
  expect(listener.functionCallResults).toEqual([`must be an object`, '3']);
@@ -992,19 +1131,25 @@ describe('resource completions', () => {
992
1131
 
993
1132
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
994
1133
 
995
- const runner = openai.beta.chat.completions.runFunctions({
1134
+ const runner = openai.beta.chat.completions.runTools({
996
1135
  messages: [{ role: 'user', content: 'tell me what the weather is like' }],
997
1136
  model: 'gpt-3.5-turbo',
998
- function_call: {
999
- name: 'getWeather',
1137
+ tool_choice: {
1138
+ type: 'function',
1139
+ function: {
1140
+ name: 'getWeather',
1141
+ },
1000
1142
  },
1001
- functions: [
1143
+ tools: [
1002
1144
  {
1003
- function: function getWeather() {
1004
- return `it's raining`;
1145
+ type: 'function',
1146
+ function: {
1147
+ function: function getWeather() {
1148
+ return `it's raining`;
1149
+ },
1150
+ parameters: {},
1151
+ description: 'gets the weather',
1005
1152
  },
1006
- parameters: {},
1007
- description: 'gets the weather',
1008
1153
  },
1009
1154
  ],
1010
1155
  });
@@ -1022,10 +1167,16 @@ describe('resource completions', () => {
1022
1167
  message: {
1023
1168
  role: 'assistant',
1024
1169
  content: null,
1025
- function_call: {
1026
- arguments: '',
1027
- name: 'getWeather',
1028
- },
1170
+ tool_calls: [
1171
+ {
1172
+ type: 'function',
1173
+ id: '123',
1174
+ function: {
1175
+ arguments: '',
1176
+ name: 'getWeather',
1177
+ },
1178
+ },
1179
+ ],
1029
1180
  },
1030
1181
  },
1031
1182
  ],
@@ -1039,8 +1190,21 @@ describe('resource completions', () => {
1039
1190
 
1040
1191
  expect(listener.messages).toEqual([
1041
1192
  { role: 'user', content: 'tell me what the weather is like' },
1042
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1043
- { role: 'function', content: `it's raining`, name: 'getWeather' },
1193
+ {
1194
+ role: 'assistant',
1195
+ content: null,
1196
+ tool_calls: [
1197
+ {
1198
+ type: 'function',
1199
+ id: '123',
1200
+ function: {
1201
+ arguments: '',
1202
+ name: 'getWeather',
1203
+ },
1204
+ },
1205
+ ],
1206
+ },
1207
+ { role: 'tool', content: `it's raining`, tool_call_id: '123' },
1044
1208
  ]);
1045
1209
  expect(listener.functionCallResults).toEqual([`it's raining`]);
1046
1210
  await listener.sanityCheck();
@@ -1050,16 +1214,19 @@ describe('resource completions', () => {
1050
1214
 
1051
1215
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1052
1216
 
1053
- const runner = openai.beta.chat.completions.runFunctions({
1217
+ const runner = openai.beta.chat.completions.runTools({
1054
1218
  messages: [{ role: 'user', content: 'tell me what the weather is like' }],
1055
1219
  model: 'gpt-3.5-turbo',
1056
- functions: [
1220
+ tools: [
1057
1221
  {
1058
- function: function getWeather() {
1059
- return `it's raining`;
1222
+ type: 'function',
1223
+ function: {
1224
+ function: function getWeather() {
1225
+ return `it's raining`;
1226
+ },
1227
+ parameters: {},
1228
+ description: 'gets the weather',
1060
1229
  },
1061
- parameters: {},
1062
- description: 'gets the weather',
1063
1230
  },
1064
1231
  ],
1065
1232
  });
@@ -1077,10 +1244,16 @@ describe('resource completions', () => {
1077
1244
  message: {
1078
1245
  role: 'assistant',
1079
1246
  content: null,
1080
- function_call: {
1081
- arguments: '',
1082
- name: 'get_weather',
1083
- },
1247
+ tool_calls: [
1248
+ {
1249
+ type: 'function',
1250
+ id: '123',
1251
+ function: {
1252
+ arguments: '',
1253
+ name: 'get_weather',
1254
+ },
1255
+ },
1256
+ ],
1084
1257
  },
1085
1258
  },
1086
1259
  ],
@@ -1095,15 +1268,21 @@ describe('resource completions', () => {
1095
1268
  {
1096
1269
  role: 'assistant',
1097
1270
  content: null,
1098
- function_call: {
1099
- arguments: '',
1100
- name: 'get_weather',
1101
- },
1271
+ tool_calls: [
1272
+ {
1273
+ type: 'function',
1274
+ id: '123',
1275
+ function: {
1276
+ arguments: '',
1277
+ name: 'get_weather',
1278
+ },
1279
+ },
1280
+ ],
1102
1281
  },
1103
1282
  {
1104
- role: 'function',
1105
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1106
- name: 'get_weather',
1283
+ role: 'tool',
1284
+ content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
1285
+ tool_call_id: '123',
1107
1286
  },
1108
1287
  ]);
1109
1288
  return {
@@ -1115,10 +1294,16 @@ describe('resource completions', () => {
1115
1294
  message: {
1116
1295
  role: 'assistant',
1117
1296
  content: null,
1118
- function_call: {
1119
- arguments: '',
1120
- name: 'getWeather',
1121
- },
1297
+ tool_calls: [
1298
+ {
1299
+ type: 'function',
1300
+ id: '1234',
1301
+ function: {
1302
+ arguments: '',
1303
+ name: 'getWeather',
1304
+ },
1305
+ },
1306
+ ],
1122
1307
  },
1123
1308
  },
1124
1309
  ],
@@ -1133,28 +1318,40 @@ describe('resource completions', () => {
1133
1318
  {
1134
1319
  role: 'assistant',
1135
1320
  content: null,
1136
- function_call: {
1137
- arguments: '',
1138
- name: 'get_weather',
1139
- },
1321
+ tool_calls: [
1322
+ {
1323
+ type: 'function',
1324
+ id: '123',
1325
+ function: {
1326
+ arguments: '',
1327
+ name: 'get_weather',
1328
+ },
1329
+ },
1330
+ ],
1140
1331
  },
1141
1332
  {
1142
- role: 'function',
1143
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1144
- name: 'get_weather',
1333
+ role: 'tool',
1334
+ content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
1335
+ tool_call_id: '123',
1145
1336
  },
1146
1337
  {
1147
1338
  role: 'assistant',
1148
- content: null,
1149
- function_call: {
1150
- arguments: '',
1151
- name: 'getWeather',
1152
- },
1339
+ content: null,
1340
+ tool_calls: [
1341
+ {
1342
+ type: 'function',
1343
+ id: '1234',
1344
+ function: {
1345
+ arguments: '',
1346
+ name: 'getWeather',
1347
+ },
1348
+ },
1349
+ ],
1153
1350
  },
1154
1351
  {
1155
- role: 'function',
1352
+ role: 'tool',
1156
1353
  content: `it's raining`,
1157
- name: 'getWeather',
1354
+ tool_call_id: '1234',
1158
1355
  },
1159
1356
  ]);
1160
1357
  return {
@@ -1179,106 +1376,52 @@ describe('resource completions', () => {
1179
1376
 
1180
1377
  expect(listener.messages).toEqual([
1181
1378
  { role: 'user', content: 'tell me what the weather is like' },
1182
- { role: 'assistant', content: null, function_call: { name: 'get_weather', arguments: '' } },
1183
1379
  {
1184
- role: 'function',
1185
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1186
- name: 'get_weather',
1380
+ role: 'assistant',
1381
+ content: null,
1382
+ tool_calls: [{ type: 'function', id: '123', function: { name: 'get_weather', arguments: '' } }],
1187
1383
  },
1188
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1189
- { role: 'function', content: `it's raining`, name: 'getWeather' },
1190
- { role: 'assistant', content: "it's raining" },
1191
- ]);
1192
- expect(listener.functionCallResults).toEqual([
1193
- `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1194
- `it's raining`,
1195
- ]);
1196
- await listener.sanityCheck();
1197
- });
1198
- test('wrong function name with single function call', async () => {
1199
- const { fetch, handleRequest } = mockChatCompletionFetch();
1200
-
1201
- const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1202
-
1203
- const runner = openai.beta.chat.completions.runFunctions({
1204
- messages: [{ role: 'user', content: 'tell me what the weather is like' }],
1205
- model: 'gpt-3.5-turbo',
1206
- function_call: {
1207
- name: 'getWeather',
1384
+ {
1385
+ role: 'tool',
1386
+ content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
1387
+ tool_call_id: '123',
1208
1388
  },
1209
- functions: [
1210
- {
1211
- function: function getWeather() {
1212
- return `it's raining`;
1213
- },
1214
- parameters: {},
1215
- description: 'gets the weather',
1216
- },
1217
- ],
1218
- });
1219
- const listener = new RunnerListener(runner);
1220
-
1221
- await Promise.all([
1222
- handleRequest(async (request) => {
1223
- expect(request.messages).toEqual([{ role: 'user', content: 'tell me what the weather is like' }]);
1224
- return {
1225
- id: '1',
1226
- choices: [
1227
- {
1228
- index: 0,
1229
- finish_reason: 'function_call',
1230
- message: {
1231
- role: 'assistant',
1232
- content: null,
1233
- function_call: {
1234
- arguments: '',
1235
- name: 'get_weather',
1236
- },
1237
- },
1238
- },
1239
- ],
1240
- created: Math.floor(Date.now() / 1000),
1241
- model: 'gpt-3.5-turbo',
1242
- object: 'chat.completion',
1243
- };
1244
- }),
1245
- runner.done(),
1246
- ]);
1247
-
1248
- expect(listener.messages).toEqual([
1249
- { role: 'user', content: 'tell me what the weather is like' },
1250
- { role: 'assistant', content: null, function_call: { name: 'get_weather', arguments: '' } },
1251
1389
  {
1252
- role: 'function',
1253
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1254
- name: 'get_weather',
1390
+ role: 'assistant',
1391
+ content: null,
1392
+ tool_calls: [{ type: 'function', id: '1234', function: { name: 'getWeather', arguments: '' } }],
1255
1393
  },
1394
+ { role: 'tool', content: `it's raining`, tool_call_id: '1234' },
1395
+ { role: 'assistant', content: "it's raining" },
1256
1396
  ]);
1257
1397
  expect(listener.functionCallResults).toEqual([
1258
- `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1398
+ `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
1399
+ `it's raining`,
1259
1400
  ]);
1260
1401
  await listener.sanityCheck();
1261
1402
  });
1262
1403
  });
1263
1404
 
1264
- // TODO: re-enable
1265
- describe.skip('runFunctions with stream: true', () => {
1405
+ describe('runTools with stream: true', () => {
1266
1406
  test('successful flow', async () => {
1267
1407
  const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
1268
1408
 
1269
1409
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1270
1410
 
1271
- const runner = openai.beta.chat.completions.runFunctions({
1411
+ const runner = openai.beta.chat.completions.runTools({
1272
1412
  stream: true,
1273
1413
  messages: [{ role: 'user', content: 'tell me what the weather is like' }],
1274
1414
  model: 'gpt-3.5-turbo',
1275
- functions: [
1415
+ tools: [
1276
1416
  {
1277
- function: function getWeather() {
1278
- return `it's raining`;
1417
+ type: 'function',
1418
+ function: {
1419
+ function: function getWeather() {
1420
+ return `it's raining`;
1421
+ },
1422
+ parameters: {},
1423
+ description: 'gets the weather',
1279
1424
  },
1280
- parameters: {},
1281
- description: 'gets the weather',
1282
1425
  },
1283
1426
  ],
1284
1427
  });
@@ -1296,10 +1439,17 @@ describe('resource completions', () => {
1296
1439
  delta: {
1297
1440
  role: 'assistant',
1298
1441
  content: null,
1299
- function_call: {
1300
- arguments: '',
1301
- name: 'getWeather',
1302
- },
1442
+ tool_calls: [
1443
+ {
1444
+ type: 'function',
1445
+ index: 0,
1446
+ id: '123',
1447
+ function: {
1448
+ arguments: '',
1449
+ name: 'getWeather',
1450
+ },
1451
+ },
1452
+ ],
1303
1453
  },
1304
1454
  },
1305
1455
  ],
@@ -1314,15 +1464,21 @@ describe('resource completions', () => {
1314
1464
  {
1315
1465
  role: 'assistant',
1316
1466
  content: null,
1317
- function_call: {
1318
- arguments: '',
1319
- name: 'getWeather',
1320
- },
1467
+ tool_calls: [
1468
+ {
1469
+ type: 'function',
1470
+ id: '123',
1471
+ function: {
1472
+ arguments: '',
1473
+ name: 'getWeather',
1474
+ },
1475
+ },
1476
+ ],
1321
1477
  },
1322
1478
  {
1323
- role: 'function',
1479
+ role: 'tool',
1324
1480
  content: `it's raining`,
1325
- name: 'getWeather',
1481
+ tool_call_id: '123',
1326
1482
  },
1327
1483
  ]);
1328
1484
  for (const choice of contentChoiceDeltas(`it's raining`)) {
@@ -1339,8 +1495,21 @@ describe('resource completions', () => {
1339
1495
  ]);
1340
1496
 
1341
1497
  expect(listener.eventMessages).toEqual([
1342
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1343
- { role: 'function', content: `it's raining`, name: 'getWeather' },
1498
+ {
1499
+ role: 'assistant',
1500
+ content: null,
1501
+ tool_calls: [
1502
+ {
1503
+ type: 'function',
1504
+ id: '123',
1505
+ function: {
1506
+ arguments: '',
1507
+ name: 'getWeather',
1508
+ },
1509
+ },
1510
+ ],
1511
+ },
1512
+ { role: 'tool', content: `it's raining`, tool_call_id: '123' },
1344
1513
  { role: 'assistant', content: "it's raining" },
1345
1514
  ]);
1346
1515
  expect(listener.eventFunctionCallResults).toEqual([`it's raining`]);
@@ -1352,18 +1521,21 @@ describe('resource completions', () => {
1352
1521
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1353
1522
 
1354
1523
  const controller = new AbortController();
1355
- const runner = openai.beta.chat.completions.runFunctions(
1524
+ const runner = openai.beta.chat.completions.runTools(
1356
1525
  {
1357
1526
  stream: true,
1358
1527
  messages: [{ role: 'user', content: 'tell me what the weather is like' }],
1359
1528
  model: 'gpt-3.5-turbo',
1360
- functions: [
1529
+ tools: [
1361
1530
  {
1362
- function: function getWeather() {
1363
- return `it's raining`;
1531
+ type: 'function',
1532
+ function: {
1533
+ function: function getWeather() {
1534
+ return `it's raining`;
1535
+ },
1536
+ parameters: {},
1537
+ description: 'gets the weather',
1364
1538
  },
1365
- parameters: {},
1366
- description: 'gets the weather',
1367
1539
  },
1368
1540
  ],
1369
1541
  },
@@ -1383,10 +1555,17 @@ describe('resource completions', () => {
1383
1555
  delta: {
1384
1556
  role: 'assistant',
1385
1557
  content: null,
1386
- function_call: {
1387
- arguments: '',
1388
- name: 'getWeather',
1389
- },
1558
+ tool_calls: [
1559
+ {
1560
+ type: 'function',
1561
+ index: 0,
1562
+ id: '123',
1563
+ function: {
1564
+ arguments: '',
1565
+ name: 'getWeather',
1566
+ },
1567
+ },
1568
+ ],
1390
1569
  },
1391
1570
  },
1392
1571
  ],
@@ -1399,8 +1578,21 @@ describe('resource completions', () => {
1399
1578
  await runner.done().catch(() => {});
1400
1579
 
1401
1580
  expect(listener.eventMessages).toEqual([
1402
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1403
- { role: 'function', content: `it's raining`, name: 'getWeather' },
1581
+ {
1582
+ role: 'assistant',
1583
+ content: null,
1584
+ tool_calls: [
1585
+ {
1586
+ type: 'function',
1587
+ id: '123',
1588
+ function: {
1589
+ arguments: '',
1590
+ name: 'getWeather',
1591
+ },
1592
+ },
1593
+ ],
1594
+ },
1595
+ { role: 'tool', content: `it's raining`, tool_call_id: '123' },
1404
1596
  ]);
1405
1597
  expect(listener.eventFunctionCallResults).toEqual([`it's raining`]);
1406
1598
  await listener.sanityCheck({ error: 'Request was aborted.' });
@@ -1411,7 +1603,7 @@ describe('resource completions', () => {
1411
1603
 
1412
1604
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1413
1605
 
1414
- const runner = openai.beta.chat.completions.runFunctions({
1606
+ const runner = openai.beta.chat.completions.runTools({
1415
1607
  stream: true,
1416
1608
  messages: [
1417
1609
  {
@@ -1420,8 +1612,8 @@ describe('resource completions', () => {
1420
1612
  },
1421
1613
  ],
1422
1614
  model: 'gpt-3.5-turbo',
1423
- functions: [
1424
- new ParsingFunction({
1615
+ tools: [
1616
+ new ParsingToolFunction({
1425
1617
  name: 'numProperties',
1426
1618
  function: (obj: object) => String(Object.keys(obj).length),
1427
1619
  parameters: { type: 'object' },
@@ -1455,10 +1647,17 @@ describe('resource completions', () => {
1455
1647
  delta: {
1456
1648
  role: 'assistant',
1457
1649
  content: null,
1458
- function_call: {
1459
- arguments: '{"a": 1, "b": 2, "c": 3}',
1460
- name: 'numProperties',
1461
- },
1650
+ tool_calls: [
1651
+ {
1652
+ type: 'function',
1653
+ id: '123',
1654
+ index: 0,
1655
+ function: {
1656
+ arguments: '{"a": 1, "b": 2, "c": 3}',
1657
+ name: 'numProperties',
1658
+ },
1659
+ },
1660
+ ],
1462
1661
  },
1463
1662
  },
1464
1663
  ],
@@ -1476,15 +1675,21 @@ describe('resource completions', () => {
1476
1675
  {
1477
1676
  role: 'assistant',
1478
1677
  content: null,
1479
- function_call: {
1480
- arguments: '{"a": 1, "b": 2, "c": 3}',
1481
- name: 'numProperties',
1482
- },
1678
+ tool_calls: [
1679
+ {
1680
+ type: 'function',
1681
+ id: '123',
1682
+ function: {
1683
+ arguments: '{"a": 1, "b": 2, "c": 3}',
1684
+ name: 'numProperties',
1685
+ },
1686
+ },
1687
+ ],
1483
1688
  },
1484
1689
  {
1485
- role: 'function',
1690
+ role: 'tool',
1486
1691
  content: '3',
1487
- name: 'numProperties',
1692
+ tool_call_id: '123',
1488
1693
  },
1489
1694
  ]);
1490
1695
  for (const choice of contentChoiceDeltas(`there are 3 properties in {"a": 1, "b": 2, "c": 3}`)) {
@@ -1504,9 +1709,15 @@ describe('resource completions', () => {
1504
1709
  {
1505
1710
  role: 'assistant',
1506
1711
  content: null,
1507
- function_call: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
1712
+ tool_calls: [
1713
+ {
1714
+ type: 'function',
1715
+ id: '123',
1716
+ function: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
1717
+ },
1718
+ ],
1508
1719
  },
1509
- { role: 'function', content: '3', name: 'numProperties' },
1720
+ { role: 'tool', content: '3', tool_call_id: '123' },
1510
1721
  { role: 'assistant', content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}' },
1511
1722
  ]);
1512
1723
  expect(listener.eventFunctionCallResults).toEqual(['3']);
@@ -1517,7 +1728,7 @@ describe('resource completions', () => {
1517
1728
 
1518
1729
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1519
1730
 
1520
- const runner = openai.beta.chat.completions.runFunctions({
1731
+ const runner = openai.beta.chat.completions.runTools({
1521
1732
  stream: true,
1522
1733
  messages: [
1523
1734
  {
@@ -1526,8 +1737,8 @@ describe('resource completions', () => {
1526
1737
  },
1527
1738
  ],
1528
1739
  model: 'gpt-3.5-turbo',
1529
- functions: [
1530
- new ParsingFunction({
1740
+ tools: [
1741
+ new ParsingToolFunction({
1531
1742
  name: 'numProperties',
1532
1743
  function: (obj: object) => String(Object.keys(obj).length),
1533
1744
  parameters: { type: 'object' },
@@ -1552,7 +1763,10 @@ describe('resource completions', () => {
1552
1763
  content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}',
1553
1764
  },
1554
1765
  ]);
1555
- for (const choice of functionCallDeltas('[{"a": 1, "b": 2, "c": 3}]', { name: 'numProperties' })) {
1766
+ for (const choice of functionCallDeltas('[{"a": 1, "b": 2, "c": 3}]', {
1767
+ name: 'numProperties',
1768
+ id: '123',
1769
+ })) {
1556
1770
  yield {
1557
1771
  id: '1',
1558
1772
  choices: [choice],
@@ -1571,18 +1785,27 @@ describe('resource completions', () => {
1571
1785
  {
1572
1786
  role: 'assistant',
1573
1787
  content: null,
1574
- function_call: {
1575
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
1576
- name: 'numProperties',
1577
- },
1788
+ tool_calls: [
1789
+ {
1790
+ type: 'function',
1791
+ id: '123',
1792
+ function: {
1793
+ arguments: '[{"a": 1, "b": 2, "c": 3}]',
1794
+ name: 'numProperties',
1795
+ },
1796
+ },
1797
+ ],
1578
1798
  },
1579
1799
  {
1580
- role: 'function',
1800
+ role: 'tool',
1581
1801
  content: `must be an object`,
1582
- name: 'numProperties',
1802
+ tool_call_id: '123',
1583
1803
  },
1584
1804
  ]);
1585
- for (const choice of functionCallDeltas('{"a": 1, "b": 2, "c": 3}', { name: 'numProperties' })) {
1805
+ for (const choice of functionCallDeltas('{"a": 1, "b": 2, "c": 3}', {
1806
+ name: 'numProperties',
1807
+ id: '1234',
1808
+ })) {
1586
1809
  yield {
1587
1810
  id: '2',
1588
1811
  choices: [choice],
@@ -1601,28 +1824,40 @@ describe('resource completions', () => {
1601
1824
  {
1602
1825
  role: 'assistant',
1603
1826
  content: null,
1604
- function_call: {
1605
- arguments: '[{"a": 1, "b": 2, "c": 3}]',
1606
- name: 'numProperties',
1607
- },
1827
+ tool_calls: [
1828
+ {
1829
+ type: 'function',
1830
+ id: '123',
1831
+ function: {
1832
+ arguments: '[{"a": 1, "b": 2, "c": 3}]',
1833
+ name: 'numProperties',
1834
+ },
1835
+ },
1836
+ ],
1608
1837
  },
1609
1838
  {
1610
- role: 'function',
1839
+ role: 'tool',
1611
1840
  content: `must be an object`,
1612
- name: 'numProperties',
1841
+ tool_call_id: '123',
1613
1842
  },
1614
1843
  {
1615
1844
  role: 'assistant',
1616
1845
  content: null,
1617
- function_call: {
1618
- arguments: '{"a": 1, "b": 2, "c": 3}',
1619
- name: 'numProperties',
1620
- },
1846
+ tool_calls: [
1847
+ {
1848
+ type: 'function',
1849
+ id: '1234',
1850
+ function: {
1851
+ arguments: '{"a": 1, "b": 2, "c": 3}',
1852
+ name: 'numProperties',
1853
+ },
1854
+ },
1855
+ ],
1621
1856
  },
1622
1857
  {
1623
- role: 'function',
1858
+ role: 'tool',
1624
1859
  content: '3',
1625
- name: 'numProperties',
1860
+ tool_call_id: '1234',
1626
1861
  },
1627
1862
  ]);
1628
1863
  for (const choice of contentChoiceDeltas(`there are 3 properties in {"a": 1, "b": 2, "c": 3}`)) {
@@ -1642,15 +1877,27 @@ describe('resource completions', () => {
1642
1877
  {
1643
1878
  role: 'assistant',
1644
1879
  content: null,
1645
- function_call: { name: 'numProperties', arguments: '[{"a": 1, "b": 2, "c": 3}]' },
1880
+ tool_calls: [
1881
+ {
1882
+ type: 'function',
1883
+ id: '123',
1884
+ function: { name: 'numProperties', arguments: '[{"a": 1, "b": 2, "c": 3}]' },
1885
+ },
1886
+ ],
1646
1887
  },
1647
- { role: 'function', content: `must be an object`, name: 'numProperties' },
1888
+ { role: 'tool', content: `must be an object`, tool_call_id: '123' },
1648
1889
  {
1649
1890
  role: 'assistant',
1650
1891
  content: null,
1651
- function_call: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
1892
+ tool_calls: [
1893
+ {
1894
+ type: 'function',
1895
+ id: '1234',
1896
+ function: { name: 'numProperties', arguments: '{"a": 1, "b": 2, "c": 3}' },
1897
+ },
1898
+ ],
1652
1899
  },
1653
- { role: 'function', content: '3', name: 'numProperties' },
1900
+ { role: 'tool', content: '3', tool_call_id: '1234' },
1654
1901
  { role: 'assistant', content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}' },
1655
1902
  ]);
1656
1903
  expect(listener.eventFunctionCallResults).toEqual([`must be an object`, '3']);
@@ -1661,20 +1908,26 @@ describe('resource completions', () => {
1661
1908
 
1662
1909
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1663
1910
 
1664
- const runner = openai.beta.chat.completions.runFunctions({
1911
+ const runner = openai.beta.chat.completions.runTools({
1665
1912
  stream: true,
1666
1913
  messages: [{ role: 'user', content: 'tell me what the weather is like' }],
1667
1914
  model: 'gpt-3.5-turbo',
1668
- function_call: {
1669
- name: 'getWeather',
1915
+ tool_choice: {
1916
+ type: 'function',
1917
+ function: {
1918
+ name: 'getWeather',
1919
+ },
1670
1920
  },
1671
- functions: [
1921
+ tools: [
1672
1922
  {
1673
- function: function getWeather() {
1674
- return `it's raining`;
1923
+ type: 'function',
1924
+ function: {
1925
+ function: function getWeather() {
1926
+ return `it's raining`;
1927
+ },
1928
+ parameters: {},
1929
+ description: 'gets the weather',
1675
1930
  },
1676
- parameters: {},
1677
- description: 'gets the weather',
1678
1931
  },
1679
1932
  ],
1680
1933
  });
@@ -1692,10 +1945,17 @@ describe('resource completions', () => {
1692
1945
  delta: {
1693
1946
  role: 'assistant',
1694
1947
  content: null,
1695
- function_call: {
1696
- arguments: '',
1697
- name: 'getWeather',
1698
- },
1948
+ tool_calls: [
1949
+ {
1950
+ type: 'function',
1951
+ index: 0,
1952
+ id: '123',
1953
+ function: {
1954
+ arguments: '',
1955
+ name: 'getWeather',
1956
+ },
1957
+ },
1958
+ ],
1699
1959
  },
1700
1960
  },
1701
1961
  ],
@@ -1708,8 +1968,21 @@ describe('resource completions', () => {
1708
1968
  ]);
1709
1969
 
1710
1970
  expect(listener.eventMessages).toEqual([
1711
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1712
- { role: 'function', content: `it's raining`, name: 'getWeather' },
1971
+ {
1972
+ role: 'assistant',
1973
+ content: null,
1974
+ tool_calls: [
1975
+ {
1976
+ type: 'function',
1977
+ id: '123',
1978
+ function: {
1979
+ arguments: '',
1980
+ name: 'getWeather',
1981
+ },
1982
+ },
1983
+ ],
1984
+ },
1985
+ { role: 'tool', tool_call_id: '123', content: `it's raining` },
1713
1986
  ]);
1714
1987
  expect(listener.eventFunctionCallResults).toEqual([`it's raining`]);
1715
1988
  await listener.sanityCheck();
@@ -1719,17 +1992,20 @@ describe('resource completions', () => {
1719
1992
 
1720
1993
  const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1721
1994
 
1722
- const runner = openai.beta.chat.completions.runFunctions({
1995
+ const runner = openai.beta.chat.completions.runTools({
1723
1996
  stream: true,
1724
1997
  messages: [{ role: 'user', content: 'tell me what the weather is like' }],
1725
1998
  model: 'gpt-3.5-turbo',
1726
- functions: [
1999
+ tools: [
1727
2000
  {
1728
- function: function getWeather() {
1729
- return `it's raining`;
2001
+ type: 'function',
2002
+ function: {
2003
+ function: function getWeather() {
2004
+ return `it's raining`;
2005
+ },
2006
+ parameters: {},
2007
+ description: 'gets the weather',
1730
2008
  },
1731
- parameters: {},
1732
- description: 'gets the weather',
1733
2009
  },
1734
2010
  ],
1735
2011
  });
@@ -1747,10 +2023,17 @@ describe('resource completions', () => {
1747
2023
  delta: {
1748
2024
  role: 'assistant',
1749
2025
  content: null,
1750
- function_call: {
1751
- arguments: '',
1752
- name: 'get_weather',
1753
- },
2026
+ tool_calls: [
2027
+ {
2028
+ type: 'function',
2029
+ index: 0,
2030
+ id: '123',
2031
+ function: {
2032
+ arguments: '',
2033
+ name: 'get_weather',
2034
+ },
2035
+ },
2036
+ ],
1754
2037
  },
1755
2038
  },
1756
2039
  ],
@@ -1765,15 +2048,21 @@ describe('resource completions', () => {
1765
2048
  {
1766
2049
  role: 'assistant',
1767
2050
  content: null,
1768
- function_call: {
1769
- arguments: '',
1770
- name: 'get_weather',
1771
- },
2051
+ tool_calls: [
2052
+ {
2053
+ type: 'function',
2054
+ id: '123',
2055
+ function: {
2056
+ arguments: '',
2057
+ name: 'get_weather',
2058
+ },
2059
+ },
2060
+ ],
1772
2061
  },
1773
2062
  {
1774
- role: 'function',
1775
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1776
- name: 'get_weather',
2063
+ role: 'tool',
2064
+ content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
2065
+ tool_call_id: '123',
1777
2066
  },
1778
2067
  ]);
1779
2068
  yield {
@@ -1785,10 +2074,17 @@ describe('resource completions', () => {
1785
2074
  delta: {
1786
2075
  role: 'assistant',
1787
2076
  content: null,
1788
- function_call: {
1789
- arguments: '',
1790
- name: 'getWeather',
1791
- },
2077
+ tool_calls: [
2078
+ {
2079
+ type: 'function',
2080
+ index: 0,
2081
+ id: '1234',
2082
+ function: {
2083
+ arguments: '',
2084
+ name: 'getWeather',
2085
+ },
2086
+ },
2087
+ ],
1792
2088
  },
1793
2089
  },
1794
2090
  ],
@@ -1803,28 +2099,40 @@ describe('resource completions', () => {
1803
2099
  {
1804
2100
  role: 'assistant',
1805
2101
  content: null,
1806
- function_call: {
1807
- arguments: '',
1808
- name: 'get_weather',
1809
- },
2102
+ tool_calls: [
2103
+ {
2104
+ type: 'function',
2105
+ id: '123',
2106
+ function: {
2107
+ arguments: '',
2108
+ name: 'get_weather',
2109
+ },
2110
+ },
2111
+ ],
1810
2112
  },
1811
2113
  {
1812
- role: 'function',
1813
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1814
- name: 'get_weather',
2114
+ role: 'tool',
2115
+ content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
2116
+ tool_call_id: '123',
1815
2117
  },
1816
2118
  {
1817
2119
  role: 'assistant',
1818
2120
  content: null,
1819
- function_call: {
1820
- arguments: '',
1821
- name: 'getWeather',
1822
- },
2121
+ tool_calls: [
2122
+ {
2123
+ type: 'function',
2124
+ id: '1234',
2125
+ function: {
2126
+ arguments: '',
2127
+ name: 'getWeather',
2128
+ },
2129
+ },
2130
+ ],
1823
2131
  },
1824
2132
  {
1825
- role: 'function',
2133
+ role: 'tool',
1826
2134
  content: `it's raining`,
1827
- name: 'getWeather',
2135
+ tool_call_id: '1234',
1828
2136
  },
1829
2137
  ]);
1830
2138
  for (const choice of contentChoiceDeltas(`it's raining`)) {
@@ -1841,83 +2149,45 @@ describe('resource completions', () => {
1841
2149
  ]);
1842
2150
 
1843
2151
  expect(listener.eventMessages).toEqual([
1844
- { role: 'assistant', content: null, function_call: { name: 'get_weather', arguments: '' } },
1845
2152
  {
1846
- role: 'function',
1847
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1848
- name: 'get_weather',
2153
+ role: 'assistant',
2154
+ content: null,
2155
+ tool_calls: [
2156
+ {
2157
+ type: 'function',
2158
+ id: '123',
2159
+ function: {
2160
+ arguments: '',
2161
+ name: 'get_weather',
2162
+ },
2163
+ },
2164
+ ],
1849
2165
  },
1850
- { role: 'assistant', content: null, function_call: { name: 'getWeather', arguments: '' } },
1851
- { role: 'function', content: `it's raining`, name: 'getWeather' },
1852
- { role: 'assistant', content: "it's raining" },
1853
- ]);
1854
- expect(listener.eventFunctionCallResults).toEqual([
1855
- `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1856
- `it's raining`,
1857
- ]);
1858
- await listener.sanityCheck();
1859
- });
1860
- test('wrong function name with single function call', async () => {
1861
- const { fetch, handleRequest } = mockStreamingChatCompletionFetch();
1862
-
1863
- const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch });
1864
-
1865
- const runner = openai.beta.chat.completions.runFunctions({
1866
- stream: true,
1867
- messages: [{ role: 'user', content: 'tell me what the weather is like' }],
1868
- model: 'gpt-3.5-turbo',
1869
- function_call: {
1870
- name: 'getWeather',
2166
+ {
2167
+ role: 'tool',
2168
+ content: `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
2169
+ tool_call_id: '123',
1871
2170
  },
1872
- functions: [
1873
- {
1874
- function: function getWeather() {
1875
- return `it's raining`;
1876
- },
1877
- parameters: {},
1878
- description: 'gets the weather',
1879
- },
1880
- ],
1881
- });
1882
- const listener = new StreamingRunnerListener(runner);
1883
-
1884
- await Promise.all([
1885
- handleRequest(async function* (request): AsyncIterable<OpenAI.Chat.ChatCompletionChunk> {
1886
- expect(request.messages).toEqual([{ role: 'user', content: 'tell me what the weather is like' }]);
1887
- yield {
1888
- id: '1',
1889
- choices: [
1890
- {
1891
- index: 0,
1892
- finish_reason: 'function_call',
1893
- delta: {
1894
- role: 'assistant',
1895
- content: null,
1896
- function_call: {
1897
- arguments: '',
1898
- name: 'get_weather',
1899
- },
1900
- },
1901
- },
1902
- ],
1903
- created: Math.floor(Date.now() / 1000),
1904
- model: 'gpt-3.5-turbo',
1905
- object: 'chat.completion.chunk',
1906
- };
1907
- }),
1908
- runner.done(),
1909
- ]);
1910
-
1911
- expect(listener.eventMessages).toEqual([
1912
- { role: 'assistant', content: null, function_call: { name: 'get_weather', arguments: '' } },
1913
2171
  {
1914
- role: 'function',
1915
- content: `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
1916
- name: 'get_weather',
2172
+ role: 'assistant',
2173
+ content: null,
2174
+ tool_calls: [
2175
+ {
2176
+ type: 'function',
2177
+ id: '1234',
2178
+ function: {
2179
+ arguments: '',
2180
+ name: 'getWeather',
2181
+ },
2182
+ },
2183
+ ],
1917
2184
  },
2185
+ { role: 'tool', content: `it's raining`, tool_call_id: '1234' },
2186
+ { role: 'assistant', content: "it's raining" },
1918
2187
  ]);
1919
2188
  expect(listener.eventFunctionCallResults).toEqual([
1920
- `Invalid function_call: "get_weather". Available options are: "getWeather". Please try again`,
2189
+ `Invalid tool_call: "get_weather". Available options are: "getWeather". Please try again`,
2190
+ `it's raining`,
1921
2191
  ]);
1922
2192
  await listener.sanityCheck();
1923
2193
  });