diff --git a/node_modules/@ai-sdk/provider-utils/dist/index.js b/node_modules/@ai-sdk/provider-utils/dist/index.js index 7de9a2a..c3c87d8 100644 --- a/node_modules/@ai-sdk/provider-utils/dist/index.js +++ b/node_modules/@ai-sdk/provider-utils/dist/index.js @@ -3745,11 +3745,12 @@ function resolveSync(value) { import { InvalidResponseDataError } from "@ai-sdk/provider"; +function absentIfBlank(value) { + return value != null && value.trim() !== "" ? value : void 0; +} var StreamingToolCallTracker = class { constructor(controller, options = {}) { - this.toolCalls = /* @__PURE__ */ new Set(); - this.toolCallsById = /* @__PURE__ */ new Map(); - this.toolCallsByIndex = /* @__PURE__ */ new Map(); + this.toolCalls = []; var _a3, _b3; this.controller = controller; this._generateId = (_a3 = options.generateId) != null ? _a3 : generateId; @@ -3763,31 +3764,90 @@ var StreamingToolCallTracker = class { * events as appropriate. */ processDelta(toolCallDelta) { - const { id, index } = toolCallDelta; - let toolCall = id != null && id.length > 0 ? this.toolCallsById.get(id) : index != null ? this.toolCallsByIndex.get(index) : this.latestToolCall; + var _a3; + const wireId = absentIfBlank(toolCallDelta.id); + const wireIndex = toolCallDelta.index != null ? toolCallDelta.index : void 0; + const wireName = absentIfBlank((_a3 = toolCallDelta.function) == null ? void 0 : _a3.name); + let toolCall = this.findByAlias(wireId, wireIndex, wireName); + if (toolCall == null && this.toolCalls.length === 1) { + const only = this.toolCalls[0]; + if ((wireName === void 0 || only.function.name === wireName) && (wireId === void 0 || only.wireId === void 0) && (wireIndex === void 0 || only.index === void 0)) { + toolCall = only; + } + } if (toolCall == null) { - toolCall = this.processNewToolCall(toolCallDelta); - } else { - this.processExistingToolCall(toolCall, toolCallDelta); + this.processNewToolCall(toolCallDelta, wireId, wireIndex, wireName); + return; } - if (index != null) { - this.toolCallsByIndex.set(index, toolCall); + if (wireId !== void 0) { + toolCall.wireId = wireId; } - this.latestToolCall = toolCall; + if (wireIndex !== void 0) { + toolCall.index = wireIndex; + } + this.processExistingToolCall(toolCall, toolCallDelta); + } + /** + * The most recent tool call this delta's aliases claim. An alias the candidate has not + * seen yet cannot disagree, so it neither matches nor rejects; at least one alias must + * actually match, which is why a delta carrying only arguments never resolves here. + * + * Scanning stops at the first call an alias claims, and a `function.name` that disagrees + * with that call rejects the delta rather than letting the scan continue. Continuing past + * it reaches a call whose claim on the alias a later call has already superseded, which + * files a whole new call as a continuation of one two positions back. + */ + /** + * Whether an alias the delta carries, but the matched call has not claimed, belongs to some + * other call. The delta then addresses two calls at once, which resolves to neither — the + * other claimant cannot be it either, because the alias it did match rejected that call + * already. Agreement has to be read across the record set: a candidate missing the alias is + * not contradicted by it on its own, and reading only the candidate let exactly this + * contradiction resolve, silently, onto a call the gateway never addressed. + */ + claimedByAnother(candidate, alias, value) { + return value !== void 0 && candidate[alias] === void 0 && this.toolCalls.some((other) => other !== candidate && other[alias] === value); + } + findByAlias(wireId, wireIndex, wireName) { + for (let position = this.toolCalls.length - 1; position >= 0; position--) { + const candidate = this.toolCalls[position]; + let matched = false; + if (wireIndex !== void 0 && candidate.index !== void 0) { + if (candidate.index !== wireIndex) { + continue; + } + matched = true; + } + if (wireId !== void 0 && candidate.wireId !== void 0) { + if (candidate.wireId !== wireId) { + continue; + } + matched = true; + } + if (matched) { + if (this.claimedByAnother(candidate, "wireId", wireId) || this.claimedByAnother(candidate, "index", wireIndex)) { + return void 0; + } + return wireName !== void 0 && candidate.function.name !== wireName ? void 0 : candidate; + } + } + return void 0; } /** * Finalize any unfinished tool calls. Should be called during the stream's * flush handler to ensure all tool calls are properly completed. */ flush() { - for (const toolCall of this.toolCalls) { + const indices = this.toolCalls.map((toolCall) => toolCall.index); + const ordered = indices.every((index) => index !== void 0) && new Set(indices).size === indices.length ? [...this.toolCalls].sort((a, b) => a.index - b.index) : this.toolCalls; + for (const toolCall of ordered) { if (!toolCall.hasFinished) { this.finishToolCall(toolCall); } } } - processNewToolCall(toolCallDelta) { - var _a3, _b3, _c; + processNewToolCall(toolCallDelta, wireId, wireIndex, wireName) { + var _a3, _b3; if (this.typeValidation === "required") { if (toolCallDelta.type !== "function") { throw new InvalidResponseDataError({ @@ -3803,38 +3863,32 @@ var StreamingToolCallTracker = class { }); } } - if (toolCallDelta.id == null) { - throw new InvalidResponseDataError({ - data: toolCallDelta, - message: `Expected 'id' to be a string.` - }); - } - if (((_a3 = toolCallDelta.function) == null ? void 0 : _a3.name) == null) { + if (wireName === void 0) { throw new InvalidResponseDataError({ data: toolCallDelta, message: `Expected 'function.name' to be a string.` }); } + const mintedId = wireId === void 0 || this.toolCalls.some((candidate) => candidate.id === wireId) ? this._generateId() : wireId; this.controller.enqueue({ type: "tool-input-start", - id: toolCallDelta.id, - toolName: toolCallDelta.function.name + id: mintedId, + toolName: wireName }); - const metadata = (_b3 = this.extractMetadata) == null ? void 0 : _b3.call(this, toolCallDelta); + const metadata = (_a3 = this.extractMetadata) == null ? void 0 : _a3.call(this, toolCallDelta); const toolCall = { - id: toolCallDelta.id, + id: mintedId, type: "function", function: { - name: toolCallDelta.function.name, - arguments: (_c = toolCallDelta.function.arguments) != null ? _c : "" + name: wireName, + arguments: (_b3 = toolCallDelta.function.arguments) != null ? _b3 : "" }, hasFinished: false, - metadata + metadata, + wireId, + index: wireIndex }; - this.toolCalls.add(toolCall); - if (toolCall.id.length > 0) { - this.toolCallsById.set(toolCall.id, toolCall); - } + this.toolCalls.push(toolCall); if (toolCall.function.arguments.length > 0) { this.controller.enqueue({ type: "tool-input-delta",