@ai-sdk/openai-compatible 2.0.73 → 2.0.75

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,23 @@
1
1
  # @ai-sdk/openai-compatible
2
2
 
3
+ ## 2.0.75
4
+
5
+ ### Patch Changes
6
+
7
+ - f3c1980: fix(openai-compatible): keep reasoning streams contiguous when deltas include empty tool call arrays
8
+ - 1336501: fix(openai): return an AI SDK error for empty chat completion choices
9
+ - Updated dependencies [1a4dbb1]
10
+ - @ai-sdk/provider@3.0.16
11
+ - @ai-sdk/provider-utils@4.0.51
12
+
13
+ ## 2.0.74
14
+
15
+ ### Patch Changes
16
+
17
+ - 6d44462: Support text and thinking parts in array-based chat completion content while ignoring unknown part types.
18
+ - Updated dependencies [cc23556]
19
+ - @ai-sdk/provider-utils@4.0.50
20
+
3
21
  ## 2.0.73
4
22
 
5
23
  ### Patch Changes
package/dist/index.js CHANGED
@@ -587,11 +587,14 @@ var OpenAICompatibleChatLanguageModel = class {
587
587
  fetch: this.config.fetch
588
588
  });
589
589
  const choice = responseBody.choices[0];
590
- const content = [];
591
- const text = choice.message.content;
592
- if (text != null && text.length > 0) {
593
- content.push({ type: "text", text });
590
+ if (choice == null) {
591
+ throw new import_provider3.InvalidResponseDataError({
592
+ data: rawResponse,
593
+ message: "Response did not contain any choices."
594
+ });
594
595
  }
596
+ const content = [];
597
+ content.push(...convertOpenAICompatibleContent(choice.message.content));
595
598
  const reasoning = (_a = choice.message.reasoning_content) != null ? _a : choice.message.reasoning;
596
599
  if (reasoning != null && reasoning.length > 0) {
597
600
  content.push({
@@ -725,8 +728,11 @@ var OpenAICompatibleChatLanguageModel = class {
725
728
  return;
726
729
  }
727
730
  const delta = choice.delta;
728
- const reasoningContent = (_b = delta.reasoning_content) != null ? _b : delta.reasoning;
729
- if (reasoningContent) {
731
+ const enqueueReasoningDelta = (reasoningDelta) => {
732
+ if (isActiveText) {
733
+ controller.enqueue({ type: "text-end", id: "txt-0" });
734
+ isActiveText = false;
735
+ }
730
736
  if (!isActiveReasoning) {
731
737
  controller.enqueue({
732
738
  type: "reasoning-start",
@@ -737,10 +743,10 @@ var OpenAICompatibleChatLanguageModel = class {
737
743
  controller.enqueue({
738
744
  type: "reasoning-delta",
739
745
  id: "reasoning-0",
740
- delta: reasoningContent
746
+ delta: reasoningDelta
741
747
  });
742
- }
743
- if (delta.content) {
748
+ };
749
+ const enqueueTextDelta = (textDelta) => {
744
750
  if (isActiveReasoning) {
745
751
  controller.enqueue({
746
752
  type: "reasoning-end",
@@ -755,10 +761,23 @@ var OpenAICompatibleChatLanguageModel = class {
755
761
  controller.enqueue({
756
762
  type: "text-delta",
757
763
  id: "txt-0",
758
- delta: delta.content
764
+ delta: textDelta
759
765
  });
766
+ };
767
+ const reasoningContent = (_b = delta.reasoning_content) != null ? _b : delta.reasoning;
768
+ if (reasoningContent) {
769
+ enqueueReasoningDelta(reasoningContent);
760
770
  }
761
- if (delta.tool_calls != null) {
771
+ for (const contentPart of convertOpenAICompatibleContent(
772
+ delta.content
773
+ )) {
774
+ if (contentPart.type === "reasoning") {
775
+ enqueueReasoningDelta(contentPart.text);
776
+ } else {
777
+ enqueueTextDelta(contentPart.text);
778
+ }
779
+ }
780
+ if (delta.tool_calls != null && delta.tool_calls.length > 0) {
762
781
  if (isActiveReasoning) {
763
782
  controller.enqueue({
764
783
  type: "reasoning-end",
@@ -958,6 +977,38 @@ var openaiCompatibleTokenUsageSchema = import_v43.z.looseObject({
958
977
  rejected_prediction_tokens: import_v43.z.number().nullish()
959
978
  }).nullish()
960
979
  }).nullish();
980
+ var openAICompatibleContentSchema = import_v43.z.union([
981
+ import_v43.z.string(),
982
+ import_v43.z.array(
983
+ import_v43.z.looseObject({
984
+ type: import_v43.z.string()
985
+ })
986
+ )
987
+ ]).nullish();
988
+ function convertOpenAICompatibleContent(content) {
989
+ if (content == null) {
990
+ return [];
991
+ }
992
+ if (typeof content === "string") {
993
+ return content.length > 0 ? [{ type: "text", text: content }] : [];
994
+ }
995
+ const result = [];
996
+ for (const part of content) {
997
+ if (part.type === "text" && typeof part.text === "string") {
998
+ if (part.text.length > 0) {
999
+ result.push({ type: "text", text: part.text });
1000
+ }
1001
+ } else if (part.type === "thinking" && Array.isArray(part.thinking)) {
1002
+ const reasoningText = part.thinking.filter(
1003
+ (chunk) => chunk != null && typeof chunk === "object" && "type" in chunk && chunk.type === "text" && "text" in chunk && typeof chunk.text === "string"
1004
+ ).map((chunk) => chunk.text).join("");
1005
+ if (reasoningText.length > 0) {
1006
+ result.push({ type: "reasoning", text: reasoningText });
1007
+ }
1008
+ }
1009
+ }
1010
+ return result;
1011
+ }
961
1012
  var OpenAICompatibleChatResponseSchema = import_v43.z.looseObject({
962
1013
  id: import_v43.z.string().nullish(),
963
1014
  created: import_v43.z.number().nullish(),
@@ -966,7 +1017,7 @@ var OpenAICompatibleChatResponseSchema = import_v43.z.looseObject({
966
1017
  import_v43.z.object({
967
1018
  message: import_v43.z.object({
968
1019
  role: import_v43.z.literal("assistant").nullish(),
969
- content: import_v43.z.string().nullish(),
1020
+ content: openAICompatibleContentSchema,
970
1021
  reasoning_content: import_v43.z.string().nullish(),
971
1022
  reasoning: import_v43.z.string().nullish(),
972
1023
  tool_calls: import_v43.z.array(
@@ -998,7 +1049,7 @@ var chunkBaseSchema = import_v43.z.looseObject({
998
1049
  import_v43.z.object({
999
1050
  delta: import_v43.z.object({
1000
1051
  role: import_v43.z.enum(["assistant", ""]).nullish(),
1001
- content: import_v43.z.string().nullish(),
1052
+ content: openAICompatibleContentSchema,
1002
1053
  // Most openai-compatible models set `reasoning_content`, but some
1003
1054
  // providers serving `gpt-oss` set `reasoning`. See #7866
1004
1055
  reasoning_content: import_v43.z.string().nullish(),
@@ -1725,7 +1776,7 @@ async function fileToBlob(file) {
1725
1776
  var import_provider_utils6 = require("@ai-sdk/provider-utils");
1726
1777
 
1727
1778
  // src/version.ts
1728
- var VERSION = true ? "2.0.73" : "0.0.0-test";
1779
+ var VERSION = true ? "2.0.75" : "0.0.0-test";
1729
1780
 
1730
1781
  // src/openai-compatible-provider.ts
1731
1782
  function createOpenAICompatible(options) {