@ai-sdk/alibaba 2.0.0-beta.6 → 2.0.0-beta.61
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 +501 -0
- package/README.md +22 -1
- package/dist/index.d.ts +34 -5
- package/dist/index.js +489 -318
- package/dist/index.js.map +1 -1
- package/package.json +15 -15
- package/src/{alibaba-chat-options.ts → alibaba-chat-language-model-options.ts} +4 -3
- package/src/alibaba-chat-language-model.ts +97 -133
- package/src/alibaba-config.ts +1 -1
- package/src/alibaba-embedding-model-options.ts +33 -0
- package/src/alibaba-embedding-model.ts +178 -0
- package/src/alibaba-error.ts +17 -0
- package/src/alibaba-provider.ts +41 -25
- package/src/alibaba-video-model-options.ts +46 -0
- package/src/alibaba-video-model.ts +9 -50
- package/src/convert-to-alibaba-chat-messages.ts +59 -58
- package/src/index.ts +11 -5
- package/src/version.ts +6 -3
- package/dist/index.d.mts +0 -119
- package/dist/index.mjs +0 -1054
- package/dist/index.mjs.map +0 -1
|
@@ -3,34 +3,39 @@ import {
|
|
|
3
3
|
mapOpenAICompatibleFinishReason,
|
|
4
4
|
prepareTools,
|
|
5
5
|
} from '@ai-sdk/openai-compatible/internal';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type SharedV4Warning,
|
|
6
|
+
import type {
|
|
7
|
+
LanguageModelV4,
|
|
8
|
+
LanguageModelV4CallOptions,
|
|
9
|
+
LanguageModelV4Content,
|
|
10
|
+
LanguageModelV4FinishReason,
|
|
11
|
+
LanguageModelV4GenerateResult,
|
|
12
|
+
LanguageModelV4StreamPart,
|
|
13
|
+
LanguageModelV4StreamResult,
|
|
14
|
+
SharedV4Warning,
|
|
16
15
|
} from '@ai-sdk/provider';
|
|
17
16
|
import {
|
|
18
17
|
combineHeaders,
|
|
19
18
|
createEventSourceResponseHandler,
|
|
20
19
|
createJsonResponseHandler,
|
|
21
20
|
generateId,
|
|
22
|
-
|
|
21
|
+
isCustomReasoning,
|
|
22
|
+
mapReasoningToProviderBudget,
|
|
23
23
|
parseProviderOptions,
|
|
24
24
|
postJsonToApi,
|
|
25
|
+
serializeModelOptions,
|
|
26
|
+
StreamingToolCallTracker,
|
|
27
|
+
WORKFLOW_SERIALIZE,
|
|
28
|
+
WORKFLOW_DESERIALIZE,
|
|
29
|
+
type InferSchema,
|
|
25
30
|
type ParseResult,
|
|
26
31
|
} from '@ai-sdk/provider-utils';
|
|
27
32
|
import { z } from 'zod/v4';
|
|
28
33
|
import {
|
|
29
|
-
|
|
34
|
+
alibabaLanguageModelChatOptions,
|
|
30
35
|
type AlibabaChatModelId,
|
|
31
|
-
} from './alibaba-chat-options';
|
|
36
|
+
} from './alibaba-chat-language-model-options';
|
|
32
37
|
import type { AlibabaConfig } from './alibaba-config';
|
|
33
|
-
import { alibabaFailedResponseHandler } from './alibaba-
|
|
38
|
+
import { alibabaFailedResponseHandler } from './alibaba-error';
|
|
34
39
|
import { convertAlibabaUsage } from './convert-alibaba-usage';
|
|
35
40
|
import { convertToAlibabaChatMessages } from './convert-to-alibaba-chat-messages';
|
|
36
41
|
import { CacheControlValidator } from './get-cache-control';
|
|
@@ -44,12 +49,26 @@ import { CacheControlValidator } from './get-cache-control';
|
|
|
44
49
|
* - Thinking budget control (thinking_budget)
|
|
45
50
|
* - Prompt caching (cached_tokens tracking)
|
|
46
51
|
*/
|
|
47
|
-
export class
|
|
52
|
+
export class AlibabaChatLanguageModel implements LanguageModelV4 {
|
|
48
53
|
readonly specificationVersion = 'v4';
|
|
49
54
|
readonly modelId: AlibabaChatModelId;
|
|
50
55
|
|
|
51
56
|
private readonly config: AlibabaConfig;
|
|
52
57
|
|
|
58
|
+
static [WORKFLOW_SERIALIZE](model: AlibabaChatLanguageModel) {
|
|
59
|
+
return serializeModelOptions({
|
|
60
|
+
modelId: model.modelId,
|
|
61
|
+
config: model.config,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static [WORKFLOW_DESERIALIZE](options: {
|
|
66
|
+
modelId: AlibabaChatModelId;
|
|
67
|
+
config: AlibabaConfig;
|
|
68
|
+
}) {
|
|
69
|
+
return new AlibabaChatLanguageModel(options.modelId, options.config);
|
|
70
|
+
}
|
|
71
|
+
|
|
53
72
|
constructor(modelId: AlibabaChatModelId, config: AlibabaConfig) {
|
|
54
73
|
this.modelId = modelId;
|
|
55
74
|
this.config = config;
|
|
@@ -78,6 +97,7 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
78
97
|
stopSequences,
|
|
79
98
|
responseFormat,
|
|
80
99
|
seed,
|
|
100
|
+
reasoning,
|
|
81
101
|
providerOptions,
|
|
82
102
|
tools,
|
|
83
103
|
toolChoice,
|
|
@@ -89,7 +109,7 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
89
109
|
const alibabaOptions = await parseProviderOptions({
|
|
90
110
|
provider: 'alibaba',
|
|
91
111
|
providerOptions,
|
|
92
|
-
schema:
|
|
112
|
+
schema: alibabaLanguageModelChatOptions,
|
|
93
113
|
});
|
|
94
114
|
|
|
95
115
|
// Warn about unsupported features
|
|
@@ -121,13 +141,11 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
121
141
|
: { type: 'json_object' }
|
|
122
142
|
: undefined,
|
|
123
143
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
? { thinking_budget: alibabaOptions.thinkingBudget }
|
|
130
|
-
: {}),
|
|
144
|
+
...resolveAlibabaThinking({
|
|
145
|
+
reasoning,
|
|
146
|
+
alibabaOptions,
|
|
147
|
+
warnings,
|
|
148
|
+
}),
|
|
131
149
|
|
|
132
150
|
// Convert messages with cache control support
|
|
133
151
|
messages: convertToAlibabaChatMessages({
|
|
@@ -170,7 +188,7 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
170
188
|
rawValue: rawResponse,
|
|
171
189
|
} = await postJsonToApi({
|
|
172
190
|
url: `${this.config.baseURL}/chat/completions`,
|
|
173
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
191
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
174
192
|
body: args,
|
|
175
193
|
failedResponseHandler: alibabaFailedResponseHandler,
|
|
176
194
|
successfulResponseHandler: createJsonResponseHandler(
|
|
@@ -203,7 +221,7 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
203
221
|
for (const toolCall of choice.message.tool_calls) {
|
|
204
222
|
content.push({
|
|
205
223
|
type: 'tool-call',
|
|
206
|
-
toolCallId: toolCall.id,
|
|
224
|
+
toolCallId: toolCall.id ?? generateId(),
|
|
207
225
|
toolName: toolCall.function.name,
|
|
208
226
|
input: toolCall.function.arguments!,
|
|
209
227
|
});
|
|
@@ -241,7 +259,7 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
241
259
|
|
|
242
260
|
const { responseHeaders, value: response } = await postJsonToApi({
|
|
243
261
|
url: `${this.config.baseURL}/chat/completions`,
|
|
244
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
262
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
245
263
|
body,
|
|
246
264
|
failedResponseHandler: alibabaFailedResponseHandler,
|
|
247
265
|
successfulResponseHandler: createEventSourceResponseHandler(
|
|
@@ -262,13 +280,7 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
262
280
|
let activeText = false;
|
|
263
281
|
let activeReasoningId: string | null = null;
|
|
264
282
|
|
|
265
|
-
|
|
266
|
-
const toolCalls: Array<{
|
|
267
|
-
id: string;
|
|
268
|
-
type: 'function';
|
|
269
|
-
function: { name: string; arguments: string };
|
|
270
|
-
hasFinished: boolean;
|
|
271
|
-
}> = [];
|
|
283
|
+
let toolCallTracker: StreamingToolCallTracker;
|
|
272
284
|
|
|
273
285
|
return {
|
|
274
286
|
stream: response.pipeThrough(
|
|
@@ -277,6 +289,9 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
277
289
|
LanguageModelV4StreamPart
|
|
278
290
|
>({
|
|
279
291
|
start(controller) {
|
|
292
|
+
toolCallTracker = new StreamingToolCallTracker(controller, {
|
|
293
|
+
generateId,
|
|
294
|
+
});
|
|
280
295
|
controller.enqueue({ type: 'stream-start', warnings });
|
|
281
296
|
},
|
|
282
297
|
|
|
@@ -381,106 +396,7 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
381
396
|
}
|
|
382
397
|
|
|
383
398
|
for (const toolCallDelta of delta.tool_calls) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
// New tool call - first chunk with id and name
|
|
387
|
-
if (toolCalls[index] == null) {
|
|
388
|
-
if (toolCallDelta.id == null) {
|
|
389
|
-
throw new InvalidResponseDataError({
|
|
390
|
-
data: toolCallDelta,
|
|
391
|
-
message: `Expected 'id' to be a string.`,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
if (toolCallDelta.function?.name == null) {
|
|
396
|
-
throw new InvalidResponseDataError({
|
|
397
|
-
data: toolCallDelta,
|
|
398
|
-
message: `Expected 'function.name' to be a string.`,
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
controller.enqueue({
|
|
403
|
-
type: 'tool-input-start',
|
|
404
|
-
id: toolCallDelta.id,
|
|
405
|
-
toolName: toolCallDelta.function.name,
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
toolCalls[index] = {
|
|
409
|
-
id: toolCallDelta.id,
|
|
410
|
-
type: 'function',
|
|
411
|
-
function: {
|
|
412
|
-
name: toolCallDelta.function.name,
|
|
413
|
-
arguments: toolCallDelta.function.arguments ?? '',
|
|
414
|
-
},
|
|
415
|
-
hasFinished: false,
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
const toolCall = toolCalls[index];
|
|
419
|
-
|
|
420
|
-
// Send initial delta if arguments started
|
|
421
|
-
if (toolCall.function.arguments.length > 0) {
|
|
422
|
-
controller.enqueue({
|
|
423
|
-
type: 'tool-input-delta',
|
|
424
|
-
id: toolCall.id,
|
|
425
|
-
delta: toolCall.function.arguments,
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Check if already complete (some providers send full tool call at once)
|
|
430
|
-
if (isParsableJson(toolCall.function.arguments)) {
|
|
431
|
-
controller.enqueue({
|
|
432
|
-
type: 'tool-input-end',
|
|
433
|
-
id: toolCall.id,
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
controller.enqueue({
|
|
437
|
-
type: 'tool-call',
|
|
438
|
-
toolCallId: toolCall.id,
|
|
439
|
-
toolName: toolCall.function.name,
|
|
440
|
-
input: toolCall.function.arguments,
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
toolCall.hasFinished = true;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
continue;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Existing tool call - accumulate arguments
|
|
450
|
-
const toolCall = toolCalls[index];
|
|
451
|
-
|
|
452
|
-
if (toolCall.hasFinished) {
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Append arguments if not null (skip arguments: null chunks)
|
|
457
|
-
if (toolCallDelta.function?.arguments != null) {
|
|
458
|
-
toolCall.function.arguments +=
|
|
459
|
-
toolCallDelta.function.arguments;
|
|
460
|
-
|
|
461
|
-
controller.enqueue({
|
|
462
|
-
type: 'tool-input-delta',
|
|
463
|
-
id: toolCall.id,
|
|
464
|
-
delta: toolCallDelta.function.arguments,
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// Check if tool call is now complete
|
|
469
|
-
if (isParsableJson(toolCall.function.arguments)) {
|
|
470
|
-
controller.enqueue({
|
|
471
|
-
type: 'tool-input-end',
|
|
472
|
-
id: toolCall.id,
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
controller.enqueue({
|
|
476
|
-
type: 'tool-call',
|
|
477
|
-
toolCallId: toolCall.id,
|
|
478
|
-
toolName: toolCall.function.name,
|
|
479
|
-
input: toolCall.function.arguments,
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
toolCall.hasFinished = true;
|
|
483
|
-
}
|
|
399
|
+
toolCallTracker.processDelta(toolCallDelta);
|
|
484
400
|
}
|
|
485
401
|
}
|
|
486
402
|
|
|
@@ -505,6 +421,8 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
505
421
|
controller.enqueue({ type: 'text-end', id: '0' });
|
|
506
422
|
}
|
|
507
423
|
|
|
424
|
+
toolCallTracker.flush();
|
|
425
|
+
|
|
508
426
|
controller.enqueue({
|
|
509
427
|
type: 'finish',
|
|
510
428
|
finishReason,
|
|
@@ -519,6 +437,52 @@ export class AlibabaLanguageModel implements LanguageModelV4 {
|
|
|
519
437
|
}
|
|
520
438
|
}
|
|
521
439
|
|
|
440
|
+
function resolveAlibabaThinking({
|
|
441
|
+
reasoning,
|
|
442
|
+
alibabaOptions,
|
|
443
|
+
warnings,
|
|
444
|
+
}: {
|
|
445
|
+
reasoning: LanguageModelV4CallOptions['reasoning'];
|
|
446
|
+
alibabaOptions:
|
|
447
|
+
| InferSchema<typeof alibabaLanguageModelChatOptions>
|
|
448
|
+
| undefined;
|
|
449
|
+
warnings: SharedV4Warning[];
|
|
450
|
+
}): { enable_thinking?: boolean; thinking_budget?: number } {
|
|
451
|
+
if (
|
|
452
|
+
alibabaOptions?.enableThinking != null ||
|
|
453
|
+
alibabaOptions?.thinkingBudget != null
|
|
454
|
+
) {
|
|
455
|
+
return {
|
|
456
|
+
...(alibabaOptions.enableThinking != null
|
|
457
|
+
? { enable_thinking: alibabaOptions.enableThinking }
|
|
458
|
+
: {}),
|
|
459
|
+
...(alibabaOptions.thinkingBudget != null
|
|
460
|
+
? { thinking_budget: alibabaOptions.thinkingBudget }
|
|
461
|
+
: {}),
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (!isCustomReasoning(reasoning)) {
|
|
466
|
+
return {};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (reasoning === 'none') {
|
|
470
|
+
return { enable_thinking: false };
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const thinkingBudget = mapReasoningToProviderBudget({
|
|
474
|
+
reasoning,
|
|
475
|
+
maxOutputTokens: 16384,
|
|
476
|
+
maxReasoningBudget: 16384,
|
|
477
|
+
warnings,
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
enable_thinking: true,
|
|
482
|
+
...(thinkingBudget != null ? { thinking_budget: thinkingBudget } : {}),
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
522
486
|
/**
|
|
523
487
|
* Reference for schemas below:
|
|
524
488
|
* https://www.alibabacloud.com/help/en/model-studio/qwen-api-via-openai-chat-completions
|
package/src/alibaba-config.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { FetchFunction } from '@ai-sdk/provider-utils';
|
|
|
3
3
|
export interface AlibabaConfig {
|
|
4
4
|
provider: string;
|
|
5
5
|
baseURL: string;
|
|
6
|
-
headers
|
|
6
|
+
headers?: () => Record<string, string | undefined>;
|
|
7
7
|
fetch?: FetchFunction;
|
|
8
8
|
includeUsage?: boolean;
|
|
9
9
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
|
|
3
|
+
export type AlibabaEmbeddingModelId =
|
|
4
|
+
| 'text-embedding-v4'
|
|
5
|
+
| 'text-embedding-v3'
|
|
6
|
+
| (string & {});
|
|
7
|
+
|
|
8
|
+
export const alibabaEmbeddingModelOptions = z.object({
|
|
9
|
+
/**
|
|
10
|
+
* Differentiates query text from document text for asymmetric retrieval tasks.
|
|
11
|
+
* Defaults to `document`.
|
|
12
|
+
*/
|
|
13
|
+
textType: z.enum(['query', 'document']).optional(),
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The dimension of the output embedding vectors. Defaults to 1024.
|
|
17
|
+
*
|
|
18
|
+
* `text-embedding-v4` also supports 1536 and 2048 dimensions.
|
|
19
|
+
*/
|
|
20
|
+
dimension: z.number().optional(),
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The output vector type. Defaults to `dense`.
|
|
24
|
+
*
|
|
25
|
+
* Sparse-only output is not supported by the AI SDK embedding interface,
|
|
26
|
+
* which requires dense number arrays.
|
|
27
|
+
*/
|
|
28
|
+
outputType: z.enum(['dense', 'sparse', 'dense&sparse']).optional(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export type AlibabaEmbeddingModelOptions = z.infer<
|
|
32
|
+
typeof alibabaEmbeddingModelOptions
|
|
33
|
+
>;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TooManyEmbeddingValuesForCallError,
|
|
3
|
+
UnsupportedFunctionalityError,
|
|
4
|
+
type EmbeddingModelV4,
|
|
5
|
+
} from '@ai-sdk/provider';
|
|
6
|
+
import {
|
|
7
|
+
combineHeaders,
|
|
8
|
+
createJsonErrorResponseHandler,
|
|
9
|
+
createJsonResponseHandler,
|
|
10
|
+
parseProviderOptions,
|
|
11
|
+
postJsonToApi,
|
|
12
|
+
serializeModelOptions,
|
|
13
|
+
WORKFLOW_SERIALIZE,
|
|
14
|
+
WORKFLOW_DESERIALIZE,
|
|
15
|
+
} from '@ai-sdk/provider-utils';
|
|
16
|
+
import { z } from 'zod/v4';
|
|
17
|
+
import {
|
|
18
|
+
alibabaEmbeddingModelOptions,
|
|
19
|
+
type AlibabaEmbeddingModelId,
|
|
20
|
+
} from './alibaba-embedding-model-options';
|
|
21
|
+
import type { AlibabaConfig } from './alibaba-config';
|
|
22
|
+
|
|
23
|
+
// TODO: Add Alibaba multimodal embedding support in a follow-up change.
|
|
24
|
+
const alibabaEmbeddingFailedResponseHandler = createJsonErrorResponseHandler({
|
|
25
|
+
errorSchema: z.object({
|
|
26
|
+
code: z.string().nullish(),
|
|
27
|
+
message: z.string(),
|
|
28
|
+
request_id: z.string().nullish(),
|
|
29
|
+
}),
|
|
30
|
+
errorToMessage: data => data.message,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export class AlibabaEmbeddingModel implements EmbeddingModelV4 {
|
|
34
|
+
readonly specificationVersion = 'v4';
|
|
35
|
+
readonly modelId: AlibabaEmbeddingModelId;
|
|
36
|
+
readonly maxEmbeddingsPerCall = 10;
|
|
37
|
+
readonly supportsParallelCalls = false;
|
|
38
|
+
|
|
39
|
+
private readonly config: AlibabaConfig;
|
|
40
|
+
|
|
41
|
+
static [WORKFLOW_SERIALIZE](model: AlibabaEmbeddingModel) {
|
|
42
|
+
return serializeModelOptions({
|
|
43
|
+
modelId: model.modelId,
|
|
44
|
+
config: model.config,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static [WORKFLOW_DESERIALIZE](options: {
|
|
49
|
+
modelId: AlibabaEmbeddingModelId;
|
|
50
|
+
config: AlibabaConfig;
|
|
51
|
+
}) {
|
|
52
|
+
return new AlibabaEmbeddingModel(options.modelId, options.config);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
constructor(modelId: AlibabaEmbeddingModelId, config: AlibabaConfig) {
|
|
56
|
+
this.modelId = modelId;
|
|
57
|
+
this.config = config;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get provider(): string {
|
|
61
|
+
return this.config.provider;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async doEmbed({
|
|
65
|
+
values,
|
|
66
|
+
headers,
|
|
67
|
+
abortSignal,
|
|
68
|
+
providerOptions,
|
|
69
|
+
}: Parameters<EmbeddingModelV4['doEmbed']>[0]): Promise<
|
|
70
|
+
Awaited<ReturnType<EmbeddingModelV4['doEmbed']>>
|
|
71
|
+
> {
|
|
72
|
+
if (values.length > this.maxEmbeddingsPerCall) {
|
|
73
|
+
throw new TooManyEmbeddingValuesForCallError({
|
|
74
|
+
provider: this.provider,
|
|
75
|
+
modelId: this.modelId,
|
|
76
|
+
maxEmbeddingsPerCall: this.maxEmbeddingsPerCall,
|
|
77
|
+
values,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const alibabaOptions = await parseProviderOptions({
|
|
82
|
+
provider: 'alibaba',
|
|
83
|
+
providerOptions,
|
|
84
|
+
schema: alibabaEmbeddingModelOptions,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// TODO: Explore first-class sparse embedding support in AI SDK core.
|
|
88
|
+
if (alibabaOptions?.outputType === 'sparse') {
|
|
89
|
+
throw new UnsupportedFunctionalityError({
|
|
90
|
+
functionality: "Alibaba embedding outputType 'sparse'",
|
|
91
|
+
message:
|
|
92
|
+
"Alibaba embedding outputType 'sparse' is not supported because AI SDK embeddings require dense number arrays. Use 'dense' or 'dense&sparse' instead.",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const {
|
|
97
|
+
responseHeaders,
|
|
98
|
+
value: response,
|
|
99
|
+
rawValue,
|
|
100
|
+
} = await postJsonToApi({
|
|
101
|
+
url: `${this.config.baseURL}/services/embeddings/text-embedding/text-embedding`,
|
|
102
|
+
headers: combineHeaders(this.config.headers?.(), headers),
|
|
103
|
+
body: {
|
|
104
|
+
model: this.modelId,
|
|
105
|
+
input: {
|
|
106
|
+
texts: values,
|
|
107
|
+
},
|
|
108
|
+
parameters: {
|
|
109
|
+
text_type: alibabaOptions?.textType,
|
|
110
|
+
dimension: alibabaOptions?.dimension,
|
|
111
|
+
output_type: alibabaOptions?.outputType,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
failedResponseHandler: alibabaEmbeddingFailedResponseHandler,
|
|
115
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
116
|
+
alibabaTextEmbeddingResponseSchema,
|
|
117
|
+
),
|
|
118
|
+
abortSignal,
|
|
119
|
+
fetch: this.config.fetch,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const sortedEmbeddings = response.output.embeddings.sort(
|
|
123
|
+
(a, b) => a.text_index - b.text_index,
|
|
124
|
+
);
|
|
125
|
+
const sparseEmbeddings = sortedEmbeddings
|
|
126
|
+
.map(item =>
|
|
127
|
+
item.sparse_embedding == null
|
|
128
|
+
? undefined
|
|
129
|
+
: {
|
|
130
|
+
textIndex: item.text_index,
|
|
131
|
+
sparseEmbedding: item.sparse_embedding,
|
|
132
|
+
},
|
|
133
|
+
)
|
|
134
|
+
.filter(item => item != null);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
warnings: [],
|
|
138
|
+
embeddings: sortedEmbeddings.map(item => item.embedding),
|
|
139
|
+
usage: response.usage
|
|
140
|
+
? { tokens: response.usage.total_tokens }
|
|
141
|
+
: undefined,
|
|
142
|
+
providerMetadata:
|
|
143
|
+
sparseEmbeddings.length > 0
|
|
144
|
+
? {
|
|
145
|
+
alibaba: {
|
|
146
|
+
sparseEmbeddings,
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
: undefined,
|
|
150
|
+
response: { headers: responseHeaders, body: rawValue },
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const alibabaTextEmbeddingSparseEmbeddingSchema = z.object({
|
|
156
|
+
index: z.number(),
|
|
157
|
+
value: z.number(),
|
|
158
|
+
token: z.string().nullish(),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const alibabaTextEmbeddingResponseSchema = z.object({
|
|
162
|
+
output: z.object({
|
|
163
|
+
embeddings: z.array(
|
|
164
|
+
z.object({
|
|
165
|
+
embedding: z.array(z.number()),
|
|
166
|
+
text_index: z.number(),
|
|
167
|
+
sparse_embedding: z
|
|
168
|
+
.array(alibabaTextEmbeddingSparseEmbeddingSchema)
|
|
169
|
+
.nullish(),
|
|
170
|
+
}),
|
|
171
|
+
),
|
|
172
|
+
}),
|
|
173
|
+
usage: z
|
|
174
|
+
.object({
|
|
175
|
+
total_tokens: z.number(),
|
|
176
|
+
})
|
|
177
|
+
.nullish(),
|
|
178
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';
|
|
2
|
+
import { z } from 'zod/v4';
|
|
3
|
+
|
|
4
|
+
const alibabaErrorDataSchema = z.object({
|
|
5
|
+
error: z.object({
|
|
6
|
+
message: z.string(),
|
|
7
|
+
code: z.string().nullish(),
|
|
8
|
+
type: z.string().nullish(),
|
|
9
|
+
}),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type AlibabaErrorData = z.infer<typeof alibabaErrorDataSchema>;
|
|
13
|
+
|
|
14
|
+
export const alibabaFailedResponseHandler = createJsonErrorResponseHandler({
|
|
15
|
+
errorSchema: alibabaErrorDataSchema,
|
|
16
|
+
errorToMessage: data => data.error.message,
|
|
17
|
+
});
|