@ai-sdk/deepseek 2.0.8 → 2.0.9
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 +6 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -2
- package/src/chat/__fixtures__/deepseek-json.json +32 -0
- package/src/chat/__fixtures__/deepseek-reasoning.chunks.txt +220 -0
- package/src/chat/__fixtures__/deepseek-reasoning.json +32 -0
- package/src/chat/__fixtures__/deepseek-text.chunks.txt +402 -0
- package/src/chat/__fixtures__/deepseek-text.json +28 -0
- package/src/chat/__fixtures__/deepseek-tool-call.chunks.txt +52 -0
- package/src/chat/__fixtures__/deepseek-tool-call.json +43 -0
- package/src/chat/__snapshots__/deepseek-chat-language-model.test.ts.snap +4106 -0
- package/src/chat/convert-to-deepseek-chat-messages.test.ts +332 -0
- package/src/chat/convert-to-deepseek-chat-messages.ts +177 -0
- package/src/chat/convert-to-deepseek-usage.ts +56 -0
- package/src/chat/deepseek-chat-api-types.ts +157 -0
- package/src/chat/deepseek-chat-language-model.test.ts +524 -0
- package/src/chat/deepseek-chat-language-model.ts +534 -0
- package/src/chat/deepseek-chat-options.ts +20 -0
- package/src/chat/deepseek-prepare-tools.test.ts +178 -0
- package/src/chat/deepseek-prepare-tools.ts +82 -0
- package/src/chat/get-response-metadata.ts +15 -0
- package/src/chat/map-deepseek-finish-reason.ts +20 -0
- package/src/deepseek-provider.ts +108 -0
- package/src/index.ts +8 -0
- package/src/version.ts +6 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { prepareTools } from './deepseek-prepare-tools';
|
|
3
|
+
|
|
4
|
+
describe('prepareTools', () => {
|
|
5
|
+
it('should pass through strict mode when strict is true', () => {
|
|
6
|
+
const result = prepareTools({
|
|
7
|
+
tools: [
|
|
8
|
+
{
|
|
9
|
+
type: 'function',
|
|
10
|
+
name: 'testFunction',
|
|
11
|
+
description: 'A test function',
|
|
12
|
+
inputSchema: { type: 'object', properties: {} },
|
|
13
|
+
strict: true,
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(result).toMatchInlineSnapshot(`
|
|
19
|
+
{
|
|
20
|
+
"toolChoice": undefined,
|
|
21
|
+
"toolWarnings": [],
|
|
22
|
+
"tools": [
|
|
23
|
+
{
|
|
24
|
+
"function": {
|
|
25
|
+
"description": "A test function",
|
|
26
|
+
"name": "testFunction",
|
|
27
|
+
"parameters": {
|
|
28
|
+
"properties": {},
|
|
29
|
+
"type": "object",
|
|
30
|
+
},
|
|
31
|
+
"strict": true,
|
|
32
|
+
},
|
|
33
|
+
"type": "function",
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
}
|
|
37
|
+
`);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should pass through strict mode when strict is false', () => {
|
|
41
|
+
const result = prepareTools({
|
|
42
|
+
tools: [
|
|
43
|
+
{
|
|
44
|
+
type: 'function',
|
|
45
|
+
name: 'testFunction',
|
|
46
|
+
description: 'A test function',
|
|
47
|
+
inputSchema: { type: 'object', properties: {} },
|
|
48
|
+
strict: false,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(result).toMatchInlineSnapshot(`
|
|
54
|
+
{
|
|
55
|
+
"toolChoice": undefined,
|
|
56
|
+
"toolWarnings": [],
|
|
57
|
+
"tools": [
|
|
58
|
+
{
|
|
59
|
+
"function": {
|
|
60
|
+
"description": "A test function",
|
|
61
|
+
"name": "testFunction",
|
|
62
|
+
"parameters": {
|
|
63
|
+
"properties": {},
|
|
64
|
+
"type": "object",
|
|
65
|
+
},
|
|
66
|
+
"strict": false,
|
|
67
|
+
},
|
|
68
|
+
"type": "function",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
}
|
|
72
|
+
`);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should not include strict mode when strict is undefined', () => {
|
|
76
|
+
const result = prepareTools({
|
|
77
|
+
tools: [
|
|
78
|
+
{
|
|
79
|
+
type: 'function',
|
|
80
|
+
name: 'testFunction',
|
|
81
|
+
description: 'A test function',
|
|
82
|
+
inputSchema: { type: 'object', properties: {} },
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(result).toMatchInlineSnapshot(`
|
|
88
|
+
{
|
|
89
|
+
"toolChoice": undefined,
|
|
90
|
+
"toolWarnings": [],
|
|
91
|
+
"tools": [
|
|
92
|
+
{
|
|
93
|
+
"function": {
|
|
94
|
+
"description": "A test function",
|
|
95
|
+
"name": "testFunction",
|
|
96
|
+
"parameters": {
|
|
97
|
+
"properties": {},
|
|
98
|
+
"type": "object",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
"type": "function",
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
}
|
|
105
|
+
`);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should pass through strict mode for multiple tools with different strict settings', () => {
|
|
109
|
+
const result = prepareTools({
|
|
110
|
+
tools: [
|
|
111
|
+
{
|
|
112
|
+
type: 'function',
|
|
113
|
+
name: 'strictTool',
|
|
114
|
+
description: 'A strict tool',
|
|
115
|
+
inputSchema: { type: 'object', properties: {} },
|
|
116
|
+
strict: true,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
type: 'function',
|
|
120
|
+
name: 'nonStrictTool',
|
|
121
|
+
description: 'A non-strict tool',
|
|
122
|
+
inputSchema: { type: 'object', properties: {} },
|
|
123
|
+
strict: false,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'function',
|
|
127
|
+
name: 'defaultTool',
|
|
128
|
+
description: 'A tool without strict setting',
|
|
129
|
+
inputSchema: { type: 'object', properties: {} },
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(result).toMatchInlineSnapshot(`
|
|
135
|
+
{
|
|
136
|
+
"toolChoice": undefined,
|
|
137
|
+
"toolWarnings": [],
|
|
138
|
+
"tools": [
|
|
139
|
+
{
|
|
140
|
+
"function": {
|
|
141
|
+
"description": "A strict tool",
|
|
142
|
+
"name": "strictTool",
|
|
143
|
+
"parameters": {
|
|
144
|
+
"properties": {},
|
|
145
|
+
"type": "object",
|
|
146
|
+
},
|
|
147
|
+
"strict": true,
|
|
148
|
+
},
|
|
149
|
+
"type": "function",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"function": {
|
|
153
|
+
"description": "A non-strict tool",
|
|
154
|
+
"name": "nonStrictTool",
|
|
155
|
+
"parameters": {
|
|
156
|
+
"properties": {},
|
|
157
|
+
"type": "object",
|
|
158
|
+
},
|
|
159
|
+
"strict": false,
|
|
160
|
+
},
|
|
161
|
+
"type": "function",
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"function": {
|
|
165
|
+
"description": "A tool without strict setting",
|
|
166
|
+
"name": "defaultTool",
|
|
167
|
+
"parameters": {
|
|
168
|
+
"properties": {},
|
|
169
|
+
"type": "object",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
"type": "function",
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
}
|
|
176
|
+
`);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { LanguageModelV3CallOptions, SharedV3Warning } from '@ai-sdk/provider';
|
|
2
|
+
import {
|
|
3
|
+
DeepSeekFunctionTool,
|
|
4
|
+
DeepSeekToolChoice,
|
|
5
|
+
} from './deepseek-chat-api-types';
|
|
6
|
+
|
|
7
|
+
export function prepareTools({
|
|
8
|
+
tools,
|
|
9
|
+
toolChoice,
|
|
10
|
+
}: {
|
|
11
|
+
tools: LanguageModelV3CallOptions['tools'];
|
|
12
|
+
toolChoice?: LanguageModelV3CallOptions['toolChoice'];
|
|
13
|
+
}): {
|
|
14
|
+
tools: undefined | Array<DeepSeekFunctionTool>;
|
|
15
|
+
toolChoice: DeepSeekToolChoice;
|
|
16
|
+
toolWarnings: SharedV3Warning[];
|
|
17
|
+
} {
|
|
18
|
+
// when the tools array is empty, change it to undefined to prevent errors:
|
|
19
|
+
tools = tools?.length ? tools : undefined;
|
|
20
|
+
|
|
21
|
+
const toolWarnings: SharedV3Warning[] = [];
|
|
22
|
+
|
|
23
|
+
if (tools == null) {
|
|
24
|
+
return { tools: undefined, toolChoice: undefined, toolWarnings };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const deepseekTools: Array<DeepSeekFunctionTool> = [];
|
|
28
|
+
|
|
29
|
+
for (const tool of tools) {
|
|
30
|
+
if (tool.type === 'provider') {
|
|
31
|
+
toolWarnings.push({
|
|
32
|
+
type: 'unsupported',
|
|
33
|
+
feature: `provider-defined tool ${tool.id}`,
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
deepseekTools.push({
|
|
37
|
+
type: 'function',
|
|
38
|
+
function: {
|
|
39
|
+
name: tool.name,
|
|
40
|
+
description: tool.description,
|
|
41
|
+
parameters: tool.inputSchema,
|
|
42
|
+
...(tool.strict != null ? { strict: tool.strict } : {}),
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (toolChoice == null) {
|
|
49
|
+
return { tools: deepseekTools, toolChoice: undefined, toolWarnings };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const type = toolChoice?.type;
|
|
53
|
+
|
|
54
|
+
switch (type) {
|
|
55
|
+
case 'auto':
|
|
56
|
+
case 'none':
|
|
57
|
+
case 'required':
|
|
58
|
+
return { tools: deepseekTools, toolChoice: type, toolWarnings };
|
|
59
|
+
case 'tool':
|
|
60
|
+
return {
|
|
61
|
+
tools: deepseekTools,
|
|
62
|
+
toolChoice: {
|
|
63
|
+
type: 'function',
|
|
64
|
+
function: { name: toolChoice.toolName },
|
|
65
|
+
},
|
|
66
|
+
toolWarnings,
|
|
67
|
+
};
|
|
68
|
+
default: {
|
|
69
|
+
return {
|
|
70
|
+
tools: deepseekTools,
|
|
71
|
+
toolChoice: undefined,
|
|
72
|
+
toolWarnings: [
|
|
73
|
+
...toolWarnings,
|
|
74
|
+
{
|
|
75
|
+
type: 'unsupported',
|
|
76
|
+
feature: `tool choice type: ${type}`,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function getResponseMetadata({
|
|
2
|
+
id,
|
|
3
|
+
model,
|
|
4
|
+
created,
|
|
5
|
+
}: {
|
|
6
|
+
id?: string | undefined | null;
|
|
7
|
+
created?: number | undefined | null;
|
|
8
|
+
model?: string | undefined | null;
|
|
9
|
+
}) {
|
|
10
|
+
return {
|
|
11
|
+
id: id ?? undefined,
|
|
12
|
+
modelId: model ?? undefined,
|
|
13
|
+
timestamp: created != null ? new Date(created * 1000) : undefined,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
|
|
2
|
+
|
|
3
|
+
export function mapDeepSeekFinishReason(
|
|
4
|
+
finishReason: string | null | undefined,
|
|
5
|
+
): LanguageModelV3FinishReason['unified'] {
|
|
6
|
+
switch (finishReason) {
|
|
7
|
+
case 'stop':
|
|
8
|
+
return 'stop';
|
|
9
|
+
case 'length':
|
|
10
|
+
return 'length';
|
|
11
|
+
case 'content_filter':
|
|
12
|
+
return 'content-filter';
|
|
13
|
+
case 'tool_calls':
|
|
14
|
+
return 'tool-calls';
|
|
15
|
+
case 'insufficient_system_resource':
|
|
16
|
+
return 'error';
|
|
17
|
+
default:
|
|
18
|
+
return 'other';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LanguageModelV3,
|
|
3
|
+
NoSuchModelError,
|
|
4
|
+
ProviderV3,
|
|
5
|
+
} from '@ai-sdk/provider';
|
|
6
|
+
import {
|
|
7
|
+
FetchFunction,
|
|
8
|
+
loadApiKey,
|
|
9
|
+
withoutTrailingSlash,
|
|
10
|
+
withUserAgentSuffix,
|
|
11
|
+
} from '@ai-sdk/provider-utils';
|
|
12
|
+
import { DeepSeekChatModelId } from './chat/deepseek-chat-options';
|
|
13
|
+
import { DeepSeekChatLanguageModel } from './chat/deepseek-chat-language-model';
|
|
14
|
+
import { VERSION } from './version';
|
|
15
|
+
|
|
16
|
+
export interface DeepSeekProviderSettings {
|
|
17
|
+
/**
|
|
18
|
+
* DeepSeek API key.
|
|
19
|
+
*/
|
|
20
|
+
apiKey?: string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Base URL for the API calls.
|
|
24
|
+
*/
|
|
25
|
+
baseURL?: string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Custom headers to include in the requests.
|
|
29
|
+
*/
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Custom fetch implementation. You can use it as a middleware to intercept requests,
|
|
34
|
+
* or to provide a custom fetch implementation for e.g. testing.
|
|
35
|
+
*/
|
|
36
|
+
fetch?: FetchFunction;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DeepSeekProvider extends ProviderV3 {
|
|
40
|
+
/**
|
|
41
|
+
Creates a DeepSeek model for text generation.
|
|
42
|
+
*/
|
|
43
|
+
(modelId: DeepSeekChatModelId): LanguageModelV3;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
Creates a DeepSeek model for text generation.
|
|
47
|
+
*/
|
|
48
|
+
languageModel(modelId: DeepSeekChatModelId): LanguageModelV3;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
Creates a DeepSeek chat model for text generation.
|
|
52
|
+
*/
|
|
53
|
+
chat(modelId: DeepSeekChatModelId): LanguageModelV3;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @deprecated Use `embeddingModel` instead.
|
|
57
|
+
*/
|
|
58
|
+
textEmbeddingModel(modelId: string): never;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function createDeepSeek(
|
|
62
|
+
options: DeepSeekProviderSettings = {},
|
|
63
|
+
): DeepSeekProvider {
|
|
64
|
+
const baseURL = withoutTrailingSlash(
|
|
65
|
+
options.baseURL ?? 'https://api.deepseek.com',
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const getHeaders = () =>
|
|
69
|
+
withUserAgentSuffix(
|
|
70
|
+
{
|
|
71
|
+
Authorization: `Bearer ${loadApiKey({
|
|
72
|
+
apiKey: options.apiKey,
|
|
73
|
+
environmentVariableName: 'DEEPSEEK_API_KEY',
|
|
74
|
+
description: 'DeepSeek API key',
|
|
75
|
+
})}`,
|
|
76
|
+
...options.headers,
|
|
77
|
+
},
|
|
78
|
+
`ai-sdk/deepseek/${VERSION}`,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const createLanguageModel = (modelId: DeepSeekChatModelId) => {
|
|
82
|
+
return new DeepSeekChatLanguageModel(modelId, {
|
|
83
|
+
provider: `deepseek.chat`,
|
|
84
|
+
url: ({ path }) => `${baseURL}${path}`,
|
|
85
|
+
headers: getHeaders,
|
|
86
|
+
fetch: options.fetch,
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const provider = (modelId: DeepSeekChatModelId) =>
|
|
91
|
+
createLanguageModel(modelId);
|
|
92
|
+
|
|
93
|
+
provider.specificationVersion = 'v3' as const;
|
|
94
|
+
provider.languageModel = createLanguageModel;
|
|
95
|
+
provider.chat = createLanguageModel;
|
|
96
|
+
|
|
97
|
+
provider.embeddingModel = (modelId: string) => {
|
|
98
|
+
throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' });
|
|
99
|
+
};
|
|
100
|
+
provider.textEmbeddingModel = provider.embeddingModel;
|
|
101
|
+
provider.imageModel = (modelId: string) => {
|
|
102
|
+
throw new NoSuchModelError({ modelId, modelType: 'imageModel' });
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return provider;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const deepseek = createDeepSeek();
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createDeepSeek, deepseek } from './deepseek-provider';
|
|
2
|
+
export type {
|
|
3
|
+
DeepSeekProvider,
|
|
4
|
+
DeepSeekProviderSettings,
|
|
5
|
+
} from './deepseek-provider';
|
|
6
|
+
export { VERSION } from './version';
|
|
7
|
+
export type { DeepSeekChatOptions } from './chat/deepseek-chat-options';
|
|
8
|
+
export type { DeepSeekErrorData } from './chat/deepseek-chat-api-types';
|