@ai-sdk/openai-compatible 2.0.57 → 2.0.58

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @ai-sdk/openai-compatible
2
2
 
3
+ ## 2.0.58
4
+
5
+ ### Patch Changes
6
+
7
+ - 4d4e176: fix(openai-compatible): buffer tool call deltas until function.name arrives
8
+ - bef93ae: fix(security): prevent streaming tool calls from finalizing on parsable partial JSON
9
+
10
+ Streaming tool call arguments were finalized using `isParsableJson()` as a heuristic for completion. If partial accumulated JSON happened to be valid JSON before all chunks arrived, the tool call would be executed with incomplete arguments. Tool call finalization now only occurs in `flush()` after the stream is fully consumed.
11
+
12
+ - 327642b: fix: more precise default message for tool execution denial
13
+ - Updated dependencies [d559de9]
14
+ - @ai-sdk/provider-utils@4.0.37
15
+
3
16
  ## 2.0.57
4
17
 
5
18
  ### Patch Changes
package/dist/index.js CHANGED
@@ -276,7 +276,7 @@ function convertToOpenAICompatibleChatMessages(prompt) {
276
276
  contentValue = output.value;
277
277
  break;
278
278
  case "execution-denied":
279
- contentValue = (_c = output.reason) != null ? _c : "Tool execution denied.";
279
+ contentValue = (_c = output.reason) != null ? _c : "Tool call execution denied.";
280
280
  break;
281
281
  case "content":
282
282
  case "json":
@@ -670,6 +670,7 @@ var OpenAICompatibleChatLanguageModel = class {
670
670
  fetch: this.config.fetch
671
671
  });
672
672
  const toolCalls = [];
673
+ const pendingToolCalls = /* @__PURE__ */ new Map();
673
674
  let finishReason = {
674
675
  unified: "other",
675
676
  raw: void 0
@@ -687,7 +688,7 @@ var OpenAICompatibleChatLanguageModel = class {
687
688
  controller.enqueue({ type: "stream-start", warnings });
688
689
  },
689
690
  transform(chunk, controller) {
690
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
691
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
691
692
  if (options.includeRawChunks) {
692
693
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
693
694
  }
@@ -771,35 +772,84 @@ var OpenAICompatibleChatLanguageModel = class {
771
772
  for (const toolCallDelta of delta.tool_calls) {
772
773
  const index = (_c = toolCallDelta.index) != null ? _c : toolCalls.length;
773
774
  if (toolCalls[index] == null) {
774
- if (toolCallDelta.id == null) {
775
- throw new import_provider3.InvalidResponseDataError({
776
- data: toolCallDelta,
777
- message: `Expected 'id' to be a string.`
775
+ if (toolCallDelta.index != null) {
776
+ let pending = pendingToolCalls.get(index);
777
+ if (pending == null) {
778
+ pending = {
779
+ id: (_d = toolCallDelta.id) != null ? _d : null,
780
+ bufferedArguments: "",
781
+ thoughtSignature: (_g = (_f = (_e = toolCallDelta.extra_content) == null ? void 0 : _e.google) == null ? void 0 : _f.thought_signature) != null ? _g : void 0
782
+ };
783
+ pendingToolCalls.set(index, pending);
784
+ } else {
785
+ if (pending.id == null && toolCallDelta.id != null) {
786
+ pending.id = toolCallDelta.id;
787
+ }
788
+ if (pending.thoughtSignature == null && ((_i = (_h = toolCallDelta.extra_content) == null ? void 0 : _h.google) == null ? void 0 : _i.thought_signature) != null) {
789
+ pending.thoughtSignature = toolCallDelta.extra_content.google.thought_signature;
790
+ }
791
+ }
792
+ const argumentsDelta = (_j = toolCallDelta.function) == null ? void 0 : _j.arguments;
793
+ if (argumentsDelta != null) {
794
+ pending.bufferedArguments += argumentsDelta;
795
+ }
796
+ const name = (_k = toolCallDelta.function) == null ? void 0 : _k.name;
797
+ if (name == null) {
798
+ continue;
799
+ }
800
+ pendingToolCalls.delete(index);
801
+ if (pending.id == null) {
802
+ throw new import_provider3.InvalidResponseDataError({
803
+ data: toolCallDelta,
804
+ message: `Expected 'id' to be a string.`
805
+ });
806
+ }
807
+ controller.enqueue({
808
+ type: "tool-input-start",
809
+ id: pending.id,
810
+ toolName: name
778
811
  });
779
- }
780
- if (((_d = toolCallDelta.function) == null ? void 0 : _d.name) == null) {
781
- throw new import_provider3.InvalidResponseDataError({
782
- data: toolCallDelta,
783
- message: `Expected 'function.name' to be a string.`
812
+ toolCalls[index] = {
813
+ id: pending.id,
814
+ type: "function",
815
+ function: {
816
+ name,
817
+ arguments: pending.bufferedArguments
818
+ },
819
+ hasFinished: false,
820
+ thoughtSignature: pending.thoughtSignature
821
+ };
822
+ } else {
823
+ if (toolCallDelta.id == null) {
824
+ throw new import_provider3.InvalidResponseDataError({
825
+ data: toolCallDelta,
826
+ message: `Expected 'id' to be a string.`
827
+ });
828
+ }
829
+ if (((_l = toolCallDelta.function) == null ? void 0 : _l.name) == null) {
830
+ throw new import_provider3.InvalidResponseDataError({
831
+ data: toolCallDelta,
832
+ message: `Expected 'function.name' to be a string.`
833
+ });
834
+ }
835
+ controller.enqueue({
836
+ type: "tool-input-start",
837
+ id: toolCallDelta.id,
838
+ toolName: toolCallDelta.function.name
784
839
  });
840
+ toolCalls[index] = {
841
+ id: toolCallDelta.id,
842
+ type: "function",
843
+ function: {
844
+ name: toolCallDelta.function.name,
845
+ arguments: (_m = toolCallDelta.function.arguments) != null ? _m : ""
846
+ },
847
+ hasFinished: false,
848
+ thoughtSignature: (_p = (_o = (_n = toolCallDelta.extra_content) == null ? void 0 : _n.google) == null ? void 0 : _o.thought_signature) != null ? _p : void 0
849
+ };
785
850
  }
786
- controller.enqueue({
787
- type: "tool-input-start",
788
- id: toolCallDelta.id,
789
- toolName: toolCallDelta.function.name
790
- });
791
- toolCalls[index] = {
792
- id: toolCallDelta.id,
793
- type: "function",
794
- function: {
795
- name: toolCallDelta.function.name,
796
- arguments: (_e = toolCallDelta.function.arguments) != null ? _e : ""
797
- },
798
- hasFinished: false,
799
- thoughtSignature: (_h = (_g = (_f = toolCallDelta.extra_content) == null ? void 0 : _f.google) == null ? void 0 : _g.thought_signature) != null ? _h : void 0
800
- };
801
851
  const toolCall2 = toolCalls[index];
802
- if (((_i = toolCall2.function) == null ? void 0 : _i.name) != null && ((_j = toolCall2.function) == null ? void 0 : _j.arguments) != null) {
852
+ if (((_q = toolCall2.function) == null ? void 0 : _q.name) != null && ((_r = toolCall2.function) == null ? void 0 : _r.arguments) != null) {
803
853
  if (toolCall2.function.arguments.length > 0) {
804
854
  controller.enqueue({
805
855
  type: "tool-input-delta",
@@ -807,26 +857,6 @@ var OpenAICompatibleChatLanguageModel = class {
807
857
  delta: toolCall2.function.arguments
808
858
  });
809
859
  }
810
- if ((0, import_provider_utils2.isParsableJson)(toolCall2.function.arguments)) {
811
- controller.enqueue({
812
- type: "tool-input-end",
813
- id: toolCall2.id
814
- });
815
- controller.enqueue({
816
- type: "tool-call",
817
- toolCallId: (_k = toolCall2.id) != null ? _k : (0, import_provider_utils2.generateId)(),
818
- toolName: toolCall2.function.name,
819
- input: toolCall2.function.arguments,
820
- ...toolCall2.thoughtSignature ? {
821
- providerMetadata: {
822
- [providerOptionsName]: {
823
- thoughtSignature: toolCall2.thoughtSignature
824
- }
825
- }
826
- } : {}
827
- });
828
- toolCall2.hasFinished = true;
829
- }
830
860
  }
831
861
  continue;
832
862
  }
@@ -834,34 +864,14 @@ var OpenAICompatibleChatLanguageModel = class {
834
864
  if (toolCall.hasFinished) {
835
865
  continue;
836
866
  }
837
- if (((_l = toolCallDelta.function) == null ? void 0 : _l.arguments) != null) {
838
- toolCall.function.arguments += (_n = (_m = toolCallDelta.function) == null ? void 0 : _m.arguments) != null ? _n : "";
867
+ if (((_s = toolCallDelta.function) == null ? void 0 : _s.arguments) != null) {
868
+ toolCall.function.arguments += (_u = (_t = toolCallDelta.function) == null ? void 0 : _t.arguments) != null ? _u : "";
839
869
  }
840
870
  controller.enqueue({
841
871
  type: "tool-input-delta",
842
872
  id: toolCall.id,
843
- delta: (_o = toolCallDelta.function.arguments) != null ? _o : ""
873
+ delta: (_v = toolCallDelta.function.arguments) != null ? _v : ""
844
874
  });
845
- if (((_p = toolCall.function) == null ? void 0 : _p.name) != null && ((_q = toolCall.function) == null ? void 0 : _q.arguments) != null && (0, import_provider_utils2.isParsableJson)(toolCall.function.arguments)) {
846
- controller.enqueue({
847
- type: "tool-input-end",
848
- id: toolCall.id
849
- });
850
- controller.enqueue({
851
- type: "tool-call",
852
- toolCallId: (_r = toolCall.id) != null ? _r : (0, import_provider_utils2.generateId)(),
853
- toolName: toolCall.function.name,
854
- input: toolCall.function.arguments,
855
- ...toolCall.thoughtSignature ? {
856
- providerMetadata: {
857
- [providerOptionsName]: {
858
- thoughtSignature: toolCall.thoughtSignature
859
- }
860
- }
861
- } : {}
862
- });
863
- toolCall.hasFinished = true;
864
- }
865
875
  }
866
876
  }
867
877
  },
@@ -873,6 +883,16 @@ var OpenAICompatibleChatLanguageModel = class {
873
883
  if (isActiveText) {
874
884
  controller.enqueue({ type: "text-end", id: "txt-0" });
875
885
  }
886
+ for (const [index, pending] of pendingToolCalls) {
887
+ throw new import_provider3.InvalidResponseDataError({
888
+ data: {
889
+ index,
890
+ id: pending.id,
891
+ function: { arguments: pending.bufferedArguments }
892
+ },
893
+ message: `Expected 'function.name' to be a string.`
894
+ });
895
+ }
876
896
  for (const toolCall of toolCalls.filter(
877
897
  (toolCall2) => !toolCall2.hasFinished
878
898
  )) {
@@ -1698,7 +1718,7 @@ async function fileToBlob(file) {
1698
1718
  var import_provider_utils6 = require("@ai-sdk/provider-utils");
1699
1719
 
1700
1720
  // src/version.ts
1701
- var VERSION = true ? "2.0.57" : "0.0.0-test";
1721
+ var VERSION = true ? "2.0.58" : "0.0.0-test";
1702
1722
 
1703
1723
  // src/openai-compatible-provider.ts
1704
1724
  function createOpenAICompatible(options) {