@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.
@@ -62,7 +62,7 @@ import { deepSeek } from '@ai-sdk/deepseek';
62
62
  import { generateText } from 'ai';
63
63
 
64
64
  const { text } = await generateText({
65
- model: deepSeek('deepseek-chat'),
65
+ model: deepSeek('deepseek-v4-flash'),
66
66
  prompt: 'Write a vegetarian lasagna recipe for 4 people.',
67
67
  });
68
68
  ```
@@ -70,31 +70,64 @@ const { text } = await generateText({
70
70
  You can also use the `.chat()` or `.languageModel()` factory methods:
71
71
 
72
72
  ```ts
73
- const model = deepSeek.chat('deepseek-chat');
73
+ const model = deepSeek.chat('deepseek-v4-flash');
74
74
  // or
75
- const model = deepSeek.languageModel('deepseek-chat');
75
+ const model = deepSeek.languageModel('deepseek-v4-flash');
76
76
  ```
77
77
 
78
78
  DeepSeek language models can be used in the `streamText` function
79
79
  (see [AI SDK Core](/docs/ai-sdk-core)).
80
80
 
81
+ DeepSeek retired the `deepseek-chat` and `deepseek-reasoner` aliases on July 24, 2026. Use `deepseek-v4-flash` or `deepseek-v4-pro` for the current API. Custom
82
+ and legacy model IDs remain accepted as strings for compatibility with custom
83
+ endpoints.
84
+
81
85
  The following optional provider options are available for DeepSeek models:
82
86
 
87
+ - `logprobs` _boolean_
88
+
89
+ Optional. Returns log probabilities for generated content and reasoning
90
+ tokens in `providerMetadata.deepseek.logprobs`.
91
+
92
+ - `topLogprobs` _number_
93
+
94
+ Optional. Returns the specified number of most likely tokens at each token
95
+ position. Accepts values from `0` through `20` and automatically enables
96
+ `logprobs`.
97
+
98
+ - `userId` _string_
99
+
100
+ Optional. An opaque end-user identifier that DeepSeek uses for content-safety
101
+ tracing, KV-cache isolation, and scheduling isolation. The value must match
102
+ `^[a-zA-Z0-9_-]+$` and contain at most 512 characters. Do not include names,
103
+ email addresses, or other private user information.
104
+
83
105
  - `thinking` _object_
84
106
 
85
- Optional. Controls thinking mode (chain-of-thought reasoning). You can enable thinking mode either by using the `deepseek-reasoner` model or by setting this option.
86
- - `type`: `'adaptive' | 'enabled' | 'disabled'` - Enable, disable, or let the model decide (`adaptive`) when to think. See [DeepSeek's thinking mode docs](https://api-docs.deepseek.com/guides/thinking_mode).
107
+ Optional. Controls thinking mode (chain-of-thought reasoning) for DeepSeek V4 models.
108
+ - `type`: `'enabled' | 'disabled'` - Enable or disable thinking mode. See [DeepSeek's thinking mode docs](https://api-docs.deepseek.com/guides/thinking_mode).
87
109
 
88
- - `reasoningEffort` _'low' | 'medium' | 'high' | 'xhigh' | 'max'_
110
+ - `reasoningEffort` _'low' | 'high' | 'max'_
89
111
 
90
- Optional. Controls thinking strength for DeepSeek V4 reasoning models. Per
91
- DeepSeek's docs, `low` and `medium` are mapped to `high`, and `xhigh` is
92
- mapped to `max` server-side for compatibility with other providers. When
93
- using the top-level `reasoning` setting, `minimal` is sent as `low`, and
94
- `low`, `medium`, `high`, and `xhigh` pass through to DeepSeek's native
95
- effort values.
112
+ Optional. Controls thinking strength for DeepSeek V4 reasoning models. When
113
+ using the top-level `reasoning` setting, `minimal` is sent as `low`,
114
+ `medium` is sent as `high`, and `xhigh` is sent as `max`. A compatibility
115
+ warning is returned whenever the requested value is mapped.
96
116
 
97
- ```ts highlight="7-12"
117
+ For backwards compatibility, legacy provider options supplied at runtime are
118
+ also mapped to documented values: `thinking.type: 'adaptive'` becomes
119
+ `'enabled'`, `reasoningEffort: 'medium'` becomes `'high'`, and
120
+ `reasoningEffort: 'xhigh'` becomes `'max'`. Each mapping returns a compatibility
121
+ warning so callers can migrate to a canonical value.
122
+
123
+ DeepSeek has deprecated the top-level `frequencyPenalty` and `presencePenalty`
124
+ settings. The provider omits these settings and returns a deprecation warning
125
+ when they are used. `temperature` and `topP` have no effect while thinking is
126
+ enabled, including the default thinking mode for DeepSeek V4 models, so the
127
+ provider omits them with an unsupported warning. Explicitly set
128
+ `thinking.type` to `'disabled'` to use `temperature` and `topP`.
129
+
130
+ ```ts highlight="7-15"
98
131
  import {
99
132
  deepSeek,
100
133
  type DeepSeekLanguageModelChatOptions,
@@ -102,10 +135,11 @@ import {
102
135
  import { generateText } from 'ai';
103
136
 
104
137
  const { text, reasoning } = await generateText({
105
- model: deepSeek('deepseek-chat'),
138
+ model: deepSeek('deepseek-v4-flash'),
106
139
  prompt: 'How many "r"s are in the word "strawberry"?',
107
140
  providerOptions: {
108
141
  deepseek: {
142
+ userId: 'tenant_123-user',
109
143
  thinking: { type: 'enabled' },
110
144
  reasoningEffort: 'high',
111
145
  } satisfies DeepSeekLanguageModelChatOptions,
@@ -113,16 +147,106 @@ const { text, reasoning } = await generateText({
113
147
  });
114
148
  ```
115
149
 
150
+ ### Message Names
151
+
152
+ DeepSeek supports optional participant names on system, user, and assistant
153
+ messages. Set `providerOptions.deepseek.name` on each message that should
154
+ include a name:
155
+
156
+ ```ts
157
+ import {
158
+ deepSeek,
159
+ type DeepSeekMessageProviderOptions,
160
+ } from '@ai-sdk/deepseek';
161
+ import { generateText } from 'ai';
162
+
163
+ const { text } = await generateText({
164
+ model: deepSeek('deepseek-chat'),
165
+ instructions: {
166
+ role: 'system',
167
+ content: 'Help the customer plan a short trip.',
168
+ providerOptions: {
169
+ deepseek: {
170
+ name: 'travel_planner',
171
+ } satisfies DeepSeekMessageProviderOptions,
172
+ },
173
+ },
174
+ messages: [
175
+ {
176
+ role: 'user',
177
+ content: 'I want to visit Lisbon for a weekend.',
178
+ providerOptions: {
179
+ deepseek: {
180
+ name: 'customer',
181
+ } satisfies DeepSeekMessageProviderOptions,
182
+ },
183
+ },
184
+ {
185
+ role: 'assistant',
186
+ content: 'What kinds of activities do you enjoy?',
187
+ providerOptions: {
188
+ deepseek: {
189
+ name: 'travel_planner',
190
+ } satisfies DeepSeekMessageProviderOptions,
191
+ },
192
+ },
193
+ {
194
+ role: 'user',
195
+ content: 'Food, architecture, and walking.',
196
+ providerOptions: {
197
+ deepseek: {
198
+ name: 'customer',
199
+ } satisfies DeepSeekMessageProviderOptions,
200
+ },
201
+ },
202
+ ],
203
+ });
204
+ ```
205
+
206
+ The same message option works with `streamText`:
207
+
208
+ ```ts
209
+ import {
210
+ deepSeek,
211
+ type DeepSeekMessageProviderOptions,
212
+ } from '@ai-sdk/deepseek';
213
+ import { streamText } from 'ai';
214
+
215
+ const result = streamText({
216
+ model: deepSeek('deepseek-chat'),
217
+ messages: [
218
+ {
219
+ role: 'user',
220
+ content: 'Suggest a name for my neighborhood book club.',
221
+ providerOptions: {
222
+ deepseek: {
223
+ name: 'organizer',
224
+ } satisfies DeepSeekMessageProviderOptions,
225
+ },
226
+ },
227
+ ],
228
+ });
229
+
230
+ for await (const textPart of result.textStream) {
231
+ process.stdout.write(textPart);
232
+ }
233
+ ```
234
+
235
+ Names are omitted when the option is not set. The `name` value must be a
236
+ string. DeepSeek does not support names on tool messages, so the provider
237
+ ignores that placement and returns an unsupported-feature warning. Avoid
238
+ including unnecessary personal or identifying information in message names.
239
+
116
240
  ### Reasoning
117
241
 
118
- DeepSeek has reasoning support for the `deepseek-reasoner` model. The reasoning is exposed through streaming:
242
+ DeepSeek V4 models support reasoning. The reasoning is exposed through streaming:
119
243
 
120
244
  ```ts
121
245
  import { deepSeek } from '@ai-sdk/deepseek';
122
246
  import { streamText } from 'ai';
123
247
 
124
248
  const result = streamText({
125
- model: deepSeek('deepseek-reasoner'),
249
+ model: deepSeek('deepseek-v4-pro'),
126
250
  prompt: 'How many "r"s are in the word "strawberry"?',
127
251
  });
128
252
 
@@ -140,35 +264,180 @@ for await (const part of result.stream) {
140
264
  See [AI SDK UI: Chatbot](/docs/ai-sdk-ui/chatbot#reasoning) for more details
141
265
  on how to integrate reasoning into your chatbot.
142
266
 
143
- ### Cache Token Usage
267
+ ### Chat Prefix Completion
268
+
269
+ DeepSeek's beta [chat prefix completion](https://api-docs.deepseek.com/guides/chat_prefix_completion/)
270
+ continues the content of a final assistant message. Create a provider with a
271
+ beta base URL and set `prefix: true` in that assistant message's provider
272
+ options:
273
+
274
+ ```ts highlight="8,20-26"
275
+ import {
276
+ createDeepSeek,
277
+ type DeepSeekAssistantMessageProviderOptions,
278
+ } from '@ai-sdk/deepseek';
279
+ import { generateText } from 'ai';
280
+
281
+ const deepSeek = createDeepSeek({
282
+ baseURL: 'https://api.deepseek.com/beta',
283
+ });
284
+
285
+ const { text } = await generateText({
286
+ model: deepSeek('deepseek-v4-flash'),
287
+ messages: [
288
+ {
289
+ role: 'user',
290
+ content: 'Write a short sentence about the color of the sky.',
291
+ },
292
+ {
293
+ role: 'assistant',
294
+ content: 'The sky is',
295
+ providerOptions: {
296
+ deepseek: {
297
+ prefix: true,
298
+ } satisfies DeepSeekAssistantMessageProviderOptions,
299
+ },
300
+ },
301
+ ],
302
+ });
303
+ ```
304
+
305
+ The prefixed message must be an assistant message and the final message in the
306
+ prompt. The configured `baseURL` must end in `/beta`, including when using a
307
+ proxy. Invalid placement or a non-beta base URL causes the request to fail
308
+ before it is sent.
309
+
310
+ <Note>
311
+ Chat prefix completion is a DeepSeek beta feature and its behavior may change.
312
+ </Note>
313
+
314
+ ### Strict Tool Calls
315
+
316
+ DeepSeek's strict tool-call mode is a beta feature. Create the provider with a
317
+ beta base URL and set `strict: true` on every function tool in the request:
318
+
319
+ ```ts highlight="5,14"
320
+ import { createDeepSeek } from '@ai-sdk/deepseek';
321
+ import { generateText, tool } from 'ai';
322
+ import { z } from 'zod';
323
+
324
+ const deepSeek = createDeepSeek({
325
+ baseURL: 'https://api.deepseek.com/beta',
326
+ });
327
+
328
+ const result = await generateText({
329
+ model: deepSeek('deepseek-chat'),
330
+ prompt: 'What is the weather in San Francisco?',
331
+ tools: {
332
+ weather: tool({
333
+ description: 'Get the weather for a location.',
334
+ inputSchema: z.object({ location: z.string() }),
335
+ strict: true,
336
+ execute: async ({ location }) => ({ location, temperature: 18 }),
337
+ }),
338
+ },
339
+ });
340
+ ```
341
+
342
+ Strict tools fail locally when the base URL does not end in `/beta`. When any
343
+ function tool is strict, every function tool in the same request must set
344
+ `strict: true`.
144
345
 
145
- DeepSeek provides context caching on disk technology that can significantly reduce token costs for repeated content. You can access the cache hit/miss metrics through the `providerMetadata` property in the response:
346
+ ### Provider Metadata
347
+
348
+ DeepSeek exposes the response system fingerprint and context cache usage through
349
+ the `providerMetadata` property:
146
350
 
147
351
  ```ts
148
352
  import { deepSeek } from '@ai-sdk/deepseek';
149
353
  import { generateText } from 'ai';
150
354
 
151
355
  const result = await generateText({
152
- model: deepSeek('deepseek-chat'),
356
+ model: deepSeek('deepseek-v4-flash'),
153
357
  prompt: 'Your prompt here',
154
358
  });
155
359
 
156
360
  console.log(result.providerMetadata);
157
- // Example output: { deepseek: { promptCacheHitTokens: 1856, promptCacheMissTokens: 5 } }
361
+ // Example output:
362
+ // {
363
+ // deepseek: {
364
+ // systemFingerprint: 'fp_eaab8d114b_prod0820_fp8_kvcache',
365
+ // promptCacheHitTokens: 1856,
366
+ // promptCacheMissTokens: 5,
367
+ // },
368
+ // }
158
369
  ```
159
370
 
160
- The metrics include:
371
+ The metadata includes:
161
372
 
373
+ - `systemFingerprint`: The backend configuration fingerprint for the response
162
374
  - `promptCacheHitTokens`: Number of input tokens that were cached
163
375
  - `promptCacheMissTokens`: Number of input tokens that were not cached
164
376
 
377
+ For streamed responses, the latest non-null fingerprint from the response
378
+ chunks is returned.
379
+
165
380
  <Note>
166
381
  For more details about DeepSeek's caching system, see the [DeepSeek caching
167
382
  documentation](https://api-docs.deepseek.com/guides/kv_cache#checking-cache-hit-status).
168
383
  </Note>
169
384
 
385
+ ### Chat Response Metadata
386
+
387
+ DeepSeek preserves provider-specific response fields in
388
+ `providerMetadata.deepseek` for generated and streamed responses:
389
+
390
+ - `responseObject`: `chat.completion` or `chat.completion.chunk`
391
+ - `choiceIndex`: the selected response choice index
392
+ - `messageRole`: the response message role, when supplied
393
+ - `toolCallTypes`: the tool-call type for each returned call
394
+
395
+ These fields remain in provider metadata because they are specific to
396
+ DeepSeek's Chat Completions response rather than shared AI SDK result fields.
397
+
170
398
  ### File Uploads
171
399
 
400
+ For inline images or image URLs, use file-part provider options to select the
401
+ image processing detail. DeepSeek supports `low`, `high`, `original`, and
402
+ `auto`:
403
+
404
+ ```ts highlight="2,13-17"
405
+ import {
406
+ deepSeek,
407
+ type DeepSeekFilePartProviderOptions,
408
+ } from '@ai-sdk/deepseek';
409
+ import { generateText } from 'ai';
410
+
411
+ const { text } = await generateText({
412
+ model: deepSeek('deepseek-v4-flash-vision-exp'),
413
+ messages: [
414
+ {
415
+ role: 'user',
416
+ content: [
417
+ { type: 'text', text: 'Describe this image.' },
418
+ {
419
+ type: 'file',
420
+ data: new URL('https://example.com/image.webp'),
421
+ mediaType: 'image/webp',
422
+ providerOptions: {
423
+ deepseek: {
424
+ imageDetail: 'low',
425
+ } satisfies DeepSeekFilePartProviderOptions,
426
+ },
427
+ },
428
+ ],
429
+ },
430
+ ],
431
+ });
432
+ ```
433
+
434
+ Set `fileData: true` on an inline image file part to use DeepSeek's
435
+ `file_data` content-part representation. This preserves the file part's
436
+ `filename`. `fileData` cannot be used with image URLs or `imageDetail`.
437
+
438
+ DeepSeek accepts JPEG, PNG, GIF, and WebP image inputs. HTTP image URLs can be
439
+ at most 8,192 characters.
440
+
172
441
  You can upload images using the [DeepSeek Files API](https://api-docs.deepseek.com/guides/files_api) and pass the returned provider reference to `deepseek-v4-flash-vision-exp`. This avoids sending the image bytes again in each request.
173
442
 
174
443
  ```ts
@@ -207,12 +476,26 @@ const { text } = await generateText({
207
476
 
208
477
  The optional `expiresAfter` setting specifies the lifetime in seconds. DeepSeek accepts values from 3,600 seconds (one hour) through 2,592,000 seconds (30 days). Files are permanent when no expiration is specified.
209
478
 
479
+ The provider requires a valid file ID in successful upload responses. It also
480
+ validates returned `object` and `purpose` discriminators and numeric metadata.
481
+ Other response metadata remains optional for compatibility with incomplete
482
+ responses; omitted values are not included in `providerMetadata`, and an
483
+ omitted response filename falls back to the filename supplied to `uploadFile`.
484
+
485
+ DeepSeek file uploads support JPEG (`.jpg` and `.jpeg`), PNG, GIF, and WebP
486
+ images. Each file can be at most 64 MiB, and filenames can contain at most 512
487
+ characters. The AI SDK validates these constraints before sending the upload
488
+ request. The `image/jpg` media type alias is accepted, and a supported filename
489
+ extension is used as a fallback when the media type is generic (for example,
490
+ `application/octet-stream`). Recognizable non-image content is rejected even
491
+ when its declared media type or filename indicates a supported image format.
492
+
210
493
  ## Model Capabilities
211
494
 
212
495
  | Model | Text Generation | Object Generation | Image Input | Tool Usage | Tool Streaming |
213
496
  | ------------------------------ | --------------- | ----------------- | ----------- | ---------- | -------------- |
214
- | `deepseek-chat` | <Check /> | <Check /> | <Cross /> | <Check /> | <Check /> |
215
- | `deepseek-reasoner` | <Check /> | <Check /> | <Cross /> | <Check /> | <Check /> |
497
+ | `deepseek-v4-flash` | <Check /> | <Check /> | <Cross /> | <Check /> | <Check /> |
498
+ | `deepseek-v4-pro` | <Check /> | <Check /> | <Cross /> | <Check /> | <Check /> |
216
499
  | `deepseek-v4-flash-vision-exp` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
217
500
 
218
501
  <Note>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/deepseek",
3
- "version": "3.0.31",
3
+ "version": "3.0.32",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,16 +35,16 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.7",
39
- "@ai-sdk/provider-utils": "5.0.29"
38
+ "@ai-sdk/provider": "4.0.8",
39
+ "@ai-sdk/provider-utils": "5.0.30"
40
40
  },
41
41
  "devDependencies": {
42
+ "@ai-sdk/test-server": "2.0.1",
42
43
  "@types/node": "22.19.19",
44
+ "@vercel/ai-tsconfig": "0.0.0",
43
45
  "tsup": "^8.5.1",
44
46
  "typescript": "5.8.3",
45
- "zod": "3.25.76",
46
- "@vercel/ai-tsconfig": "0.0.0",
47
- "@ai-sdk/test-server": "2.0.1"
47
+ "zod": "3.25.76"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "zod": "^3.25.76 || ^4.1.8"