@ai-sdk/openai-compatible 2.0.72 → 2.0.74
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 +15 -0
- package/dist/index.js +58 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +58 -13
- package/dist/index.mjs.map +1 -1
- package/docs/index.mdx +1 -0
- package/package.json +2 -2
- package/src/chat/openai-compatible-chat-language-model.ts +83 -15
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.74",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@ai-sdk/provider": "3.0.15",
|
|
40
|
-
"@ai-sdk/provider-utils": "4.0.
|
|
40
|
+
"@ai-sdk/provider-utils": "4.0.50"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "20.17.24",
|
|
@@ -301,11 +301,7 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
|
301
301
|
const choice = responseBody.choices[0];
|
|
302
302
|
const content: Array<LanguageModelV3Content> = [];
|
|
303
303
|
|
|
304
|
-
|
|
305
|
-
const text = choice.message.content;
|
|
306
|
-
if (text != null && text.length > 0) {
|
|
307
|
-
content.push({ type: 'text', text });
|
|
308
|
-
}
|
|
304
|
+
content.push(...convertOpenAICompatibleContent(choice.message.content));
|
|
309
305
|
|
|
310
306
|
// reasoning content:
|
|
311
307
|
const reasoning =
|
|
@@ -508,9 +504,12 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
|
508
504
|
|
|
509
505
|
const delta = choice.delta;
|
|
510
506
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
507
|
+
const enqueueReasoningDelta = (reasoningDelta: string) => {
|
|
508
|
+
if (isActiveText) {
|
|
509
|
+
controller.enqueue({ type: 'text-end', id: 'txt-0' });
|
|
510
|
+
isActiveText = false;
|
|
511
|
+
}
|
|
512
|
+
|
|
514
513
|
if (!isActiveReasoning) {
|
|
515
514
|
controller.enqueue({
|
|
516
515
|
type: 'reasoning-start',
|
|
@@ -522,12 +521,11 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
|
522
521
|
controller.enqueue({
|
|
523
522
|
type: 'reasoning-delta',
|
|
524
523
|
id: 'reasoning-0',
|
|
525
|
-
delta:
|
|
524
|
+
delta: reasoningDelta,
|
|
526
525
|
});
|
|
527
|
-
}
|
|
526
|
+
};
|
|
528
527
|
|
|
529
|
-
|
|
530
|
-
// end active reasoning block before text starts
|
|
528
|
+
const enqueueTextDelta = (textDelta: string) => {
|
|
531
529
|
if (isActiveReasoning) {
|
|
532
530
|
controller.enqueue({
|
|
533
531
|
type: 'reasoning-end',
|
|
@@ -544,8 +542,24 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
|
|
|
544
542
|
controller.enqueue({
|
|
545
543
|
type: 'text-delta',
|
|
546
544
|
id: 'txt-0',
|
|
547
|
-
delta:
|
|
545
|
+
delta: textDelta,
|
|
548
546
|
});
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
// enqueue reasoning before text deltas:
|
|
550
|
+
const reasoningContent = delta.reasoning_content ?? delta.reasoning;
|
|
551
|
+
if (reasoningContent) {
|
|
552
|
+
enqueueReasoningDelta(reasoningContent);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
for (const contentPart of convertOpenAICompatibleContent(
|
|
556
|
+
delta.content,
|
|
557
|
+
)) {
|
|
558
|
+
if (contentPart.type === 'reasoning') {
|
|
559
|
+
enqueueReasoningDelta(contentPart.text);
|
|
560
|
+
} else {
|
|
561
|
+
enqueueTextDelta(contentPart.text);
|
|
562
|
+
}
|
|
549
563
|
}
|
|
550
564
|
|
|
551
565
|
if (delta.tool_calls != null) {
|
|
@@ -815,6 +829,60 @@ const openaiCompatibleTokenUsageSchema = z
|
|
|
815
829
|
})
|
|
816
830
|
.nullish();
|
|
817
831
|
|
|
832
|
+
const openAICompatibleContentSchema = z
|
|
833
|
+
.union([
|
|
834
|
+
z.string(),
|
|
835
|
+
z.array(
|
|
836
|
+
z.looseObject({
|
|
837
|
+
type: z.string(),
|
|
838
|
+
}),
|
|
839
|
+
),
|
|
840
|
+
])
|
|
841
|
+
.nullish();
|
|
842
|
+
|
|
843
|
+
function convertOpenAICompatibleContent(
|
|
844
|
+
content: z.infer<typeof openAICompatibleContentSchema>,
|
|
845
|
+
): Array<Extract<LanguageModelV3Content, { type: 'text' | 'reasoning' }>> {
|
|
846
|
+
if (content == null) {
|
|
847
|
+
return [];
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (typeof content === 'string') {
|
|
851
|
+
return content.length > 0 ? [{ type: 'text', text: content }] : [];
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
const result: Array<
|
|
855
|
+
Extract<LanguageModelV3Content, { type: 'text' | 'reasoning' }>
|
|
856
|
+
> = [];
|
|
857
|
+
|
|
858
|
+
for (const part of content) {
|
|
859
|
+
if (part.type === 'text' && typeof part.text === 'string') {
|
|
860
|
+
if (part.text.length > 0) {
|
|
861
|
+
result.push({ type: 'text', text: part.text });
|
|
862
|
+
}
|
|
863
|
+
} else if (part.type === 'thinking' && Array.isArray(part.thinking)) {
|
|
864
|
+
const reasoningText = part.thinking
|
|
865
|
+
.filter(
|
|
866
|
+
chunk =>
|
|
867
|
+
chunk != null &&
|
|
868
|
+
typeof chunk === 'object' &&
|
|
869
|
+
'type' in chunk &&
|
|
870
|
+
chunk.type === 'text' &&
|
|
871
|
+
'text' in chunk &&
|
|
872
|
+
typeof chunk.text === 'string',
|
|
873
|
+
)
|
|
874
|
+
.map(chunk => chunk.text)
|
|
875
|
+
.join('');
|
|
876
|
+
|
|
877
|
+
if (reasoningText.length > 0) {
|
|
878
|
+
result.push({ type: 'reasoning', text: reasoningText });
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
return result;
|
|
884
|
+
}
|
|
885
|
+
|
|
818
886
|
// limited version of the schema, focussed on what is needed for the implementation
|
|
819
887
|
// this approach limits breakages when the API changes and increases efficiency
|
|
820
888
|
const OpenAICompatibleChatResponseSchema = z.looseObject({
|
|
@@ -825,7 +893,7 @@ const OpenAICompatibleChatResponseSchema = z.looseObject({
|
|
|
825
893
|
z.object({
|
|
826
894
|
message: z.object({
|
|
827
895
|
role: z.literal('assistant').nullish(),
|
|
828
|
-
content:
|
|
896
|
+
content: openAICompatibleContentSchema,
|
|
829
897
|
reasoning_content: z.string().nullish(),
|
|
830
898
|
reasoning: z.string().nullish(),
|
|
831
899
|
tool_calls: z
|
|
@@ -865,7 +933,7 @@ const chunkBaseSchema = z.looseObject({
|
|
|
865
933
|
delta: z
|
|
866
934
|
.object({
|
|
867
935
|
role: z.enum(['assistant', '']).nullish(),
|
|
868
|
-
content:
|
|
936
|
+
content: openAICompatibleContentSchema,
|
|
869
937
|
// Most openai-compatible models set `reasoning_content`, but some
|
|
870
938
|
// providers serving `gpt-oss` set `reasoning`. See #7866
|
|
871
939
|
reasoning_content: z.string().nullish(),
|