@ai-sdk/deepseek 3.0.56 → 3.0.58
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 +19 -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/internal/index.js
CHANGED
|
@@ -1,1246 +1,1025 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
InvalidResponseDataError
|
|
4
|
-
} from "@ai-sdk/provider";
|
|
5
|
-
import {
|
|
6
|
-
combineHeaders,
|
|
7
|
-
createEventSourceResponseHandler,
|
|
8
|
-
createJsonErrorResponseHandler,
|
|
9
|
-
createJsonResponseHandler,
|
|
10
|
-
createProviderStreamError,
|
|
11
|
-
generateId,
|
|
12
|
-
isCustomReasoning,
|
|
13
|
-
mapReasoningToProviderEffort,
|
|
14
|
-
parseProviderOptions as parseProviderOptions2,
|
|
15
|
-
postJsonToApi,
|
|
16
|
-
serializeModelOptions,
|
|
17
|
-
StreamingToolCallTracker,
|
|
18
|
-
WORKFLOW_SERIALIZE,
|
|
19
|
-
WORKFLOW_DESERIALIZE
|
|
20
|
-
} from "@ai-sdk/provider-utils";
|
|
21
|
-
|
|
22
|
-
// src/chat/convert-to-deepseek-chat-messages.ts
|
|
23
|
-
import {
|
|
24
|
-
InvalidPromptError,
|
|
25
|
-
UnsupportedFunctionalityError
|
|
26
|
-
} from "@ai-sdk/provider";
|
|
27
|
-
import {
|
|
28
|
-
convertToBase64,
|
|
29
|
-
getTopLevelMediaType,
|
|
30
|
-
parseProviderOptions,
|
|
31
|
-
resolveFullMediaType,
|
|
32
|
-
resolveProviderReference
|
|
33
|
-
} from "@ai-sdk/provider-utils";
|
|
34
|
-
|
|
35
|
-
// src/chat/deepseek-file-part-options.ts
|
|
1
|
+
import { InvalidPromptError, InvalidResponseDataError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
|
|
2
|
+
import { StreamingToolCallTracker, WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, convertToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonResponseHandler, createLanguageModelResponseMetadata as getResponseMetadata, createNullLanguageModelUsage, createProviderStreamError, generateId, getTopLevelMediaType, isCustomReasoning, lazySchema, mapReasoningToProviderEffort, parseProviderOptions, postJsonToApi, resolveFullMediaType, resolveProviderReference, serializeModelOptions, zodSchema } from "@ai-sdk/provider-utils";
|
|
36
3
|
import { z } from "zod/v4";
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* Whether to return log probabilities for generated tokens.
|
|
60
|
-
*/
|
|
61
|
-
logprobs: z2.boolean().optional(),
|
|
62
|
-
/**
|
|
63
|
-
* Number of most likely tokens to return at each token position.
|
|
64
|
-
*
|
|
65
|
-
* Setting this option automatically enables `logprobs`.
|
|
66
|
-
*/
|
|
67
|
-
topLogprobs: z2.number().int().min(0).max(20).optional(),
|
|
68
|
-
/**
|
|
69
|
-
* An opaque identifier for the end user. DeepSeek uses this identifier for
|
|
70
|
-
* content-safety tracing and request isolation.
|
|
71
|
-
*
|
|
72
|
-
* Must contain only ASCII letters, numbers, underscores, and hyphens, and
|
|
73
|
-
* must be at most 512 characters long.
|
|
74
|
-
*/
|
|
75
|
-
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(),
|
|
76
|
-
/**
|
|
77
|
-
* Type of thinking to use. Defaults to `enabled`.
|
|
78
|
-
*/
|
|
79
|
-
thinking: z2.object({
|
|
80
|
-
// `adaptive` is accepted at runtime for backwards compatibility and
|
|
81
|
-
// mapped to `enabled`, but is intentionally excluded from the exported
|
|
82
|
-
// provider options type.
|
|
83
|
-
type: z2.enum(["adaptive", "enabled", "disabled"]).optional()
|
|
84
|
-
}).optional(),
|
|
85
|
-
/**
|
|
86
|
-
* Controls the thinking strength for DeepSeek V4 reasoning models.
|
|
87
|
-
*/
|
|
88
|
-
// `medium` and `xhigh` are accepted at runtime for backwards compatibility
|
|
89
|
-
// and mapped to canonical DeepSeek values, but are intentionally excluded
|
|
90
|
-
// from the exported provider options type.
|
|
91
|
-
reasoningEffort: z2.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
|
|
92
|
-
/**
|
|
93
|
-
* Whether to use strict JSON schema validation for structured outputs.
|
|
94
|
-
* Only applies when the serving endpoint supports JSON schema response
|
|
95
|
-
* formats (e.g. Azure). Defaults to `true`.
|
|
96
|
-
*/
|
|
97
|
-
strictJsonSchema: z2.boolean().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()
|
|
98
26
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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()
|
|
106
72
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
73
|
+
const deepseekMessageProviderOptions = 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() });
|
|
80
|
+
const deepseekAssistantMessageProviderOptions = deepseekMessageProviderOptions.extend({
|
|
81
|
+
/**
|
|
82
|
+
* Whether the assistant message content is a prefix that DeepSeek should
|
|
83
|
+
* continue. This beta feature is only supported on the final assistant
|
|
84
|
+
* message when using a beta base URL.
|
|
85
|
+
*/
|
|
86
|
+
prefix: z.literal(true).optional() });
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/chat/is-deepseek-v4-model.ts
|
|
89
|
+
/**
|
|
90
|
+
* Whether a model id is a DeepSeek V4-generation model (thinking mode on by
|
|
91
|
+
* default, `reasoning_content` required on every assistant turn).
|
|
92
|
+
*
|
|
93
|
+
* DeepSeek publishes V4 models under both versioned ids (`deepseek-v4-pro`,
|
|
94
|
+
* `deepseek-v4-flash-*`) and unversioned aliases (`deepseek-flash`, currently
|
|
95
|
+
* serving V4.1 Flash). Only the legacy `deepseek-chat` / `deepseek-reasoner`
|
|
96
|
+
* ids predate V4.
|
|
97
|
+
*/
|
|
117
98
|
function isDeepSeekV4Model(modelId) {
|
|
118
|
-
|
|
99
|
+
return modelId.includes("deepseek-v4") || modelId.startsWith("deepseek-flash") || modelId.startsWith("deepseek-pro");
|
|
119
100
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/chat/convert-to-deepseek-chat-messages.ts
|
|
103
|
+
const supportedImageMediaTypes = /* @__PURE__ */ new Set([
|
|
104
|
+
"image/gif",
|
|
105
|
+
"image/jpeg",
|
|
106
|
+
"image/jpg",
|
|
107
|
+
"image/png",
|
|
108
|
+
"image/webp"
|
|
128
109
|
]);
|
|
129
110
|
function resolveDeepSeekImageMediaType(part) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
return resolvedMediaType;
|
|
111
|
+
const resolvedMediaType = resolveFullMediaType({ part });
|
|
112
|
+
if (!supportedImageMediaTypes.has(resolvedMediaType)) throw new UnsupportedFunctionalityError({
|
|
113
|
+
functionality: `DeepSeek image media type ${resolvedMediaType}`,
|
|
114
|
+
message: "DeepSeek supports JPEG, PNG, GIF, and WebP image inputs."
|
|
115
|
+
});
|
|
116
|
+
return resolvedMediaType;
|
|
138
117
|
}
|
|
139
|
-
function validateDeepSeekImageUrl({
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
throw new InvalidPromptError({
|
|
145
|
-
prompt,
|
|
146
|
-
message: "DeepSeek image URLs must not exceed 8192 characters."
|
|
147
|
-
});
|
|
148
|
-
}
|
|
118
|
+
function validateDeepSeekImageUrl({ url, prompt }) {
|
|
119
|
+
if (url.length > 8192) throw new InvalidPromptError({
|
|
120
|
+
prompt,
|
|
121
|
+
message: "DeepSeek image URLs must not exceed 8192 characters."
|
|
122
|
+
});
|
|
149
123
|
}
|
|
150
|
-
async function convertToDeepSeekChatMessages({
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
const hasImagePart = output.value.some(
|
|
411
|
-
(part) => part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image"
|
|
412
|
-
);
|
|
413
|
-
if (!hasImagePart) {
|
|
414
|
-
contentValue = JSON.stringify(output.value);
|
|
415
|
-
break;
|
|
416
|
-
}
|
|
417
|
-
contentValue = [];
|
|
418
|
-
for (const part of output.value) {
|
|
419
|
-
if (part.type === "text") {
|
|
420
|
-
contentValue.push({ type: "text", text: part.text });
|
|
421
|
-
} else if (part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image") {
|
|
422
|
-
if (part.data.type === "reference") {
|
|
423
|
-
contentValue.push({
|
|
424
|
-
type: "file",
|
|
425
|
-
file_id: resolveProviderReference({
|
|
426
|
-
reference: part.data.reference,
|
|
427
|
-
provider: "deepseek"
|
|
428
|
-
})
|
|
429
|
-
});
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
const filePartOptions = await parseProviderOptions({
|
|
433
|
-
provider: providerOptionsName,
|
|
434
|
-
providerOptions: part.providerOptions,
|
|
435
|
-
schema: deepseekFilePartProviderOptions
|
|
436
|
-
});
|
|
437
|
-
const resolvedMediaType = resolveDeepSeekImageMediaType(part);
|
|
438
|
-
let url;
|
|
439
|
-
if (part.data.type === "url") {
|
|
440
|
-
url = part.data.url.toString();
|
|
441
|
-
validateDeepSeekImageUrl({ url, prompt });
|
|
442
|
-
} else {
|
|
443
|
-
url = `data:${resolvedMediaType === "image/jpg" ? "image/jpeg" : resolvedMediaType};base64,${convertToBase64(part.data.data)}`;
|
|
444
|
-
}
|
|
445
|
-
contentValue.push({
|
|
446
|
-
type: "image_url",
|
|
447
|
-
image_url: {
|
|
448
|
-
url,
|
|
449
|
-
...filePartOptions?.imageDetail != null && {
|
|
450
|
-
detail: filePartOptions.imageDetail
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
});
|
|
454
|
-
} else {
|
|
455
|
-
warnings.push({
|
|
456
|
-
type: "unsupported",
|
|
457
|
-
feature: `tool result content part type: ${part.type}`
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
break;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
messages.push({
|
|
465
|
-
role: "tool",
|
|
466
|
-
tool_call_id: toolResponse.toolCallId,
|
|
467
|
-
content: contentValue
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
break;
|
|
471
|
-
}
|
|
472
|
-
default: {
|
|
473
|
-
warnings.push({
|
|
474
|
-
type: "unsupported",
|
|
475
|
-
feature: `message role: ${role}`
|
|
476
|
-
});
|
|
477
|
-
break;
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
return { messages, warnings };
|
|
124
|
+
async function convertToDeepSeekChatMessages({ prompt, responseFormat, modelId, providerOptionsName = "deepseek", supportsAssistantPrefixCompletion = false, supportsStructuredOutputs = false }) {
|
|
125
|
+
const isDeepSeekV4 = isDeepSeekV4Model(modelId);
|
|
126
|
+
const messages = [];
|
|
127
|
+
const warnings = [];
|
|
128
|
+
if (responseFormat?.type === "json") {
|
|
129
|
+
if (responseFormat.schema == null) messages.push({
|
|
130
|
+
role: "system",
|
|
131
|
+
content: "Return JSON."
|
|
132
|
+
});
|
|
133
|
+
else if (!supportsStructuredOutputs) {
|
|
134
|
+
messages.push({
|
|
135
|
+
role: "system",
|
|
136
|
+
content: "Return JSON that conforms to the following schema: " + JSON.stringify(responseFormat.schema)
|
|
137
|
+
});
|
|
138
|
+
warnings.push({
|
|
139
|
+
type: "compatibility",
|
|
140
|
+
feature: "responseFormat JSON schema",
|
|
141
|
+
details: "JSON response schema is injected into the system message."
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
let lastUserMessageIndex = -1;
|
|
146
|
+
for (let i = prompt.length - 1; i >= 0; i--) if (prompt[i].role === "user") {
|
|
147
|
+
lastUserMessageIndex = i;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
let index = -1;
|
|
151
|
+
for (const { role, content, providerOptions } of prompt) {
|
|
152
|
+
index++;
|
|
153
|
+
const deepseekMessageOptions = await parseProviderOptions({
|
|
154
|
+
provider: providerOptionsName,
|
|
155
|
+
providerOptions,
|
|
156
|
+
schema: deepseekAssistantMessageProviderOptions
|
|
157
|
+
});
|
|
158
|
+
if (deepseekMessageOptions?.prefix === true && role !== "assistant") throw new InvalidPromptError({
|
|
159
|
+
prompt,
|
|
160
|
+
message: "DeepSeek assistant prefix completion requires `prefix: true` on an assistant message."
|
|
161
|
+
});
|
|
162
|
+
switch (role) {
|
|
163
|
+
case "system":
|
|
164
|
+
messages.push({
|
|
165
|
+
role: "system",
|
|
166
|
+
content,
|
|
167
|
+
...deepseekMessageOptions?.name != null && { name: deepseekMessageOptions.name }
|
|
168
|
+
});
|
|
169
|
+
break;
|
|
170
|
+
case "user": {
|
|
171
|
+
if (!content.some((part) => part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image")) {
|
|
172
|
+
let userContent = "";
|
|
173
|
+
for (const part of content) if (part.type === "text") userContent += part.text;
|
|
174
|
+
else warnings.push({
|
|
175
|
+
type: "unsupported",
|
|
176
|
+
feature: `user message part type: ${part.type}`
|
|
177
|
+
});
|
|
178
|
+
messages.push({
|
|
179
|
+
role: "user",
|
|
180
|
+
content: userContent,
|
|
181
|
+
...deepseekMessageOptions?.name != null && { name: deepseekMessageOptions.name }
|
|
182
|
+
});
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
const userContent = [];
|
|
186
|
+
for (const part of content) if (part.type === "text") userContent.push({
|
|
187
|
+
type: "text",
|
|
188
|
+
text: part.text
|
|
189
|
+
});
|
|
190
|
+
else if (part.type === "file" && getTopLevelMediaType(part.mediaType) === "image") {
|
|
191
|
+
const filePartOptions = await parseProviderOptions({
|
|
192
|
+
provider: providerOptionsName,
|
|
193
|
+
providerOptions: part.providerOptions,
|
|
194
|
+
schema: deepseekFilePartProviderOptions
|
|
195
|
+
});
|
|
196
|
+
if (part.data.type === "reference") userContent.push({
|
|
197
|
+
type: "file",
|
|
198
|
+
file_id: resolveProviderReference({
|
|
199
|
+
reference: part.data.reference,
|
|
200
|
+
provider: "deepseek"
|
|
201
|
+
})
|
|
202
|
+
});
|
|
203
|
+
else if (part.data.type === "url" || part.data.type === "data") {
|
|
204
|
+
const resolvedMediaType = resolveDeepSeekImageMediaType(part);
|
|
205
|
+
if (part.data.type === "url") {
|
|
206
|
+
const url = part.data.url.toString();
|
|
207
|
+
validateDeepSeekImageUrl({
|
|
208
|
+
url,
|
|
209
|
+
prompt
|
|
210
|
+
});
|
|
211
|
+
if (filePartOptions?.fileData === true) throw new InvalidPromptError({
|
|
212
|
+
prompt,
|
|
213
|
+
message: "DeepSeek `fileData` image parts require inline data, not a URL."
|
|
214
|
+
});
|
|
215
|
+
userContent.push({
|
|
216
|
+
type: "image_url",
|
|
217
|
+
image_url: {
|
|
218
|
+
url,
|
|
219
|
+
...filePartOptions?.imageDetail != null && { detail: filePartOptions.imageDetail }
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
} else {
|
|
223
|
+
const dataUrl = `data:${resolvedMediaType === "image/jpg" ? "image/jpeg" : resolvedMediaType};base64,${convertToBase64(part.data.data)}`;
|
|
224
|
+
if (filePartOptions?.fileData === true) {
|
|
225
|
+
if (filePartOptions.imageDetail != null) throw new InvalidPromptError({
|
|
226
|
+
prompt,
|
|
227
|
+
message: "DeepSeek `imageDetail` cannot be combined with `fileData`."
|
|
228
|
+
});
|
|
229
|
+
userContent.push({
|
|
230
|
+
type: "file",
|
|
231
|
+
file_data: dataUrl,
|
|
232
|
+
...part.filename != null && { filename: part.filename }
|
|
233
|
+
});
|
|
234
|
+
} else userContent.push({
|
|
235
|
+
type: "image_url",
|
|
236
|
+
image_url: {
|
|
237
|
+
url: dataUrl,
|
|
238
|
+
...filePartOptions?.imageDetail != null && { detail: filePartOptions.imageDetail }
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
} else warnings.push({
|
|
243
|
+
type: "unsupported",
|
|
244
|
+
feature: `user message part type: ${part.type}`
|
|
245
|
+
});
|
|
246
|
+
} else warnings.push({
|
|
247
|
+
type: "unsupported",
|
|
248
|
+
feature: `user message part type: ${part.type}`
|
|
249
|
+
});
|
|
250
|
+
messages.push({
|
|
251
|
+
role: "user",
|
|
252
|
+
content: userContent,
|
|
253
|
+
...deepseekMessageOptions?.name != null && { name: deepseekMessageOptions.name }
|
|
254
|
+
});
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
case "assistant": {
|
|
258
|
+
if (deepseekMessageOptions?.prefix === true) {
|
|
259
|
+
if (index !== prompt.length - 1) throw new InvalidPromptError({
|
|
260
|
+
prompt,
|
|
261
|
+
message: "DeepSeek assistant prefix completion requires the prefixed assistant message to be the final message."
|
|
262
|
+
});
|
|
263
|
+
if (!supportsAssistantPrefixCompletion) throw new UnsupportedFunctionalityError({
|
|
264
|
+
functionality: "DeepSeek assistant prefix completion",
|
|
265
|
+
message: "DeepSeek assistant prefix completion requires a beta base URL ending in `/beta`."
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
let text = "";
|
|
269
|
+
let reasoning;
|
|
270
|
+
const toolCalls = [];
|
|
271
|
+
for (const part of content) switch (part.type) {
|
|
272
|
+
case "text":
|
|
273
|
+
text += part.text;
|
|
274
|
+
break;
|
|
275
|
+
case "reasoning":
|
|
276
|
+
if (index <= lastUserMessageIndex && !isDeepSeekV4) break;
|
|
277
|
+
if (reasoning == null) reasoning = part.text;
|
|
278
|
+
else reasoning += part.text;
|
|
279
|
+
break;
|
|
280
|
+
case "tool-call": toolCalls.push({
|
|
281
|
+
id: part.toolCallId,
|
|
282
|
+
type: "function",
|
|
283
|
+
function: {
|
|
284
|
+
name: part.toolName,
|
|
285
|
+
arguments: JSON.stringify(part.input)
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
messages.push({
|
|
290
|
+
role: "assistant",
|
|
291
|
+
content: text,
|
|
292
|
+
...deepseekMessageOptions?.name != null && { name: deepseekMessageOptions.name },
|
|
293
|
+
...deepseekMessageOptions?.prefix === true && { prefix: true },
|
|
294
|
+
reasoning_content: reasoning ?? (isDeepSeekV4 ? "" : void 0),
|
|
295
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
|
|
296
|
+
});
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
case "tool":
|
|
300
|
+
if (deepseekMessageOptions?.name != null) warnings.push({
|
|
301
|
+
type: "unsupported",
|
|
302
|
+
feature: "message name on tool messages"
|
|
303
|
+
});
|
|
304
|
+
for (const toolResponse of content) {
|
|
305
|
+
if (toolResponse.type === "tool-approval-response") continue;
|
|
306
|
+
const output = toolResponse.output;
|
|
307
|
+
let contentValue;
|
|
308
|
+
switch (output.type) {
|
|
309
|
+
case "text":
|
|
310
|
+
case "error-text":
|
|
311
|
+
contentValue = output.value;
|
|
312
|
+
break;
|
|
313
|
+
case "execution-denied":
|
|
314
|
+
contentValue = output.reason ?? "Tool call execution denied.";
|
|
315
|
+
break;
|
|
316
|
+
case "json":
|
|
317
|
+
case "error-json":
|
|
318
|
+
contentValue = JSON.stringify(output.value);
|
|
319
|
+
break;
|
|
320
|
+
case "content":
|
|
321
|
+
if (!output.value.some((part) => part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image")) {
|
|
322
|
+
contentValue = JSON.stringify(output.value);
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
contentValue = [];
|
|
326
|
+
for (const part of output.value) if (part.type === "text") contentValue.push({
|
|
327
|
+
type: "text",
|
|
328
|
+
text: part.text
|
|
329
|
+
});
|
|
330
|
+
else if (part.type === "file" && (part.data.type === "reference" || part.data.type === "url" || part.data.type === "data") && getTopLevelMediaType(part.mediaType) === "image") {
|
|
331
|
+
if (part.data.type === "reference") {
|
|
332
|
+
contentValue.push({
|
|
333
|
+
type: "file",
|
|
334
|
+
file_id: resolveProviderReference({
|
|
335
|
+
reference: part.data.reference,
|
|
336
|
+
provider: "deepseek"
|
|
337
|
+
})
|
|
338
|
+
});
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
const filePartOptions = await parseProviderOptions({
|
|
342
|
+
provider: providerOptionsName,
|
|
343
|
+
providerOptions: part.providerOptions,
|
|
344
|
+
schema: deepseekFilePartProviderOptions
|
|
345
|
+
});
|
|
346
|
+
const resolvedMediaType = resolveDeepSeekImageMediaType(part);
|
|
347
|
+
let url;
|
|
348
|
+
if (part.data.type === "url") {
|
|
349
|
+
url = part.data.url.toString();
|
|
350
|
+
validateDeepSeekImageUrl({
|
|
351
|
+
url,
|
|
352
|
+
prompt
|
|
353
|
+
});
|
|
354
|
+
} else url = `data:${resolvedMediaType === "image/jpg" ? "image/jpeg" : resolvedMediaType};base64,${convertToBase64(part.data.data)}`;
|
|
355
|
+
contentValue.push({
|
|
356
|
+
type: "image_url",
|
|
357
|
+
image_url: {
|
|
358
|
+
url,
|
|
359
|
+
...filePartOptions?.imageDetail != null && { detail: filePartOptions.imageDetail }
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
} else warnings.push({
|
|
363
|
+
type: "unsupported",
|
|
364
|
+
feature: `tool result content part type: ${part.type}`
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
messages.push({
|
|
368
|
+
role: "tool",
|
|
369
|
+
tool_call_id: toolResponse.toolCallId,
|
|
370
|
+
content: contentValue
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
break;
|
|
374
|
+
default: warnings.push({
|
|
375
|
+
type: "unsupported",
|
|
376
|
+
feature: `message role: ${role}`
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
messages,
|
|
382
|
+
warnings
|
|
383
|
+
};
|
|
482
384
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
import { createNullLanguageModelUsage } from "@ai-sdk/provider-utils";
|
|
385
|
+
//#endregion
|
|
386
|
+
//#region src/chat/convert-to-deepseek-usage.ts
|
|
486
387
|
function convertDeepSeekUsage(usage) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
raw: usage
|
|
507
|
-
};
|
|
388
|
+
if (usage == null) return createNullLanguageModelUsage();
|
|
389
|
+
const promptTokens = usage.prompt_tokens ?? 0;
|
|
390
|
+
const completionTokens = usage.completion_tokens ?? 0;
|
|
391
|
+
const cacheReadTokens = usage.prompt_cache_hit_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
392
|
+
const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? 0;
|
|
393
|
+
return {
|
|
394
|
+
inputTokens: {
|
|
395
|
+
total: promptTokens,
|
|
396
|
+
noCache: promptTokens - cacheReadTokens,
|
|
397
|
+
cacheRead: cacheReadTokens,
|
|
398
|
+
cacheWrite: void 0
|
|
399
|
+
},
|
|
400
|
+
outputTokens: {
|
|
401
|
+
total: completionTokens,
|
|
402
|
+
text: Math.max(0, completionTokens - reasoningTokens),
|
|
403
|
+
reasoning: reasoningTokens
|
|
404
|
+
},
|
|
405
|
+
raw: usage
|
|
406
|
+
};
|
|
508
407
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
prompt_tokens_details: z3.looseObject({
|
|
520
|
-
cached_tokens: z3.number().nullish()
|
|
521
|
-
}).nullish(),
|
|
522
|
-
completion_tokens_details: z3.looseObject({
|
|
523
|
-
reasoning_tokens: z3.number().nullish()
|
|
524
|
-
}).nullish()
|
|
408
|
+
//#endregion
|
|
409
|
+
//#region src/chat/deepseek-chat-api-types.ts
|
|
410
|
+
const tokenUsageSchema = z.looseObject({
|
|
411
|
+
prompt_tokens: z.number().nullish(),
|
|
412
|
+
completion_tokens: z.number().nullish(),
|
|
413
|
+
prompt_cache_hit_tokens: z.number().nullish(),
|
|
414
|
+
prompt_cache_miss_tokens: z.number().nullish(),
|
|
415
|
+
total_tokens: z.number().nullish(),
|
|
416
|
+
prompt_tokens_details: z.looseObject({ cached_tokens: z.number().nullish() }).nullish(),
|
|
417
|
+
completion_tokens_details: z.looseObject({ reasoning_tokens: z.number().nullish() }).nullish()
|
|
525
418
|
}).nullish();
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
logprob: z3.number(),
|
|
542
|
-
bytes: z3.array(z3.number()).nullable()
|
|
543
|
-
})
|
|
544
|
-
)
|
|
419
|
+
const deepSeekErrorSchema = z.object({ error: z.object({
|
|
420
|
+
message: z.string(),
|
|
421
|
+
type: z.string().nullish(),
|
|
422
|
+
param: z.any().nullish(),
|
|
423
|
+
code: z.union([z.string(), z.number()]).nullish()
|
|
424
|
+
}) });
|
|
425
|
+
const deepseekChatLogprobSchema = z.object({
|
|
426
|
+
token: z.string(),
|
|
427
|
+
logprob: z.number(),
|
|
428
|
+
bytes: z.array(z.number()).nullable(),
|
|
429
|
+
top_logprobs: z.array(z.object({
|
|
430
|
+
token: z.string(),
|
|
431
|
+
logprob: z.number(),
|
|
432
|
+
bytes: z.array(z.number()).nullable()
|
|
433
|
+
}))
|
|
545
434
|
});
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
435
|
+
const deepseekChatLogprobsSchema = z.object({
|
|
436
|
+
content: z.array(deepseekChatLogprobSchema).nullish(),
|
|
437
|
+
reasoning_content: z.array(deepseekChatLogprobSchema).nullish()
|
|
549
438
|
}).nullish();
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
finish_reason: z3.string().nullish()
|
|
576
|
-
})
|
|
577
|
-
),
|
|
578
|
-
usage: tokenUsageSchema
|
|
439
|
+
const deepseekChatResponseSchema = z.object({
|
|
440
|
+
id: z.string().nullish(),
|
|
441
|
+
created: z.number().nullish(),
|
|
442
|
+
model: z.string().nullish(),
|
|
443
|
+
object: z.literal("chat.completion").nullish(),
|
|
444
|
+
system_fingerprint: z.string().nullish(),
|
|
445
|
+
choices: z.array(z.object({
|
|
446
|
+
index: z.number().nullish(),
|
|
447
|
+
message: z.object({
|
|
448
|
+
role: z.literal("assistant").nullish(),
|
|
449
|
+
content: z.string().nullish(),
|
|
450
|
+
reasoning_content: z.string().nullish(),
|
|
451
|
+
tool_calls: z.array(z.object({
|
|
452
|
+
id: z.string().nullish(),
|
|
453
|
+
type: z.literal("function").nullish(),
|
|
454
|
+
function: z.object({
|
|
455
|
+
name: z.string(),
|
|
456
|
+
arguments: z.string()
|
|
457
|
+
})
|
|
458
|
+
})).nullish()
|
|
459
|
+
}),
|
|
460
|
+
logprobs: deepseekChatLogprobsSchema,
|
|
461
|
+
finish_reason: z.string().nullish()
|
|
462
|
+
})),
|
|
463
|
+
usage: tokenUsageSchema
|
|
579
464
|
});
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
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
|
-
case "none":
|
|
673
|
-
case "required":
|
|
674
|
-
return { tools: deepseekTools, toolChoice: type, toolWarnings };
|
|
675
|
-
case "tool":
|
|
676
|
-
return {
|
|
677
|
-
tools: deepseekTools,
|
|
678
|
-
toolChoice: {
|
|
679
|
-
type: "function",
|
|
680
|
-
function: { name: toolChoice.toolName }
|
|
681
|
-
},
|
|
682
|
-
toolWarnings
|
|
683
|
-
};
|
|
684
|
-
default: {
|
|
685
|
-
return {
|
|
686
|
-
tools: deepseekTools,
|
|
687
|
-
toolChoice: void 0,
|
|
688
|
-
toolWarnings: [
|
|
689
|
-
...toolWarnings,
|
|
690
|
-
{
|
|
691
|
-
type: "unsupported",
|
|
692
|
-
feature: `tool choice type: ${type}`
|
|
693
|
-
}
|
|
694
|
-
]
|
|
695
|
-
};
|
|
696
|
-
}
|
|
697
|
-
}
|
|
465
|
+
const deepseekChatChunkSchema = lazySchema(() => zodSchema(z.union([z.object({
|
|
466
|
+
id: z.string().nullish(),
|
|
467
|
+
created: z.number().nullish(),
|
|
468
|
+
model: z.string().nullish(),
|
|
469
|
+
object: z.literal("chat.completion.chunk").nullish(),
|
|
470
|
+
system_fingerprint: z.string().nullish(),
|
|
471
|
+
choices: z.array(z.object({
|
|
472
|
+
index: z.number().nullish(),
|
|
473
|
+
delta: z.object({
|
|
474
|
+
role: z.enum(["assistant"]).nullish(),
|
|
475
|
+
content: z.string().nullish(),
|
|
476
|
+
reasoning_content: z.string().nullish(),
|
|
477
|
+
tool_calls: z.array(z.object({
|
|
478
|
+
index: z.number(),
|
|
479
|
+
id: z.string().nullish(),
|
|
480
|
+
type: z.literal("function").nullish(),
|
|
481
|
+
function: z.object({
|
|
482
|
+
name: z.string().nullish(),
|
|
483
|
+
arguments: z.string().nullish()
|
|
484
|
+
})
|
|
485
|
+
})).nullish()
|
|
486
|
+
}).nullish(),
|
|
487
|
+
logprobs: deepseekChatLogprobsSchema,
|
|
488
|
+
finish_reason: z.string().nullish()
|
|
489
|
+
})),
|
|
490
|
+
usage: tokenUsageSchema
|
|
491
|
+
}), deepSeekErrorSchema])));
|
|
492
|
+
//#endregion
|
|
493
|
+
//#region src/chat/deepseek-prepare-tools.ts
|
|
494
|
+
function prepareTools({ tools, toolChoice, supportsStrictToolCalls }) {
|
|
495
|
+
tools = tools?.length ? tools : void 0;
|
|
496
|
+
const toolWarnings = [];
|
|
497
|
+
if (tools == null) return {
|
|
498
|
+
tools: void 0,
|
|
499
|
+
toolChoice: void 0,
|
|
500
|
+
toolWarnings
|
|
501
|
+
};
|
|
502
|
+
const functionTools = tools.filter((tool) => tool.type === "function");
|
|
503
|
+
const hasStrictTool = functionTools.some((tool) => tool.strict === true);
|
|
504
|
+
if (hasStrictTool && supportsStrictToolCalls === false) throw new UnsupportedFunctionalityError({
|
|
505
|
+
functionality: "DeepSeek strict tool calls",
|
|
506
|
+
message: "DeepSeek strict tool calls require a beta base URL ending in `/beta`."
|
|
507
|
+
});
|
|
508
|
+
if (hasStrictTool && supportsStrictToolCalls === true && functionTools.some((tool) => tool.strict !== true)) throw new UnsupportedFunctionalityError({
|
|
509
|
+
functionality: "mixed DeepSeek strict and non-strict tool calls",
|
|
510
|
+
message: "DeepSeek strict mode requires every function tool in the request to set `strict: true`."
|
|
511
|
+
});
|
|
512
|
+
const deepseekTools = [];
|
|
513
|
+
for (const tool of tools) if (tool.type === "provider") toolWarnings.push({
|
|
514
|
+
type: "unsupported",
|
|
515
|
+
feature: `provider-defined tool ${tool.id}`
|
|
516
|
+
});
|
|
517
|
+
else deepseekTools.push({
|
|
518
|
+
type: "function",
|
|
519
|
+
function: {
|
|
520
|
+
name: tool.name,
|
|
521
|
+
description: tool.description,
|
|
522
|
+
parameters: tool.inputSchema,
|
|
523
|
+
...tool.strict != null ? { strict: tool.strict } : {}
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
if (toolChoice == null) return {
|
|
527
|
+
tools: deepseekTools,
|
|
528
|
+
toolChoice: void 0,
|
|
529
|
+
toolWarnings
|
|
530
|
+
};
|
|
531
|
+
const type = toolChoice?.type;
|
|
532
|
+
switch (type) {
|
|
533
|
+
case "auto":
|
|
534
|
+
case "none":
|
|
535
|
+
case "required": return {
|
|
536
|
+
tools: deepseekTools,
|
|
537
|
+
toolChoice: type,
|
|
538
|
+
toolWarnings
|
|
539
|
+
};
|
|
540
|
+
case "tool": return {
|
|
541
|
+
tools: deepseekTools,
|
|
542
|
+
toolChoice: {
|
|
543
|
+
type: "function",
|
|
544
|
+
function: { name: toolChoice.toolName }
|
|
545
|
+
},
|
|
546
|
+
toolWarnings
|
|
547
|
+
};
|
|
548
|
+
default: return {
|
|
549
|
+
tools: deepseekTools,
|
|
550
|
+
toolChoice: void 0,
|
|
551
|
+
toolWarnings: [...toolWarnings, {
|
|
552
|
+
type: "unsupported",
|
|
553
|
+
feature: `tool choice type: ${type}`
|
|
554
|
+
}]
|
|
555
|
+
};
|
|
556
|
+
}
|
|
698
557
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
import { createLanguageModelResponseMetadata } from "@ai-sdk/provider-utils";
|
|
702
|
-
|
|
703
|
-
// src/chat/map-deepseek-finish-reason.ts
|
|
558
|
+
//#endregion
|
|
559
|
+
//#region src/chat/map-deepseek-finish-reason.ts
|
|
704
560
|
function mapDeepSeekFinishReason(finishReason) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
return "tool-calls";
|
|
714
|
-
case "insufficient_system_resource":
|
|
715
|
-
return "error";
|
|
716
|
-
default:
|
|
717
|
-
return "other";
|
|
718
|
-
}
|
|
561
|
+
switch (finishReason) {
|
|
562
|
+
case "stop": return "stop";
|
|
563
|
+
case "length": return "length";
|
|
564
|
+
case "content_filter": return "content-filter";
|
|
565
|
+
case "tool_calls": return "tool-calls";
|
|
566
|
+
case "insufficient_system_resource": return "error";
|
|
567
|
+
default: return "other";
|
|
568
|
+
}
|
|
719
569
|
}
|
|
720
|
-
|
|
721
|
-
|
|
570
|
+
//#endregion
|
|
571
|
+
//#region src/chat/deepseek-chat-language-model.ts
|
|
722
572
|
function createDeepSeekStreamError(error, data) {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
573
|
+
const metadata = getDeepSeekStreamErrorMetadata(error);
|
|
574
|
+
return createProviderStreamError({
|
|
575
|
+
message: error.message,
|
|
576
|
+
type: error.type ?? void 0,
|
|
577
|
+
code: error.code ?? void 0,
|
|
578
|
+
...metadata,
|
|
579
|
+
data
|
|
580
|
+
});
|
|
731
581
|
}
|
|
732
582
|
function getDeepSeekStreamErrorMetadata(error) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
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
|
-
|
|
583
|
+
if (error.code === "insufficient_quota" || error.type === "insufficient_quota") return {
|
|
584
|
+
statusCode: 429,
|
|
585
|
+
isRetryable: false
|
|
586
|
+
};
|
|
587
|
+
const explicitStatusCode = getHttpStatusCode(error.code);
|
|
588
|
+
if (explicitStatusCode != null) return {
|
|
589
|
+
statusCode: explicitStatusCode,
|
|
590
|
+
isRetryable: isRetryableStatusCode(explicitStatusCode)
|
|
591
|
+
};
|
|
592
|
+
for (const discriminator of [error.code, error.type]) switch (discriminator) {
|
|
593
|
+
case "rate_limit_exceeded":
|
|
594
|
+
case "rate_limit_error": return {
|
|
595
|
+
statusCode: 429,
|
|
596
|
+
isRetryable: true
|
|
597
|
+
};
|
|
598
|
+
case "server_error":
|
|
599
|
+
case "api_error":
|
|
600
|
+
case "internal_server_error": return {
|
|
601
|
+
statusCode: 500,
|
|
602
|
+
isRetryable: true
|
|
603
|
+
};
|
|
604
|
+
case "overloaded_error":
|
|
605
|
+
case "service_unavailable": return {
|
|
606
|
+
statusCode: 503,
|
|
607
|
+
isRetryable: true
|
|
608
|
+
};
|
|
609
|
+
case "timeout":
|
|
610
|
+
case "timeout_error": return {
|
|
611
|
+
statusCode: 504,
|
|
612
|
+
isRetryable: true
|
|
613
|
+
};
|
|
614
|
+
case "authentication_error":
|
|
615
|
+
case "invalid_api_key": return {
|
|
616
|
+
statusCode: 401,
|
|
617
|
+
isRetryable: false
|
|
618
|
+
};
|
|
619
|
+
case "permission_error": return {
|
|
620
|
+
statusCode: 403,
|
|
621
|
+
isRetryable: false
|
|
622
|
+
};
|
|
623
|
+
case "not_found_error":
|
|
624
|
+
case "model_not_found": return {
|
|
625
|
+
statusCode: 404,
|
|
626
|
+
isRetryable: false
|
|
627
|
+
};
|
|
628
|
+
case "bad_request":
|
|
629
|
+
case "context_length_exceeded":
|
|
630
|
+
case "invalid_request_error": return {
|
|
631
|
+
statusCode: 400,
|
|
632
|
+
isRetryable: false
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
return {};
|
|
773
636
|
}
|
|
774
637
|
function getHttpStatusCode(value) {
|
|
775
|
-
|
|
776
|
-
|
|
638
|
+
const statusCode = typeof value === "string" && /^\d{3}$/.test(value) ? Number(value) : value;
|
|
639
|
+
return typeof statusCode === "number" && Number.isInteger(statusCode) && statusCode >= 400 && statusCode <= 599 ? statusCode : void 0;
|
|
777
640
|
}
|
|
778
641
|
function isRetryableStatusCode(statusCode) {
|
|
779
|
-
|
|
642
|
+
return statusCode === 408 || statusCode === 409 || statusCode === 429 || statusCode >= 500;
|
|
780
643
|
}
|
|
781
|
-
function mapDeepSeekProviderReasoningEffort({
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
feature: "reasoningEffort",
|
|
790
|
-
details: `reasoningEffort "${reasoningEffort}" is not a canonical DeepSeek value. mapped to "${mapped}".`
|
|
791
|
-
});
|
|
792
|
-
}
|
|
793
|
-
return mapped;
|
|
644
|
+
function mapDeepSeekProviderReasoningEffort({ reasoningEffort, warnings }) {
|
|
645
|
+
const mapped = reasoningEffort === "medium" ? "high" : reasoningEffort === "xhigh" ? "max" : reasoningEffort;
|
|
646
|
+
if (mapped !== reasoningEffort) warnings.push({
|
|
647
|
+
type: "compatibility",
|
|
648
|
+
feature: "reasoningEffort",
|
|
649
|
+
details: `reasoningEffort "${reasoningEffort}" is not a canonical DeepSeek value. mapped to "${mapped}".`
|
|
650
|
+
});
|
|
651
|
+
return mapped;
|
|
794
652
|
}
|
|
795
|
-
var DeepSeekChatLanguageModel = class
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
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
|
-
if (!isActiveText) {
|
|
1164
|
-
controller.enqueue({ type: "text-start", id: "txt-0" });
|
|
1165
|
-
isActiveText = true;
|
|
1166
|
-
}
|
|
1167
|
-
if (isActiveReasoning) {
|
|
1168
|
-
controller.enqueue({
|
|
1169
|
-
type: "reasoning-end",
|
|
1170
|
-
id: "reasoning-0"
|
|
1171
|
-
});
|
|
1172
|
-
isActiveReasoning = false;
|
|
1173
|
-
}
|
|
1174
|
-
controller.enqueue({
|
|
1175
|
-
type: "text-delta",
|
|
1176
|
-
id: "txt-0",
|
|
1177
|
-
delta: delta.content
|
|
1178
|
-
});
|
|
1179
|
-
}
|
|
1180
|
-
if (delta.tool_calls != null && delta.tool_calls.length > 0) {
|
|
1181
|
-
if (isActiveReasoning) {
|
|
1182
|
-
controller.enqueue({
|
|
1183
|
-
type: "reasoning-end",
|
|
1184
|
-
id: "reasoning-0"
|
|
1185
|
-
});
|
|
1186
|
-
isActiveReasoning = false;
|
|
1187
|
-
}
|
|
1188
|
-
for (const toolCallDelta of delta.tool_calls) {
|
|
1189
|
-
if (toolCallDelta.type != null) {
|
|
1190
|
-
toolCallTypes.set(toolCallDelta.index, toolCallDelta.type);
|
|
1191
|
-
}
|
|
1192
|
-
toolCallTracker.processDelta(toolCallDelta);
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
},
|
|
1196
|
-
flush(controller) {
|
|
1197
|
-
if (isActiveReasoning) {
|
|
1198
|
-
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
1199
|
-
}
|
|
1200
|
-
if (isActiveText) {
|
|
1201
|
-
controller.enqueue({ type: "text-end", id: "txt-0" });
|
|
1202
|
-
}
|
|
1203
|
-
toolCallTracker.flush();
|
|
1204
|
-
controller.enqueue({
|
|
1205
|
-
type: "finish",
|
|
1206
|
-
finishReason,
|
|
1207
|
-
usage: convertDeepSeekUsage(usage),
|
|
1208
|
-
providerMetadata: {
|
|
1209
|
-
[providerOptionsName]: {
|
|
1210
|
-
promptCacheHitTokens: usage?.prompt_cache_hit_tokens ?? void 0,
|
|
1211
|
-
promptCacheMissTokens: usage?.prompt_cache_miss_tokens ?? void 0,
|
|
1212
|
-
...responseObject != null && { responseObject },
|
|
1213
|
-
...choiceIndex != null && { choiceIndex },
|
|
1214
|
-
...messageRole != null && { messageRole },
|
|
1215
|
-
...toolCallTypes.size > 0 && {
|
|
1216
|
-
toolCallTypes: [...toolCallTypes.entries()].sort(([left], [right]) => left - right).map(([, type]) => type)
|
|
1217
|
-
},
|
|
1218
|
-
...(contentLogprobs.length > 0 || reasoningLogprobs.length > 0) && {
|
|
1219
|
-
logprobs: {
|
|
1220
|
-
...contentLogprobs.length > 0 && {
|
|
1221
|
-
content: contentLogprobs
|
|
1222
|
-
},
|
|
1223
|
-
...reasoningLogprobs.length > 0 && {
|
|
1224
|
-
reasoning_content: reasoningLogprobs
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
},
|
|
1228
|
-
...systemFingerprint != null && { systemFingerprint }
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
})
|
|
1234
|
-
),
|
|
1235
|
-
request: { body },
|
|
1236
|
-
response: { headers: responseHeaders }
|
|
1237
|
-
};
|
|
1238
|
-
}
|
|
1239
|
-
};
|
|
1240
|
-
export {
|
|
1241
|
-
DeepSeekChatLanguageModel,
|
|
1242
|
-
deepseekAssistantMessageProviderOptions,
|
|
1243
|
-
deepseekLanguageModelChatOptions,
|
|
1244
|
-
deepseekMessageProviderOptions
|
|
653
|
+
var DeepSeekChatLanguageModel = class DeepSeekChatLanguageModel {
|
|
654
|
+
static [WORKFLOW_SERIALIZE](model) {
|
|
655
|
+
return serializeModelOptions({
|
|
656
|
+
modelId: model.modelId,
|
|
657
|
+
config: model.config
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
static [WORKFLOW_DESERIALIZE](options) {
|
|
661
|
+
return new DeepSeekChatLanguageModel(options.modelId, options.config);
|
|
662
|
+
}
|
|
663
|
+
constructor(modelId, config) {
|
|
664
|
+
this.specificationVersion = "v4";
|
|
665
|
+
this.supportedUrls = { "image/*": [/^https?:\/\/.*$/] };
|
|
666
|
+
this.modelId = modelId;
|
|
667
|
+
this.config = config;
|
|
668
|
+
this.failedResponseHandler = createJsonErrorResponseHandler({
|
|
669
|
+
errorSchema: deepSeekErrorSchema,
|
|
670
|
+
errorToMessage: (error) => error.error.message
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
get provider() {
|
|
674
|
+
return this.config.provider;
|
|
675
|
+
}
|
|
676
|
+
get providerOptionsName() {
|
|
677
|
+
return this.config.provider.split(".")[0].trim();
|
|
678
|
+
}
|
|
679
|
+
async getArgs({ prompt, maxOutputTokens, temperature, topP, topK, frequencyPenalty, presencePenalty, reasoning, providerOptions, stopSequences, responseFormat, seed, toolChoice, tools }) {
|
|
680
|
+
const deepseekOptions = await parseProviderOptions({
|
|
681
|
+
provider: this.providerOptionsName,
|
|
682
|
+
providerOptions,
|
|
683
|
+
schema: deepseekLanguageModelChatOptions
|
|
684
|
+
}) ?? {};
|
|
685
|
+
const supportsStructuredOutputs = this.config.supportsStructuredOutputs === true;
|
|
686
|
+
const supportsPenaltySampling = this.config.supportsPenaltySampling === true;
|
|
687
|
+
const { messages, warnings } = await convertToDeepSeekChatMessages({
|
|
688
|
+
prompt,
|
|
689
|
+
responseFormat,
|
|
690
|
+
modelId: this.modelId,
|
|
691
|
+
providerOptionsName: this.providerOptionsName,
|
|
692
|
+
supportsAssistantPrefixCompletion: this.config.supportsAssistantPrefixCompletion,
|
|
693
|
+
supportsStructuredOutputs
|
|
694
|
+
});
|
|
695
|
+
const allWarnings = [...warnings];
|
|
696
|
+
if (topK != null) allWarnings.push({
|
|
697
|
+
type: "unsupported",
|
|
698
|
+
feature: "topK"
|
|
699
|
+
});
|
|
700
|
+
if (seed != null) allWarnings.push({
|
|
701
|
+
type: "unsupported",
|
|
702
|
+
feature: "seed"
|
|
703
|
+
});
|
|
704
|
+
if (!supportsPenaltySampling && frequencyPenalty != null) allWarnings.push({
|
|
705
|
+
type: "deprecated",
|
|
706
|
+
setting: "frequencyPenalty",
|
|
707
|
+
message: "frequencyPenalty is deprecated by DeepSeek and has been omitted. Remove frequencyPenalty from the request."
|
|
708
|
+
});
|
|
709
|
+
if (!supportsPenaltySampling && presencePenalty != null) allWarnings.push({
|
|
710
|
+
type: "deprecated",
|
|
711
|
+
setting: "presencePenalty",
|
|
712
|
+
message: "presencePenalty is deprecated by DeepSeek and has been omitted. Remove presencePenalty from the request."
|
|
713
|
+
});
|
|
714
|
+
const { tools: deepseekTools, toolChoice: deepseekToolChoices, toolWarnings } = prepareTools({
|
|
715
|
+
tools,
|
|
716
|
+
toolChoice,
|
|
717
|
+
supportsStrictToolCalls: this.config.supportsStrictToolCalls
|
|
718
|
+
});
|
|
719
|
+
const thinkingType = deepseekOptions.thinking?.type;
|
|
720
|
+
if (thinkingType === "adaptive") allWarnings.push({
|
|
721
|
+
type: "compatibility",
|
|
722
|
+
feature: "thinking.type",
|
|
723
|
+
details: "thinking.type \"adaptive\" is not a canonical DeepSeek value. mapped to \"enabled\"."
|
|
724
|
+
});
|
|
725
|
+
const thinking = this.config.supportsThinking === false ? void 0 : thinkingType != null ? { type: thinkingType === "adaptive" ? "enabled" : thinkingType } : isCustomReasoning(reasoning) ? { type: reasoning === "none" ? "disabled" : "enabled" } : void 0;
|
|
726
|
+
const isThinkingEnabled = this.config.supportsThinking !== false && thinking?.type !== "disabled" && (thinking != null || this.modelId === "deepseek-reasoner" || isDeepSeekV4Model(this.modelId));
|
|
727
|
+
if (isThinkingEnabled && temperature != null) allWarnings.push({
|
|
728
|
+
type: "unsupported",
|
|
729
|
+
feature: "temperature",
|
|
730
|
+
details: "temperature has no effect when DeepSeek thinking is enabled. Set providerOptions.deepseek.thinking.type to 'disabled' to use temperature."
|
|
731
|
+
});
|
|
732
|
+
if (isThinkingEnabled && topP != null) allWarnings.push({
|
|
733
|
+
type: "unsupported",
|
|
734
|
+
feature: "topP",
|
|
735
|
+
details: "topP has no effect when DeepSeek thinking is enabled. Set providerOptions.deepseek.thinking.type to 'disabled' to use topP."
|
|
736
|
+
});
|
|
737
|
+
const reasoningEffort = deepseekOptions.reasoningEffort != null ? mapDeepSeekProviderReasoningEffort({
|
|
738
|
+
reasoningEffort: deepseekOptions.reasoningEffort,
|
|
739
|
+
warnings: allWarnings
|
|
740
|
+
}) : isCustomReasoning(reasoning) && reasoning !== "none" ? mapReasoningToProviderEffort({
|
|
741
|
+
reasoning,
|
|
742
|
+
effortMap: {
|
|
743
|
+
minimal: "low",
|
|
744
|
+
low: "low",
|
|
745
|
+
medium: "high",
|
|
746
|
+
high: "high",
|
|
747
|
+
xhigh: "max"
|
|
748
|
+
},
|
|
749
|
+
warnings: allWarnings
|
|
750
|
+
}) : void 0;
|
|
751
|
+
return {
|
|
752
|
+
args: {
|
|
753
|
+
model: this.modelId,
|
|
754
|
+
...(deepseekOptions.logprobs === true || deepseekOptions.topLogprobs != null) && { logprobs: true },
|
|
755
|
+
...deepseekOptions.topLogprobs != null && { top_logprobs: deepseekOptions.topLogprobs },
|
|
756
|
+
max_tokens: maxOutputTokens,
|
|
757
|
+
temperature: isThinkingEnabled ? void 0 : temperature,
|
|
758
|
+
top_p: isThinkingEnabled ? void 0 : topP,
|
|
759
|
+
frequency_penalty: supportsPenaltySampling ? frequencyPenalty : void 0,
|
|
760
|
+
presence_penalty: supportsPenaltySampling ? presencePenalty : void 0,
|
|
761
|
+
response_format: responseFormat?.type === "json" ? supportsStructuredOutputs && responseFormat.schema != null ? {
|
|
762
|
+
type: "json_schema",
|
|
763
|
+
json_schema: {
|
|
764
|
+
schema: responseFormat.schema,
|
|
765
|
+
strict: deepseekOptions.strictJsonSchema ?? true,
|
|
766
|
+
name: responseFormat.name ?? "response",
|
|
767
|
+
description: responseFormat.description
|
|
768
|
+
}
|
|
769
|
+
} : { type: "json_object" } : void 0,
|
|
770
|
+
stop: stopSequences,
|
|
771
|
+
messages,
|
|
772
|
+
tools: deepseekTools,
|
|
773
|
+
tool_choice: deepseekToolChoices,
|
|
774
|
+
thinking,
|
|
775
|
+
...deepseekOptions.userId != null && { user_id: deepseekOptions.userId },
|
|
776
|
+
...thinking?.type !== "disabled" && reasoningEffort != null && { reasoning_effort: reasoningEffort }
|
|
777
|
+
},
|
|
778
|
+
warnings: [...allWarnings, ...toolWarnings]
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
async doGenerate(options) {
|
|
782
|
+
const { args, warnings } = await this.getArgs({ ...options });
|
|
783
|
+
const { responseHeaders, value: responseBody, rawValue: rawResponse } = await postJsonToApi({
|
|
784
|
+
url: this.config.url({
|
|
785
|
+
path: "/chat/completions",
|
|
786
|
+
modelId: this.modelId
|
|
787
|
+
}),
|
|
788
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
789
|
+
body: args,
|
|
790
|
+
failedResponseHandler: this.failedResponseHandler,
|
|
791
|
+
successfulResponseHandler: createJsonResponseHandler(deepseekChatResponseSchema),
|
|
792
|
+
abortSignal: options.abortSignal,
|
|
793
|
+
fetch: this.config.fetch
|
|
794
|
+
});
|
|
795
|
+
const choice = responseBody.choices[0];
|
|
796
|
+
if (choice == null) throw new InvalidResponseDataError({
|
|
797
|
+
data: rawResponse,
|
|
798
|
+
message: "Response did not contain any choices."
|
|
799
|
+
});
|
|
800
|
+
const content = [];
|
|
801
|
+
const reasoning = choice.message.reasoning_content;
|
|
802
|
+
if (reasoning != null && reasoning.length > 0) content.push({
|
|
803
|
+
type: "reasoning",
|
|
804
|
+
text: reasoning
|
|
805
|
+
});
|
|
806
|
+
if (choice.message.tool_calls != null) for (const toolCall of choice.message.tool_calls) content.push({
|
|
807
|
+
type: "tool-call",
|
|
808
|
+
toolCallId: toolCall.id || generateId(),
|
|
809
|
+
toolName: toolCall.function.name,
|
|
810
|
+
input: toolCall.function.arguments
|
|
811
|
+
});
|
|
812
|
+
const text = choice.message.content;
|
|
813
|
+
if (text != null && text.length > 0) content.push({
|
|
814
|
+
type: "text",
|
|
815
|
+
text
|
|
816
|
+
});
|
|
817
|
+
return {
|
|
818
|
+
content,
|
|
819
|
+
finishReason: {
|
|
820
|
+
unified: mapDeepSeekFinishReason(choice.finish_reason),
|
|
821
|
+
raw: choice.finish_reason ?? void 0
|
|
822
|
+
},
|
|
823
|
+
usage: convertDeepSeekUsage(responseBody.usage),
|
|
824
|
+
providerMetadata: { [this.providerOptionsName]: {
|
|
825
|
+
promptCacheHitTokens: responseBody.usage?.prompt_cache_hit_tokens,
|
|
826
|
+
promptCacheMissTokens: responseBody.usage?.prompt_cache_miss_tokens,
|
|
827
|
+
...responseBody.object != null && { responseObject: responseBody.object },
|
|
828
|
+
...choice.index != null && { choiceIndex: choice.index },
|
|
829
|
+
...choice.message.role != null && { messageRole: choice.message.role },
|
|
830
|
+
...choice.message.tool_calls != null && { toolCallTypes: choice.message.tool_calls.map((toolCall) => toolCall.type).filter((type) => type != null) },
|
|
831
|
+
...choice.logprobs != null && { logprobs: choice.logprobs },
|
|
832
|
+
...responseBody.system_fingerprint != null && { systemFingerprint: responseBody.system_fingerprint }
|
|
833
|
+
} },
|
|
834
|
+
request: { body: args },
|
|
835
|
+
response: {
|
|
836
|
+
...getResponseMetadata(responseBody),
|
|
837
|
+
headers: responseHeaders,
|
|
838
|
+
body: rawResponse
|
|
839
|
+
},
|
|
840
|
+
warnings
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
async doStream(options) {
|
|
844
|
+
const { args, warnings } = await this.getArgs({ ...options });
|
|
845
|
+
const body = {
|
|
846
|
+
...args,
|
|
847
|
+
stream: true,
|
|
848
|
+
stream_options: { include_usage: true }
|
|
849
|
+
};
|
|
850
|
+
const { responseHeaders, value: response } = await postJsonToApi({
|
|
851
|
+
url: this.config.url({
|
|
852
|
+
path: "/chat/completions",
|
|
853
|
+
modelId: this.modelId
|
|
854
|
+
}),
|
|
855
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
856
|
+
body,
|
|
857
|
+
failedResponseHandler: this.failedResponseHandler,
|
|
858
|
+
successfulResponseHandler: createEventSourceResponseHandler(deepseekChatChunkSchema),
|
|
859
|
+
abortSignal: options.abortSignal,
|
|
860
|
+
fetch: this.config.fetch
|
|
861
|
+
});
|
|
862
|
+
let toolCallTracker;
|
|
863
|
+
let finishReason = {
|
|
864
|
+
unified: "other",
|
|
865
|
+
raw: void 0
|
|
866
|
+
};
|
|
867
|
+
let usage = void 0;
|
|
868
|
+
let systemFingerprint = void 0;
|
|
869
|
+
let isFirstChunk = true;
|
|
870
|
+
const providerOptionsName = this.providerOptionsName;
|
|
871
|
+
let isActiveReasoning = false;
|
|
872
|
+
let isActiveText = false;
|
|
873
|
+
let responseObject;
|
|
874
|
+
let choiceIndex;
|
|
875
|
+
let messageRole;
|
|
876
|
+
const toolCallTypes = /* @__PURE__ */ new Map();
|
|
877
|
+
const contentLogprobs = [];
|
|
878
|
+
const reasoningLogprobs = [];
|
|
879
|
+
return {
|
|
880
|
+
stream: response.pipeThrough(new TransformStream({
|
|
881
|
+
start(controller) {
|
|
882
|
+
toolCallTracker = new StreamingToolCallTracker(controller, { generateId });
|
|
883
|
+
controller.enqueue({
|
|
884
|
+
type: "stream-start",
|
|
885
|
+
warnings
|
|
886
|
+
});
|
|
887
|
+
},
|
|
888
|
+
transform(chunk, controller) {
|
|
889
|
+
if (options.includeRawChunks) controller.enqueue({
|
|
890
|
+
type: "raw",
|
|
891
|
+
rawValue: chunk.rawValue
|
|
892
|
+
});
|
|
893
|
+
if (!chunk.success) {
|
|
894
|
+
finishReason = {
|
|
895
|
+
unified: "error",
|
|
896
|
+
raw: void 0
|
|
897
|
+
};
|
|
898
|
+
controller.enqueue({
|
|
899
|
+
type: "error",
|
|
900
|
+
error: chunk.error
|
|
901
|
+
});
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
const value = chunk.value;
|
|
905
|
+
if ("error" in value) {
|
|
906
|
+
finishReason = {
|
|
907
|
+
unified: "error",
|
|
908
|
+
raw: void 0
|
|
909
|
+
};
|
|
910
|
+
controller.enqueue({
|
|
911
|
+
type: "error",
|
|
912
|
+
error: createDeepSeekStreamError(value.error, value)
|
|
913
|
+
});
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
if (isFirstChunk) {
|
|
917
|
+
isFirstChunk = false;
|
|
918
|
+
controller.enqueue({
|
|
919
|
+
type: "response-metadata",
|
|
920
|
+
...getResponseMetadata(value)
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
if (value.usage != null) usage = value.usage;
|
|
924
|
+
if (value.object != null) responseObject = value.object;
|
|
925
|
+
if (value.system_fingerprint != null) systemFingerprint = value.system_fingerprint;
|
|
926
|
+
const choice = value.choices[0];
|
|
927
|
+
if (choice?.index != null) choiceIndex = choice.index;
|
|
928
|
+
if (choice?.finish_reason != null) finishReason = {
|
|
929
|
+
unified: mapDeepSeekFinishReason(choice.finish_reason),
|
|
930
|
+
raw: choice.finish_reason
|
|
931
|
+
};
|
|
932
|
+
if (choice?.logprobs?.content != null) contentLogprobs.push(...choice.logprobs.content);
|
|
933
|
+
if (choice?.logprobs?.reasoning_content != null) reasoningLogprobs.push(...choice.logprobs.reasoning_content);
|
|
934
|
+
if (choice?.delta == null) return;
|
|
935
|
+
const delta = choice.delta;
|
|
936
|
+
if (delta.role != null) messageRole = delta.role;
|
|
937
|
+
const reasoningContent = delta.reasoning_content;
|
|
938
|
+
if (reasoningContent) {
|
|
939
|
+
if (!isActiveReasoning) {
|
|
940
|
+
controller.enqueue({
|
|
941
|
+
type: "reasoning-start",
|
|
942
|
+
id: "reasoning-0"
|
|
943
|
+
});
|
|
944
|
+
isActiveReasoning = true;
|
|
945
|
+
}
|
|
946
|
+
controller.enqueue({
|
|
947
|
+
type: "reasoning-delta",
|
|
948
|
+
id: "reasoning-0",
|
|
949
|
+
delta: reasoningContent
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
if (delta.content) {
|
|
953
|
+
if (!isActiveText) {
|
|
954
|
+
controller.enqueue({
|
|
955
|
+
type: "text-start",
|
|
956
|
+
id: "txt-0"
|
|
957
|
+
});
|
|
958
|
+
isActiveText = true;
|
|
959
|
+
}
|
|
960
|
+
if (isActiveReasoning) {
|
|
961
|
+
controller.enqueue({
|
|
962
|
+
type: "reasoning-end",
|
|
963
|
+
id: "reasoning-0"
|
|
964
|
+
});
|
|
965
|
+
isActiveReasoning = false;
|
|
966
|
+
}
|
|
967
|
+
controller.enqueue({
|
|
968
|
+
type: "text-delta",
|
|
969
|
+
id: "txt-0",
|
|
970
|
+
delta: delta.content
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
if (delta.tool_calls != null && delta.tool_calls.length > 0) {
|
|
974
|
+
if (isActiveReasoning) {
|
|
975
|
+
controller.enqueue({
|
|
976
|
+
type: "reasoning-end",
|
|
977
|
+
id: "reasoning-0"
|
|
978
|
+
});
|
|
979
|
+
isActiveReasoning = false;
|
|
980
|
+
}
|
|
981
|
+
for (const toolCallDelta of delta.tool_calls) {
|
|
982
|
+
if (toolCallDelta.type != null) toolCallTypes.set(toolCallDelta.index, toolCallDelta.type);
|
|
983
|
+
toolCallTracker.processDelta(toolCallDelta);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
},
|
|
987
|
+
flush(controller) {
|
|
988
|
+
if (isActiveReasoning) controller.enqueue({
|
|
989
|
+
type: "reasoning-end",
|
|
990
|
+
id: "reasoning-0"
|
|
991
|
+
});
|
|
992
|
+
if (isActiveText) controller.enqueue({
|
|
993
|
+
type: "text-end",
|
|
994
|
+
id: "txt-0"
|
|
995
|
+
});
|
|
996
|
+
toolCallTracker.flush();
|
|
997
|
+
controller.enqueue({
|
|
998
|
+
type: "finish",
|
|
999
|
+
finishReason,
|
|
1000
|
+
usage: convertDeepSeekUsage(usage),
|
|
1001
|
+
providerMetadata: { [providerOptionsName]: {
|
|
1002
|
+
promptCacheHitTokens: usage?.prompt_cache_hit_tokens ?? void 0,
|
|
1003
|
+
promptCacheMissTokens: usage?.prompt_cache_miss_tokens ?? void 0,
|
|
1004
|
+
...responseObject != null && { responseObject },
|
|
1005
|
+
...choiceIndex != null && { choiceIndex },
|
|
1006
|
+
...messageRole != null && { messageRole },
|
|
1007
|
+
...toolCallTypes.size > 0 && { toolCallTypes: [...toolCallTypes.entries()].sort(([left], [right]) => left - right).map(([, type]) => type) },
|
|
1008
|
+
...(contentLogprobs.length > 0 || reasoningLogprobs.length > 0) && { logprobs: {
|
|
1009
|
+
...contentLogprobs.length > 0 && { content: contentLogprobs },
|
|
1010
|
+
...reasoningLogprobs.length > 0 && { reasoning_content: reasoningLogprobs }
|
|
1011
|
+
} },
|
|
1012
|
+
...systemFingerprint != null && { systemFingerprint }
|
|
1013
|
+
} }
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
})),
|
|
1017
|
+
request: { body },
|
|
1018
|
+
response: { headers: responseHeaders }
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1245
1021
|
};
|
|
1022
|
+
//#endregion
|
|
1023
|
+
export { DeepSeekChatLanguageModel, deepseekAssistantMessageProviderOptions, deepseekLanguageModelChatOptions, deepseekMessageProviderOptions };
|
|
1024
|
+
|
|
1246
1025
|
//# sourceMappingURL=index.js.map
|