@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 +18 -0
- package/dist/index.js +65 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +65 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/chat/openai-compatible-chat-language-model.ts +91 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/openai-compatible",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.75",
|
|
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.
|
|
40
|
-
"@ai-sdk/provider-utils": "4.0.
|
|
39
|
+
"@ai-sdk/provider": "3.0.16",
|
|
40
|
+
"@ai-sdk/provider-utils": "4.0.51"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "20.17.24",
|
|
@@ -299,13 +299,16 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
|
299
299
|
});
|
|
300
300
|
|
|
301
301
|
const choice = responseBody.choices[0];
|
|
302
|
+
if (choice == null) {
|
|
303
|
+
throw new InvalidResponseDataError({
|
|
304
|
+
data: rawResponse,
|
|
305
|
+
message: 'Response did not contain any choices.',
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
302
309
|
const content: Array<LanguageModelV3Content> = [];
|
|
303
310
|
|
|
304
|
-
|
|
305
|
-
const text = choice.message.content;
|
|
306
|
-
if (text != null && text.length > 0) {
|
|
307
|
-
content.push({ type: 'text', text });
|
|
308
|
-
}
|
|
311
|
+
content.push(...convertOpenAICompatibleContent(choice.message.content));
|
|
309
312
|
|
|
310
313
|
// reasoning content:
|
|
311
314
|
const reasoning =
|
|
@@ -508,9 +511,12 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
|
508
511
|
|
|
509
512
|
const delta = choice.delta;
|
|
510
513
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
+
const enqueueReasoningDelta = (reasoningDelta: string) => {
|
|
515
|
+
if (isActiveText) {
|
|
516
|
+
controller.enqueue({ type: 'text-end', id: 'txt-0' });
|
|
517
|
+
isActiveText = false;
|
|
518
|
+
}
|
|
519
|
+
|
|
514
520
|
if (!isActiveReasoning) {
|
|
515
521
|
controller.enqueue({
|
|
516
522
|
type: 'reasoning-start',
|
|
@@ -522,12 +528,11 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
|
522
528
|
controller.enqueue({
|
|
523
529
|
type: 'reasoning-delta',
|
|
524
530
|
id: 'reasoning-0',
|
|
525
|
-
delta:
|
|
531
|
+
delta: reasoningDelta,
|
|
526
532
|
});
|
|
527
|
-
}
|
|
533
|
+
};
|
|
528
534
|
|
|
529
|
-
|
|
530
|
-
// end active reasoning block before text starts
|
|
535
|
+
const enqueueTextDelta = (textDelta: string) => {
|
|
531
536
|
if (isActiveReasoning) {
|
|
532
537
|
controller.enqueue({
|
|
533
538
|
type: 'reasoning-end',
|
|
@@ -544,11 +549,27 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
|
544
549
|
controller.enqueue({
|
|
545
550
|
type: 'text-delta',
|
|
546
551
|
id: 'txt-0',
|
|
547
|
-
delta:
|
|
552
|
+
delta: textDelta,
|
|
548
553
|
});
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// enqueue reasoning before text deltas:
|
|
557
|
+
const reasoningContent = delta.reasoning_content ?? delta.reasoning;
|
|
558
|
+
if (reasoningContent) {
|
|
559
|
+
enqueueReasoningDelta(reasoningContent);
|
|
549
560
|
}
|
|
550
561
|
|
|
551
|
-
|
|
562
|
+
for (const contentPart of convertOpenAICompatibleContent(
|
|
563
|
+
delta.content,
|
|
564
|
+
)) {
|
|
565
|
+
if (contentPart.type === 'reasoning') {
|
|
566
|
+
enqueueReasoningDelta(contentPart.text);
|
|
567
|
+
} else {
|
|
568
|
+
enqueueTextDelta(contentPart.text);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (delta.tool_calls != null && delta.tool_calls.length > 0) {
|
|
552
573
|
// end active reasoning block before tool calls start
|
|
553
574
|
if (isActiveReasoning) {
|
|
554
575
|
controller.enqueue({
|
|
@@ -815,6 +836,60 @@ const openaiCompatibleTokenUsageSchema = z
|
|
|
815
836
|
})
|
|
816
837
|
.nullish();
|
|
817
838
|
|
|
839
|
+
const openAICompatibleContentSchema = z
|
|
840
|
+
.union([
|
|
841
|
+
z.string(),
|
|
842
|
+
z.array(
|
|
843
|
+
z.looseObject({
|
|
844
|
+
type: z.string(),
|
|
845
|
+
}),
|
|
846
|
+
),
|
|
847
|
+
])
|
|
848
|
+
.nullish();
|
|
849
|
+
|
|
850
|
+
function convertOpenAICompatibleContent(
|
|
851
|
+
content: z.infer<typeof openAICompatibleContentSchema>,
|
|
852
|
+
): Array<Extract<LanguageModelV3Content, { type: 'text' | 'reasoning' }>> {
|
|
853
|
+
if (content == null) {
|
|
854
|
+
return [];
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
if (typeof content === 'string') {
|
|
858
|
+
return content.length > 0 ? [{ type: 'text', text: content }] : [];
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const result: Array<
|
|
862
|
+
Extract<LanguageModelV3Content, { type: 'text' | 'reasoning' }>
|
|
863
|
+
> = [];
|
|
864
|
+
|
|
865
|
+
for (const part of content) {
|
|
866
|
+
if (part.type === 'text' && typeof part.text === 'string') {
|
|
867
|
+
if (part.text.length > 0) {
|
|
868
|
+
result.push({ type: 'text', text: part.text });
|
|
869
|
+
}
|
|
870
|
+
} else if (part.type === 'thinking' && Array.isArray(part.thinking)) {
|
|
871
|
+
const reasoningText = part.thinking
|
|
872
|
+
.filter(
|
|
873
|
+
chunk =>
|
|
874
|
+
chunk != null &&
|
|
875
|
+
typeof chunk === 'object' &&
|
|
876
|
+
'type' in chunk &&
|
|
877
|
+
chunk.type === 'text' &&
|
|
878
|
+
'text' in chunk &&
|
|
879
|
+
typeof chunk.text === 'string',
|
|
880
|
+
)
|
|
881
|
+
.map(chunk => chunk.text)
|
|
882
|
+
.join('');
|
|
883
|
+
|
|
884
|
+
if (reasoningText.length > 0) {
|
|
885
|
+
result.push({ type: 'reasoning', text: reasoningText });
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
return result;
|
|
891
|
+
}
|
|
892
|
+
|
|
818
893
|
// limited version of the schema, focussed on what is needed for the implementation
|
|
819
894
|
// this approach limits breakages when the API changes and increases efficiency
|
|
820
895
|
const OpenAICompatibleChatResponseSchema = z.looseObject({
|
|
@@ -825,7 +900,7 @@ const OpenAICompatibleChatResponseSchema = z.looseObject({
|
|
|
825
900
|
z.object({
|
|
826
901
|
message: z.object({
|
|
827
902
|
role: z.literal('assistant').nullish(),
|
|
828
|
-
content:
|
|
903
|
+
content: openAICompatibleContentSchema,
|
|
829
904
|
reasoning_content: z.string().nullish(),
|
|
830
905
|
reasoning: z.string().nullish(),
|
|
831
906
|
tool_calls: z
|
|
@@ -865,7 +940,7 @@ const chunkBaseSchema = z.looseObject({
|
|
|
865
940
|
delta: z
|
|
866
941
|
.object({
|
|
867
942
|
role: z.enum(['assistant', '']).nullish(),
|
|
868
|
-
content:
|
|
943
|
+
content: openAICompatibleContentSchema,
|
|
869
944
|
// Most openai-compatible models set `reasoning_content`, but some
|
|
870
945
|
// providers serving `gpt-oss` set `reasoning`. See #7866
|
|
871
946
|
reasoning_content: z.string().nullish(),
|