@ai-sdk/deepseek 3.0.56 → 3.0.57
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 +10 -0
- package/dist/index.d.ts +109 -104
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1173 -1469
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +104 -104
- package/dist/internal/index.d.ts.map +1 -0
- package/dist/internal/index.js +995 -1216
- package/dist/internal/index.js.map +1 -1
- package/package.json +8 -8
- package/src/chat/convert-to-deepseek-usage.ts +10 -1
package/dist/index.js
CHANGED
|
@@ -1,1512 +1,1216 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
NoSuchModelError
|
|
4
|
-
} from "@ai-sdk/provider";
|
|
5
|
-
import {
|
|
6
|
-
loadApiKey,
|
|
7
|
-
withoutTrailingSlash,
|
|
8
|
-
withUserAgentSuffix
|
|
9
|
-
} from "@ai-sdk/provider-utils";
|
|
10
|
-
|
|
11
|
-
// src/chat/deepseek-chat-language-model.ts
|
|
12
|
-
import {
|
|
13
|
-
InvalidResponseDataError
|
|
14
|
-
} from "@ai-sdk/provider";
|
|
15
|
-
import {
|
|
16
|
-
combineHeaders,
|
|
17
|
-
createEventSourceResponseHandler,
|
|
18
|
-
createJsonErrorResponseHandler,
|
|
19
|
-
createJsonResponseHandler,
|
|
20
|
-
createProviderStreamError,
|
|
21
|
-
generateId,
|
|
22
|
-
isCustomReasoning,
|
|
23
|
-
mapReasoningToProviderEffort,
|
|
24
|
-
parseProviderOptions as parseProviderOptions2,
|
|
25
|
-
postJsonToApi,
|
|
26
|
-
serializeModelOptions,
|
|
27
|
-
StreamingToolCallTracker,
|
|
28
|
-
WORKFLOW_SERIALIZE,
|
|
29
|
-
WORKFLOW_DESERIALIZE
|
|
30
|
-
} from "@ai-sdk/provider-utils";
|
|
31
|
-
|
|
32
|
-
// src/chat/convert-to-deepseek-chat-messages.ts
|
|
33
|
-
import {
|
|
34
|
-
InvalidPromptError,
|
|
35
|
-
UnsupportedFunctionalityError
|
|
36
|
-
} from "@ai-sdk/provider";
|
|
37
|
-
import {
|
|
38
|
-
convertToBase64,
|
|
39
|
-
getTopLevelMediaType,
|
|
40
|
-
parseProviderOptions,
|
|
41
|
-
resolveFullMediaType,
|
|
42
|
-
resolveProviderReference
|
|
43
|
-
} from "@ai-sdk/provider-utils";
|
|
44
|
-
|
|
45
|
-
// src/chat/deepseek-file-part-options.ts
|
|
1
|
+
import { InvalidArgumentError, InvalidPromptError, InvalidResponseDataError, NoSuchModelError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
|
|
2
|
+
import { StreamingToolCallTracker, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, convertInlineFileDataToUint8Array, convertToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonResponseHandler, createLanguageModelResponseMetadata as getResponseMetadata, createNullLanguageModelUsage, createProviderStreamError, detectMediaType, generateId, getTopLevelMediaType, isCustomReasoning, lazySchema, loadApiKey, mapReasoningToProviderEffort, parseProviderOptions, postFormDataToApi, postJsonToApi, resolveFullMediaType, resolveProviderReference, serializeModelOptions, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
|
|
46
3
|
import { z } from "zod/v4";
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
* Whether to return log probabilities for generated tokens.
|
|
70
|
-
*/
|
|
71
|
-
logprobs: z2.boolean().optional(),
|
|
72
|
-
/**
|
|
73
|
-
* Number of most likely tokens to return at each token position.
|
|
74
|
-
*
|
|
75
|
-
* Setting this option automatically enables `logprobs`.
|
|
76
|
-
*/
|
|
77
|
-
topLogprobs: z2.number().int().min(0).max(20).optional(),
|
|
78
|
-
/**
|
|
79
|
-
* An opaque identifier for the end user. DeepSeek uses this identifier for
|
|
80
|
-
* content-safety tracing and request isolation.
|
|
81
|
-
*
|
|
82
|
-
* Must contain only ASCII letters, numbers, underscores, and hyphens, and
|
|
83
|
-
* must be at most 512 characters long.
|
|
84
|
-
*/
|
|
85
|
-
userId: z2.string().regex(/^[a-zA-Z0-9_-]+$/, "userId must match /^[a-zA-Z0-9_-]+$/").max(512, "userId must be at most 512 characters long").optional(),
|
|
86
|
-
/**
|
|
87
|
-
* Type of thinking to use. Defaults to `enabled`.
|
|
88
|
-
*/
|
|
89
|
-
thinking: z2.object({
|
|
90
|
-
// `adaptive` is accepted at runtime for backwards compatibility and
|
|
91
|
-
// mapped to `enabled`, but is intentionally excluded from the exported
|
|
92
|
-
// provider options type.
|
|
93
|
-
type: z2.enum(["adaptive", "enabled", "disabled"]).optional()
|
|
94
|
-
}).optional(),
|
|
95
|
-
/**
|
|
96
|
-
* Controls the thinking strength for DeepSeek V4 reasoning models.
|
|
97
|
-
*/
|
|
98
|
-
// `medium` and `xhigh` are accepted at runtime for backwards compatibility
|
|
99
|
-
// and mapped to canonical DeepSeek values, but are intentionally excluded
|
|
100
|
-
// from the exported provider options type.
|
|
101
|
-
reasoningEffort: z2.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
|
|
102
|
-
/**
|
|
103
|
-
* Whether to use strict JSON schema validation for structured outputs.
|
|
104
|
-
* Only applies when the serving endpoint supports JSON schema response
|
|
105
|
-
* formats (e.g. Azure). Defaults to `true`.
|
|
106
|
-
*/
|
|
107
|
-
strictJsonSchema: z2.boolean().optional()
|
|
108
|
-
});
|
|
109
|
-
var deepseekMessageProviderOptions = z2.object({
|
|
110
|
-
/**
|
|
111
|
-
* The name of the participant represented by the message.
|
|
112
|
-
*
|
|
113
|
-
* Supported on system, user, and assistant messages.
|
|
114
|
-
*/
|
|
115
|
-
name: z2.string().optional()
|
|
4
|
+
//#region src/chat/deepseek-file-part-options.ts
|
|
5
|
+
const deepseekFilePartProviderOptions = z.object({
|
|
6
|
+
/**
|
|
7
|
+
* Controls how DeepSeek processes an image sent as an `image_url` part.
|
|
8
|
+
*
|
|
9
|
+
* @see https://api-docs.deepseek.com/api/create-chat-completion/
|
|
10
|
+
*/
|
|
11
|
+
imageDetail: z.enum([
|
|
12
|
+
"low",
|
|
13
|
+
"high",
|
|
14
|
+
"original",
|
|
15
|
+
"auto"
|
|
16
|
+
]).optional(),
|
|
17
|
+
/**
|
|
18
|
+
* Sends inline image data as a DeepSeek `file` part using `file_data`
|
|
19
|
+
* instead of an `image_url` data URL. When set, the file part's filename
|
|
20
|
+
* is preserved.
|
|
21
|
+
*
|
|
22
|
+
* This option only applies to inline image data. It cannot be combined
|
|
23
|
+
* with `imageDetail`.
|
|
24
|
+
*/
|
|
25
|
+
fileData: z.literal(true).optional()
|
|
116
26
|
});
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/chat/deepseek-chat-language-model-options.ts
|
|
29
|
+
const deepseekLanguageModelChatOptions = z.object({
|
|
30
|
+
/**
|
|
31
|
+
* Whether to return log probabilities for generated tokens.
|
|
32
|
+
*/
|
|
33
|
+
logprobs: z.boolean().optional(),
|
|
34
|
+
/**
|
|
35
|
+
* Number of most likely tokens to return at each token position.
|
|
36
|
+
*
|
|
37
|
+
* Setting this option automatically enables `logprobs`.
|
|
38
|
+
*/
|
|
39
|
+
topLogprobs: z.number().int().min(0).max(20).optional(),
|
|
40
|
+
/**
|
|
41
|
+
* An opaque identifier for the end user. DeepSeek uses this identifier for
|
|
42
|
+
* content-safety tracing and request isolation.
|
|
43
|
+
*
|
|
44
|
+
* Must contain only ASCII letters, numbers, underscores, and hyphens, and
|
|
45
|
+
* must be at most 512 characters long.
|
|
46
|
+
*/
|
|
47
|
+
userId: z.string().regex(/^[a-zA-Z0-9_-]+$/, "userId must match /^[a-zA-Z0-9_-]+$/").max(512, "userId must be at most 512 characters long").optional(),
|
|
48
|
+
/**
|
|
49
|
+
* Type of thinking to use. Defaults to `enabled`.
|
|
50
|
+
*/
|
|
51
|
+
thinking: z.object({ type: z.enum([
|
|
52
|
+
"adaptive",
|
|
53
|
+
"enabled",
|
|
54
|
+
"disabled"
|
|
55
|
+
]).optional() }).optional(),
|
|
56
|
+
/**
|
|
57
|
+
* Controls the thinking strength for DeepSeek V4 reasoning models.
|
|
58
|
+
*/
|
|
59
|
+
reasoningEffort: z.enum([
|
|
60
|
+
"low",
|
|
61
|
+
"medium",
|
|
62
|
+
"high",
|
|
63
|
+
"xhigh",
|
|
64
|
+
"max"
|
|
65
|
+
]).optional(),
|
|
66
|
+
/**
|
|
67
|
+
* Whether to use strict JSON schema validation for structured outputs.
|
|
68
|
+
* Only applies when the serving endpoint supports JSON schema response
|
|
69
|
+
* formats (e.g. Azure). Defaults to `true`.
|
|
70
|
+
*/
|
|
71
|
+
strictJsonSchema: z.boolean().optional()
|
|
124
72
|
});
|
|
125
|
-
|
|
126
|
-
|
|
73
|
+
const deepseekAssistantMessageProviderOptions = z.object({
|
|
74
|
+
/**
|
|
75
|
+
* The name of the participant represented by the message.
|
|
76
|
+
*
|
|
77
|
+
* Supported on system, user, and assistant messages.
|
|
78
|
+
*/
|
|
79
|
+
name: z.string().optional() }).extend({
|
|
80
|
+
/**
|
|
81
|
+
* Whether the assistant message content is a prefix that DeepSeek should
|
|
82
|
+
* continue. This beta feature is only supported on the final assistant
|
|
83
|
+
* message when using a beta base URL.
|
|
84
|
+
*/
|
|
85
|
+
prefix: z.literal(true).optional() });
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/chat/is-deepseek-v4-model.ts
|
|
88
|
+
/**
|
|
89
|
+
* Whether a model id is a DeepSeek V4-generation model (thinking mode on by
|
|
90
|
+
* default, `reasoning_content` required on every assistant turn).
|
|
91
|
+
*
|
|
92
|
+
* DeepSeek publishes V4 models under both versioned ids (`deepseek-v4-pro`,
|
|
93
|
+
* `deepseek-v4-flash-*`) and unversioned aliases (`deepseek-flash`, currently
|
|
94
|
+
* serving V4.1 Flash). Only the legacy `deepseek-chat` / `deepseek-reasoner`
|
|
95
|
+
* ids predate V4.
|
|
96
|
+
*/
|
|
127
97
|
function isDeepSeekV4Model(modelId) {
|
|
128
|
-
|
|
98
|
+
return modelId.includes("deepseek-v4") || modelId.startsWith("deepseek-flash") || modelId.startsWith("deepseek-pro");
|
|
129
99
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/chat/convert-to-deepseek-chat-messages.ts
|
|
102
|
+
const supportedImageMediaTypes = /* @__PURE__ */ new Set([
|
|
103
|
+
"image/gif",
|
|
104
|
+
"image/jpeg",
|
|
105
|
+
"image/jpg",
|
|
106
|
+
"image/png",
|
|
107
|
+
"image/webp"
|
|
138
108
|
]);
|
|
139
109
|
function resolveDeepSeekImageMediaType(part) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
return resolvedMediaType;
|
|
110
|
+
const resolvedMediaType = resolveFullMediaType({ part });
|
|
111
|
+
if (!supportedImageMediaTypes.has(resolvedMediaType)) throw new UnsupportedFunctionalityError({
|
|
112
|
+
functionality: `DeepSeek image media type ${resolvedMediaType}`,
|
|
113
|
+
message: "DeepSeek supports JPEG, PNG, GIF, and WebP image inputs."
|
|
114
|
+
});
|
|
115
|
+
return resolvedMediaType;
|
|
148
116
|
}
|
|
149
|
-
function validateDeepSeekImageUrl({
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
throw new InvalidPromptError({
|
|
155
|
-
prompt,
|
|
156
|
-
message: "DeepSeek image URLs must not exceed 8192 characters."
|
|
157
|
-
});
|
|
158
|
-
}
|
|
117
|
+
function validateDeepSeekImageUrl({ url, prompt }) {
|
|
118
|
+
if (url.length > 8192) throw new InvalidPromptError({
|
|
119
|
+
prompt,
|
|
120
|
+
message: "DeepSeek image URLs must not exceed 8192 characters."
|
|
121
|
+
});
|
|
159
122
|
}
|
|
160
|
-
async function convertToDeepSeekChatMessages({
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const hasImagePart = output.value.some(
|
|
421
|
-
(part) => part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image"
|
|
422
|
-
);
|
|
423
|
-
if (!hasImagePart) {
|
|
424
|
-
contentValue = JSON.stringify(output.value);
|
|
425
|
-
break;
|
|
426
|
-
}
|
|
427
|
-
contentValue = [];
|
|
428
|
-
for (const part of output.value) {
|
|
429
|
-
if (part.type === "text") {
|
|
430
|
-
contentValue.push({ type: "text", text: part.text });
|
|
431
|
-
} else if (part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image") {
|
|
432
|
-
if (part.data.type === "reference") {
|
|
433
|
-
contentValue.push({
|
|
434
|
-
type: "file",
|
|
435
|
-
file_id: resolveProviderReference({
|
|
436
|
-
reference: part.data.reference,
|
|
437
|
-
provider: "deepseek"
|
|
438
|
-
})
|
|
439
|
-
});
|
|
440
|
-
continue;
|
|
441
|
-
}
|
|
442
|
-
const filePartOptions = await parseProviderOptions({
|
|
443
|
-
provider: providerOptionsName,
|
|
444
|
-
providerOptions: part.providerOptions,
|
|
445
|
-
schema: deepseekFilePartProviderOptions
|
|
446
|
-
});
|
|
447
|
-
const resolvedMediaType = resolveDeepSeekImageMediaType(part);
|
|
448
|
-
let url;
|
|
449
|
-
if (part.data.type === "url") {
|
|
450
|
-
url = part.data.url.toString();
|
|
451
|
-
validateDeepSeekImageUrl({ url, prompt });
|
|
452
|
-
} else {
|
|
453
|
-
url = `data:${resolvedMediaType === "image/jpg" ? "image/jpeg" : resolvedMediaType};base64,${convertToBase64(part.data.data)}`;
|
|
454
|
-
}
|
|
455
|
-
contentValue.push({
|
|
456
|
-
type: "image_url",
|
|
457
|
-
image_url: {
|
|
458
|
-
url,
|
|
459
|
-
...filePartOptions?.imageDetail != null && {
|
|
460
|
-
detail: filePartOptions.imageDetail
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
|
-
} else {
|
|
465
|
-
warnings.push({
|
|
466
|
-
type: "unsupported",
|
|
467
|
-
feature: `tool result content part type: ${part.type}`
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
break;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
messages.push({
|
|
475
|
-
role: "tool",
|
|
476
|
-
tool_call_id: toolResponse.toolCallId,
|
|
477
|
-
content: contentValue
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
break;
|
|
481
|
-
}
|
|
482
|
-
default: {
|
|
483
|
-
warnings.push({
|
|
484
|
-
type: "unsupported",
|
|
485
|
-
feature: `message role: ${role}`
|
|
486
|
-
});
|
|
487
|
-
break;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
return { messages, warnings };
|
|
123
|
+
async function convertToDeepSeekChatMessages({ prompt, responseFormat, modelId, providerOptionsName = "deepseek", supportsAssistantPrefixCompletion = false, supportsStructuredOutputs = false }) {
|
|
124
|
+
const isDeepSeekV4 = isDeepSeekV4Model(modelId);
|
|
125
|
+
const messages = [];
|
|
126
|
+
const warnings = [];
|
|
127
|
+
if (responseFormat?.type === "json") {
|
|
128
|
+
if (responseFormat.schema == null) messages.push({
|
|
129
|
+
role: "system",
|
|
130
|
+
content: "Return JSON."
|
|
131
|
+
});
|
|
132
|
+
else if (!supportsStructuredOutputs) {
|
|
133
|
+
messages.push({
|
|
134
|
+
role: "system",
|
|
135
|
+
content: "Return JSON that conforms to the following schema: " + JSON.stringify(responseFormat.schema)
|
|
136
|
+
});
|
|
137
|
+
warnings.push({
|
|
138
|
+
type: "compatibility",
|
|
139
|
+
feature: "responseFormat JSON schema",
|
|
140
|
+
details: "JSON response schema is injected into the system message."
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
let lastUserMessageIndex = -1;
|
|
145
|
+
for (let i = prompt.length - 1; i >= 0; i--) if (prompt[i].role === "user") {
|
|
146
|
+
lastUserMessageIndex = i;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
let index = -1;
|
|
150
|
+
for (const { role, content, providerOptions } of prompt) {
|
|
151
|
+
index++;
|
|
152
|
+
const deepseekMessageOptions = await parseProviderOptions({
|
|
153
|
+
provider: providerOptionsName,
|
|
154
|
+
providerOptions,
|
|
155
|
+
schema: deepseekAssistantMessageProviderOptions
|
|
156
|
+
});
|
|
157
|
+
if (deepseekMessageOptions?.prefix === true && role !== "assistant") throw new InvalidPromptError({
|
|
158
|
+
prompt,
|
|
159
|
+
message: "DeepSeek assistant prefix completion requires `prefix: true` on an assistant message."
|
|
160
|
+
});
|
|
161
|
+
switch (role) {
|
|
162
|
+
case "system":
|
|
163
|
+
messages.push({
|
|
164
|
+
role: "system",
|
|
165
|
+
content,
|
|
166
|
+
...deepseekMessageOptions?.name != null && { name: deepseekMessageOptions.name }
|
|
167
|
+
});
|
|
168
|
+
break;
|
|
169
|
+
case "user": {
|
|
170
|
+
if (!content.some((part) => part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image")) {
|
|
171
|
+
let userContent = "";
|
|
172
|
+
for (const part of content) if (part.type === "text") userContent += part.text;
|
|
173
|
+
else warnings.push({
|
|
174
|
+
type: "unsupported",
|
|
175
|
+
feature: `user message part type: ${part.type}`
|
|
176
|
+
});
|
|
177
|
+
messages.push({
|
|
178
|
+
role: "user",
|
|
179
|
+
content: userContent,
|
|
180
|
+
...deepseekMessageOptions?.name != null && { name: deepseekMessageOptions.name }
|
|
181
|
+
});
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
const userContent = [];
|
|
185
|
+
for (const part of content) if (part.type === "text") userContent.push({
|
|
186
|
+
type: "text",
|
|
187
|
+
text: part.text
|
|
188
|
+
});
|
|
189
|
+
else if (part.type === "file" && getTopLevelMediaType(part.mediaType) === "image") {
|
|
190
|
+
const filePartOptions = await parseProviderOptions({
|
|
191
|
+
provider: providerOptionsName,
|
|
192
|
+
providerOptions: part.providerOptions,
|
|
193
|
+
schema: deepseekFilePartProviderOptions
|
|
194
|
+
});
|
|
195
|
+
if (part.data.type === "reference") userContent.push({
|
|
196
|
+
type: "file",
|
|
197
|
+
file_id: resolveProviderReference({
|
|
198
|
+
reference: part.data.reference,
|
|
199
|
+
provider: "deepseek"
|
|
200
|
+
})
|
|
201
|
+
});
|
|
202
|
+
else if (part.data.type === "url" || part.data.type === "data") {
|
|
203
|
+
const resolvedMediaType = resolveDeepSeekImageMediaType(part);
|
|
204
|
+
if (part.data.type === "url") {
|
|
205
|
+
const url = part.data.url.toString();
|
|
206
|
+
validateDeepSeekImageUrl({
|
|
207
|
+
url,
|
|
208
|
+
prompt
|
|
209
|
+
});
|
|
210
|
+
if (filePartOptions?.fileData === true) throw new InvalidPromptError({
|
|
211
|
+
prompt,
|
|
212
|
+
message: "DeepSeek `fileData` image parts require inline data, not a URL."
|
|
213
|
+
});
|
|
214
|
+
userContent.push({
|
|
215
|
+
type: "image_url",
|
|
216
|
+
image_url: {
|
|
217
|
+
url,
|
|
218
|
+
...filePartOptions?.imageDetail != null && { detail: filePartOptions.imageDetail }
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
} else {
|
|
222
|
+
const dataUrl = `data:${resolvedMediaType === "image/jpg" ? "image/jpeg" : resolvedMediaType};base64,${convertToBase64(part.data.data)}`;
|
|
223
|
+
if (filePartOptions?.fileData === true) {
|
|
224
|
+
if (filePartOptions.imageDetail != null) throw new InvalidPromptError({
|
|
225
|
+
prompt,
|
|
226
|
+
message: "DeepSeek `imageDetail` cannot be combined with `fileData`."
|
|
227
|
+
});
|
|
228
|
+
userContent.push({
|
|
229
|
+
type: "file",
|
|
230
|
+
file_data: dataUrl,
|
|
231
|
+
...part.filename != null && { filename: part.filename }
|
|
232
|
+
});
|
|
233
|
+
} else userContent.push({
|
|
234
|
+
type: "image_url",
|
|
235
|
+
image_url: {
|
|
236
|
+
url: dataUrl,
|
|
237
|
+
...filePartOptions?.imageDetail != null && { detail: filePartOptions.imageDetail }
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
} else warnings.push({
|
|
242
|
+
type: "unsupported",
|
|
243
|
+
feature: `user message part type: ${part.type}`
|
|
244
|
+
});
|
|
245
|
+
} else warnings.push({
|
|
246
|
+
type: "unsupported",
|
|
247
|
+
feature: `user message part type: ${part.type}`
|
|
248
|
+
});
|
|
249
|
+
messages.push({
|
|
250
|
+
role: "user",
|
|
251
|
+
content: userContent,
|
|
252
|
+
...deepseekMessageOptions?.name != null && { name: deepseekMessageOptions.name }
|
|
253
|
+
});
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
case "assistant": {
|
|
257
|
+
if (deepseekMessageOptions?.prefix === true) {
|
|
258
|
+
if (index !== prompt.length - 1) throw new InvalidPromptError({
|
|
259
|
+
prompt,
|
|
260
|
+
message: "DeepSeek assistant prefix completion requires the prefixed assistant message to be the final message."
|
|
261
|
+
});
|
|
262
|
+
if (!supportsAssistantPrefixCompletion) throw new UnsupportedFunctionalityError({
|
|
263
|
+
functionality: "DeepSeek assistant prefix completion",
|
|
264
|
+
message: "DeepSeek assistant prefix completion requires a beta base URL ending in `/beta`."
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
let text = "";
|
|
268
|
+
let reasoning;
|
|
269
|
+
const toolCalls = [];
|
|
270
|
+
for (const part of content) switch (part.type) {
|
|
271
|
+
case "text":
|
|
272
|
+
text += part.text;
|
|
273
|
+
break;
|
|
274
|
+
case "reasoning":
|
|
275
|
+
if (index <= lastUserMessageIndex && !isDeepSeekV4) break;
|
|
276
|
+
if (reasoning == null) reasoning = part.text;
|
|
277
|
+
else reasoning += part.text;
|
|
278
|
+
break;
|
|
279
|
+
case "tool-call": toolCalls.push({
|
|
280
|
+
id: part.toolCallId,
|
|
281
|
+
type: "function",
|
|
282
|
+
function: {
|
|
283
|
+
name: part.toolName,
|
|
284
|
+
arguments: JSON.stringify(part.input)
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
messages.push({
|
|
289
|
+
role: "assistant",
|
|
290
|
+
content: text,
|
|
291
|
+
...deepseekMessageOptions?.name != null && { name: deepseekMessageOptions.name },
|
|
292
|
+
...deepseekMessageOptions?.prefix === true && { prefix: true },
|
|
293
|
+
reasoning_content: reasoning ?? (isDeepSeekV4 ? "" : void 0),
|
|
294
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
|
|
295
|
+
});
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
case "tool":
|
|
299
|
+
if (deepseekMessageOptions?.name != null) warnings.push({
|
|
300
|
+
type: "unsupported",
|
|
301
|
+
feature: "message name on tool messages"
|
|
302
|
+
});
|
|
303
|
+
for (const toolResponse of content) {
|
|
304
|
+
if (toolResponse.type === "tool-approval-response") continue;
|
|
305
|
+
const output = toolResponse.output;
|
|
306
|
+
let contentValue;
|
|
307
|
+
switch (output.type) {
|
|
308
|
+
case "text":
|
|
309
|
+
case "error-text":
|
|
310
|
+
contentValue = output.value;
|
|
311
|
+
break;
|
|
312
|
+
case "execution-denied":
|
|
313
|
+
contentValue = output.reason ?? "Tool call execution denied.";
|
|
314
|
+
break;
|
|
315
|
+
case "json":
|
|
316
|
+
case "error-json":
|
|
317
|
+
contentValue = JSON.stringify(output.value);
|
|
318
|
+
break;
|
|
319
|
+
case "content":
|
|
320
|
+
if (!output.value.some((part) => part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image")) {
|
|
321
|
+
contentValue = JSON.stringify(output.value);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
contentValue = [];
|
|
325
|
+
for (const part of output.value) if (part.type === "text") contentValue.push({
|
|
326
|
+
type: "text",
|
|
327
|
+
text: part.text
|
|
328
|
+
});
|
|
329
|
+
else if (part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image") {
|
|
330
|
+
if (part.data.type === "reference") {
|
|
331
|
+
contentValue.push({
|
|
332
|
+
type: "file",
|
|
333
|
+
file_id: resolveProviderReference({
|
|
334
|
+
reference: part.data.reference,
|
|
335
|
+
provider: "deepseek"
|
|
336
|
+
})
|
|
337
|
+
});
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
const filePartOptions = await parseProviderOptions({
|
|
341
|
+
provider: providerOptionsName,
|
|
342
|
+
providerOptions: part.providerOptions,
|
|
343
|
+
schema: deepseekFilePartProviderOptions
|
|
344
|
+
});
|
|
345
|
+
const resolvedMediaType = resolveDeepSeekImageMediaType(part);
|
|
346
|
+
let url;
|
|
347
|
+
if (part.data.type === "url") {
|
|
348
|
+
url = part.data.url.toString();
|
|
349
|
+
validateDeepSeekImageUrl({
|
|
350
|
+
url,
|
|
351
|
+
prompt
|
|
352
|
+
});
|
|
353
|
+
} else url = `data:${resolvedMediaType === "image/jpg" ? "image/jpeg" : resolvedMediaType};base64,${convertToBase64(part.data.data)}`;
|
|
354
|
+
contentValue.push({
|
|
355
|
+
type: "image_url",
|
|
356
|
+
image_url: {
|
|
357
|
+
url,
|
|
358
|
+
...filePartOptions?.imageDetail != null && { detail: filePartOptions.imageDetail }
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
} else warnings.push({
|
|
362
|
+
type: "unsupported",
|
|
363
|
+
feature: `tool result content part type: ${part.type}`
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
messages.push({
|
|
367
|
+
role: "tool",
|
|
368
|
+
tool_call_id: toolResponse.toolCallId,
|
|
369
|
+
content: contentValue
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
break;
|
|
373
|
+
default: warnings.push({
|
|
374
|
+
type: "unsupported",
|
|
375
|
+
feature: `message role: ${role}`
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
messages,
|
|
381
|
+
warnings
|
|
382
|
+
};
|
|
492
383
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
import { createNullLanguageModelUsage } from "@ai-sdk/provider-utils";
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/chat/convert-to-deepseek-usage.ts
|
|
496
386
|
function convertDeepSeekUsage(usage) {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
raw: usage
|
|
517
|
-
};
|
|
387
|
+
if (usage == null) return createNullLanguageModelUsage();
|
|
388
|
+
const promptTokens = usage.prompt_tokens ?? 0;
|
|
389
|
+
const completionTokens = usage.completion_tokens ?? 0;
|
|
390
|
+
const cacheReadTokens = usage.prompt_cache_hit_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
391
|
+
const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? 0;
|
|
392
|
+
return {
|
|
393
|
+
inputTokens: {
|
|
394
|
+
total: promptTokens,
|
|
395
|
+
noCache: promptTokens - cacheReadTokens,
|
|
396
|
+
cacheRead: cacheReadTokens,
|
|
397
|
+
cacheWrite: void 0
|
|
398
|
+
},
|
|
399
|
+
outputTokens: {
|
|
400
|
+
total: completionTokens,
|
|
401
|
+
text: Math.max(0, completionTokens - reasoningTokens),
|
|
402
|
+
reasoning: reasoningTokens
|
|
403
|
+
},
|
|
404
|
+
raw: usage
|
|
405
|
+
};
|
|
518
406
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
prompt_tokens_details: z3.looseObject({
|
|
530
|
-
cached_tokens: z3.number().nullish()
|
|
531
|
-
}).nullish(),
|
|
532
|
-
completion_tokens_details: z3.looseObject({
|
|
533
|
-
reasoning_tokens: z3.number().nullish()
|
|
534
|
-
}).nullish()
|
|
407
|
+
//#endregion
|
|
408
|
+
//#region src/chat/deepseek-chat-api-types.ts
|
|
409
|
+
const tokenUsageSchema = z.looseObject({
|
|
410
|
+
prompt_tokens: z.number().nullish(),
|
|
411
|
+
completion_tokens: z.number().nullish(),
|
|
412
|
+
prompt_cache_hit_tokens: z.number().nullish(),
|
|
413
|
+
prompt_cache_miss_tokens: z.number().nullish(),
|
|
414
|
+
total_tokens: z.number().nullish(),
|
|
415
|
+
prompt_tokens_details: z.looseObject({ cached_tokens: z.number().nullish() }).nullish(),
|
|
416
|
+
completion_tokens_details: z.looseObject({ reasoning_tokens: z.number().nullish() }).nullish()
|
|
535
417
|
}).nullish();
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
logprob: z3.number(),
|
|
552
|
-
bytes: z3.array(z3.number()).nullable()
|
|
553
|
-
})
|
|
554
|
-
)
|
|
418
|
+
const deepSeekErrorSchema = z.object({ error: z.object({
|
|
419
|
+
message: z.string(),
|
|
420
|
+
type: z.string().nullish(),
|
|
421
|
+
param: z.any().nullish(),
|
|
422
|
+
code: z.union([z.string(), z.number()]).nullish()
|
|
423
|
+
}) });
|
|
424
|
+
const deepseekChatLogprobSchema = z.object({
|
|
425
|
+
token: z.string(),
|
|
426
|
+
logprob: z.number(),
|
|
427
|
+
bytes: z.array(z.number()).nullable(),
|
|
428
|
+
top_logprobs: z.array(z.object({
|
|
429
|
+
token: z.string(),
|
|
430
|
+
logprob: z.number(),
|
|
431
|
+
bytes: z.array(z.number()).nullable()
|
|
432
|
+
}))
|
|
555
433
|
});
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
434
|
+
const deepseekChatLogprobsSchema = z.object({
|
|
435
|
+
content: z.array(deepseekChatLogprobSchema).nullish(),
|
|
436
|
+
reasoning_content: z.array(deepseekChatLogprobSchema).nullish()
|
|
559
437
|
}).nullish();
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
finish_reason: z3.string().nullish()
|
|
586
|
-
})
|
|
587
|
-
),
|
|
588
|
-
usage: tokenUsageSchema
|
|
438
|
+
const deepseekChatResponseSchema = z.object({
|
|
439
|
+
id: z.string().nullish(),
|
|
440
|
+
created: z.number().nullish(),
|
|
441
|
+
model: z.string().nullish(),
|
|
442
|
+
object: z.literal("chat.completion").nullish(),
|
|
443
|
+
system_fingerprint: z.string().nullish(),
|
|
444
|
+
choices: z.array(z.object({
|
|
445
|
+
index: z.number().nullish(),
|
|
446
|
+
message: z.object({
|
|
447
|
+
role: z.literal("assistant").nullish(),
|
|
448
|
+
content: z.string().nullish(),
|
|
449
|
+
reasoning_content: z.string().nullish(),
|
|
450
|
+
tool_calls: z.array(z.object({
|
|
451
|
+
id: z.string().nullish(),
|
|
452
|
+
type: z.literal("function").nullish(),
|
|
453
|
+
function: z.object({
|
|
454
|
+
name: z.string(),
|
|
455
|
+
arguments: z.string()
|
|
456
|
+
})
|
|
457
|
+
})).nullish()
|
|
458
|
+
}),
|
|
459
|
+
logprobs: deepseekChatLogprobsSchema,
|
|
460
|
+
finish_reason: z.string().nullish()
|
|
461
|
+
})),
|
|
462
|
+
usage: tokenUsageSchema
|
|
589
463
|
});
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
);
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
case "none":
|
|
683
|
-
case "required":
|
|
684
|
-
return { tools: deepseekTools, toolChoice: type, toolWarnings };
|
|
685
|
-
case "tool":
|
|
686
|
-
return {
|
|
687
|
-
tools: deepseekTools,
|
|
688
|
-
toolChoice: {
|
|
689
|
-
type: "function",
|
|
690
|
-
function: { name: toolChoice.toolName }
|
|
691
|
-
},
|
|
692
|
-
toolWarnings
|
|
693
|
-
};
|
|
694
|
-
default: {
|
|
695
|
-
return {
|
|
696
|
-
tools: deepseekTools,
|
|
697
|
-
toolChoice: void 0,
|
|
698
|
-
toolWarnings: [
|
|
699
|
-
...toolWarnings,
|
|
700
|
-
{
|
|
701
|
-
type: "unsupported",
|
|
702
|
-
feature: `tool choice type: ${type}`
|
|
703
|
-
}
|
|
704
|
-
]
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
|
-
}
|
|
464
|
+
const deepseekChatChunkSchema = lazySchema(() => zodSchema(z.union([z.object({
|
|
465
|
+
id: z.string().nullish(),
|
|
466
|
+
created: z.number().nullish(),
|
|
467
|
+
model: z.string().nullish(),
|
|
468
|
+
object: z.literal("chat.completion.chunk").nullish(),
|
|
469
|
+
system_fingerprint: z.string().nullish(),
|
|
470
|
+
choices: z.array(z.object({
|
|
471
|
+
index: z.number().nullish(),
|
|
472
|
+
delta: z.object({
|
|
473
|
+
role: z.enum(["assistant"]).nullish(),
|
|
474
|
+
content: z.string().nullish(),
|
|
475
|
+
reasoning_content: z.string().nullish(),
|
|
476
|
+
tool_calls: z.array(z.object({
|
|
477
|
+
index: z.number(),
|
|
478
|
+
id: z.string().nullish(),
|
|
479
|
+
type: z.literal("function").nullish(),
|
|
480
|
+
function: z.object({
|
|
481
|
+
name: z.string().nullish(),
|
|
482
|
+
arguments: z.string().nullish()
|
|
483
|
+
})
|
|
484
|
+
})).nullish()
|
|
485
|
+
}).nullish(),
|
|
486
|
+
logprobs: deepseekChatLogprobsSchema,
|
|
487
|
+
finish_reason: z.string().nullish()
|
|
488
|
+
})),
|
|
489
|
+
usage: tokenUsageSchema
|
|
490
|
+
}), deepSeekErrorSchema])));
|
|
491
|
+
//#endregion
|
|
492
|
+
//#region src/chat/deepseek-prepare-tools.ts
|
|
493
|
+
function prepareTools({ tools, toolChoice, supportsStrictToolCalls }) {
|
|
494
|
+
tools = tools?.length ? tools : void 0;
|
|
495
|
+
const toolWarnings = [];
|
|
496
|
+
if (tools == null) return {
|
|
497
|
+
tools: void 0,
|
|
498
|
+
toolChoice: void 0,
|
|
499
|
+
toolWarnings
|
|
500
|
+
};
|
|
501
|
+
const functionTools = tools.filter((tool) => tool.type === "function");
|
|
502
|
+
const hasStrictTool = functionTools.some((tool) => tool.strict === true);
|
|
503
|
+
if (hasStrictTool && supportsStrictToolCalls === false) throw new UnsupportedFunctionalityError({
|
|
504
|
+
functionality: "DeepSeek strict tool calls",
|
|
505
|
+
message: "DeepSeek strict tool calls require a beta base URL ending in `/beta`."
|
|
506
|
+
});
|
|
507
|
+
if (hasStrictTool && supportsStrictToolCalls === true && functionTools.some((tool) => tool.strict !== true)) throw new UnsupportedFunctionalityError({
|
|
508
|
+
functionality: "mixed DeepSeek strict and non-strict tool calls",
|
|
509
|
+
message: "DeepSeek strict mode requires every function tool in the request to set `strict: true`."
|
|
510
|
+
});
|
|
511
|
+
const deepseekTools = [];
|
|
512
|
+
for (const tool of tools) if (tool.type === "provider") toolWarnings.push({
|
|
513
|
+
type: "unsupported",
|
|
514
|
+
feature: `provider-defined tool ${tool.id}`
|
|
515
|
+
});
|
|
516
|
+
else deepseekTools.push({
|
|
517
|
+
type: "function",
|
|
518
|
+
function: {
|
|
519
|
+
name: tool.name,
|
|
520
|
+
description: tool.description,
|
|
521
|
+
parameters: tool.inputSchema,
|
|
522
|
+
...tool.strict != null ? { strict: tool.strict } : {}
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
if (toolChoice == null) return {
|
|
526
|
+
tools: deepseekTools,
|
|
527
|
+
toolChoice: void 0,
|
|
528
|
+
toolWarnings
|
|
529
|
+
};
|
|
530
|
+
const type = toolChoice?.type;
|
|
531
|
+
switch (type) {
|
|
532
|
+
case "auto":
|
|
533
|
+
case "none":
|
|
534
|
+
case "required": return {
|
|
535
|
+
tools: deepseekTools,
|
|
536
|
+
toolChoice: type,
|
|
537
|
+
toolWarnings
|
|
538
|
+
};
|
|
539
|
+
case "tool": return {
|
|
540
|
+
tools: deepseekTools,
|
|
541
|
+
toolChoice: {
|
|
542
|
+
type: "function",
|
|
543
|
+
function: { name: toolChoice.toolName }
|
|
544
|
+
},
|
|
545
|
+
toolWarnings
|
|
546
|
+
};
|
|
547
|
+
default: return {
|
|
548
|
+
tools: deepseekTools,
|
|
549
|
+
toolChoice: void 0,
|
|
550
|
+
toolWarnings: [...toolWarnings, {
|
|
551
|
+
type: "unsupported",
|
|
552
|
+
feature: `tool choice type: ${type}`
|
|
553
|
+
}]
|
|
554
|
+
};
|
|
555
|
+
}
|
|
708
556
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
import { createLanguageModelResponseMetadata } from "@ai-sdk/provider-utils";
|
|
712
|
-
|
|
713
|
-
// src/chat/map-deepseek-finish-reason.ts
|
|
557
|
+
//#endregion
|
|
558
|
+
//#region src/chat/map-deepseek-finish-reason.ts
|
|
714
559
|
function mapDeepSeekFinishReason(finishReason) {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
return "tool-calls";
|
|
724
|
-
case "insufficient_system_resource":
|
|
725
|
-
return "error";
|
|
726
|
-
default:
|
|
727
|
-
return "other";
|
|
728
|
-
}
|
|
560
|
+
switch (finishReason) {
|
|
561
|
+
case "stop": return "stop";
|
|
562
|
+
case "length": return "length";
|
|
563
|
+
case "content_filter": return "content-filter";
|
|
564
|
+
case "tool_calls": return "tool-calls";
|
|
565
|
+
case "insufficient_system_resource": return "error";
|
|
566
|
+
default: return "other";
|
|
567
|
+
}
|
|
729
568
|
}
|
|
730
|
-
|
|
731
|
-
|
|
569
|
+
//#endregion
|
|
570
|
+
//#region src/chat/deepseek-chat-language-model.ts
|
|
732
571
|
function createDeepSeekStreamError(error, data) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
572
|
+
const metadata = getDeepSeekStreamErrorMetadata(error);
|
|
573
|
+
return createProviderStreamError({
|
|
574
|
+
message: error.message,
|
|
575
|
+
type: error.type ?? void 0,
|
|
576
|
+
code: error.code ?? void 0,
|
|
577
|
+
...metadata,
|
|
578
|
+
data
|
|
579
|
+
});
|
|
741
580
|
}
|
|
742
581
|
function getDeepSeekStreamErrorMetadata(error) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
582
|
+
if (error.code === "insufficient_quota" || error.type === "insufficient_quota") return {
|
|
583
|
+
statusCode: 429,
|
|
584
|
+
isRetryable: false
|
|
585
|
+
};
|
|
586
|
+
const explicitStatusCode = getHttpStatusCode(error.code);
|
|
587
|
+
if (explicitStatusCode != null) return {
|
|
588
|
+
statusCode: explicitStatusCode,
|
|
589
|
+
isRetryable: isRetryableStatusCode(explicitStatusCode)
|
|
590
|
+
};
|
|
591
|
+
for (const discriminator of [error.code, error.type]) switch (discriminator) {
|
|
592
|
+
case "rate_limit_exceeded":
|
|
593
|
+
case "rate_limit_error": return {
|
|
594
|
+
statusCode: 429,
|
|
595
|
+
isRetryable: true
|
|
596
|
+
};
|
|
597
|
+
case "server_error":
|
|
598
|
+
case "api_error":
|
|
599
|
+
case "internal_server_error": return {
|
|
600
|
+
statusCode: 500,
|
|
601
|
+
isRetryable: true
|
|
602
|
+
};
|
|
603
|
+
case "overloaded_error":
|
|
604
|
+
case "service_unavailable": return {
|
|
605
|
+
statusCode: 503,
|
|
606
|
+
isRetryable: true
|
|
607
|
+
};
|
|
608
|
+
case "timeout":
|
|
609
|
+
case "timeout_error": return {
|
|
610
|
+
statusCode: 504,
|
|
611
|
+
isRetryable: true
|
|
612
|
+
};
|
|
613
|
+
case "authentication_error":
|
|
614
|
+
case "invalid_api_key": return {
|
|
615
|
+
statusCode: 401,
|
|
616
|
+
isRetryable: false
|
|
617
|
+
};
|
|
618
|
+
case "permission_error": return {
|
|
619
|
+
statusCode: 403,
|
|
620
|
+
isRetryable: false
|
|
621
|
+
};
|
|
622
|
+
case "not_found_error":
|
|
623
|
+
case "model_not_found": return {
|
|
624
|
+
statusCode: 404,
|
|
625
|
+
isRetryable: false
|
|
626
|
+
};
|
|
627
|
+
case "bad_request":
|
|
628
|
+
case "context_length_exceeded":
|
|
629
|
+
case "invalid_request_error": return {
|
|
630
|
+
statusCode: 400,
|
|
631
|
+
isRetryable: false
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
return {};
|
|
783
635
|
}
|
|
784
636
|
function getHttpStatusCode(value) {
|
|
785
|
-
|
|
786
|
-
|
|
637
|
+
const statusCode = typeof value === "string" && /^\d{3}$/.test(value) ? Number(value) : value;
|
|
638
|
+
return typeof statusCode === "number" && Number.isInteger(statusCode) && statusCode >= 400 && statusCode <= 599 ? statusCode : void 0;
|
|
787
639
|
}
|
|
788
640
|
function isRetryableStatusCode(statusCode) {
|
|
789
|
-
|
|
641
|
+
return statusCode === 408 || statusCode === 409 || statusCode === 429 || statusCode >= 500;
|
|
790
642
|
}
|
|
791
|
-
function mapDeepSeekProviderReasoningEffort({
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
feature: "reasoningEffort",
|
|
800
|
-
details: `reasoningEffort "${reasoningEffort}" is not a canonical DeepSeek value. mapped to "${mapped}".`
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
|
-
return mapped;
|
|
643
|
+
function mapDeepSeekProviderReasoningEffort({ reasoningEffort, warnings }) {
|
|
644
|
+
const mapped = reasoningEffort === "medium" ? "high" : reasoningEffort === "xhigh" ? "max" : reasoningEffort;
|
|
645
|
+
if (mapped !== reasoningEffort) warnings.push({
|
|
646
|
+
type: "compatibility",
|
|
647
|
+
feature: "reasoningEffort",
|
|
648
|
+
details: `reasoningEffort "${reasoningEffort}" is not a canonical DeepSeek value. mapped to "${mapped}".`
|
|
649
|
+
});
|
|
650
|
+
return mapped;
|
|
804
651
|
}
|
|
805
|
-
var DeepSeekChatLanguageModel = class
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
if (!isActiveText) {
|
|
1174
|
-
controller.enqueue({ type: "text-start", id: "txt-0" });
|
|
1175
|
-
isActiveText = true;
|
|
1176
|
-
}
|
|
1177
|
-
if (isActiveReasoning) {
|
|
1178
|
-
controller.enqueue({
|
|
1179
|
-
type: "reasoning-end",
|
|
1180
|
-
id: "reasoning-0"
|
|
1181
|
-
});
|
|
1182
|
-
isActiveReasoning = false;
|
|
1183
|
-
}
|
|
1184
|
-
controller.enqueue({
|
|
1185
|
-
type: "text-delta",
|
|
1186
|
-
id: "txt-0",
|
|
1187
|
-
delta: delta.content
|
|
1188
|
-
});
|
|
1189
|
-
}
|
|
1190
|
-
if (delta.tool_calls != null && delta.tool_calls.length > 0) {
|
|
1191
|
-
if (isActiveReasoning) {
|
|
1192
|
-
controller.enqueue({
|
|
1193
|
-
type: "reasoning-end",
|
|
1194
|
-
id: "reasoning-0"
|
|
1195
|
-
});
|
|
1196
|
-
isActiveReasoning = false;
|
|
1197
|
-
}
|
|
1198
|
-
for (const toolCallDelta of delta.tool_calls) {
|
|
1199
|
-
if (toolCallDelta.type != null) {
|
|
1200
|
-
toolCallTypes.set(toolCallDelta.index, toolCallDelta.type);
|
|
1201
|
-
}
|
|
1202
|
-
toolCallTracker.processDelta(toolCallDelta);
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
},
|
|
1206
|
-
flush(controller) {
|
|
1207
|
-
if (isActiveReasoning) {
|
|
1208
|
-
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
1209
|
-
}
|
|
1210
|
-
if (isActiveText) {
|
|
1211
|
-
controller.enqueue({ type: "text-end", id: "txt-0" });
|
|
1212
|
-
}
|
|
1213
|
-
toolCallTracker.flush();
|
|
1214
|
-
controller.enqueue({
|
|
1215
|
-
type: "finish",
|
|
1216
|
-
finishReason,
|
|
1217
|
-
usage: convertDeepSeekUsage(usage),
|
|
1218
|
-
providerMetadata: {
|
|
1219
|
-
[providerOptionsName]: {
|
|
1220
|
-
promptCacheHitTokens: usage?.prompt_cache_hit_tokens ?? void 0,
|
|
1221
|
-
promptCacheMissTokens: usage?.prompt_cache_miss_tokens ?? void 0,
|
|
1222
|
-
...responseObject != null && { responseObject },
|
|
1223
|
-
...choiceIndex != null && { choiceIndex },
|
|
1224
|
-
...messageRole != null && { messageRole },
|
|
1225
|
-
...toolCallTypes.size > 0 && {
|
|
1226
|
-
toolCallTypes: [...toolCallTypes.entries()].sort(([left], [right]) => left - right).map(([, type]) => type)
|
|
1227
|
-
},
|
|
1228
|
-
...(contentLogprobs.length > 0 || reasoningLogprobs.length > 0) && {
|
|
1229
|
-
logprobs: {
|
|
1230
|
-
...contentLogprobs.length > 0 && {
|
|
1231
|
-
content: contentLogprobs
|
|
1232
|
-
},
|
|
1233
|
-
...reasoningLogprobs.length > 0 && {
|
|
1234
|
-
reasoning_content: reasoningLogprobs
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
},
|
|
1238
|
-
...systemFingerprint != null && { systemFingerprint }
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
});
|
|
1242
|
-
}
|
|
1243
|
-
})
|
|
1244
|
-
),
|
|
1245
|
-
request: { body },
|
|
1246
|
-
response: { headers: responseHeaders }
|
|
1247
|
-
};
|
|
1248
|
-
}
|
|
652
|
+
var DeepSeekChatLanguageModel = class DeepSeekChatLanguageModel {
|
|
653
|
+
static [WORKFLOW_SERIALIZE](model) {
|
|
654
|
+
return serializeModelOptions({
|
|
655
|
+
modelId: model.modelId,
|
|
656
|
+
config: model.config
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
static [WORKFLOW_DESERIALIZE](options) {
|
|
660
|
+
return new DeepSeekChatLanguageModel(options.modelId, options.config);
|
|
661
|
+
}
|
|
662
|
+
constructor(modelId, config) {
|
|
663
|
+
this.specificationVersion = "v4";
|
|
664
|
+
this.supportedUrls = { "image/*": [/^https?:\/\/.*$/] };
|
|
665
|
+
this.modelId = modelId;
|
|
666
|
+
this.config = config;
|
|
667
|
+
this.failedResponseHandler = createJsonErrorResponseHandler({
|
|
668
|
+
errorSchema: deepSeekErrorSchema,
|
|
669
|
+
errorToMessage: (error) => error.error.message
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
get provider() {
|
|
673
|
+
return this.config.provider;
|
|
674
|
+
}
|
|
675
|
+
get providerOptionsName() {
|
|
676
|
+
return this.config.provider.split(".")[0].trim();
|
|
677
|
+
}
|
|
678
|
+
async getArgs({ prompt, maxOutputTokens, temperature, topP, topK, frequencyPenalty, presencePenalty, reasoning, providerOptions, stopSequences, responseFormat, seed, toolChoice, tools }) {
|
|
679
|
+
const deepseekOptions = await parseProviderOptions({
|
|
680
|
+
provider: this.providerOptionsName,
|
|
681
|
+
providerOptions,
|
|
682
|
+
schema: deepseekLanguageModelChatOptions
|
|
683
|
+
}) ?? {};
|
|
684
|
+
const supportsStructuredOutputs = this.config.supportsStructuredOutputs === true;
|
|
685
|
+
const supportsPenaltySampling = this.config.supportsPenaltySampling === true;
|
|
686
|
+
const { messages, warnings } = await convertToDeepSeekChatMessages({
|
|
687
|
+
prompt,
|
|
688
|
+
responseFormat,
|
|
689
|
+
modelId: this.modelId,
|
|
690
|
+
providerOptionsName: this.providerOptionsName,
|
|
691
|
+
supportsAssistantPrefixCompletion: this.config.supportsAssistantPrefixCompletion,
|
|
692
|
+
supportsStructuredOutputs
|
|
693
|
+
});
|
|
694
|
+
const allWarnings = [...warnings];
|
|
695
|
+
if (topK != null) allWarnings.push({
|
|
696
|
+
type: "unsupported",
|
|
697
|
+
feature: "topK"
|
|
698
|
+
});
|
|
699
|
+
if (seed != null) allWarnings.push({
|
|
700
|
+
type: "unsupported",
|
|
701
|
+
feature: "seed"
|
|
702
|
+
});
|
|
703
|
+
if (!supportsPenaltySampling && frequencyPenalty != null) allWarnings.push({
|
|
704
|
+
type: "deprecated",
|
|
705
|
+
setting: "frequencyPenalty",
|
|
706
|
+
message: "frequencyPenalty is deprecated by DeepSeek and has been omitted. Remove frequencyPenalty from the request."
|
|
707
|
+
});
|
|
708
|
+
if (!supportsPenaltySampling && presencePenalty != null) allWarnings.push({
|
|
709
|
+
type: "deprecated",
|
|
710
|
+
setting: "presencePenalty",
|
|
711
|
+
message: "presencePenalty is deprecated by DeepSeek and has been omitted. Remove presencePenalty from the request."
|
|
712
|
+
});
|
|
713
|
+
const { tools: deepseekTools, toolChoice: deepseekToolChoices, toolWarnings } = prepareTools({
|
|
714
|
+
tools,
|
|
715
|
+
toolChoice,
|
|
716
|
+
supportsStrictToolCalls: this.config.supportsStrictToolCalls
|
|
717
|
+
});
|
|
718
|
+
const thinkingType = deepseekOptions.thinking?.type;
|
|
719
|
+
if (thinkingType === "adaptive") allWarnings.push({
|
|
720
|
+
type: "compatibility",
|
|
721
|
+
feature: "thinking.type",
|
|
722
|
+
details: "thinking.type \"adaptive\" is not a canonical DeepSeek value. mapped to \"enabled\"."
|
|
723
|
+
});
|
|
724
|
+
const thinking = this.config.supportsThinking === false ? void 0 : thinkingType != null ? { type: thinkingType === "adaptive" ? "enabled" : thinkingType } : isCustomReasoning(reasoning) ? { type: reasoning === "none" ? "disabled" : "enabled" } : void 0;
|
|
725
|
+
const isThinkingEnabled = this.config.supportsThinking !== false && thinking?.type !== "disabled" && (thinking != null || this.modelId === "deepseek-reasoner" || isDeepSeekV4Model(this.modelId));
|
|
726
|
+
if (isThinkingEnabled && temperature != null) allWarnings.push({
|
|
727
|
+
type: "unsupported",
|
|
728
|
+
feature: "temperature",
|
|
729
|
+
details: "temperature has no effect when DeepSeek thinking is enabled. Set providerOptions.deepseek.thinking.type to 'disabled' to use temperature."
|
|
730
|
+
});
|
|
731
|
+
if (isThinkingEnabled && topP != null) allWarnings.push({
|
|
732
|
+
type: "unsupported",
|
|
733
|
+
feature: "topP",
|
|
734
|
+
details: "topP has no effect when DeepSeek thinking is enabled. Set providerOptions.deepseek.thinking.type to 'disabled' to use topP."
|
|
735
|
+
});
|
|
736
|
+
const reasoningEffort = deepseekOptions.reasoningEffort != null ? mapDeepSeekProviderReasoningEffort({
|
|
737
|
+
reasoningEffort: deepseekOptions.reasoningEffort,
|
|
738
|
+
warnings: allWarnings
|
|
739
|
+
}) : isCustomReasoning(reasoning) && reasoning !== "none" ? mapReasoningToProviderEffort({
|
|
740
|
+
reasoning,
|
|
741
|
+
effortMap: {
|
|
742
|
+
minimal: "low",
|
|
743
|
+
low: "low",
|
|
744
|
+
medium: "high",
|
|
745
|
+
high: "high",
|
|
746
|
+
xhigh: "max"
|
|
747
|
+
},
|
|
748
|
+
warnings: allWarnings
|
|
749
|
+
}) : void 0;
|
|
750
|
+
return {
|
|
751
|
+
args: {
|
|
752
|
+
model: this.modelId,
|
|
753
|
+
...(deepseekOptions.logprobs === true || deepseekOptions.topLogprobs != null) && { logprobs: true },
|
|
754
|
+
...deepseekOptions.topLogprobs != null && { top_logprobs: deepseekOptions.topLogprobs },
|
|
755
|
+
max_tokens: maxOutputTokens,
|
|
756
|
+
temperature: isThinkingEnabled ? void 0 : temperature,
|
|
757
|
+
top_p: isThinkingEnabled ? void 0 : topP,
|
|
758
|
+
frequency_penalty: supportsPenaltySampling ? frequencyPenalty : void 0,
|
|
759
|
+
presence_penalty: supportsPenaltySampling ? presencePenalty : void 0,
|
|
760
|
+
response_format: responseFormat?.type === "json" ? supportsStructuredOutputs && responseFormat.schema != null ? {
|
|
761
|
+
type: "json_schema",
|
|
762
|
+
json_schema: {
|
|
763
|
+
schema: responseFormat.schema,
|
|
764
|
+
strict: deepseekOptions.strictJsonSchema ?? true,
|
|
765
|
+
name: responseFormat.name ?? "response",
|
|
766
|
+
description: responseFormat.description
|
|
767
|
+
}
|
|
768
|
+
} : { type: "json_object" } : void 0,
|
|
769
|
+
stop: stopSequences,
|
|
770
|
+
messages,
|
|
771
|
+
tools: deepseekTools,
|
|
772
|
+
tool_choice: deepseekToolChoices,
|
|
773
|
+
thinking,
|
|
774
|
+
...deepseekOptions.userId != null && { user_id: deepseekOptions.userId },
|
|
775
|
+
...thinking?.type !== "disabled" && reasoningEffort != null && { reasoning_effort: reasoningEffort }
|
|
776
|
+
},
|
|
777
|
+
warnings: [...allWarnings, ...toolWarnings]
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
async doGenerate(options) {
|
|
781
|
+
const { args, warnings } = await this.getArgs({ ...options });
|
|
782
|
+
const { responseHeaders, value: responseBody, rawValue: rawResponse } = await postJsonToApi({
|
|
783
|
+
url: this.config.url({
|
|
784
|
+
path: "/chat/completions",
|
|
785
|
+
modelId: this.modelId
|
|
786
|
+
}),
|
|
787
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
788
|
+
body: args,
|
|
789
|
+
failedResponseHandler: this.failedResponseHandler,
|
|
790
|
+
successfulResponseHandler: createJsonResponseHandler(deepseekChatResponseSchema),
|
|
791
|
+
abortSignal: options.abortSignal,
|
|
792
|
+
fetch: this.config.fetch
|
|
793
|
+
});
|
|
794
|
+
const choice = responseBody.choices[0];
|
|
795
|
+
if (choice == null) throw new InvalidResponseDataError({
|
|
796
|
+
data: rawResponse,
|
|
797
|
+
message: "Response did not contain any choices."
|
|
798
|
+
});
|
|
799
|
+
const content = [];
|
|
800
|
+
const reasoning = choice.message.reasoning_content;
|
|
801
|
+
if (reasoning != null && reasoning.length > 0) content.push({
|
|
802
|
+
type: "reasoning",
|
|
803
|
+
text: reasoning
|
|
804
|
+
});
|
|
805
|
+
if (choice.message.tool_calls != null) for (const toolCall of choice.message.tool_calls) content.push({
|
|
806
|
+
type: "tool-call",
|
|
807
|
+
toolCallId: toolCall.id || generateId(),
|
|
808
|
+
toolName: toolCall.function.name,
|
|
809
|
+
input: toolCall.function.arguments
|
|
810
|
+
});
|
|
811
|
+
const text = choice.message.content;
|
|
812
|
+
if (text != null && text.length > 0) content.push({
|
|
813
|
+
type: "text",
|
|
814
|
+
text
|
|
815
|
+
});
|
|
816
|
+
return {
|
|
817
|
+
content,
|
|
818
|
+
finishReason: {
|
|
819
|
+
unified: mapDeepSeekFinishReason(choice.finish_reason),
|
|
820
|
+
raw: choice.finish_reason ?? void 0
|
|
821
|
+
},
|
|
822
|
+
usage: convertDeepSeekUsage(responseBody.usage),
|
|
823
|
+
providerMetadata: { [this.providerOptionsName]: {
|
|
824
|
+
promptCacheHitTokens: responseBody.usage?.prompt_cache_hit_tokens,
|
|
825
|
+
promptCacheMissTokens: responseBody.usage?.prompt_cache_miss_tokens,
|
|
826
|
+
...responseBody.object != null && { responseObject: responseBody.object },
|
|
827
|
+
...choice.index != null && { choiceIndex: choice.index },
|
|
828
|
+
...choice.message.role != null && { messageRole: choice.message.role },
|
|
829
|
+
...choice.message.tool_calls != null && { toolCallTypes: choice.message.tool_calls.map((toolCall) => toolCall.type).filter((type) => type != null) },
|
|
830
|
+
...choice.logprobs != null && { logprobs: choice.logprobs },
|
|
831
|
+
...responseBody.system_fingerprint != null && { systemFingerprint: responseBody.system_fingerprint }
|
|
832
|
+
} },
|
|
833
|
+
request: { body: args },
|
|
834
|
+
response: {
|
|
835
|
+
...getResponseMetadata(responseBody),
|
|
836
|
+
headers: responseHeaders,
|
|
837
|
+
body: rawResponse
|
|
838
|
+
},
|
|
839
|
+
warnings
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
async doStream(options) {
|
|
843
|
+
const { args, warnings } = await this.getArgs({ ...options });
|
|
844
|
+
const body = {
|
|
845
|
+
...args,
|
|
846
|
+
stream: true,
|
|
847
|
+
stream_options: { include_usage: true }
|
|
848
|
+
};
|
|
849
|
+
const { responseHeaders, value: response } = await postJsonToApi({
|
|
850
|
+
url: this.config.url({
|
|
851
|
+
path: "/chat/completions",
|
|
852
|
+
modelId: this.modelId
|
|
853
|
+
}),
|
|
854
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
855
|
+
body,
|
|
856
|
+
failedResponseHandler: this.failedResponseHandler,
|
|
857
|
+
successfulResponseHandler: createEventSourceResponseHandler(deepseekChatChunkSchema),
|
|
858
|
+
abortSignal: options.abortSignal,
|
|
859
|
+
fetch: this.config.fetch
|
|
860
|
+
});
|
|
861
|
+
let toolCallTracker;
|
|
862
|
+
let finishReason = {
|
|
863
|
+
unified: "other",
|
|
864
|
+
raw: void 0
|
|
865
|
+
};
|
|
866
|
+
let usage = void 0;
|
|
867
|
+
let systemFingerprint = void 0;
|
|
868
|
+
let isFirstChunk = true;
|
|
869
|
+
const providerOptionsName = this.providerOptionsName;
|
|
870
|
+
let isActiveReasoning = false;
|
|
871
|
+
let isActiveText = false;
|
|
872
|
+
let responseObject;
|
|
873
|
+
let choiceIndex;
|
|
874
|
+
let messageRole;
|
|
875
|
+
const toolCallTypes = /* @__PURE__ */ new Map();
|
|
876
|
+
const contentLogprobs = [];
|
|
877
|
+
const reasoningLogprobs = [];
|
|
878
|
+
return {
|
|
879
|
+
stream: response.pipeThrough(new TransformStream({
|
|
880
|
+
start(controller) {
|
|
881
|
+
toolCallTracker = new StreamingToolCallTracker(controller, { generateId });
|
|
882
|
+
controller.enqueue({
|
|
883
|
+
type: "stream-start",
|
|
884
|
+
warnings
|
|
885
|
+
});
|
|
886
|
+
},
|
|
887
|
+
transform(chunk, controller) {
|
|
888
|
+
if (options.includeRawChunks) controller.enqueue({
|
|
889
|
+
type: "raw",
|
|
890
|
+
rawValue: chunk.rawValue
|
|
891
|
+
});
|
|
892
|
+
if (!chunk.success) {
|
|
893
|
+
finishReason = {
|
|
894
|
+
unified: "error",
|
|
895
|
+
raw: void 0
|
|
896
|
+
};
|
|
897
|
+
controller.enqueue({
|
|
898
|
+
type: "error",
|
|
899
|
+
error: chunk.error
|
|
900
|
+
});
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
const value = chunk.value;
|
|
904
|
+
if ("error" in value) {
|
|
905
|
+
finishReason = {
|
|
906
|
+
unified: "error",
|
|
907
|
+
raw: void 0
|
|
908
|
+
};
|
|
909
|
+
controller.enqueue({
|
|
910
|
+
type: "error",
|
|
911
|
+
error: createDeepSeekStreamError(value.error, value)
|
|
912
|
+
});
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
if (isFirstChunk) {
|
|
916
|
+
isFirstChunk = false;
|
|
917
|
+
controller.enqueue({
|
|
918
|
+
type: "response-metadata",
|
|
919
|
+
...getResponseMetadata(value)
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
if (value.usage != null) usage = value.usage;
|
|
923
|
+
if (value.object != null) responseObject = value.object;
|
|
924
|
+
if (value.system_fingerprint != null) systemFingerprint = value.system_fingerprint;
|
|
925
|
+
const choice = value.choices[0];
|
|
926
|
+
if (choice?.index != null) choiceIndex = choice.index;
|
|
927
|
+
if (choice?.finish_reason != null) finishReason = {
|
|
928
|
+
unified: mapDeepSeekFinishReason(choice.finish_reason),
|
|
929
|
+
raw: choice.finish_reason
|
|
930
|
+
};
|
|
931
|
+
if (choice?.logprobs?.content != null) contentLogprobs.push(...choice.logprobs.content);
|
|
932
|
+
if (choice?.logprobs?.reasoning_content != null) reasoningLogprobs.push(...choice.logprobs.reasoning_content);
|
|
933
|
+
if (choice?.delta == null) return;
|
|
934
|
+
const delta = choice.delta;
|
|
935
|
+
if (delta.role != null) messageRole = delta.role;
|
|
936
|
+
const reasoningContent = delta.reasoning_content;
|
|
937
|
+
if (reasoningContent) {
|
|
938
|
+
if (!isActiveReasoning) {
|
|
939
|
+
controller.enqueue({
|
|
940
|
+
type: "reasoning-start",
|
|
941
|
+
id: "reasoning-0"
|
|
942
|
+
});
|
|
943
|
+
isActiveReasoning = true;
|
|
944
|
+
}
|
|
945
|
+
controller.enqueue({
|
|
946
|
+
type: "reasoning-delta",
|
|
947
|
+
id: "reasoning-0",
|
|
948
|
+
delta: reasoningContent
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
if (delta.content) {
|
|
952
|
+
if (!isActiveText) {
|
|
953
|
+
controller.enqueue({
|
|
954
|
+
type: "text-start",
|
|
955
|
+
id: "txt-0"
|
|
956
|
+
});
|
|
957
|
+
isActiveText = true;
|
|
958
|
+
}
|
|
959
|
+
if (isActiveReasoning) {
|
|
960
|
+
controller.enqueue({
|
|
961
|
+
type: "reasoning-end",
|
|
962
|
+
id: "reasoning-0"
|
|
963
|
+
});
|
|
964
|
+
isActiveReasoning = false;
|
|
965
|
+
}
|
|
966
|
+
controller.enqueue({
|
|
967
|
+
type: "text-delta",
|
|
968
|
+
id: "txt-0",
|
|
969
|
+
delta: delta.content
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
if (delta.tool_calls != null && delta.tool_calls.length > 0) {
|
|
973
|
+
if (isActiveReasoning) {
|
|
974
|
+
controller.enqueue({
|
|
975
|
+
type: "reasoning-end",
|
|
976
|
+
id: "reasoning-0"
|
|
977
|
+
});
|
|
978
|
+
isActiveReasoning = false;
|
|
979
|
+
}
|
|
980
|
+
for (const toolCallDelta of delta.tool_calls) {
|
|
981
|
+
if (toolCallDelta.type != null) toolCallTypes.set(toolCallDelta.index, toolCallDelta.type);
|
|
982
|
+
toolCallTracker.processDelta(toolCallDelta);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
},
|
|
986
|
+
flush(controller) {
|
|
987
|
+
if (isActiveReasoning) controller.enqueue({
|
|
988
|
+
type: "reasoning-end",
|
|
989
|
+
id: "reasoning-0"
|
|
990
|
+
});
|
|
991
|
+
if (isActiveText) controller.enqueue({
|
|
992
|
+
type: "text-end",
|
|
993
|
+
id: "txt-0"
|
|
994
|
+
});
|
|
995
|
+
toolCallTracker.flush();
|
|
996
|
+
controller.enqueue({
|
|
997
|
+
type: "finish",
|
|
998
|
+
finishReason,
|
|
999
|
+
usage: convertDeepSeekUsage(usage),
|
|
1000
|
+
providerMetadata: { [providerOptionsName]: {
|
|
1001
|
+
promptCacheHitTokens: usage?.prompt_cache_hit_tokens ?? void 0,
|
|
1002
|
+
promptCacheMissTokens: usage?.prompt_cache_miss_tokens ?? void 0,
|
|
1003
|
+
...responseObject != null && { responseObject },
|
|
1004
|
+
...choiceIndex != null && { choiceIndex },
|
|
1005
|
+
...messageRole != null && { messageRole },
|
|
1006
|
+
...toolCallTypes.size > 0 && { toolCallTypes: [...toolCallTypes.entries()].sort(([left], [right]) => left - right).map(([, type]) => type) },
|
|
1007
|
+
...(contentLogprobs.length > 0 || reasoningLogprobs.length > 0) && { logprobs: {
|
|
1008
|
+
...contentLogprobs.length > 0 && { content: contentLogprobs },
|
|
1009
|
+
...reasoningLogprobs.length > 0 && { reasoning_content: reasoningLogprobs }
|
|
1010
|
+
} },
|
|
1011
|
+
...systemFingerprint != null && { systemFingerprint }
|
|
1012
|
+
} }
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
})),
|
|
1016
|
+
request: { body },
|
|
1017
|
+
response: { headers: responseHeaders }
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1249
1020
|
};
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
// uploads remain resilient to incomplete responses while validating any
|
|
1275
|
-
// returned values precisely enough to avoid misleading metadata.
|
|
1276
|
-
object: z4.literal("file").nullish(),
|
|
1277
|
-
bytes: z4.number().int().nonnegative().nullish(),
|
|
1278
|
-
created_at: z4.number().int().nonnegative().nullish(),
|
|
1279
|
-
filename: z4.string().nullish(),
|
|
1280
|
-
purpose: z4.literal("user_data").nullish(),
|
|
1281
|
-
expires_at: z4.number().int().nonnegative().nullish()
|
|
1282
|
-
})
|
|
1283
|
-
)
|
|
1284
|
-
);
|
|
1285
|
-
|
|
1286
|
-
// src/files/deepseek-files-options.ts
|
|
1287
|
-
import {
|
|
1288
|
-
lazySchema as lazySchema3,
|
|
1289
|
-
zodSchema as zodSchema3
|
|
1290
|
-
} from "@ai-sdk/provider-utils";
|
|
1291
|
-
import { z as z5 } from "zod/v4";
|
|
1292
|
-
var deepSeekFilesOptionsSchema = lazySchema3(
|
|
1293
|
-
() => zodSchema3(
|
|
1294
|
-
z5.object({
|
|
1295
|
-
/**
|
|
1296
|
-
* Number of seconds after creation before the file expires.
|
|
1297
|
-
* Must be between 1 hour and 30 days.
|
|
1298
|
-
*/
|
|
1299
|
-
expiresAfter: z5.number().int().min(3600).max(2592e3).optional()
|
|
1300
|
-
})
|
|
1301
|
-
)
|
|
1302
|
-
);
|
|
1303
|
-
|
|
1304
|
-
// src/files/deepseek-files.ts
|
|
1305
|
-
var deepSeekFailedResponseHandler = createJsonErrorResponseHandler2({
|
|
1306
|
-
errorSchema: deepSeekErrorSchema,
|
|
1307
|
-
errorToMessage: (error) => error.error.message
|
|
1021
|
+
//#endregion
|
|
1022
|
+
//#region src/files/deepseek-files-api.ts
|
|
1023
|
+
const deepSeekFilesResponseSchema = lazySchema(() => zodSchema(z.object({
|
|
1024
|
+
id: z.string(),
|
|
1025
|
+
object: z.literal("file").nullish(),
|
|
1026
|
+
bytes: z.number().int().nonnegative().nullish(),
|
|
1027
|
+
created_at: z.number().int().nonnegative().nullish(),
|
|
1028
|
+
filename: z.string().nullish(),
|
|
1029
|
+
purpose: z.literal("user_data").nullish(),
|
|
1030
|
+
expires_at: z.number().int().nonnegative().nullish()
|
|
1031
|
+
})));
|
|
1032
|
+
//#endregion
|
|
1033
|
+
//#region src/files/deepseek-files-options.ts
|
|
1034
|
+
const deepSeekFilesOptionsSchema = lazySchema(() => zodSchema(z.object({
|
|
1035
|
+
/**
|
|
1036
|
+
* Number of seconds after creation before the file expires.
|
|
1037
|
+
* Must be between 1 hour and 30 days.
|
|
1038
|
+
*/
|
|
1039
|
+
expiresAfter: z.number().int().min(3600).max(2592e3).optional() })));
|
|
1040
|
+
//#endregion
|
|
1041
|
+
//#region src/files/deepseek-files.ts
|
|
1042
|
+
const deepSeekFailedResponseHandler = createJsonErrorResponseHandler({
|
|
1043
|
+
errorSchema: deepSeekErrorSchema,
|
|
1044
|
+
errorToMessage: (error) => error.error.message
|
|
1308
1045
|
});
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1046
|
+
const MAX_FILE_SIZE_BYTES = 67108864;
|
|
1047
|
+
const MAX_FILENAME_LENGTH = 512;
|
|
1048
|
+
const supportedMediaTypes = /* @__PURE__ */ new Set([
|
|
1049
|
+
"image/gif",
|
|
1050
|
+
"image/jpeg",
|
|
1051
|
+
"image/jpg",
|
|
1052
|
+
"image/png",
|
|
1053
|
+
"image/webp"
|
|
1317
1054
|
]);
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1055
|
+
const genericMediaTypes = /* @__PURE__ */ new Set([
|
|
1056
|
+
"",
|
|
1057
|
+
"application/binary",
|
|
1058
|
+
"application/octet-stream",
|
|
1059
|
+
"binary/octet-stream",
|
|
1060
|
+
"image",
|
|
1061
|
+
"image/*"
|
|
1325
1062
|
]);
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1063
|
+
const supportedFilenameExtensions = /* @__PURE__ */ new Set([
|
|
1064
|
+
"gif",
|
|
1065
|
+
"jpeg",
|
|
1066
|
+
"jpg",
|
|
1067
|
+
"png",
|
|
1068
|
+
"webp"
|
|
1332
1069
|
]);
|
|
1333
1070
|
var DeepSeekFiles = class {
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
...mediaType != null ? { mediaType } : {},
|
|
1387
|
-
providerMetadata: {
|
|
1388
|
-
deepseek: {
|
|
1389
|
-
...response.object != null ? { object: response.object } : {},
|
|
1390
|
-
...response.filename != null ? { filename: response.filename } : {},
|
|
1391
|
-
...response.purpose != null ? { purpose: response.purpose } : {},
|
|
1392
|
-
...response.bytes != null ? { bytes: response.bytes } : {},
|
|
1393
|
-
...response.created_at != null ? { createdAt: response.created_at } : {},
|
|
1394
|
-
...response.expires_at != null ? { expiresAt: response.expires_at } : {}
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
};
|
|
1398
|
-
}
|
|
1071
|
+
get provider() {
|
|
1072
|
+
return this.config.provider;
|
|
1073
|
+
}
|
|
1074
|
+
constructor(config) {
|
|
1075
|
+
this.config = config;
|
|
1076
|
+
this.specificationVersion = "v4";
|
|
1077
|
+
}
|
|
1078
|
+
async uploadFile({ data, mediaType, filename, abortSignal, headers, providerOptions }) {
|
|
1079
|
+
const deepSeekOptions = await parseProviderOptions({
|
|
1080
|
+
provider: "deepseek",
|
|
1081
|
+
providerOptions,
|
|
1082
|
+
schema: deepSeekFilesOptionsSchema
|
|
1083
|
+
});
|
|
1084
|
+
const fileBytes = convertInlineFileDataToUint8Array(data);
|
|
1085
|
+
validateFileUpload({
|
|
1086
|
+
fileBytes,
|
|
1087
|
+
mediaType,
|
|
1088
|
+
filename
|
|
1089
|
+
});
|
|
1090
|
+
const blob = new Blob([fileBytes], { type: mediaType });
|
|
1091
|
+
const formData = new FormData();
|
|
1092
|
+
if (filename != null) formData.append("file", blob, filename);
|
|
1093
|
+
else formData.append("file", blob);
|
|
1094
|
+
formData.append("purpose", "user_data");
|
|
1095
|
+
if (deepSeekOptions?.expiresAfter != null) {
|
|
1096
|
+
formData.append("expires_after[anchor]", "created_at");
|
|
1097
|
+
formData.append("expires_after[seconds]", String(deepSeekOptions.expiresAfter));
|
|
1098
|
+
}
|
|
1099
|
+
const { value: response } = await postFormDataToApi({
|
|
1100
|
+
url: `${this.config.baseURL}/files`,
|
|
1101
|
+
headers: combineHeaders(this.config.headers(), headers),
|
|
1102
|
+
formData,
|
|
1103
|
+
failedResponseHandler: deepSeekFailedResponseHandler,
|
|
1104
|
+
successfulResponseHandler: createJsonResponseHandler(deepSeekFilesResponseSchema),
|
|
1105
|
+
abortSignal,
|
|
1106
|
+
fetch: this.config.fetch
|
|
1107
|
+
});
|
|
1108
|
+
return {
|
|
1109
|
+
warnings: [],
|
|
1110
|
+
providerReference: { deepseek: response.id },
|
|
1111
|
+
...response.filename ?? filename ? { filename: response.filename ?? filename } : {},
|
|
1112
|
+
...mediaType != null ? { mediaType } : {},
|
|
1113
|
+
providerMetadata: { deepseek: {
|
|
1114
|
+
...response.object != null ? { object: response.object } : {},
|
|
1115
|
+
...response.filename != null ? { filename: response.filename } : {},
|
|
1116
|
+
...response.purpose != null ? { purpose: response.purpose } : {},
|
|
1117
|
+
...response.bytes != null ? { bytes: response.bytes } : {},
|
|
1118
|
+
...response.created_at != null ? { createdAt: response.created_at } : {},
|
|
1119
|
+
...response.expires_at != null ? { expiresAt: response.expires_at } : {}
|
|
1120
|
+
} }
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1399
1123
|
};
|
|
1400
|
-
function validateFileUpload({
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
})
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
if (supportedMediaTypes.has(normalizedMediaType)) {
|
|
1429
|
-
return;
|
|
1430
|
-
}
|
|
1431
|
-
if (!genericMediaTypes.has(normalizedMediaType)) {
|
|
1432
|
-
throw new InvalidArgumentError({
|
|
1433
|
-
argument: "mediaType",
|
|
1434
|
-
message: `DeepSeek file uploads support JPEG, PNG, GIF, and WebP images. Received unsupported media type "${mediaType}".`
|
|
1435
|
-
});
|
|
1436
|
-
}
|
|
1437
|
-
if (detectedMediaType != null || hasSupportedFilenameExtension(filename)) {
|
|
1438
|
-
return;
|
|
1439
|
-
}
|
|
1440
|
-
throw new InvalidArgumentError({
|
|
1441
|
-
argument: "mediaType",
|
|
1442
|
-
message: `DeepSeek file uploads support JPEG, PNG, GIF, and WebP images. Provide a supported media type or a filename ending in .jpg, .jpeg, .png, .gif, or .webp. Received "${mediaType}".`
|
|
1443
|
-
});
|
|
1124
|
+
function validateFileUpload({ fileBytes, mediaType, filename }) {
|
|
1125
|
+
if (fileBytes.length > MAX_FILE_SIZE_BYTES) throw new InvalidArgumentError({
|
|
1126
|
+
argument: "data",
|
|
1127
|
+
message: `DeepSeek file uploads must not exceed 64 MiB (${MAX_FILE_SIZE_BYTES.toLocaleString("en-US")} bytes). Received ${fileBytes.length.toLocaleString("en-US")} bytes.`
|
|
1128
|
+
});
|
|
1129
|
+
if (filename != null) {
|
|
1130
|
+
const filenameLength = Array.from(filename).length;
|
|
1131
|
+
if (filenameLength > MAX_FILENAME_LENGTH) throw new InvalidArgumentError({
|
|
1132
|
+
argument: "filename",
|
|
1133
|
+
message: `DeepSeek filenames must not exceed ${MAX_FILENAME_LENGTH} characters. Received ${filenameLength} characters.`
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
const normalizedMediaType = normalizeMediaType(mediaType);
|
|
1137
|
+
const detectedMediaType = detectMediaType({ data: fileBytes });
|
|
1138
|
+
if (detectedMediaType != null && !supportedMediaTypes.has(detectedMediaType)) throw new InvalidArgumentError({
|
|
1139
|
+
argument: "data",
|
|
1140
|
+
message: `DeepSeek file uploads support JPEG, PNG, GIF, and WebP images. Detected unsupported file content type "${detectedMediaType}".`
|
|
1141
|
+
});
|
|
1142
|
+
if (supportedMediaTypes.has(normalizedMediaType)) return;
|
|
1143
|
+
if (!genericMediaTypes.has(normalizedMediaType)) throw new InvalidArgumentError({
|
|
1144
|
+
argument: "mediaType",
|
|
1145
|
+
message: `DeepSeek file uploads support JPEG, PNG, GIF, and WebP images. Received unsupported media type "${mediaType}".`
|
|
1146
|
+
});
|
|
1147
|
+
if (detectedMediaType != null || hasSupportedFilenameExtension(filename)) return;
|
|
1148
|
+
throw new InvalidArgumentError({
|
|
1149
|
+
argument: "mediaType",
|
|
1150
|
+
message: `DeepSeek file uploads support JPEG, PNG, GIF, and WebP images. Provide a supported media type or a filename ending in .jpg, .jpeg, .png, .gif, or .webp. Received "${mediaType}".`
|
|
1151
|
+
});
|
|
1444
1152
|
}
|
|
1445
1153
|
function normalizeMediaType(mediaType) {
|
|
1446
|
-
|
|
1154
|
+
return mediaType.split(";", 1)[0].trim().toLowerCase();
|
|
1447
1155
|
}
|
|
1448
1156
|
function hasSupportedFilenameExtension(filename) {
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
const extensionSeparatorIndex = filename.lastIndexOf(".");
|
|
1453
|
-
return extensionSeparatorIndex !== -1 && supportedFilenameExtensions.has(
|
|
1454
|
-
filename.slice(extensionSeparatorIndex + 1).toLowerCase()
|
|
1455
|
-
);
|
|
1157
|
+
if (filename == null) return false;
|
|
1158
|
+
const extensionSeparatorIndex = filename.lastIndexOf(".");
|
|
1159
|
+
return extensionSeparatorIndex !== -1 && supportedFilenameExtensions.has(filename.slice(extensionSeparatorIndex + 1).toLowerCase());
|
|
1456
1160
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1161
|
+
//#endregion
|
|
1162
|
+
//#region src/version.ts
|
|
1163
|
+
const VERSION = "3.0.57";
|
|
1164
|
+
//#endregion
|
|
1165
|
+
//#region src/deepseek-provider.ts
|
|
1462
1166
|
function createDeepSeek(options = {}) {
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1167
|
+
const baseURL = withoutTrailingSlash(options.baseURL ?? "https://api.deepseek.com") ?? "https://api.deepseek.com";
|
|
1168
|
+
const getHeaders = () => withUserAgentSuffix({
|
|
1169
|
+
Authorization: `Bearer ${loadApiKey({
|
|
1170
|
+
apiKey: options.apiKey,
|
|
1171
|
+
environmentVariableName: "DEEPSEEK_API_KEY",
|
|
1172
|
+
description: "DeepSeek API key"
|
|
1173
|
+
})}`,
|
|
1174
|
+
...options.headers
|
|
1175
|
+
}, `ai-sdk-deepseek/${VERSION}`);
|
|
1176
|
+
const createLanguageModel = (modelId) => {
|
|
1177
|
+
return new DeepSeekChatLanguageModel(modelId, {
|
|
1178
|
+
provider: `deepseek.chat`,
|
|
1179
|
+
url: ({ path }) => `${baseURL}${path}`,
|
|
1180
|
+
headers: getHeaders,
|
|
1181
|
+
fetch: options.fetch,
|
|
1182
|
+
supportsAssistantPrefixCompletion: baseURL.endsWith("/beta"),
|
|
1183
|
+
supportsStrictToolCalls: baseURL.endsWith("/beta")
|
|
1184
|
+
});
|
|
1185
|
+
};
|
|
1186
|
+
const createFiles = () => new DeepSeekFiles({
|
|
1187
|
+
provider: "deepseek.files",
|
|
1188
|
+
baseURL,
|
|
1189
|
+
headers: getHeaders,
|
|
1190
|
+
fetch: options.fetch
|
|
1191
|
+
});
|
|
1192
|
+
const provider = (modelId) => createLanguageModel(modelId);
|
|
1193
|
+
provider.specificationVersion = "v4";
|
|
1194
|
+
provider.languageModel = createLanguageModel;
|
|
1195
|
+
provider.chat = createLanguageModel;
|
|
1196
|
+
provider.files = createFiles;
|
|
1197
|
+
provider.embeddingModel = (modelId) => {
|
|
1198
|
+
throw new NoSuchModelError({
|
|
1199
|
+
modelId,
|
|
1200
|
+
modelType: "embeddingModel"
|
|
1201
|
+
});
|
|
1202
|
+
};
|
|
1203
|
+
provider.textEmbeddingModel = provider.embeddingModel;
|
|
1204
|
+
provider.imageModel = (modelId) => {
|
|
1205
|
+
throw new NoSuchModelError({
|
|
1206
|
+
modelId,
|
|
1207
|
+
modelType: "imageModel"
|
|
1208
|
+
});
|
|
1209
|
+
};
|
|
1210
|
+
return provider;
|
|
1504
1211
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
deepSeek,
|
|
1510
|
-
deepSeek as deepseek
|
|
1511
|
-
};
|
|
1212
|
+
const deepSeek = createDeepSeek();
|
|
1213
|
+
//#endregion
|
|
1214
|
+
export { VERSION, createDeepSeek, deepSeek, deepSeek as deepseek };
|
|
1215
|
+
|
|
1512
1216
|
//# sourceMappingURL=index.js.map
|