@ai-sdk/provider-utils 5.0.20 → 5.0.21

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/provider-utils",
3
- "version": "5.0.20",
3
+ "version": "5.0.21",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -77,7 +77,10 @@ type StreamingToolCallTrackerController = Pick<
77
77
  export class StreamingToolCallTracker<
78
78
  DELTA extends StreamingToolCallDelta = StreamingToolCallDelta,
79
79
  > {
80
- private toolCalls: TrackedToolCall[] = [];
80
+ private toolCalls = new Set<TrackedToolCall>();
81
+ private toolCallsById = new Map<string, TrackedToolCall>();
82
+ private toolCallsByIndex = new Map<number, TrackedToolCall>();
83
+ private latestToolCall: TrackedToolCall | undefined;
81
84
  private readonly controller: StreamingToolCallTrackerController;
82
85
  private readonly _generateId: () => string;
83
86
  private readonly typeValidation: 'none' | 'if-present' | 'required';
@@ -105,13 +108,24 @@ export class StreamingToolCallTracker<
105
108
  * events as appropriate.
106
109
  */
107
110
  processDelta(toolCallDelta: DELTA): void {
108
- const index = toolCallDelta.index ?? this.toolCalls.length;
109
-
110
- if (this.toolCalls[index] == null) {
111
- this.processNewToolCall(index, toolCallDelta);
111
+ const { id, index } = toolCallDelta;
112
+ let toolCall =
113
+ id != null && id.length > 0
114
+ ? this.toolCallsById.get(id)
115
+ : index != null
116
+ ? this.toolCallsByIndex.get(index)
117
+ : this.latestToolCall;
118
+
119
+ if (toolCall == null) {
120
+ toolCall = this.processNewToolCall(toolCallDelta);
112
121
  } else {
113
- this.processExistingToolCall(index, toolCallDelta);
122
+ this.processExistingToolCall(toolCall, toolCallDelta);
123
+ }
124
+
125
+ if (index != null) {
126
+ this.toolCallsByIndex.set(index, toolCall);
114
127
  }
128
+ this.latestToolCall = toolCall;
115
129
  }
116
130
 
117
131
  /**
@@ -126,7 +140,7 @@ export class StreamingToolCallTracker<
126
140
  }
127
141
  }
128
142
 
129
- private processNewToolCall(index: number, toolCallDelta: DELTA): void {
143
+ private processNewToolCall(toolCallDelta: DELTA): TrackedToolCall {
130
144
  if (this.typeValidation === 'required') {
131
145
  if (toolCallDelta.type !== 'function') {
132
146
  throw new InvalidResponseDataError({
@@ -165,7 +179,7 @@ export class StreamingToolCallTracker<
165
179
 
166
180
  const metadata = this.extractMetadata?.(toolCallDelta);
167
181
 
168
- this.toolCalls[index] = {
182
+ const toolCall: TrackedToolCall = {
169
183
  id: toolCallDelta.id,
170
184
  type: 'function',
171
185
  function: {
@@ -175,8 +189,10 @@ export class StreamingToolCallTracker<
175
189
  hasFinished: false,
176
190
  metadata,
177
191
  };
178
-
179
- const toolCall = this.toolCalls[index];
192
+ this.toolCalls.add(toolCall);
193
+ if (toolCall.id.length > 0) {
194
+ this.toolCallsById.set(toolCall.id, toolCall);
195
+ }
180
196
 
181
197
  // Emit initial delta if arguments already present
182
198
  if (toolCall.function.arguments.length > 0) {
@@ -191,11 +207,13 @@ export class StreamingToolCallTracker<
191
207
  // argument buffer can still be the prefix of a longer argument string,
192
208
  // so acting on it early would use truncated inputs (see #13137).
193
209
  // Finalization happens in flush().
210
+ return toolCall;
194
211
  }
195
212
 
196
- private processExistingToolCall(index: number, toolCallDelta: DELTA): void {
197
- const toolCall = this.toolCalls[index];
198
-
213
+ private processExistingToolCall(
214
+ toolCall: TrackedToolCall,
215
+ toolCallDelta: DELTA,
216
+ ): void {
199
217
  if (toolCall.hasFinished) {
200
218
  return;
201
219
  }