@ai-sdk/openai 3.0.118 → 3.0.120

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "3.0.118",
3
+ "version": "3.0.120",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -36,8 +36,8 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@ai-sdk/provider": "3.0.17",
40
- "@ai-sdk/provider-utils": "4.0.54"
39
+ "@ai-sdk/provider": "3.0.18",
40
+ "@ai-sdk/provider-utils": "4.0.56"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "20.17.24",
@@ -11,6 +11,7 @@ import {
11
11
  type SharedV3Warning,
12
12
  } from '@ai-sdk/provider';
13
13
  import {
14
+ StreamingToolCallTracker,
14
15
  combineHeaders,
15
16
  createEventSourceResponseHandler,
16
17
  createJsonResponseHandler,
@@ -482,15 +483,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV3 {
482
483
  responseHeaders,
483
484
  });
484
485
 
485
- const toolCalls: Array<{
486
- id: string;
487
- type: 'function';
488
- function: {
489
- name: string;
490
- arguments: string;
491
- };
492
- hasFinished: boolean;
493
- }> = [];
486
+ let toolCallTracker: StreamingToolCallTracker;
494
487
 
495
488
  let finishReason: LanguageModelV3FinishReason = {
496
489
  unified: 'other',
@@ -509,6 +502,10 @@ export class OpenAIChatLanguageModel implements LanguageModelV3 {
509
502
  LanguageModelV3StreamPart
510
503
  >({
511
504
  start(controller) {
505
+ toolCallTracker = new StreamingToolCallTracker(controller, {
506
+ generateId,
507
+ typeValidation: 'if-present',
508
+ });
512
509
  controller.enqueue({ type: 'stream-start', warnings });
513
510
  },
514
511
 
@@ -600,87 +597,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV3 {
600
597
 
601
598
  if (delta.tool_calls != null) {
602
599
  for (const toolCallDelta of delta.tool_calls) {
603
- const index = toolCallDelta.index;
604
-
605
- // Tool call start. OpenAI returns all information except the arguments in the first chunk.
606
- if (toolCalls[index] == null) {
607
- if (
608
- toolCallDelta.type != null &&
609
- toolCallDelta.type !== 'function'
610
- ) {
611
- throw new InvalidResponseDataError({
612
- data: toolCallDelta,
613
- message: `Expected 'function' type.`,
614
- });
615
- }
616
-
617
- if (toolCallDelta.id == null) {
618
- throw new InvalidResponseDataError({
619
- data: toolCallDelta,
620
- message: `Expected 'id' to be a string.`,
621
- });
622
- }
623
-
624
- if (toolCallDelta.function?.name == null) {
625
- throw new InvalidResponseDataError({
626
- data: toolCallDelta,
627
- message: `Expected 'function.name' to be a string.`,
628
- });
629
- }
630
-
631
- controller.enqueue({
632
- type: 'tool-input-start',
633
- id: toolCallDelta.id,
634
- toolName: toolCallDelta.function.name,
635
- });
636
-
637
- toolCalls[index] = {
638
- id: toolCallDelta.id,
639
- type: 'function',
640
- function: {
641
- name: toolCallDelta.function.name,
642
- arguments: toolCallDelta.function.arguments ?? '',
643
- },
644
- hasFinished: false,
645
- };
646
-
647
- const toolCall = toolCalls[index];
648
-
649
- if (
650
- toolCall.function?.name != null &&
651
- toolCall.function?.arguments != null
652
- ) {
653
- // send delta if the argument text has already started:
654
- if (toolCall.function.arguments.length > 0) {
655
- controller.enqueue({
656
- type: 'tool-input-delta',
657
- id: toolCall.id,
658
- delta: toolCall.function.arguments,
659
- });
660
- }
661
- }
662
-
663
- continue;
664
- }
665
-
666
- // existing tool call, merge if not finished
667
- const toolCall = toolCalls[index];
668
-
669
- if (toolCall.hasFinished) {
670
- continue;
671
- }
672
-
673
- if (toolCallDelta.function?.arguments != null) {
674
- toolCall.function!.arguments +=
675
- toolCallDelta.function?.arguments ?? '';
676
- }
677
-
678
- // send delta
679
- controller.enqueue({
680
- type: 'tool-input-delta',
681
- id: toolCall.id,
682
- delta: toolCallDelta.function.arguments ?? '',
683
- });
600
+ toolCallTracker.processDelta(toolCallDelta);
684
601
  }
685
602
  }
686
603
 
@@ -703,25 +620,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV3 {
703
620
  controller.enqueue({ type: 'text-end', id: '0' });
704
621
  }
705
622
 
706
- // Finalize any unfinished tool calls. Tool calls are only
707
- // finalized here (on stream end) to prevent premature
708
- // execution when partial JSON is coincidentally parsable.
709
- for (const toolCall of toolCalls) {
710
- if (!toolCall.hasFinished) {
711
- controller.enqueue({
712
- type: 'tool-input-end',
713
- id: toolCall.id,
714
- });
715
-
716
- controller.enqueue({
717
- type: 'tool-call',
718
- toolCallId: toolCall.id ?? generateId(),
719
- toolName: toolCall.function.name,
720
- input: toolCall.function.arguments,
721
- });
722
- toolCall.hasFinished = true;
723
- }
724
- }
623
+ toolCallTracker.flush();
725
624
 
726
625
  controller.enqueue({
727
626
  type: 'finish',