@ai-sdk/openai-compatible 3.0.0-beta.16 → 3.0.0-beta.19
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 +24 -0
- package/dist/index.js +94 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +94 -29
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/chat/openai-compatible-chat-language-model.ts +39 -12
- package/src/completion/openai-compatible-completion-language-model.ts +21 -3
- package/src/embedding/openai-compatible-embedding-model.ts +11 -2
- package/src/image/openai-compatible-image-model.ts +11 -6
- package/src/utils/to-camel-case.ts +43 -0
|
@@ -26,6 +26,11 @@ import {
|
|
|
26
26
|
ResponseHandler,
|
|
27
27
|
} from '@ai-sdk/provider-utils';
|
|
28
28
|
import { z } from 'zod/v4';
|
|
29
|
+
import {
|
|
30
|
+
resolveProviderOptionsKey,
|
|
31
|
+
toCamelCase,
|
|
32
|
+
warnIfDeprecatedProviderOptionsKey,
|
|
33
|
+
} from '../utils/to-camel-case';
|
|
29
34
|
import {
|
|
30
35
|
defaultOpenAICompatibleErrorStructure,
|
|
31
36
|
ProviderErrorStructure,
|
|
@@ -139,11 +144,19 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
139
144
|
|
|
140
145
|
if (deprecatedOptions != null) {
|
|
141
146
|
warnings.push({
|
|
142
|
-
type: '
|
|
143
|
-
|
|
147
|
+
type: 'deprecated',
|
|
148
|
+
setting: "providerOptions key 'openai-compatible'",
|
|
149
|
+
message: "Use 'openaiCompatible' instead.",
|
|
144
150
|
});
|
|
145
151
|
}
|
|
146
152
|
|
|
153
|
+
// Warn when the raw (non-camelCase) provider name is used
|
|
154
|
+
warnIfDeprecatedProviderOptionsKey({
|
|
155
|
+
rawName: this.providerOptionsName,
|
|
156
|
+
providerOptions,
|
|
157
|
+
warnings,
|
|
158
|
+
});
|
|
159
|
+
|
|
147
160
|
const compatibleOptions = Object.assign(
|
|
148
161
|
deprecatedOptions ?? {},
|
|
149
162
|
(await parseProviderOptions({
|
|
@@ -156,6 +169,11 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
156
169
|
providerOptions,
|
|
157
170
|
schema: openaiCompatibleLanguageModelChatOptions,
|
|
158
171
|
})) ?? {},
|
|
172
|
+
(await parseProviderOptions({
|
|
173
|
+
provider: toCamelCase(this.providerOptionsName),
|
|
174
|
+
providerOptions,
|
|
175
|
+
schema: openaiCompatibleLanguageModelChatOptions,
|
|
176
|
+
})) ?? {},
|
|
159
177
|
);
|
|
160
178
|
|
|
161
179
|
const strictJsonSchema = compatibleOptions?.strictJsonSchema ?? true;
|
|
@@ -186,7 +204,13 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
186
204
|
toolChoice,
|
|
187
205
|
});
|
|
188
206
|
|
|
207
|
+
const metadataKey = resolveProviderOptionsKey(
|
|
208
|
+
this.providerOptionsName,
|
|
209
|
+
providerOptions,
|
|
210
|
+
);
|
|
211
|
+
|
|
189
212
|
return {
|
|
213
|
+
metadataKey,
|
|
190
214
|
args: {
|
|
191
215
|
// model id:
|
|
192
216
|
model: this.modelId,
|
|
@@ -219,9 +243,10 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
219
243
|
stop: stopSequences,
|
|
220
244
|
seed,
|
|
221
245
|
...Object.fromEntries(
|
|
222
|
-
Object.entries(
|
|
223
|
-
providerOptions?.[this.providerOptionsName]
|
|
224
|
-
|
|
246
|
+
Object.entries({
|
|
247
|
+
...providerOptions?.[this.providerOptionsName],
|
|
248
|
+
...providerOptions?.[toCamelCase(this.providerOptionsName)],
|
|
249
|
+
}).filter(
|
|
225
250
|
([key]) =>
|
|
226
251
|
!Object.keys(
|
|
227
252
|
openaiCompatibleLanguageModelChatOptions.shape,
|
|
@@ -250,7 +275,7 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
250
275
|
async doGenerate(
|
|
251
276
|
options: LanguageModelV4CallOptions,
|
|
252
277
|
): Promise<LanguageModelV4GenerateResult> {
|
|
253
|
-
const { args, warnings } = await this.getArgs({ ...options });
|
|
278
|
+
const { args, warnings, metadataKey } = await this.getArgs({ ...options });
|
|
254
279
|
|
|
255
280
|
const transformedBody = this.transformRequestBody(args);
|
|
256
281
|
const body = JSON.stringify(transformedBody);
|
|
@@ -306,7 +331,7 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
306
331
|
...(thoughtSignature
|
|
307
332
|
? {
|
|
308
333
|
providerMetadata: {
|
|
309
|
-
[
|
|
334
|
+
[metadataKey]: { thoughtSignature },
|
|
310
335
|
},
|
|
311
336
|
}
|
|
312
337
|
: {}),
|
|
@@ -316,7 +341,7 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
316
341
|
|
|
317
342
|
// provider metadata:
|
|
318
343
|
const providerMetadata: SharedV4ProviderMetadata = {
|
|
319
|
-
[
|
|
344
|
+
[metadataKey]: {},
|
|
320
345
|
...(await this.config.metadataExtractor?.extractMetadata?.({
|
|
321
346
|
parsedBody: rawResponse,
|
|
322
347
|
})),
|
|
@@ -324,11 +349,11 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
324
349
|
const completionTokenDetails =
|
|
325
350
|
responseBody.usage?.completion_tokens_details;
|
|
326
351
|
if (completionTokenDetails?.accepted_prediction_tokens != null) {
|
|
327
|
-
providerMetadata[
|
|
352
|
+
providerMetadata[metadataKey].acceptedPredictionTokens =
|
|
328
353
|
completionTokenDetails?.accepted_prediction_tokens;
|
|
329
354
|
}
|
|
330
355
|
if (completionTokenDetails?.rejected_prediction_tokens != null) {
|
|
331
|
-
providerMetadata[
|
|
356
|
+
providerMetadata[metadataKey].rejectedPredictionTokens =
|
|
332
357
|
completionTokenDetails?.rejected_prediction_tokens;
|
|
333
358
|
}
|
|
334
359
|
|
|
@@ -353,7 +378,9 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
353
378
|
async doStream(
|
|
354
379
|
options: LanguageModelV4CallOptions,
|
|
355
380
|
): Promise<LanguageModelV4StreamResult> {
|
|
356
|
-
const { args, warnings } = await this.getArgs({
|
|
381
|
+
const { args, warnings, metadataKey } = await this.getArgs({
|
|
382
|
+
...options,
|
|
383
|
+
});
|
|
357
384
|
|
|
358
385
|
const body = this.transformRequestBody({
|
|
359
386
|
...args,
|
|
@@ -401,7 +428,7 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV4 {
|
|
|
401
428
|
let usage: z.infer<typeof openaiCompatibleTokenUsageSchema> | undefined =
|
|
402
429
|
undefined;
|
|
403
430
|
let isFirstChunk = true;
|
|
404
|
-
const providerOptionsName =
|
|
431
|
+
const providerOptionsName = metadataKey;
|
|
405
432
|
let isActiveReasoning = false;
|
|
406
433
|
let isActiveText = false;
|
|
407
434
|
|
|
@@ -21,6 +21,10 @@ import {
|
|
|
21
21
|
ResponseHandler,
|
|
22
22
|
} from '@ai-sdk/provider-utils';
|
|
23
23
|
import { z } from 'zod/v4';
|
|
24
|
+
import {
|
|
25
|
+
toCamelCase,
|
|
26
|
+
warnIfDeprecatedProviderOptionsKey,
|
|
27
|
+
} from '../utils/to-camel-case';
|
|
24
28
|
import {
|
|
25
29
|
defaultOpenAICompatibleErrorStructure,
|
|
26
30
|
ProviderErrorStructure,
|
|
@@ -101,13 +105,26 @@ export class OpenAICompatibleCompletionLanguageModel implements LanguageModelV4
|
|
|
101
105
|
}: LanguageModelV4CallOptions) {
|
|
102
106
|
const warnings: SharedV4Warning[] = [];
|
|
103
107
|
|
|
104
|
-
//
|
|
105
|
-
|
|
108
|
+
// Warn when the raw (non-camelCase) provider name is used
|
|
109
|
+
warnIfDeprecatedProviderOptionsKey({
|
|
110
|
+
rawName: this.providerOptionsName,
|
|
111
|
+
providerOptions,
|
|
112
|
+
warnings,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Parse provider options (support both raw and camelCase keys)
|
|
116
|
+
const completionOptions = Object.assign(
|
|
106
117
|
(await parseProviderOptions({
|
|
107
118
|
provider: this.providerOptionsName,
|
|
108
119
|
providerOptions,
|
|
109
120
|
schema: openaiCompatibleLanguageModelCompletionOptions,
|
|
110
|
-
})) ?? {}
|
|
121
|
+
})) ?? {},
|
|
122
|
+
(await parseProviderOptions({
|
|
123
|
+
provider: toCamelCase(this.providerOptionsName),
|
|
124
|
+
providerOptions,
|
|
125
|
+
schema: openaiCompatibleLanguageModelCompletionOptions,
|
|
126
|
+
})) ?? {},
|
|
127
|
+
);
|
|
111
128
|
|
|
112
129
|
if (topK != null) {
|
|
113
130
|
warnings.push({ type: 'unsupported', feature: 'topK' });
|
|
@@ -153,6 +170,7 @@ export class OpenAICompatibleCompletionLanguageModel implements LanguageModelV4
|
|
|
153
170
|
presence_penalty: presencePenalty,
|
|
154
171
|
seed,
|
|
155
172
|
...providerOptions?.[this.providerOptionsName],
|
|
173
|
+
...providerOptions?.[toCamelCase(this.providerOptionsName)],
|
|
156
174
|
|
|
157
175
|
// prompt:
|
|
158
176
|
prompt: completionPrompt,
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
defaultOpenAICompatibleErrorStructure,
|
|
21
21
|
ProviderErrorStructure,
|
|
22
22
|
} from '../openai-compatible-error';
|
|
23
|
+
import { warnIfDeprecatedProviderOptionsKey } from '../utils/to-camel-case';
|
|
23
24
|
|
|
24
25
|
type OpenAICompatibleEmbeddingConfig = {
|
|
25
26
|
/**
|
|
@@ -88,11 +89,19 @@ export class OpenAICompatibleEmbeddingModel implements EmbeddingModelV4 {
|
|
|
88
89
|
|
|
89
90
|
if (deprecatedOptions != null) {
|
|
90
91
|
warnings.push({
|
|
91
|
-
type: '
|
|
92
|
-
|
|
92
|
+
type: 'deprecated',
|
|
93
|
+
setting: "providerOptions key 'openai-compatible'",
|
|
94
|
+
message: "Use 'openaiCompatible' instead.",
|
|
93
95
|
});
|
|
94
96
|
}
|
|
95
97
|
|
|
98
|
+
// Warn when the raw (non-camelCase) provider name is used
|
|
99
|
+
warnIfDeprecatedProviderOptionsKey({
|
|
100
|
+
rawName: this.providerOptionsName,
|
|
101
|
+
providerOptions,
|
|
102
|
+
warnings,
|
|
103
|
+
});
|
|
104
|
+
|
|
96
105
|
const compatibleOptions = Object.assign(
|
|
97
106
|
deprecatedOptions ?? {},
|
|
98
107
|
(await parseProviderOptions({
|
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
SharedV4ProviderOptions,
|
|
5
5
|
SharedV4Warning,
|
|
6
6
|
} from '@ai-sdk/provider';
|
|
7
|
+
import {
|
|
8
|
+
toCamelCase,
|
|
9
|
+
warnIfDeprecatedProviderOptionsKey,
|
|
10
|
+
} from '../utils/to-camel-case';
|
|
7
11
|
import {
|
|
8
12
|
combineHeaders,
|
|
9
13
|
convertBase64ToUint8Array,
|
|
@@ -53,10 +57,15 @@ export class OpenAICompatibleImageModel implements ImageModelV4 {
|
|
|
53
57
|
private readonly config: OpenAICompatibleImageModelConfig,
|
|
54
58
|
) {}
|
|
55
59
|
|
|
56
|
-
// TODO: deprecate non-camelCase keys and remove in future major version
|
|
57
60
|
private getArgs(
|
|
58
61
|
providerOptions: SharedV4ProviderOptions,
|
|
62
|
+
warnings: SharedV4Warning[],
|
|
59
63
|
): Record<string, unknown> {
|
|
64
|
+
warnIfDeprecatedProviderOptionsKey({
|
|
65
|
+
rawName: this.providerOptionsKey,
|
|
66
|
+
providerOptions,
|
|
67
|
+
warnings,
|
|
68
|
+
});
|
|
60
69
|
return {
|
|
61
70
|
...providerOptions[this.providerOptionsKey],
|
|
62
71
|
...providerOptions[toCamelCase(this.providerOptionsKey)],
|
|
@@ -94,7 +103,7 @@ export class OpenAICompatibleImageModel implements ImageModelV4 {
|
|
|
94
103
|
|
|
95
104
|
const currentDate = this.config._internal?.currentDate?.() ?? new Date();
|
|
96
105
|
|
|
97
|
-
const args = this.getArgs(providerOptions);
|
|
106
|
+
const args = this.getArgs(providerOptions, warnings);
|
|
98
107
|
|
|
99
108
|
// Image editing mode - use form data and /images/edits endpoint
|
|
100
109
|
if (files != null && files.length > 0) {
|
|
@@ -199,7 +208,3 @@ async function fileToBlob(file: ImageModelV4File): Promise<Blob> {
|
|
|
199
208
|
|
|
200
209
|
return new Blob([data as BlobPart], { type: file.mediaType });
|
|
201
210
|
}
|
|
202
|
-
|
|
203
|
-
function toCamelCase(str: string): string {
|
|
204
|
-
return str.replace(/[_-]([a-z])/g, g => g[1].toUpperCase());
|
|
205
|
-
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { SharedV4Warning } from '@ai-sdk/provider';
|
|
2
|
+
|
|
3
|
+
export function toCamelCase(str: string): string {
|
|
4
|
+
return str.replace(/[_-]([a-z])/g, g => g[1].toUpperCase());
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
Resolves which key to use for providerMetadata based on what the caller
|
|
9
|
+
passed in providerOptions. Returns the camelCase variant when the caller
|
|
10
|
+
supplied it, otherwise falls back to the raw name.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveProviderOptionsKey(
|
|
13
|
+
rawName: string,
|
|
14
|
+
providerOptions: Record<string, unknown> | undefined,
|
|
15
|
+
): string {
|
|
16
|
+
const camelName = toCamelCase(rawName);
|
|
17
|
+
if (camelName !== rawName && providerOptions?.[camelName] != null) {
|
|
18
|
+
return camelName;
|
|
19
|
+
}
|
|
20
|
+
return rawName;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
Pushes a deprecation warning when the user supplies providerOptions under a non-camelCase key
|
|
25
|
+
*/
|
|
26
|
+
export function warnIfDeprecatedProviderOptionsKey({
|
|
27
|
+
rawName,
|
|
28
|
+
providerOptions,
|
|
29
|
+
warnings,
|
|
30
|
+
}: {
|
|
31
|
+
rawName: string;
|
|
32
|
+
providerOptions: Record<string, unknown> | undefined;
|
|
33
|
+
warnings: SharedV4Warning[];
|
|
34
|
+
}): void {
|
|
35
|
+
const camelName = toCamelCase(rawName);
|
|
36
|
+
if (camelName !== rawName && providerOptions?.[rawName] != null) {
|
|
37
|
+
warnings.push({
|
|
38
|
+
type: 'deprecated',
|
|
39
|
+
setting: `providerOptions key '${rawName}'`,
|
|
40
|
+
message: `Use '${camelName}' instead.`,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|