@ai-sdk/deepseek 3.0.31 → 3.0.32

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/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  generateId,
18
18
  isCustomReasoning,
19
19
  mapReasoningToProviderEffort,
20
- parseProviderOptions,
20
+ parseProviderOptions as parseProviderOptions2,
21
21
  postJsonToApi,
22
22
  serializeModelOptions,
23
23
  StreamingToolCallTracker,
@@ -26,16 +26,113 @@ import {
26
26
  } from "@ai-sdk/provider-utils";
27
27
 
28
28
  // src/chat/convert-to-deepseek-chat-messages.ts
29
+ import {
30
+ InvalidPromptError,
31
+ UnsupportedFunctionalityError
32
+ } from "@ai-sdk/provider";
29
33
  import {
30
34
  convertToBase64,
31
35
  getTopLevelMediaType,
36
+ parseProviderOptions,
32
37
  resolveFullMediaType,
33
38
  resolveProviderReference
34
39
  } from "@ai-sdk/provider-utils";
35
- function convertToDeepSeekChatMessages({
40
+
41
+ // src/chat/deepseek-file-part-options.ts
42
+ import { z } from "zod/v4";
43
+ var deepseekFilePartProviderOptions = z.object({
44
+ /**
45
+ * Controls how DeepSeek processes an image sent as an `image_url` part.
46
+ *
47
+ * @see https://api-docs.deepseek.com/api/create-chat-completion/
48
+ */
49
+ imageDetail: z.enum(["low", "high", "original", "auto"]).optional(),
50
+ /**
51
+ * Sends inline image data as a DeepSeek `file` part using `file_data`
52
+ * instead of an `image_url` data URL. When set, the file part's filename
53
+ * is preserved.
54
+ *
55
+ * This option only applies to inline image data. It cannot be combined
56
+ * with `imageDetail`.
57
+ */
58
+ fileData: z.literal(true).optional()
59
+ });
60
+
61
+ // src/chat/deepseek-chat-language-model-options.ts
62
+ import { z as z2 } from "zod/v4";
63
+ var deepseekLanguageModelChatOptions = z2.object({
64
+ /**
65
+ * Whether to return log probabilities for generated tokens.
66
+ */
67
+ logprobs: z2.boolean().optional(),
68
+ /**
69
+ * Number of most likely tokens to return at each token position.
70
+ *
71
+ * Setting this option automatically enables `logprobs`.
72
+ */
73
+ topLogprobs: z2.number().int().min(0).max(20).optional(),
74
+ /**
75
+ * An opaque identifier for the end user. DeepSeek uses this identifier for
76
+ * content-safety tracing and request isolation.
77
+ *
78
+ * Must contain only ASCII letters, numbers, underscores, and hyphens, and
79
+ * must be at most 512 characters long.
80
+ */
81
+ 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(),
82
+ /**
83
+ * Type of thinking to use. Defaults to `enabled`.
84
+ */
85
+ thinking: z2.object({
86
+ // `adaptive` is accepted at runtime for backwards compatibility and
87
+ // mapped to `enabled`, but is intentionally excluded from the exported
88
+ // provider options type.
89
+ type: z2.enum(["adaptive", "enabled", "disabled"]).optional()
90
+ }).optional(),
91
+ /**
92
+ * Controls the thinking strength for DeepSeek V4 reasoning models.
93
+ */
94
+ // `medium` and `xhigh` are accepted at runtime for backwards compatibility
95
+ // and mapped to canonical DeepSeek values, but are intentionally excluded
96
+ // from the exported provider options type.
97
+ reasoningEffort: z2.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
98
+ /**
99
+ * Whether to use strict JSON schema validation for structured outputs.
100
+ * Only applies when the serving endpoint supports JSON schema response
101
+ * formats (e.g. Azure). Defaults to `true`.
102
+ */
103
+ strictJsonSchema: z2.boolean().optional()
104
+ });
105
+ var deepseekMessageProviderOptions = z2.object({
106
+ /**
107
+ * The name of the participant represented by the message.
108
+ *
109
+ * Supported on system, user, and assistant messages.
110
+ */
111
+ name: z2.string().optional()
112
+ });
113
+ var deepseekAssistantMessageProviderOptions = deepseekMessageProviderOptions.extend({
114
+ /**
115
+ * Whether the assistant message content is a prefix that DeepSeek should
116
+ * continue. This beta feature is only supported on the final assistant
117
+ * message when using a beta base URL.
118
+ */
119
+ prefix: z2.literal(true).optional()
120
+ });
121
+
122
+ // src/chat/convert-to-deepseek-chat-messages.ts
123
+ var supportedImageMediaTypes = /* @__PURE__ */ new Set([
124
+ "image/gif",
125
+ "image/jpeg",
126
+ "image/jpg",
127
+ "image/png",
128
+ "image/webp"
129
+ ]);
130
+ async function convertToDeepSeekChatMessages({
36
131
  prompt,
37
132
  responseFormat,
38
133
  modelId,
134
+ providerOptionsName = "deepseek",
135
+ supportsAssistantPrefixCompletion = false,
39
136
  supportsStructuredOutputs = false
40
137
  }) {
41
138
  var _a;
@@ -68,11 +165,28 @@ function convertToDeepSeekChatMessages({
68
165
  }
69
166
  }
70
167
  let index = -1;
71
- for (const { role, content } of prompt) {
168
+ for (const { role, content, providerOptions } of prompt) {
72
169
  index++;
170
+ const deepseekMessageOptions = await parseProviderOptions({
171
+ provider: providerOptionsName,
172
+ providerOptions,
173
+ schema: deepseekAssistantMessageProviderOptions
174
+ });
175
+ if ((deepseekMessageOptions == null ? void 0 : deepseekMessageOptions.prefix) === true && role !== "assistant") {
176
+ throw new InvalidPromptError({
177
+ prompt,
178
+ message: "DeepSeek assistant prefix completion requires `prefix: true` on an assistant message."
179
+ });
180
+ }
73
181
  switch (role) {
74
182
  case "system": {
75
- messages.push({ role: "system", content });
183
+ messages.push({
184
+ role: "system",
185
+ content,
186
+ ...(deepseekMessageOptions == null ? void 0 : deepseekMessageOptions.name) != null && {
187
+ name: deepseekMessageOptions.name
188
+ }
189
+ });
76
190
  break;
77
191
  }
78
192
  case "user": {
@@ -91,7 +205,13 @@ function convertToDeepSeekChatMessages({
91
205
  });
92
206
  }
93
207
  }
94
- messages.push({ role: "user", content: userContent2 });
208
+ messages.push({
209
+ role: "user",
210
+ content: userContent2,
211
+ ...(deepseekMessageOptions == null ? void 0 : deepseekMessageOptions.name) != null && {
212
+ name: deepseekMessageOptions.name
213
+ }
214
+ });
95
215
  break;
96
216
  }
97
217
  const userContent = [];
@@ -99,6 +219,11 @@ function convertToDeepSeekChatMessages({
99
219
  if (part.type === "text") {
100
220
  userContent.push({ type: "text", text: part.text });
101
221
  } else if (part.type === "file" && getTopLevelMediaType(part.mediaType) === "image") {
222
+ const filePartOptions = await parseProviderOptions({
223
+ provider: providerOptionsName,
224
+ providerOptions: part.providerOptions,
225
+ schema: deepseekFilePartProviderOptions
226
+ });
102
227
  if (part.data.type === "reference") {
103
228
  userContent.push({
104
229
  type: "file",
@@ -108,12 +233,62 @@ function convertToDeepSeekChatMessages({
108
233
  })
109
234
  });
110
235
  } else if (part.data.type === "url" || part.data.type === "data") {
111
- userContent.push({
112
- type: "image_url",
113
- image_url: {
114
- url: part.data.type === "url" ? part.data.url.toString() : `data:${resolveFullMediaType({ part })};base64,${convertToBase64(part.data.data)}`
236
+ const resolvedMediaType = resolveFullMediaType({ part });
237
+ if (!supportedImageMediaTypes.has(resolvedMediaType)) {
238
+ throw new UnsupportedFunctionalityError({
239
+ functionality: `DeepSeek image media type ${resolvedMediaType}`,
240
+ message: "DeepSeek supports JPEG, PNG, GIF, and WebP image inputs."
241
+ });
242
+ }
243
+ if (part.data.type === "url") {
244
+ const url = part.data.url.toString();
245
+ if (url.length > 8192) {
246
+ throw new InvalidPromptError({
247
+ prompt,
248
+ message: "DeepSeek image URLs must not exceed 8192 characters."
249
+ });
115
250
  }
116
- });
251
+ if ((filePartOptions == null ? void 0 : filePartOptions.fileData) === true) {
252
+ throw new InvalidPromptError({
253
+ prompt,
254
+ message: "DeepSeek `fileData` image parts require inline data, not a URL."
255
+ });
256
+ }
257
+ userContent.push({
258
+ type: "image_url",
259
+ image_url: {
260
+ url,
261
+ ...(filePartOptions == null ? void 0 : filePartOptions.imageDetail) != null && {
262
+ detail: filePartOptions.imageDetail
263
+ }
264
+ }
265
+ });
266
+ } else {
267
+ const dataUrl = `data:${resolvedMediaType === "image/jpg" ? "image/jpeg" : resolvedMediaType};base64,${convertToBase64(part.data.data)}`;
268
+ if ((filePartOptions == null ? void 0 : filePartOptions.fileData) === true) {
269
+ if (filePartOptions.imageDetail != null) {
270
+ throw new InvalidPromptError({
271
+ prompt,
272
+ message: "DeepSeek `imageDetail` cannot be combined with `fileData`."
273
+ });
274
+ }
275
+ userContent.push({
276
+ type: "file",
277
+ file_data: dataUrl,
278
+ ...part.filename != null && { filename: part.filename }
279
+ });
280
+ } else {
281
+ userContent.push({
282
+ type: "image_url",
283
+ image_url: {
284
+ url: dataUrl,
285
+ ...(filePartOptions == null ? void 0 : filePartOptions.imageDetail) != null && {
286
+ detail: filePartOptions.imageDetail
287
+ }
288
+ }
289
+ });
290
+ }
291
+ }
117
292
  } else {
118
293
  warnings.push({
119
294
  type: "unsupported",
@@ -129,11 +304,28 @@ function convertToDeepSeekChatMessages({
129
304
  }
130
305
  messages.push({
131
306
  role: "user",
132
- content: userContent
307
+ content: userContent,
308
+ ...(deepseekMessageOptions == null ? void 0 : deepseekMessageOptions.name) != null && {
309
+ name: deepseekMessageOptions.name
310
+ }
133
311
  });
134
312
  break;
135
313
  }
136
314
  case "assistant": {
315
+ if ((deepseekMessageOptions == null ? void 0 : deepseekMessageOptions.prefix) === true) {
316
+ if (index !== prompt.length - 1) {
317
+ throw new InvalidPromptError({
318
+ prompt,
319
+ message: "DeepSeek assistant prefix completion requires the prefixed assistant message to be the final message."
320
+ });
321
+ }
322
+ if (!supportsAssistantPrefixCompletion) {
323
+ throw new UnsupportedFunctionalityError({
324
+ functionality: "DeepSeek assistant prefix completion",
325
+ message: "DeepSeek assistant prefix completion requires a beta base URL ending in `/beta`."
326
+ });
327
+ }
328
+ }
137
329
  let text = "";
138
330
  let reasoning;
139
331
  const toolCalls = [];
@@ -170,12 +362,24 @@ function convertToDeepSeekChatMessages({
170
362
  messages.push({
171
363
  role: "assistant",
172
364
  content: text,
365
+ ...(deepseekMessageOptions == null ? void 0 : deepseekMessageOptions.name) != null && {
366
+ name: deepseekMessageOptions.name
367
+ },
368
+ ...(deepseekMessageOptions == null ? void 0 : deepseekMessageOptions.prefix) === true && {
369
+ prefix: true
370
+ },
173
371
  reasoning_content: reasoning != null ? reasoning : isDeepSeekV4 ? "" : void 0,
174
372
  tool_calls: toolCalls.length > 0 ? toolCalls : void 0
175
373
  });
176
374
  break;
177
375
  }
178
376
  case "tool": {
377
+ if ((deepseekMessageOptions == null ? void 0 : deepseekMessageOptions.name) != null) {
378
+ warnings.push({
379
+ type: "unsupported",
380
+ feature: "message name on tool messages"
381
+ });
382
+ }
179
383
  for (const toolResponse of content) {
180
384
  if (toolResponse.type === "tool-approval-response") {
181
385
  continue;
@@ -236,7 +440,7 @@ function convertDeepSeekUsage(usage) {
236
440
  },
237
441
  outputTokens: {
238
442
  total: completionTokens,
239
- text: completionTokens - reasoningTokens,
443
+ text: Math.max(0, completionTokens - reasoningTokens),
240
444
  reasoning: reasoningTokens
241
445
  },
242
446
  raw: usage
@@ -245,75 +449,101 @@ function convertDeepSeekUsage(usage) {
245
449
 
246
450
  // src/chat/deepseek-chat-api-types.ts
247
451
  import { lazySchema, zodSchema } from "@ai-sdk/provider-utils";
248
- import { z } from "zod/v4";
249
- var tokenUsageSchema = z.object({
250
- prompt_tokens: z.number().nullish(),
251
- completion_tokens: z.number().nullish(),
252
- prompt_cache_hit_tokens: z.number().nullish(),
253
- prompt_cache_miss_tokens: z.number().nullish(),
254
- total_tokens: z.number().nullish(),
255
- completion_tokens_details: z.object({
256
- reasoning_tokens: z.number().nullish()
452
+ import { z as z3 } from "zod/v4";
453
+ var tokenUsageSchema = z3.object({
454
+ prompt_tokens: z3.number().nullish(),
455
+ completion_tokens: z3.number().nullish(),
456
+ prompt_cache_hit_tokens: z3.number().nullish(),
457
+ prompt_cache_miss_tokens: z3.number().nullish(),
458
+ total_tokens: z3.number().nullish(),
459
+ completion_tokens_details: z3.object({
460
+ reasoning_tokens: z3.number().nullish()
257
461
  }).nullish()
258
462
  }).nullish();
259
- var deepSeekErrorSchema = z.object({
260
- error: z.object({
261
- message: z.string(),
262
- type: z.string().nullish(),
263
- param: z.any().nullish(),
264
- code: z.union([z.string(), z.number()]).nullish()
463
+ var deepSeekErrorSchema = z3.object({
464
+ error: z3.object({
465
+ message: z3.string(),
466
+ type: z3.string().nullish(),
467
+ param: z3.any().nullish(),
468
+ code: z3.union([z3.string(), z3.number()]).nullish()
265
469
  })
266
470
  });
267
- var deepseekChatResponseSchema = z.object({
268
- id: z.string().nullish(),
269
- created: z.number().nullish(),
270
- model: z.string().nullish(),
271
- choices: z.array(
272
- z.object({
273
- message: z.object({
274
- role: z.literal("assistant").nullish(),
275
- content: z.string().nullish(),
276
- reasoning_content: z.string().nullish(),
277
- tool_calls: z.array(
278
- z.object({
279
- id: z.string().nullish(),
280
- function: z.object({
281
- name: z.string(),
282
- arguments: z.string()
471
+ var deepseekChatLogprobSchema = z3.object({
472
+ token: z3.string(),
473
+ logprob: z3.number(),
474
+ bytes: z3.array(z3.number()).nullable(),
475
+ top_logprobs: z3.array(
476
+ z3.object({
477
+ token: z3.string(),
478
+ logprob: z3.number(),
479
+ bytes: z3.array(z3.number()).nullable()
480
+ })
481
+ )
482
+ });
483
+ var deepseekChatLogprobsSchema = z3.object({
484
+ content: z3.array(deepseekChatLogprobSchema).nullish(),
485
+ reasoning_content: z3.array(deepseekChatLogprobSchema).nullish()
486
+ }).nullish();
487
+ var deepseekChatResponseSchema = z3.object({
488
+ id: z3.string().nullish(),
489
+ created: z3.number().nullish(),
490
+ model: z3.string().nullish(),
491
+ object: z3.literal("chat.completion").nullish(),
492
+ system_fingerprint: z3.string().nullish(),
493
+ choices: z3.array(
494
+ z3.object({
495
+ index: z3.number().nullish(),
496
+ message: z3.object({
497
+ role: z3.literal("assistant").nullish(),
498
+ content: z3.string().nullish(),
499
+ reasoning_content: z3.string().nullish(),
500
+ tool_calls: z3.array(
501
+ z3.object({
502
+ id: z3.string().nullish(),
503
+ type: z3.literal("function").nullish(),
504
+ function: z3.object({
505
+ name: z3.string(),
506
+ arguments: z3.string()
283
507
  })
284
508
  })
285
509
  ).nullish()
286
510
  }),
287
- finish_reason: z.string().nullish()
511
+ logprobs: deepseekChatLogprobsSchema,
512
+ finish_reason: z3.string().nullish()
288
513
  })
289
514
  ),
290
515
  usage: tokenUsageSchema
291
516
  });
292
517
  var deepseekChatChunkSchema = lazySchema(
293
518
  () => zodSchema(
294
- z.union([
295
- z.object({
296
- id: z.string().nullish(),
297
- created: z.number().nullish(),
298
- model: z.string().nullish(),
299
- choices: z.array(
300
- z.object({
301
- delta: z.object({
302
- role: z.enum(["assistant"]).nullish(),
303
- content: z.string().nullish(),
304
- reasoning_content: z.string().nullish(),
305
- tool_calls: z.array(
306
- z.object({
307
- index: z.number(),
308
- id: z.string().nullish(),
309
- function: z.object({
310
- name: z.string().nullish(),
311
- arguments: z.string().nullish()
519
+ z3.union([
520
+ z3.object({
521
+ id: z3.string().nullish(),
522
+ created: z3.number().nullish(),
523
+ model: z3.string().nullish(),
524
+ object: z3.literal("chat.completion.chunk").nullish(),
525
+ system_fingerprint: z3.string().nullish(),
526
+ choices: z3.array(
527
+ z3.object({
528
+ index: z3.number().nullish(),
529
+ delta: z3.object({
530
+ role: z3.enum(["assistant"]).nullish(),
531
+ content: z3.string().nullish(),
532
+ reasoning_content: z3.string().nullish(),
533
+ tool_calls: z3.array(
534
+ z3.object({
535
+ index: z3.number(),
536
+ id: z3.string().nullish(),
537
+ type: z3.literal("function").nullish(),
538
+ function: z3.object({
539
+ name: z3.string().nullish(),
540
+ arguments: z3.string().nullish()
312
541
  })
313
542
  })
314
543
  ).nullish()
315
544
  }).nullish(),
316
- finish_reason: z.string().nullish()
545
+ logprobs: deepseekChatLogprobsSchema,
546
+ finish_reason: z3.string().nullish()
317
547
  })
318
548
  ),
319
549
  usage: tokenUsageSchema
@@ -323,44 +553,34 @@ var deepseekChatChunkSchema = lazySchema(
323
553
  )
324
554
  );
325
555
 
326
- // src/chat/deepseek-chat-language-model-options.ts
327
- import { z as z2 } from "zod/v4";
328
- var deepseekLanguageModelChatOptions = z2.object({
329
- /**
330
- * Type of thinking to use. Defaults to `enabled`.
331
- *
332
- * See https://api-docs.deepseek.com/guides/thinking_mode for the
333
- * `adaptive` option, which lets the model decide when to think.
334
- */
335
- thinking: z2.object({
336
- type: z2.enum(["adaptive", "enabled", "disabled"]).optional()
337
- }).optional(),
338
- /**
339
- * Controls the thinking strength for DeepSeek V4 reasoning models.
340
- *
341
- * DeepSeek's API accepts `low`, `medium`, `high`, `xhigh`, and `max`.
342
- * Per their docs, `low` and `medium` are mapped to `high`, and `xhigh`
343
- * is mapped to `max` server-side for compatibility with other providers.
344
- */
345
- reasoningEffort: z2.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
346
- /**
347
- * Whether to use strict JSON schema validation for structured outputs.
348
- * Only applies when the serving endpoint supports JSON schema response
349
- * formats (e.g. Azure). Defaults to `true`.
350
- */
351
- strictJsonSchema: z2.boolean().optional()
352
- });
353
-
354
556
  // src/chat/deepseek-prepare-tools.ts
557
+ import {
558
+ UnsupportedFunctionalityError as UnsupportedFunctionalityError2
559
+ } from "@ai-sdk/provider";
355
560
  function prepareTools({
356
561
  tools,
357
- toolChoice
562
+ toolChoice,
563
+ supportsStrictToolCalls
358
564
  }) {
359
565
  tools = (tools == null ? void 0 : tools.length) ? tools : void 0;
360
566
  const toolWarnings = [];
361
567
  if (tools == null) {
362
568
  return { tools: void 0, toolChoice: void 0, toolWarnings };
363
569
  }
570
+ const functionTools = tools.filter((tool) => tool.type === "function");
571
+ const hasStrictTool = functionTools.some((tool) => tool.strict === true);
572
+ if (hasStrictTool && supportsStrictToolCalls === false) {
573
+ throw new UnsupportedFunctionalityError2({
574
+ functionality: "DeepSeek strict tool calls",
575
+ message: "DeepSeek strict tool calls require a beta base URL ending in `/beta`."
576
+ });
577
+ }
578
+ if (hasStrictTool && supportsStrictToolCalls === true && functionTools.some((tool) => tool.strict !== true)) {
579
+ throw new UnsupportedFunctionalityError2({
580
+ functionality: "mixed DeepSeek strict and non-strict tool calls",
581
+ message: "DeepSeek strict mode requires every function tool in the request to set `strict: true`."
582
+ });
583
+ }
364
584
  const deepseekTools = [];
365
585
  for (const tool of tools) {
366
586
  if (tool.type === "provider") {
@@ -436,6 +656,20 @@ function mapDeepSeekFinishReason(finishReason) {
436
656
  }
437
657
 
438
658
  // src/chat/deepseek-chat-language-model.ts
659
+ function mapDeepSeekProviderReasoningEffort({
660
+ reasoningEffort,
661
+ warnings
662
+ }) {
663
+ const mapped = reasoningEffort === "medium" ? "high" : reasoningEffort === "xhigh" ? "max" : reasoningEffort;
664
+ if (mapped !== reasoningEffort) {
665
+ warnings.push({
666
+ type: "compatibility",
667
+ feature: "reasoningEffort",
668
+ details: `reasoningEffort "${reasoningEffort}" is not a canonical DeepSeek value. mapped to "${mapped}".`
669
+ });
670
+ }
671
+ return mapped;
672
+ }
439
673
  var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
440
674
  constructor(modelId, config) {
441
675
  this.specificationVersion = "v4";
@@ -480,17 +714,20 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
480
714
  toolChoice,
481
715
  tools
482
716
  }) {
483
- var _a, _b, _c, _d, _e;
484
- const deepseekOptions = (_a = await parseProviderOptions({
717
+ var _a, _b, _c, _d;
718
+ const deepseekOptions = (_a = await parseProviderOptions2({
485
719
  provider: this.providerOptionsName,
486
720
  providerOptions,
487
721
  schema: deepseekLanguageModelChatOptions
488
722
  })) != null ? _a : {};
489
723
  const supportsStructuredOutputs = this.config.supportsStructuredOutputs === true;
490
- const { messages, warnings } = convertToDeepSeekChatMessages({
724
+ const supportsPenaltySampling = this.config.supportsPenaltySampling === true;
725
+ const { messages, warnings } = await convertToDeepSeekChatMessages({
491
726
  prompt,
492
727
  responseFormat,
493
728
  modelId: this.modelId,
729
+ providerOptionsName: this.providerOptionsName,
730
+ supportsAssistantPrefixCompletion: this.config.supportsAssistantPrefixCompletion,
494
731
  supportsStructuredOutputs
495
732
  });
496
733
  const allWarnings = [...warnings];
@@ -500,21 +737,62 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
500
737
  if (seed != null) {
501
738
  allWarnings.push({ type: "unsupported", feature: "seed" });
502
739
  }
740
+ if (!supportsPenaltySampling && frequencyPenalty != null) {
741
+ allWarnings.push({
742
+ type: "deprecated",
743
+ setting: "frequencyPenalty",
744
+ message: "frequencyPenalty is deprecated by DeepSeek and has been omitted. Remove frequencyPenalty from the request."
745
+ });
746
+ }
747
+ if (!supportsPenaltySampling && presencePenalty != null) {
748
+ allWarnings.push({
749
+ type: "deprecated",
750
+ setting: "presencePenalty",
751
+ message: "presencePenalty is deprecated by DeepSeek and has been omitted. Remove presencePenalty from the request."
752
+ });
753
+ }
503
754
  const {
504
755
  tools: deepseekTools,
505
756
  toolChoice: deepseekToolChoices,
506
757
  toolWarnings
507
758
  } = prepareTools({
508
759
  tools,
509
- toolChoice
760
+ toolChoice,
761
+ supportsStrictToolCalls: this.config.supportsStrictToolCalls
510
762
  });
511
- const thinking = this.config.supportsThinking === false ? void 0 : ((_b = deepseekOptions.thinking) == null ? void 0 : _b.type) != null ? { type: deepseekOptions.thinking.type } : isCustomReasoning(reasoning) ? { type: reasoning === "none" ? "disabled" : "enabled" } : void 0;
512
- const reasoningEffort = (_c = deepseekOptions.reasoningEffort) != null ? _c : isCustomReasoning(reasoning) && reasoning !== "none" ? mapReasoningToProviderEffort({
763
+ const thinkingType = (_b = deepseekOptions.thinking) == null ? void 0 : _b.type;
764
+ if (thinkingType === "adaptive") {
765
+ allWarnings.push({
766
+ type: "compatibility",
767
+ feature: "thinking.type",
768
+ details: 'thinking.type "adaptive" is not a canonical DeepSeek value. mapped to "enabled".'
769
+ });
770
+ }
771
+ const thinking = this.config.supportsThinking === false ? void 0 : thinkingType != null ? { type: thinkingType === "adaptive" ? "enabled" : thinkingType } : isCustomReasoning(reasoning) ? { type: reasoning === "none" ? "disabled" : "enabled" } : void 0;
772
+ const isThinkingEnabled = this.config.supportsThinking !== false && (thinking == null ? void 0 : thinking.type) !== "disabled" && (thinking != null || this.modelId === "deepseek-reasoner" || this.modelId.includes("deepseek-v4"));
773
+ if (isThinkingEnabled && temperature != null) {
774
+ allWarnings.push({
775
+ type: "unsupported",
776
+ feature: "temperature",
777
+ details: "temperature has no effect when DeepSeek thinking is enabled. Set providerOptions.deepseek.thinking.type to 'disabled' to use temperature."
778
+ });
779
+ }
780
+ if (isThinkingEnabled && topP != null) {
781
+ allWarnings.push({
782
+ type: "unsupported",
783
+ feature: "topP",
784
+ details: "topP has no effect when DeepSeek thinking is enabled. Set providerOptions.deepseek.thinking.type to 'disabled' to use topP."
785
+ });
786
+ }
787
+ const reasoningEffort = deepseekOptions.reasoningEffort != null ? mapDeepSeekProviderReasoningEffort({
788
+ reasoningEffort: deepseekOptions.reasoningEffort,
789
+ warnings: allWarnings
790
+ }) : isCustomReasoning(reasoning) && reasoning !== "none" ? mapReasoningToProviderEffort({
513
791
  reasoning,
514
792
  effortMap: {
515
793
  minimal: "low",
516
794
  low: "low",
517
- medium: "medium",
795
+ medium: "high",
518
796
  high: "high",
519
797
  xhigh: "max"
520
798
  },
@@ -523,17 +801,21 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
523
801
  return {
524
802
  args: {
525
803
  model: this.modelId,
804
+ ...(deepseekOptions.logprobs === true || deepseekOptions.topLogprobs != null) && { logprobs: true },
805
+ ...deepseekOptions.topLogprobs != null && {
806
+ top_logprobs: deepseekOptions.topLogprobs
807
+ },
526
808
  max_tokens: maxOutputTokens,
527
- temperature,
528
- top_p: topP,
529
- frequency_penalty: frequencyPenalty,
530
- presence_penalty: presencePenalty,
809
+ temperature: isThinkingEnabled ? void 0 : temperature,
810
+ top_p: isThinkingEnabled ? void 0 : topP,
811
+ frequency_penalty: supportsPenaltySampling ? frequencyPenalty : void 0,
812
+ presence_penalty: supportsPenaltySampling ? presencePenalty : void 0,
531
813
  response_format: (responseFormat == null ? void 0 : responseFormat.type) === "json" ? supportsStructuredOutputs && responseFormat.schema != null ? {
532
814
  type: "json_schema",
533
815
  json_schema: {
534
816
  schema: responseFormat.schema,
535
- strict: (_d = deepseekOptions.strictJsonSchema) != null ? _d : true,
536
- name: (_e = responseFormat.name) != null ? _e : "response",
817
+ strict: (_c = deepseekOptions.strictJsonSchema) != null ? _c : true,
818
+ name: (_d = responseFormat.name) != null ? _d : "response",
537
819
  description: responseFormat.description
538
820
  }
539
821
  } : { type: "json_object" } : void 0,
@@ -542,6 +824,9 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
542
824
  tools: deepseekTools,
543
825
  tool_choice: deepseekToolChoices,
544
826
  thinking,
827
+ ...deepseekOptions.userId != null && {
828
+ user_id: deepseekOptions.userId
829
+ },
545
830
  ...(thinking == null ? void 0 : thinking.type) !== "disabled" && reasoningEffort != null && {
546
831
  reasoning_effort: reasoningEffort
547
832
  }
@@ -603,7 +888,21 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
603
888
  providerMetadata: {
604
889
  [this.providerOptionsName]: {
605
890
  promptCacheHitTokens: (_d = responseBody.usage) == null ? void 0 : _d.prompt_cache_hit_tokens,
606
- promptCacheMissTokens: (_e = responseBody.usage) == null ? void 0 : _e.prompt_cache_miss_tokens
891
+ promptCacheMissTokens: (_e = responseBody.usage) == null ? void 0 : _e.prompt_cache_miss_tokens,
892
+ ...responseBody.object != null && {
893
+ responseObject: responseBody.object
894
+ },
895
+ ...choice.index != null && { choiceIndex: choice.index },
896
+ ...choice.message.role != null && {
897
+ messageRole: choice.message.role
898
+ },
899
+ ...choice.message.tool_calls != null && {
900
+ toolCallTypes: choice.message.tool_calls.map((toolCall) => toolCall.type).filter((type) => type != null)
901
+ },
902
+ ...choice.logprobs != null && { logprobs: choice.logprobs },
903
+ ...responseBody.system_fingerprint != null && {
904
+ systemFingerprint: responseBody.system_fingerprint
905
+ }
607
906
  }
608
907
  },
609
908
  request: { body: args },
@@ -643,10 +942,17 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
643
942
  raw: void 0
644
943
  };
645
944
  let usage = void 0;
945
+ let systemFingerprint = void 0;
646
946
  let isFirstChunk = true;
647
947
  const providerOptionsName = this.providerOptionsName;
648
948
  let isActiveReasoning = false;
649
949
  let isActiveText = false;
950
+ let responseObject;
951
+ let choiceIndex;
952
+ let messageRole;
953
+ const toolCallTypes = /* @__PURE__ */ new Map();
954
+ const contentLogprobs = [];
955
+ const reasoningLogprobs = [];
650
956
  return {
651
957
  stream: response.pipeThrough(
652
958
  new TransformStream({
@@ -657,6 +963,7 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
657
963
  controller.enqueue({ type: "stream-start", warnings });
658
964
  },
659
965
  transform(chunk, controller) {
966
+ var _a2, _b2;
660
967
  if (options.includeRawChunks) {
661
968
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
662
969
  }
@@ -681,17 +988,35 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
681
988
  if (value.usage != null) {
682
989
  usage = value.usage;
683
990
  }
991
+ if (value.object != null) {
992
+ responseObject = value.object;
993
+ }
994
+ if (value.system_fingerprint != null) {
995
+ systemFingerprint = value.system_fingerprint;
996
+ }
684
997
  const choice = value.choices[0];
998
+ if ((choice == null ? void 0 : choice.index) != null) {
999
+ choiceIndex = choice.index;
1000
+ }
685
1001
  if ((choice == null ? void 0 : choice.finish_reason) != null) {
686
1002
  finishReason = {
687
1003
  unified: mapDeepSeekFinishReason(choice.finish_reason),
688
1004
  raw: choice.finish_reason
689
1005
  };
690
1006
  }
1007
+ if (((_a2 = choice == null ? void 0 : choice.logprobs) == null ? void 0 : _a2.content) != null) {
1008
+ contentLogprobs.push(...choice.logprobs.content);
1009
+ }
1010
+ if (((_b2 = choice == null ? void 0 : choice.logprobs) == null ? void 0 : _b2.reasoning_content) != null) {
1011
+ reasoningLogprobs.push(...choice.logprobs.reasoning_content);
1012
+ }
691
1013
  if ((choice == null ? void 0 : choice.delta) == null) {
692
1014
  return;
693
1015
  }
694
1016
  const delta = choice.delta;
1017
+ if (delta.role != null) {
1018
+ messageRole = delta.role;
1019
+ }
695
1020
  const reasoningContent = delta.reasoning_content;
696
1021
  if (reasoningContent) {
697
1022
  if (!isActiveReasoning) {
@@ -734,6 +1059,9 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
734
1059
  isActiveReasoning = false;
735
1060
  }
736
1061
  for (const toolCallDelta of delta.tool_calls) {
1062
+ if (toolCallDelta.type != null) {
1063
+ toolCallTypes.set(toolCallDelta.index, toolCallDelta.type);
1064
+ }
737
1065
  toolCallTracker.processDelta(toolCallDelta);
738
1066
  }
739
1067
  }
@@ -754,7 +1082,24 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
754
1082
  providerMetadata: {
755
1083
  [providerOptionsName]: {
756
1084
  promptCacheHitTokens: (_a2 = usage == null ? void 0 : usage.prompt_cache_hit_tokens) != null ? _a2 : void 0,
757
- promptCacheMissTokens: (_b2 = usage == null ? void 0 : usage.prompt_cache_miss_tokens) != null ? _b2 : void 0
1085
+ promptCacheMissTokens: (_b2 = usage == null ? void 0 : usage.prompt_cache_miss_tokens) != null ? _b2 : void 0,
1086
+ ...responseObject != null && { responseObject },
1087
+ ...choiceIndex != null && { choiceIndex },
1088
+ ...messageRole != null && { messageRole },
1089
+ ...toolCallTypes.size > 0 && {
1090
+ toolCallTypes: [...toolCallTypes.entries()].sort(([left], [right]) => left - right).map(([, type]) => type)
1091
+ },
1092
+ ...(contentLogprobs.length > 0 || reasoningLogprobs.length > 0) && {
1093
+ logprobs: {
1094
+ ...contentLogprobs.length > 0 && {
1095
+ content: contentLogprobs
1096
+ },
1097
+ ...reasoningLogprobs.length > 0 && {
1098
+ reasoning_content: reasoningLogprobs
1099
+ }
1100
+ }
1101
+ },
1102
+ ...systemFingerprint != null && { systemFingerprint }
758
1103
  }
759
1104
  }
760
1105
  });
@@ -768,28 +1113,36 @@ var DeepSeekChatLanguageModel = class _DeepSeekChatLanguageModel {
768
1113
  };
769
1114
 
770
1115
  // src/files/deepseek-files.ts
1116
+ import {
1117
+ InvalidArgumentError
1118
+ } from "@ai-sdk/provider";
771
1119
  import {
772
1120
  combineHeaders as combineHeaders2,
773
1121
  convertInlineFileDataToUint8Array,
774
1122
  createJsonErrorResponseHandler as createJsonErrorResponseHandler2,
775
1123
  createJsonResponseHandler as createJsonResponseHandler2,
776
- parseProviderOptions as parseProviderOptions2,
1124
+ detectMediaType,
1125
+ parseProviderOptions as parseProviderOptions3,
777
1126
  postFormDataToApi
778
1127
  } from "@ai-sdk/provider-utils";
779
1128
 
780
1129
  // src/files/deepseek-files-api.ts
781
1130
  import { lazySchema as lazySchema2, zodSchema as zodSchema2 } from "@ai-sdk/provider-utils";
782
- import { z as z3 } from "zod/v4";
1131
+ import { z as z4 } from "zod/v4";
783
1132
  var deepSeekFilesResponseSchema = lazySchema2(
784
1133
  () => zodSchema2(
785
- z3.object({
786
- id: z3.string(),
787
- object: z3.string().nullish(),
788
- bytes: z3.number().nullish(),
789
- created_at: z3.number().nullish(),
790
- filename: z3.string().nullish(),
791
- purpose: z3.string().nullish(),
792
- expires_at: z3.number().nullish()
1134
+ z4.object({
1135
+ id: z4.string(),
1136
+ // These fields are required by DeepSeek's OpenAPI schema, but they are
1137
+ // not needed to construct the provider reference. Keep them nullish so
1138
+ // uploads remain resilient to incomplete responses while validating any
1139
+ // returned values precisely enough to avoid misleading metadata.
1140
+ object: z4.literal("file").nullish(),
1141
+ bytes: z4.number().int().nonnegative().nullish(),
1142
+ created_at: z4.number().int().nonnegative().nullish(),
1143
+ filename: z4.string().nullish(),
1144
+ purpose: z4.literal("user_data").nullish(),
1145
+ expires_at: z4.number().int().nonnegative().nullish()
793
1146
  })
794
1147
  )
795
1148
  );
@@ -799,15 +1152,15 @@ import {
799
1152
  lazySchema as lazySchema3,
800
1153
  zodSchema as zodSchema3
801
1154
  } from "@ai-sdk/provider-utils";
802
- import { z as z4 } from "zod/v4";
1155
+ import { z as z5 } from "zod/v4";
803
1156
  var deepSeekFilesOptionsSchema = lazySchema3(
804
1157
  () => zodSchema3(
805
- z4.object({
1158
+ z5.object({
806
1159
  /**
807
1160
  * Number of seconds after creation before the file expires.
808
1161
  * Must be between 1 hour and 30 days.
809
1162
  */
810
- expiresAfter: z4.number().int().min(3600).max(2592e3).optional()
1163
+ expiresAfter: z5.number().int().min(3600).max(2592e3).optional()
811
1164
  })
812
1165
  )
813
1166
  );
@@ -817,6 +1170,30 @@ var deepSeekFailedResponseHandler = createJsonErrorResponseHandler2({
817
1170
  errorSchema: deepSeekErrorSchema,
818
1171
  errorToMessage: (error) => error.error.message
819
1172
  });
1173
+ var MAX_FILE_SIZE_BYTES = 64 * 1024 * 1024;
1174
+ var MAX_FILENAME_LENGTH = 512;
1175
+ var supportedMediaTypes = /* @__PURE__ */ new Set([
1176
+ "image/gif",
1177
+ "image/jpeg",
1178
+ "image/jpg",
1179
+ "image/png",
1180
+ "image/webp"
1181
+ ]);
1182
+ var genericMediaTypes = /* @__PURE__ */ new Set([
1183
+ "",
1184
+ "application/binary",
1185
+ "application/octet-stream",
1186
+ "binary/octet-stream",
1187
+ "image",
1188
+ "image/*"
1189
+ ]);
1190
+ var supportedFilenameExtensions = /* @__PURE__ */ new Set([
1191
+ "gif",
1192
+ "jpeg",
1193
+ "jpg",
1194
+ "png",
1195
+ "webp"
1196
+ ]);
820
1197
  var DeepSeekFiles = class {
821
1198
  constructor(config) {
822
1199
  this.config = config;
@@ -832,12 +1209,13 @@ var DeepSeekFiles = class {
832
1209
  providerOptions
833
1210
  }) {
834
1211
  var _a, _b;
835
- const deepSeekOptions = await parseProviderOptions2({
1212
+ const deepSeekOptions = await parseProviderOptions3({
836
1213
  provider: "deepseek",
837
1214
  providerOptions,
838
1215
  schema: deepSeekFilesOptionsSchema
839
1216
  });
840
1217
  const fileBytes = convertInlineFileDataToUint8Array(data);
1218
+ validateFileUpload({ fileBytes, mediaType, filename });
841
1219
  const blob = new Blob([fileBytes], { type: mediaType });
842
1220
  const formData = new FormData();
843
1221
  if (filename != null) {
@@ -870,6 +1248,7 @@ var DeepSeekFiles = class {
870
1248
  ...mediaType != null ? { mediaType } : {},
871
1249
  providerMetadata: {
872
1250
  deepseek: {
1251
+ ...response.object != null ? { object: response.object } : {},
873
1252
  ...response.filename != null ? { filename: response.filename } : {},
874
1253
  ...response.purpose != null ? { purpose: response.purpose } : {},
875
1254
  ...response.bytes != null ? { bytes: response.bytes } : {},
@@ -880,9 +1259,66 @@ var DeepSeekFiles = class {
880
1259
  };
881
1260
  }
882
1261
  };
1262
+ function validateFileUpload({
1263
+ fileBytes,
1264
+ mediaType,
1265
+ filename
1266
+ }) {
1267
+ if (fileBytes.length > MAX_FILE_SIZE_BYTES) {
1268
+ throw new InvalidArgumentError({
1269
+ argument: "data",
1270
+ message: `DeepSeek file uploads must not exceed 64 MiB (${MAX_FILE_SIZE_BYTES.toLocaleString("en-US")} bytes). Received ${fileBytes.length.toLocaleString("en-US")} bytes.`
1271
+ });
1272
+ }
1273
+ if (filename != null) {
1274
+ const filenameLength = Array.from(filename).length;
1275
+ if (filenameLength > MAX_FILENAME_LENGTH) {
1276
+ throw new InvalidArgumentError({
1277
+ argument: "filename",
1278
+ message: `DeepSeek filenames must not exceed ${MAX_FILENAME_LENGTH} characters. Received ${filenameLength} characters.`
1279
+ });
1280
+ }
1281
+ }
1282
+ const normalizedMediaType = normalizeMediaType(mediaType);
1283
+ const detectedMediaType = detectMediaType({ data: fileBytes });
1284
+ if (detectedMediaType != null && !supportedMediaTypes.has(detectedMediaType)) {
1285
+ throw new InvalidArgumentError({
1286
+ argument: "data",
1287
+ message: `DeepSeek file uploads support JPEG, PNG, GIF, and WebP images. Detected unsupported file content type "${detectedMediaType}".`
1288
+ });
1289
+ }
1290
+ if (supportedMediaTypes.has(normalizedMediaType)) {
1291
+ return;
1292
+ }
1293
+ if (!genericMediaTypes.has(normalizedMediaType)) {
1294
+ throw new InvalidArgumentError({
1295
+ argument: "mediaType",
1296
+ message: `DeepSeek file uploads support JPEG, PNG, GIF, and WebP images. Received unsupported media type "${mediaType}".`
1297
+ });
1298
+ }
1299
+ if (detectedMediaType != null || hasSupportedFilenameExtension(filename)) {
1300
+ return;
1301
+ }
1302
+ throw new InvalidArgumentError({
1303
+ argument: "mediaType",
1304
+ 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}".`
1305
+ });
1306
+ }
1307
+ function normalizeMediaType(mediaType) {
1308
+ return mediaType.split(";", 1)[0].trim().toLowerCase();
1309
+ }
1310
+ function hasSupportedFilenameExtension(filename) {
1311
+ if (filename == null) {
1312
+ return false;
1313
+ }
1314
+ const extensionSeparatorIndex = filename.lastIndexOf(".");
1315
+ return extensionSeparatorIndex !== -1 && supportedFilenameExtensions.has(
1316
+ filename.slice(extensionSeparatorIndex + 1).toLowerCase()
1317
+ );
1318
+ }
883
1319
 
884
1320
  // src/version.ts
885
- var VERSION = true ? "3.0.31" : "0.0.0-test";
1321
+ var VERSION = true ? "3.0.32" : "0.0.0-test";
886
1322
 
887
1323
  // src/deepseek-provider.ts
888
1324
  function createDeepSeek(options = {}) {
@@ -904,7 +1340,9 @@ function createDeepSeek(options = {}) {
904
1340
  provider: `deepseek.chat`,
905
1341
  url: ({ path }) => `${baseURL}${path}`,
906
1342
  headers: getHeaders,
907
- fetch: options.fetch
1343
+ fetch: options.fetch,
1344
+ supportsAssistantPrefixCompletion: baseURL.endsWith("/beta"),
1345
+ supportsStrictToolCalls: baseURL.endsWith("/beta")
908
1346
  });
909
1347
  };
910
1348
  const createFiles = () => new DeepSeekFiles({