@hopemyl619/deepseek 0.2.0 → 0.3.0
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 +86 -185
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/deepseek-provider.ts +67 -25
- package/src/index.ts +18 -15
- package/src/utils/request-transformer.ts +44 -21
- package/src/utils/response-transformer.ts +33 -10
- package/src/utils/stream-parser.ts +10 -0
- package/src/utils/chinese-params-preprocessor.ts +0 -161
package/dist/index.js
CHANGED
|
@@ -1,27 +1,5 @@
|
|
|
1
1
|
// src/deepseek-provider.ts
|
|
2
|
-
import { createDeepSeek as createOfficialProvider } from "@ai-sdk/deepseek";
|
|
3
2
|
import { loadApiKey } from "@ai-sdk/provider-utils";
|
|
4
|
-
async function createProvider(options = {}) {
|
|
5
|
-
const officialProvider = createOfficialProvider({
|
|
6
|
-
apiKey: options.apiKey,
|
|
7
|
-
baseURL: options.baseURL,
|
|
8
|
-
headers: options.headers
|
|
9
|
-
});
|
|
10
|
-
const provider = {
|
|
11
|
-
id: "deepseek",
|
|
12
|
-
name: "DeepSeek AI",
|
|
13
|
-
async initialize() {
|
|
14
|
-
await loadApiKey({
|
|
15
|
-
apiKey: options.apiKey,
|
|
16
|
-
environmentVariableName: "DEEPSEEK_API_KEY",
|
|
17
|
-
description: "DeepSeek API key"
|
|
18
|
-
});
|
|
19
|
-
},
|
|
20
|
-
chat: officialProvider.chat
|
|
21
|
-
};
|
|
22
|
-
return provider;
|
|
23
|
-
}
|
|
24
|
-
var deepseek = createProvider();
|
|
25
3
|
|
|
26
4
|
// src/deepseek-chat-settings.ts
|
|
27
5
|
function validateChatSettings(settings = {}) {
|
|
@@ -34,158 +12,8 @@ function validateChatSettings(settings = {}) {
|
|
|
34
12
|
};
|
|
35
13
|
}
|
|
36
14
|
|
|
37
|
-
// src/utils/chinese-params-preprocessor.ts
|
|
38
|
-
var ChineseParamsPreprocessor = class {
|
|
39
|
-
cityMap = {
|
|
40
|
-
// 中国城市
|
|
41
|
-
"\u5317\u4EAC": "Beijing",
|
|
42
|
-
"\u4E0A\u6D77": "Shanghai",
|
|
43
|
-
"\u5E7F\u5DDE": "Guangzhou",
|
|
44
|
-
"\u6DF1\u5733": "Shenzhen",
|
|
45
|
-
"\u676D\u5DDE": "Hangzhou",
|
|
46
|
-
"\u5357\u4EAC": "Nanjing",
|
|
47
|
-
"\u6210\u90FD": "Chengdu",
|
|
48
|
-
"\u6B66\u6C49": "Wuhan",
|
|
49
|
-
"\u897F\u5B89": "Xi'an",
|
|
50
|
-
"\u91CD\u5E86": "Chongqing",
|
|
51
|
-
"\u5929\u6D25": "Tianjin",
|
|
52
|
-
"\u82CF\u5DDE": "Suzhou",
|
|
53
|
-
"\u957F\u6C99": "Changsha",
|
|
54
|
-
"\u9752\u5C9B": "Qingdao",
|
|
55
|
-
"\u5927\u8FDE": "Dalian",
|
|
56
|
-
"\u53A6\u95E8": "Xiamen",
|
|
57
|
-
"\u5B81\u6CE2": "Ningbo",
|
|
58
|
-
"\u65E0\u9521": "Wuxi",
|
|
59
|
-
"\u4F5B\u5C71": "Foshan",
|
|
60
|
-
"\u4E1C\u839E": "Dongguan",
|
|
61
|
-
"\u5408\u80A5": "Hefei",
|
|
62
|
-
"\u90D1\u5DDE": "Zhengzhou",
|
|
63
|
-
"\u798F\u5DDE": "Fuzhou",
|
|
64
|
-
"\u6D4E\u5357": "Jinan",
|
|
65
|
-
"\u6606\u660E": "Kunming",
|
|
66
|
-
"\u6C88\u9633": "Shenyang",
|
|
67
|
-
"\u957F\u6625": "Changchun",
|
|
68
|
-
"\u54C8\u5C14\u6EE8": "Harbin",
|
|
69
|
-
"\u77F3\u5BB6\u5E84": "Shijiazhuang",
|
|
70
|
-
"\u592A\u539F": "Taiyuan",
|
|
71
|
-
"\u5357\u660C": "Nanchang",
|
|
72
|
-
"\u5357\u5B81": "Nanning",
|
|
73
|
-
"\u8D35\u9633": "Guiyang",
|
|
74
|
-
"\u5170\u5DDE": "Lanzhou",
|
|
75
|
-
"\u6D77\u53E3": "Haikou",
|
|
76
|
-
"\u547C\u548C\u6D69\u7279": "Hohhot",
|
|
77
|
-
"\u94F6\u5DDD": "Yinchuan",
|
|
78
|
-
"\u897F\u5B81": "Xining",
|
|
79
|
-
"\u4E4C\u9C81\u6728\u9F50": "Urumqi",
|
|
80
|
-
"\u62C9\u8428": "Lhasa",
|
|
81
|
-
// 国际城市
|
|
82
|
-
"\u4F26\u6566": "London",
|
|
83
|
-
"\u7EBD\u7EA6": "New York",
|
|
84
|
-
"\u4E1C\u4EAC": "Tokyo",
|
|
85
|
-
"\u5DF4\u9ECE": "Paris",
|
|
86
|
-
"\u67CF\u6797": "Berlin",
|
|
87
|
-
"\u6089\u5C3C": "Sydney",
|
|
88
|
-
"\u6D1B\u6749\u77F6": "Los Angeles",
|
|
89
|
-
"\u591A\u4F26\u591A": "Toronto",
|
|
90
|
-
"\u65B0\u52A0\u5761": "Singapore",
|
|
91
|
-
"\u9999\u6E2F": "Hong Kong",
|
|
92
|
-
"\u53F0\u5317": "Taipei",
|
|
93
|
-
"\u9996\u5C14": "Seoul",
|
|
94
|
-
"\u66FC\u8C37": "Bangkok",
|
|
95
|
-
"\u8FEA\u62DC": "Dubai",
|
|
96
|
-
"\u83AB\u65AF\u79D1": "Moscow",
|
|
97
|
-
"\u65E7\u91D1\u5C71": "San Francisco",
|
|
98
|
-
"\u6CE2\u58EB\u987F": "Boston",
|
|
99
|
-
"\u829D\u52A0\u54E5": "Chicago",
|
|
100
|
-
"\u534E\u76DB\u987F": "Washington",
|
|
101
|
-
"\u4F11\u65AF\u987F": "Houston",
|
|
102
|
-
"\u8D39\u57CE": "Philadelphia",
|
|
103
|
-
"\u51E4\u51F0\u57CE": "Phoenix",
|
|
104
|
-
"\u5723\u8FED\u6208": "San Diego",
|
|
105
|
-
"\u8FBE\u62C9\u65AF": "Dallas",
|
|
106
|
-
"\u5723\u4F55\u585E": "San Jose",
|
|
107
|
-
"\u5965\u65AF\u6C40": "Austin",
|
|
108
|
-
"\u6E29\u54E5\u534E": "Vancouver",
|
|
109
|
-
"\u8499\u7279\u5229\u5C14": "Montreal",
|
|
110
|
-
"\u5361\u5C14\u52A0\u91CC": "Calgary",
|
|
111
|
-
"\u6E25\u592A\u534E": "Ottawa",
|
|
112
|
-
"\u9B41\u5317\u514B": "Quebec",
|
|
113
|
-
"\u57C3\u5FB7\u8499\u987F": "Edmonton",
|
|
114
|
-
"\u6E29\u5C3C\u4F2F": "Winnipeg",
|
|
115
|
-
"\u54C8\u5229\u6CD5\u514B\u65AF": "Halifax",
|
|
116
|
-
"\u7EF4\u591A\u5229\u4E9A": "Victoria"
|
|
117
|
-
};
|
|
118
|
-
process(request) {
|
|
119
|
-
const processed = JSON.parse(JSON.stringify(request));
|
|
120
|
-
if (processed.messages) {
|
|
121
|
-
processed.messages = this.processMessages(processed.messages);
|
|
122
|
-
}
|
|
123
|
-
if (processed.tools) {
|
|
124
|
-
processed.tools = this.processTools(processed.tools);
|
|
125
|
-
}
|
|
126
|
-
return processed;
|
|
127
|
-
}
|
|
128
|
-
processMessages(messages) {
|
|
129
|
-
return messages.map((msg) => {
|
|
130
|
-
if (msg.content && typeof msg.content === "string") {
|
|
131
|
-
msg.content = this.replaceCityNames(msg.content);
|
|
132
|
-
} else if (Array.isArray(msg.content)) {
|
|
133
|
-
msg.content = msg.content.map((part) => {
|
|
134
|
-
if (part.type === "text" && part.text) {
|
|
135
|
-
part.text = this.replaceCityNames(part.text);
|
|
136
|
-
}
|
|
137
|
-
return part;
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
return msg;
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
processTools(tools) {
|
|
144
|
-
return tools.map((tool) => {
|
|
145
|
-
if (tool.function?.parameters?.properties) {
|
|
146
|
-
this.processProperties(tool.function.parameters.properties);
|
|
147
|
-
}
|
|
148
|
-
if (tool.function?.description) {
|
|
149
|
-
tool.function.description = this.replaceCityNames(tool.function.description);
|
|
150
|
-
}
|
|
151
|
-
return tool;
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
processProperties(properties) {
|
|
155
|
-
for (const key in properties) {
|
|
156
|
-
if (properties[key].description) {
|
|
157
|
-
properties[key].description = this.replaceCityNames(properties[key].description);
|
|
158
|
-
}
|
|
159
|
-
if (properties[key].example) {
|
|
160
|
-
const exampleStr = JSON.stringify(properties[key].example);
|
|
161
|
-
properties[key].example = JSON.parse(this.replaceCityNames(exampleStr));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
replaceCityNames(text) {
|
|
166
|
-
let result = text;
|
|
167
|
-
for (const [chinese, english] of Object.entries(this.cityMap)) {
|
|
168
|
-
const regex = new RegExp(`\\b${chinese}\\b`, "g");
|
|
169
|
-
result = result.replace(regex, english);
|
|
170
|
-
}
|
|
171
|
-
return result;
|
|
172
|
-
}
|
|
173
|
-
// 添加自定义城市映射
|
|
174
|
-
addCityMapping(chinese, english) {
|
|
175
|
-
this.cityMap[chinese] = english;
|
|
176
|
-
}
|
|
177
|
-
// 批量添加城市映射
|
|
178
|
-
addCityMappings(mappings) {
|
|
179
|
-
Object.assign(this.cityMap, mappings);
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
|
|
183
15
|
// src/utils/request-transformer.ts
|
|
184
16
|
var RequestTransformer = class {
|
|
185
|
-
preprocessor;
|
|
186
|
-
constructor() {
|
|
187
|
-
this.preprocessor = new ChineseParamsPreprocessor();
|
|
188
|
-
}
|
|
189
17
|
transform(modelId, options) {
|
|
190
18
|
const transformed = {
|
|
191
19
|
model: modelId,
|
|
@@ -214,11 +42,15 @@ var RequestTransformer = class {
|
|
|
214
42
|
toolsArray = mode.tools ?? [];
|
|
215
43
|
toolChoice = mode.toolChoice;
|
|
216
44
|
}
|
|
45
|
+
if (toolsArray.length === 0 && options.tools && options.tools.length > 0) {
|
|
46
|
+
toolsArray = options.tools;
|
|
47
|
+
toolChoice = options.toolChoice;
|
|
48
|
+
}
|
|
217
49
|
if (toolsArray.length > 0) {
|
|
218
50
|
transformed.tools = this.transformTools(toolsArray);
|
|
219
51
|
transformed.tool_choice = this.transformToolChoice(toolChoice);
|
|
220
52
|
}
|
|
221
|
-
return
|
|
53
|
+
return transformed;
|
|
222
54
|
}
|
|
223
55
|
transformMessages(messages) {
|
|
224
56
|
return messages.map((msg) => {
|
|
@@ -276,14 +108,26 @@ var RequestTransformer = class {
|
|
|
276
108
|
});
|
|
277
109
|
}
|
|
278
110
|
transformTools(tools) {
|
|
279
|
-
return tools.map((tool) =>
|
|
280
|
-
type
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
111
|
+
return tools.map((tool) => {
|
|
112
|
+
if (tool.type === "function" && tool.function) {
|
|
113
|
+
return {
|
|
114
|
+
type: "function",
|
|
115
|
+
function: {
|
|
116
|
+
name: tool.function.name,
|
|
117
|
+
description: tool.function.description,
|
|
118
|
+
parameters: tool.function.parameters
|
|
119
|
+
}
|
|
120
|
+
};
|
|
285
121
|
}
|
|
286
|
-
|
|
122
|
+
return {
|
|
123
|
+
type: "function",
|
|
124
|
+
function: {
|
|
125
|
+
name: tool.name,
|
|
126
|
+
description: tool.description,
|
|
127
|
+
parameters: tool.parameters
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
});
|
|
287
131
|
}
|
|
288
132
|
transformToolChoice(toolChoice) {
|
|
289
133
|
if (toolChoice === void 0 || toolChoice === "auto") {
|
|
@@ -292,16 +136,16 @@ var RequestTransformer = class {
|
|
|
292
136
|
if (toolChoice === "none") {
|
|
293
137
|
return "none";
|
|
294
138
|
}
|
|
295
|
-
if (toolChoice === "required") {
|
|
139
|
+
if (toolChoice === "required" || typeof toolChoice === "object" && toolChoice.type === "required") {
|
|
296
140
|
return "required";
|
|
297
141
|
}
|
|
298
142
|
if (typeof toolChoice === "object" && toolChoice.type === "tool") {
|
|
299
|
-
return
|
|
143
|
+
return {
|
|
300
144
|
type: "function",
|
|
301
145
|
function: {
|
|
302
146
|
name: toolChoice.toolName
|
|
303
147
|
}
|
|
304
|
-
}
|
|
148
|
+
};
|
|
305
149
|
}
|
|
306
150
|
return "auto";
|
|
307
151
|
}
|
|
@@ -316,8 +160,21 @@ var ResponseTransformer = class {
|
|
|
316
160
|
choice?.finish_reason,
|
|
317
161
|
message.tool_calls
|
|
318
162
|
);
|
|
163
|
+
const toolCalls = this.transformToolCalls(message.tool_calls);
|
|
164
|
+
const content = [];
|
|
165
|
+
if (message.content) {
|
|
166
|
+
content.push({
|
|
167
|
+
type: "text",
|
|
168
|
+
text: message.content
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (toolCalls.length > 0) {
|
|
172
|
+
content.push(...toolCalls);
|
|
173
|
+
}
|
|
319
174
|
return {
|
|
175
|
+
content,
|
|
320
176
|
text: message.content || "",
|
|
177
|
+
// 兼容旧格式
|
|
321
178
|
finishReason,
|
|
322
179
|
usage: {
|
|
323
180
|
promptTokens: apiResponse.usage?.prompt_tokens || 0,
|
|
@@ -327,7 +184,8 @@ var ResponseTransformer = class {
|
|
|
327
184
|
rawPrompt: "",
|
|
328
185
|
rawSettings: {}
|
|
329
186
|
},
|
|
330
|
-
toolCalls
|
|
187
|
+
toolCalls,
|
|
188
|
+
// 兼容旧格式
|
|
331
189
|
warnings: []
|
|
332
190
|
};
|
|
333
191
|
}
|
|
@@ -349,6 +207,7 @@ var ResponseTransformer = class {
|
|
|
349
207
|
return [];
|
|
350
208
|
}
|
|
351
209
|
return toolCalls.map((tc) => ({
|
|
210
|
+
type: "tool-call",
|
|
352
211
|
toolCallType: "function",
|
|
353
212
|
toolCallId: tc.id,
|
|
354
213
|
toolName: tc.function.name,
|
|
@@ -359,11 +218,13 @@ var ResponseTransformer = class {
|
|
|
359
218
|
|
|
360
219
|
// src/utils/stream-parser.ts
|
|
361
220
|
var StreamParser = class {
|
|
221
|
+
hasToolCalls = false;
|
|
362
222
|
async *parse(body) {
|
|
363
223
|
const reader = body.getReader();
|
|
364
224
|
const decoder = new TextDecoder("utf-8");
|
|
365
225
|
let buffer = "";
|
|
366
226
|
let partialJson = "";
|
|
227
|
+
this.hasToolCalls = false;
|
|
367
228
|
try {
|
|
368
229
|
while (true) {
|
|
369
230
|
const { done, value } = await reader.read();
|
|
@@ -411,6 +272,7 @@ var StreamParser = class {
|
|
|
411
272
|
if (delta?.content) {
|
|
412
273
|
const toolCallData = this.tryParseToolCall(delta.content);
|
|
413
274
|
if (toolCallData) {
|
|
275
|
+
this.hasToolCalls = true;
|
|
414
276
|
yield {
|
|
415
277
|
type: "tool-call-delta",
|
|
416
278
|
toolCallType: "function",
|
|
@@ -426,6 +288,7 @@ var StreamParser = class {
|
|
|
426
288
|
}
|
|
427
289
|
}
|
|
428
290
|
if (delta?.tool_calls && delta.tool_calls.length > 0) {
|
|
291
|
+
this.hasToolCalls = true;
|
|
429
292
|
for (const toolCall of delta.tool_calls) {
|
|
430
293
|
yield {
|
|
431
294
|
type: "tool-call-delta",
|
|
@@ -450,6 +313,9 @@ var StreamParser = class {
|
|
|
450
313
|
}
|
|
451
314
|
}
|
|
452
315
|
mapFinishReason(reason) {
|
|
316
|
+
if (reason === "stop" && this.hasToolCalls) {
|
|
317
|
+
return "tool-calls";
|
|
318
|
+
}
|
|
453
319
|
const reasonMap = {
|
|
454
320
|
"stop": "stop",
|
|
455
321
|
"length": "length",
|
|
@@ -545,12 +411,47 @@ var DeepSeekChatLanguageModel = class {
|
|
|
545
411
|
};
|
|
546
412
|
}
|
|
547
413
|
};
|
|
414
|
+
|
|
415
|
+
// src/deepseek-provider.ts
|
|
416
|
+
async function createDeepSeek(options = {}) {
|
|
417
|
+
const apiKey = await loadApiKey({
|
|
418
|
+
apiKey: options.apiKey,
|
|
419
|
+
environmentVariableName: "DEEPSEEK_API_KEY",
|
|
420
|
+
description: "DeepSeek API key"
|
|
421
|
+
});
|
|
422
|
+
const baseURL = options.baseURL || "https://api.deepseek.com";
|
|
423
|
+
const providerFunction = function(modelId, settings) {
|
|
424
|
+
return new DeepSeekChatLanguageModel(
|
|
425
|
+
modelId,
|
|
426
|
+
settings,
|
|
427
|
+
{
|
|
428
|
+
baseURL,
|
|
429
|
+
headers: () => ({
|
|
430
|
+
Authorization: `Bearer ${apiKey}`,
|
|
431
|
+
...options.headers || {}
|
|
432
|
+
})
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
};
|
|
436
|
+
providerFunction.languageModel = providerFunction;
|
|
437
|
+
providerFunction.chat = providerFunction;
|
|
438
|
+
providerFunction.textEmbeddingModel = () => {
|
|
439
|
+
throw new Error("Text embedding models are not supported for DeepSeek");
|
|
440
|
+
};
|
|
441
|
+
return providerFunction;
|
|
442
|
+
}
|
|
443
|
+
var deepseek = createDeepSeek();
|
|
444
|
+
var createProvider = createDeepSeek;
|
|
445
|
+
|
|
446
|
+
// src/index.ts
|
|
447
|
+
var VERSION = "0.2.0";
|
|
548
448
|
export {
|
|
549
|
-
ChineseParamsPreprocessor,
|
|
550
449
|
DeepSeekChatLanguageModel,
|
|
551
450
|
RequestTransformer,
|
|
552
451
|
ResponseTransformer,
|
|
553
452
|
StreamParser,
|
|
453
|
+
VERSION,
|
|
454
|
+
createDeepSeek,
|
|
554
455
|
createProvider,
|
|
555
456
|
deepseek,
|
|
556
457
|
validateChatSettings
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/deepseek-provider.ts","../src/deepseek-chat-settings.ts","../src/utils/chinese-params-preprocessor.ts","../src/utils/request-transformer.ts","../src/utils/response-transformer.ts","../src/utils/stream-parser.ts","../src/deepseek-chat-language-model.ts"],"sourcesContent":["// DeepSeek Provider 工厂 - 基于官方 @ai-sdk/deepseek 扩展\n\nimport { createDeepSeek as createOfficialProvider } from '@ai-sdk/deepseek';\nimport { loadApiKey } from '@ai-sdk/provider-utils';\nimport type { DeepSeekProviderSettings } from './types';\n\ninterface DeepSeekProviderInstance {\n id: string;\n name: string;\n initialize(): Promise<void>;\n chat(modelId: string, settings?: any): any;\n}\n\nexport async function createProvider(options: DeepSeekProviderSettings = {}): Promise<DeepSeekProviderInstance> {\n const officialProvider = createOfficialProvider({\n apiKey: options.apiKey,\n baseURL: options.baseURL,\n headers: options.headers,\n });\n\n const provider: DeepSeekProviderInstance = {\n id: 'deepseek',\n name: 'DeepSeek AI',\n async initialize() {\n await loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'DEEPSEEK_API_KEY',\n description: 'DeepSeek API key',\n });\n },\n chat: officialProvider.chat,\n };\n\n return provider;\n}\n\nexport const deepseek = createProvider();","// DeepSeek Chat 模型配置\n\nimport type { DeepSeekChatSettings } from './types';\n\nexport function validateChatSettings(settings: DeepSeekChatSettings = {}): Required<DeepSeekChatSettings> {\n return {\n temperature: settings.temperature ?? 0.7,\n topP: settings.topP ?? 1.0,\n maxTokens: settings.maxTokens ?? 4096,\n presencePenalty: settings.presencePenalty ?? 0,\n frequencyPenalty: settings.frequencyPenalty ?? 0,\n };\n}","// 中文参数预处理器\n\nimport type { DeepSeekRequest } from '../types';\n\nexport class ChineseParamsPreprocessor {\n private cityMap: Record<string, string> = {\n // 中国城市\n '北京': 'Beijing',\n '上海': 'Shanghai',\n '广州': 'Guangzhou',\n '深圳': 'Shenzhen',\n '杭州': 'Hangzhou',\n '南京': 'Nanjing',\n '成都': 'Chengdu',\n '武汉': 'Wuhan',\n '西安': 'Xi\\'an',\n '重庆': 'Chongqing',\n '天津': 'Tianjin',\n '苏州': 'Suzhou',\n '长沙': 'Changsha',\n '青岛': 'Qingdao',\n '大连': 'Dalian',\n '厦门': 'Xiamen',\n '宁波': 'Ningbo',\n '无锡': 'Wuxi',\n '佛山': 'Foshan',\n '东莞': 'Dongguan',\n '合肥': 'Hefei',\n '郑州': 'Zhengzhou',\n '福州': 'Fuzhou',\n '济南': 'Jinan',\n '昆明': 'Kunming',\n '沈阳': 'Shenyang',\n '长春': 'Changchun',\n '哈尔滨': 'Harbin',\n '石家庄': 'Shijiazhuang',\n '太原': 'Taiyuan',\n '南昌': 'Nanchang',\n '南宁': 'Nanning',\n '贵阳': 'Guiyang',\n '兰州': 'Lanzhou',\n '海口': 'Haikou',\n '呼和浩特': 'Hohhot',\n '银川': 'Yinchuan',\n '西宁': 'Xining',\n '乌鲁木齐': 'Urumqi',\n '拉萨': 'Lhasa',\n // 国际城市\n '伦敦': 'London',\n '纽约': 'New York',\n '东京': 'Tokyo',\n '巴黎': 'Paris',\n '柏林': 'Berlin',\n '悉尼': 'Sydney',\n '洛杉矶': 'Los Angeles',\n '多伦多': 'Toronto',\n '新加坡': 'Singapore',\n '香港': 'Hong Kong',\n '台北': 'Taipei',\n '首尔': 'Seoul',\n '曼谷': 'Bangkok',\n '迪拜': 'Dubai',\n '莫斯科': 'Moscow',\n '旧金山': 'San Francisco',\n '波士顿': 'Boston',\n '芝加哥': 'Chicago',\n '华盛顿': 'Washington',\n '休斯顿': 'Houston',\n '费城': 'Philadelphia',\n '凤凰城': 'Phoenix',\n '圣迭戈': 'San Diego',\n '达拉斯': 'Dallas',\n '圣何塞': 'San Jose',\n '奥斯汀': 'Austin',\n '温哥华': 'Vancouver',\n '蒙特利尔': 'Montreal',\n '卡尔加里': 'Calgary',\n '渥太华': 'Ottawa',\n '魁北克': 'Quebec',\n '埃德蒙顿': 'Edmonton',\n '温尼伯': 'Winnipeg',\n '哈利法克斯': 'Halifax',\n '维多利亚': 'Victoria',\n };\n\n process(request: DeepSeekRequest): DeepSeekRequest {\n const processed = JSON.parse(JSON.stringify(request));\n\n // 处理消息内容\n if (processed.messages) {\n processed.messages = this.processMessages(processed.messages);\n }\n\n // 处理工具参数\n if (processed.tools) {\n processed.tools = this.processTools(processed.tools);\n }\n\n return processed;\n }\n\n private processMessages(messages: any[]): any[] {\n return messages.map(msg => {\n if (msg.content && typeof msg.content === 'string') {\n msg.content = this.replaceCityNames(msg.content);\n } else if (Array.isArray(msg.content)) {\n msg.content = msg.content.map((part: any) => {\n if (part.type === 'text' && part.text) {\n part.text = this.replaceCityNames(part.text);\n }\n return part;\n });\n }\n return msg;\n });\n }\n\n private processTools(tools: any[]): any[] {\n return tools.map(tool => {\n if (tool.function?.parameters?.properties) {\n this.processProperties(tool.function.parameters.properties);\n }\n if (tool.function?.description) {\n tool.function.description = this.replaceCityNames(tool.function.description);\n }\n return tool;\n });\n }\n\n private processProperties(properties: any): void {\n for (const key in properties) {\n if (properties[key].description) {\n properties[key].description = this.replaceCityNames(properties[key].description);\n }\n if (properties[key].example) {\n const exampleStr = JSON.stringify(properties[key].example);\n properties[key].example = JSON.parse(this.replaceCityNames(exampleStr));\n }\n }\n }\n\n private replaceCityNames(text: string): string {\n let result = text;\n for (const [chinese, english] of Object.entries(this.cityMap)) {\n // 使用正则表达式替换,避免替换部分匹配的词\n const regex = new RegExp(`\\\\b${chinese}\\\\b`, 'g');\n result = result.replace(regex, english);\n }\n return result;\n }\n\n // 添加自定义城市映射\n addCityMapping(chinese: string, english: string): void {\n this.cityMap[chinese] = english;\n }\n\n // 批量添加城市映射\n addCityMappings(mappings: Record<string, string>): void {\n Object.assign(this.cityMap, mappings);\n }\n}","// 请求转换器\n\nimport type {\n LanguageModelV1CallOptions,\n LanguageModelV1Prompt,\n} from '@ai-sdk/provider';\nimport type { DeepSeekRequest } from '../types';\nimport { ChineseParamsPreprocessor } from './chinese-params-preprocessor';\n\nexport class RequestTransformer {\n private preprocessor: ChineseParamsPreprocessor;\n\n constructor() {\n this.preprocessor = new ChineseParamsPreprocessor();\n }\n\n transform(modelId: string, options: LanguageModelV1CallOptions): DeepSeekRequest {\n const transformed: DeepSeekRequest = {\n model: modelId,\n messages: this.transformMessages(options.prompt),\n stream: false,\n };\n\n // 添加温度参数\n if (options.temperature !== undefined) {\n transformed.temperature = options.temperature;\n }\n\n // 添加 top_p 参数\n if (options.topP !== undefined) {\n transformed.top_p = options.topP;\n }\n\n // 添加 max_tokens 参数\n if (options.maxTokens !== undefined) {\n transformed.max_tokens = options.maxTokens;\n }\n\n // 添加 presence_penalty 参数\n if (options.presencePenalty !== undefined) {\n transformed.presence_penalty = options.presencePenalty;\n }\n\n // 添加 frequency_penalty 参数\n if (options.frequencyPenalty !== undefined) {\n transformed.frequency_penalty = options.frequencyPenalty;\n }\n\n // 添加工具配置\n const mode = options.mode;\n let toolsArray: Array<any> = [];\n let toolChoice: any;\n\n // 只有 'regular' 模式支持工具\n if (mode && mode.type === 'regular') {\n toolsArray = mode.tools ?? [];\n toolChoice = mode.toolChoice;\n }\n\n if (toolsArray.length > 0) {\n transformed.tools = this.transformTools(toolsArray);\n transformed.tool_choice = this.transformToolChoice(toolChoice);\n }\n\n // 预处理中文参数\n return this.preprocessor.process(transformed);\n }\n\n private transformMessages(messages: LanguageModelV1Prompt): Array<any> {\n return messages.map((msg) => {\n const transformed: any = {\n role: msg.role,\n };\n\n // 处理内容\n if (msg.content && Array.isArray(msg.content)) {\n const contentParts: Array<any> = [];\n let hasToolCalls = false;\n let toolCallsArray: Array<any> = [];\n\n for (const part of msg.content) {\n // 处理文本内容\n if (part.type === 'text') {\n contentParts.push({ type: 'text', text: part.text });\n }\n // 处理图像内容\n else if (part.type === 'image') {\n // V1 image part has 'image' property, convert to data for DeepSeek API\n const imageData = part.image;\n if (typeof imageData === 'string') {\n contentParts.push({ type: 'image_url', image_url: { url: imageData } });\n } else if (imageData instanceof URL) {\n contentParts.push({ type: 'image_url', image_url: { url: imageData.toString() } });\n }\n }\n // 处理工具调用 (V1 格式)\n else if (part.type === 'tool-call') {\n hasToolCalls = true;\n toolCallsArray.push({\n id: part.toolCallId,\n type: 'function',\n function: {\n name: part.toolName,\n arguments: typeof part.args === 'string' ? part.args : JSON.stringify(part.args),\n },\n });\n }\n // 处理工具结果 (V1 格式)\n else if (part.type === 'tool-result') {\n // Tool results in V1 don't get added to content directly\n // They are already part of the prompt structure\n }\n // 处理推理内容\n else if (part.type === 'reasoning' || part.type === 'redacted-reasoning') {\n // DeepSeek API doesn't support reasoning content directly\n // We'll add it as text if there's a text field\n if ('text' in part && part.text) {\n contentParts.push({ type: 'text', text: part.text });\n }\n }\n // 处理文件内容\n else if (part.type === 'file') {\n contentParts.push({\n type: 'text',\n text: `[File: ${part.filename || 'unnamed'}]`,\n });\n }\n // 其他未知类型\n else {\n contentParts.push(part);\n }\n }\n\n // 设置内容\n if (contentParts.length > 0) {\n transformed.content = contentParts;\n }\n\n // 添加工具调用\n if (hasToolCalls && toolCallsArray.length > 0) {\n transformed.tool_calls = toolCallsArray;\n }\n } else if (typeof msg.content === 'string') {\n // 系统消息等内容为字符串的情况\n transformed.content = msg.content;\n }\n\n return transformed;\n });\n }\n\n private transformTools(tools: Array<any>): Array<any> {\n return tools.map(tool => ({\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n },\n }));\n }\n\n private transformToolChoice(toolChoice: any): 'auto' | 'none' | 'required' | string {\n if (toolChoice === undefined || toolChoice === 'auto') {\n return 'auto';\n }\n if (toolChoice === 'none') {\n return 'none';\n }\n if (toolChoice === 'required') {\n return 'required';\n }\n if (typeof toolChoice === 'object' && toolChoice.type === 'tool') {\n return JSON.stringify({\n type: 'function',\n function: {\n name: toolChoice.toolName,\n },\n });\n }\n return 'auto';\n }\n}","// 响应转换器 - V1 API 兼容版本\n\nimport type {\n LanguageModelV1,\n LanguageModelV1FinishReason,\n LanguageModelV1CallWarning,\n LanguageModelV1FunctionToolCall,\n} from '@ai-sdk/provider';\nimport type { DeepSeekResponse } from '../types';\n\n// V1 API 返回结果类型\nexport interface V1GenerateResult {\n text?: string;\n reasoning?: string;\n usage: {\n promptTokens: number;\n completionTokens: number;\n };\n finishReason: LanguageModelV1FinishReason;\n toolCalls?: LanguageModelV1FunctionToolCall[];\n rawCall: {\n rawPrompt: unknown;\n rawSettings: Record<string, unknown>;\n };\n warnings?: LanguageModelV1CallWarning[];\n}\n\nexport class ResponseTransformer {\n transform(apiResponse: DeepSeekResponse): V1GenerateResult {\n const choice = apiResponse.choices?.[0];\n const message = choice?.message || {};\n\n // 修复 finish_reason\n const finishReason = this.fixFinishReason(\n choice?.finish_reason,\n message.tool_calls\n );\n\n return {\n text: message.content || '',\n finishReason: finishReason as LanguageModelV1FinishReason,\n usage: {\n promptTokens: apiResponse.usage?.prompt_tokens || 0,\n completionTokens: apiResponse.usage?.completion_tokens || 0,\n },\n rawCall: {\n rawPrompt: '',\n rawSettings: {},\n },\n toolCalls: this.transformToolCalls(message.tool_calls),\n warnings: [],\n };\n }\n\n private fixFinishReason(\n originalFinishReason: string | undefined,\n toolCalls: any[] | undefined\n ): string {\n // 如果有 tool_calls 但 finish_reason 是 \"stop\",修复为 \"tool-calls\"\n if (toolCalls && toolCalls.length > 0 && originalFinishReason === 'stop') {\n return 'tool-calls';\n }\n\n // 映射其他 finish_reason 值\n const finishReasonMap: Record<string, string> = {\n 'stop': 'stop',\n 'length': 'length',\n 'content_filter': 'content-filter',\n 'tool_calls': 'tool-calls',\n 'function_call': 'tool-calls',\n };\n\n return finishReasonMap[originalFinishReason || ''] || 'stop';\n }\n\n private transformToolCalls(toolCalls: any[] | undefined): LanguageModelV1FunctionToolCall[] {\n if (!toolCalls || toolCalls.length === 0) {\n return [];\n }\n\n return toolCalls.map((tc: any) => ({\n toolCallType: 'function' as const,\n toolCallId: tc.id,\n toolName: tc.function.name,\n args: typeof tc.function.arguments === 'string'\n ? tc.function.arguments\n : JSON.stringify(tc.function.arguments),\n }));\n }\n}","// 流解析器\n\nimport type { LanguageModelV1StreamPart } from '@ai-sdk/provider';\nimport type { DeepSeekStreamResponse, DeepSeekUsage } from '../types';\n\ninterface DeepSeekStreamChunk {\n id: string;\n object: string;\n created: number;\n model: string;\n choices: Array<{\n index: number;\n delta: {\n role?: string;\n content?: string;\n tool_calls?: Array<{\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n }>;\n };\n finish_reason?: string;\n }>;\n usage?: DeepSeekUsage;\n}\n\nexport class StreamParser {\n async *parse(body: ReadableStream<Uint8Array>): AsyncIterable<LanguageModelV1StreamPart> {\n const reader = body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n let partialJson = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n if (line.startsWith(':')) continue; // SSE 注释\n\n if (line.startsWith('data: ')) {\n const data = line.slice(6).trim();\n if (data === '[DONE]') {\n yield* this.processPartialJson(partialJson);\n partialJson = '';\n return;\n }\n\n try {\n // 尝试解析 JSON\n const parsed = JSON.parse(data);\n yield* this.processPartialJson(partialJson);\n partialJson = '';\n yield* this.processChunk(parsed);\n } catch (e) {\n // JSON 解析失败,可能是部分数据\n partialJson += data;\n }\n }\n }\n }\n\n // 处理剩余的部分 JSON\n yield* this.processPartialJson(partialJson);\n } finally {\n reader.releaseLock();\n }\n }\n\n private async *processPartialJson(partialJson: string): AsyncIterable<LanguageModelV1StreamPart> {\n if (!partialJson.trim()) return;\n\n try {\n const parsed = JSON.parse(partialJson);\n yield* this.processChunk(parsed);\n } catch (e) {\n // 仍然无法解析,跳过\n console.warn('Failed to parse partial JSON:', partialJson);\n }\n }\n\n private async *processChunk(chunk: DeepSeekStreamChunk): AsyncIterable<LanguageModelV1StreamPart> {\n const delta = chunk.choices?.[0]?.delta;\n\n // 工具调用增量 - JSON in content 格式\n if (delta?.content) {\n const toolCallData = this.tryParseToolCall(delta.content);\n if (toolCallData) {\n yield {\n type: 'tool-call-delta',\n toolCallType: 'function',\n toolCallId: toolCallData.id || `tool-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n toolName: toolCallData.name,\n argsTextDelta: JSON.stringify(toolCallData.arguments || {}),\n } as LanguageModelV1StreamPart;\n } else {\n // 普通文本增量\n yield {\n type: 'text-delta',\n textDelta: delta.content,\n } as LanguageModelV1StreamPart;\n }\n }\n\n // 工具调用增量 - 标准 tool_calls 格式\n if (delta?.tool_calls && delta.tool_calls.length > 0) {\n for (const toolCall of delta.tool_calls) {\n yield {\n type: 'tool-call-delta',\n toolCallType: 'function',\n toolCallId: toolCall.id,\n toolName: toolCall.function?.name || '',\n argsTextDelta: toolCall.function?.arguments || '',\n } as LanguageModelV1StreamPart;\n }\n }\n\n // 完成信号\n const finishReason = chunk.choices?.[0]?.finish_reason;\n if (finishReason) {\n // V1 API: usage 在 finish 类型的 part 中\n const usage = chunk.usage\n ? {\n promptTokens: chunk.usage.prompt_tokens,\n completionTokens: chunk.usage.completion_tokens,\n }\n : { promptTokens: 0, completionTokens: 0 };\n\n yield {\n type: 'finish',\n finishReason: this.mapFinishReason(finishReason),\n usage,\n } as LanguageModelV1StreamPart;\n }\n }\n\n private mapFinishReason(reason: string): 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other' | 'unknown' {\n const reasonMap: Record<string, 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other' | 'unknown'> = {\n 'stop': 'stop',\n 'length': 'length',\n 'content_filter': 'content-filter',\n 'tool_calls': 'tool-calls',\n 'function_call': 'tool-calls',\n 'error': 'error',\n };\n return reasonMap[reason] || 'unknown';\n }\n\n private tryParseToolCall(content: string): { id?: string; name: string; arguments: Record<string, unknown> } | null {\n try {\n const parsed = JSON.parse(content);\n // 检查是否是工具调用格式: { name: \"...\", arguments: {...} }\n if (parsed && typeof parsed.name === 'string' && (parsed.arguments === undefined || typeof parsed.arguments === 'object')) {\n return {\n id: parsed.id,\n name: parsed.name,\n arguments: parsed.arguments || {},\n };\n }\n } catch {\n // JSON 解析失败,不是工具调用\n }\n return null;\n }\n}\n\n\n","// DeepSeek Chat 模型实现\n\nimport type {\n LanguageModelV1,\n LanguageModelV1CallOptions,\n} from '@ai-sdk/provider';\nimport type { DeepSeekChatSettings, DeepSeekResponse } from './types';\nimport { validateChatSettings } from './deepseek-chat-settings';\nimport { RequestTransformer } from './utils/request-transformer';\nimport { ResponseTransformer } from './utils/response-transformer';\nimport { StreamParser } from './utils/stream-parser';\n\nexport class DeepSeekChatLanguageModel implements LanguageModelV1 {\n readonly specificationVersion = 'v1' as const;\n readonly provider = 'deepseek' as const;\n readonly modelId: string;\n readonly settings: Required<DeepSeekChatSettings>;\n readonly defaultObjectGenerationMode: 'json' | 'tool' | undefined = undefined;\n\n private baseURL: string;\n private headers: () => Record<string, string>;\n private requestTransformer: RequestTransformer;\n private responseTransformer: ResponseTransformer;\n private streamParser: StreamParser;\n\n constructor(\n modelId: string,\n settings: DeepSeekChatSettings = {},\n config: {\n baseURL: string;\n headers: () => Record<string, string>;\n }\n ) {\n this.modelId = modelId;\n this.settings = validateChatSettings(settings);\n this.baseURL = config.baseURL;\n this.headers = config.headers;\n this.requestTransformer = new RequestTransformer();\n this.responseTransformer = new ResponseTransformer();\n this.streamParser = new StreamParser();\n }\n\n async doGenerate(options: LanguageModelV1CallOptions) {\n const requestBody = this.requestTransformer.transform(this.modelId, options);\n\n const response = await fetch(`${this.baseURL}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.headers(),\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`DeepSeek API error: ${response.status} - ${error}`);\n }\n\n const apiResponse = (await response.json()) as DeepSeekResponse;\n return this.responseTransformer.transform(apiResponse);\n }\n\n async doStream(options: LanguageModelV1CallOptions) {\n const requestBody = {\n ...this.requestTransformer.transform(this.modelId, options),\n stream: true,\n };\n\n const response = await fetch(`${this.baseURL}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'text/event-stream',\n ...this.headers(),\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`DeepSeek API error: ${response.status} - ${error}`);\n }\n\n if (!response.body) {\n throw new Error('Response body is null');\n }\n\n return {\n stream: this.streamParser.parse(response.body) as any,\n rawCall: {\n rawPrompt: requestBody as unknown,\n rawSettings: {},\n },\n warnings: [],\n };\n }\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/deepseek-provider.ts","../src/deepseek-chat-settings.ts","../src/utils/request-transformer.ts","../src/utils/response-transformer.ts","../src/utils/stream-parser.ts","../src/deepseek-chat-language-model.ts","../src/index.ts"],"sourcesContent":["// DeepSeek Provider - 完全兼容官方 @ai-sdk/deepseek 接口\n\nimport { loadApiKey } from '@ai-sdk/provider-utils';\nimport type { DeepSeekProviderSettings, DeepSeekChatSettings } from './types';\nimport { DeepSeekChatLanguageModel } from './deepseek-chat-language-model';\n\n// Provider 接口定义(兼容官方)\nexport interface DeepSeekProvider {\n /**\n * 创建 DeepSeek 模型用于文本生成\n */\n (modelId: string, settings?: DeepSeekChatSettings): DeepSeekChatLanguageModel;\n\n /**\n * 创建 DeepSeek 模型用于文本生成\n */\n languageModel(modelId: string, settings?: DeepSeekChatSettings): DeepSeekChatLanguageModel;\n\n /**\n * 创建 DeepSeek 聊天模型用于文本生成\n */\n chat(modelId: string, settings?: DeepSeekChatSettings): DeepSeekChatLanguageModel;\n\n /**\n * 文本嵌入模型(暂不支持)\n * @deprecated\n */\n textEmbeddingModel(modelId: string): never;\n}\n\n/**\n * 创建 DeepSeek Provider\n * 完全兼容官方 @ai-sdk/deepseek 的 createDeepSeek 函数\n */\nexport async function createDeepSeek(\n options: DeepSeekProviderSettings = {}\n): Promise<DeepSeekProvider> {\n // 加载 API Key\n const apiKey = await loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'DEEPSEEK_API_KEY',\n description: 'DeepSeek API key',\n });\n\n const baseURL = options.baseURL || 'https://api.deepseek.com';\n\n // 创建 provider 函数\n const providerFunction = function(\n modelId: string,\n settings?: DeepSeekChatSettings\n ): DeepSeekChatLanguageModel {\n return new DeepSeekChatLanguageModel(\n modelId,\n settings,\n {\n baseURL,\n headers: () => ({\n Authorization: `Bearer ${apiKey}`,\n ...(options.headers || {}),\n }),\n }\n );\n } as DeepSeekProvider;\n\n // 添加方法到 provider 函数对象\n providerFunction.languageModel = providerFunction;\n providerFunction.chat = providerFunction;\n providerFunction.textEmbeddingModel = () => {\n throw new Error('Text embedding models are not supported for DeepSeek');\n };\n\n return providerFunction;\n}\n\n// 默认导出的 provider 实例\nexport const deepseek = createDeepSeek();\n\n// 为了向后兼容,保留 createProvider 作为别名\nexport const createProvider = createDeepSeek;\n","// DeepSeek Chat 模型配置\n\nimport type { DeepSeekChatSettings } from './types';\n\nexport function validateChatSettings(settings: DeepSeekChatSettings = {}): Required<DeepSeekChatSettings> {\n return {\n temperature: settings.temperature ?? 0.7,\n topP: settings.topP ?? 1.0,\n maxTokens: settings.maxTokens ?? 4096,\n presencePenalty: settings.presencePenalty ?? 0,\n frequencyPenalty: settings.frequencyPenalty ?? 0,\n };\n}","// 请求转换器\n\nimport type {\n LanguageModelV1CallOptions,\n LanguageModelV1Prompt,\n} from '@ai-sdk/provider';\nimport type { DeepSeekRequest } from '../types';\n\nexport class RequestTransformer {\n transform(modelId: string, options: LanguageModelV1CallOptions): DeepSeekRequest {\n const transformed: DeepSeekRequest = {\n model: modelId,\n messages: this.transformMessages(options.prompt),\n stream: false,\n };\n\n // 添加温度参数\n if (options.temperature !== undefined) {\n transformed.temperature = options.temperature;\n }\n\n // 添加 top_p 参数\n if (options.topP !== undefined) {\n transformed.top_p = options.topP;\n }\n\n // 添加 max_tokens 参数\n if (options.maxTokens !== undefined) {\n transformed.max_tokens = options.maxTokens;\n }\n\n // 添加 presence_penalty 参数\n if (options.presencePenalty !== undefined) {\n transformed.presence_penalty = options.presencePenalty;\n }\n\n // 添加 frequency_penalty 参数\n if (options.frequencyPenalty !== undefined) {\n transformed.frequency_penalty = options.frequencyPenalty;\n }\n\n // 添加工具配置\n const mode = options.mode;\n let toolsArray: Array<any> = [];\n let toolChoice: any;\n\n // 只有 'regular' 模式支持工具\n if (mode && mode.type === 'regular') {\n toolsArray = mode.tools ?? [];\n toolChoice = mode.toolChoice;\n }\n\n // 如果没有通过 mode 传递工具,检查直接传递的 tools 参数(向后兼容)\n if (toolsArray.length === 0 && options.tools && options.tools.length > 0) {\n toolsArray = options.tools;\n toolChoice = options.toolChoice;\n }\n\n if (toolsArray.length > 0) {\n transformed.tools = this.transformTools(toolsArray);\n transformed.tool_choice = this.transformToolChoice(toolChoice);\n }\n\n return transformed;\n }\n\n private transformMessages(messages: LanguageModelV1Prompt): Array<any> {\n return messages.map((msg) => {\n const transformed: any = {\n role: msg.role,\n };\n\n // 处理内容\n if (msg.content && Array.isArray(msg.content)) {\n const contentParts: Array<any> = [];\n let hasToolCalls = false;\n let toolCallsArray: Array<any> = [];\n\n for (const part of msg.content) {\n // 处理文本内容\n if (part.type === 'text') {\n contentParts.push({ type: 'text', text: part.text });\n }\n // 处理图像内容\n else if (part.type === 'image') {\n // V1 image part has 'image' property, convert to data for DeepSeek API\n const imageData = part.image;\n if (typeof imageData === 'string') {\n contentParts.push({ type: 'image_url', image_url: { url: imageData } });\n } else if (imageData instanceof URL) {\n contentParts.push({ type: 'image_url', image_url: { url: imageData.toString() } });\n }\n }\n // 处理工具调用 (V1 格式)\n else if (part.type === 'tool-call') {\n hasToolCalls = true;\n toolCallsArray.push({\n id: part.toolCallId,\n type: 'function',\n function: {\n name: part.toolName,\n arguments: typeof part.args === 'string' ? part.args : JSON.stringify(part.args),\n },\n });\n }\n // 处理工具结果 (V1 格式)\n else if (part.type === 'tool-result') {\n // Tool results in V1 don't get added to content directly\n // They are already part of the prompt structure\n }\n // 处理推理内容\n else if (part.type === 'reasoning' || part.type === 'redacted-reasoning') {\n // DeepSeek API doesn't support reasoning content directly\n // We'll add it as text if there's a text field\n if ('text' in part && part.text) {\n contentParts.push({ type: 'text', text: part.text });\n }\n }\n // 处理文件内容\n else if (part.type === 'file') {\n contentParts.push({\n type: 'text',\n text: `[File: ${part.filename || 'unnamed'}]`,\n });\n }\n // 其他未知类型\n else {\n contentParts.push(part);\n }\n }\n\n // 设置内容\n if (contentParts.length > 0) {\n transformed.content = contentParts;\n }\n\n // 添加工具调用\n if (hasToolCalls && toolCallsArray.length > 0) {\n transformed.tool_calls = toolCallsArray;\n }\n } else if (typeof msg.content === 'string') {\n // 系统消息等内容为字符串的情况\n transformed.content = msg.content;\n }\n\n return transformed;\n });\n }\n\n private transformTools(tools: Array<any>): Array<any> {\n return tools.map(tool => {\n // AI SDK V1 格式: { type: 'function', function: { name, description, parameters } }\n if (tool.type === 'function' && tool.function) {\n return {\n type: 'function',\n function: {\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n },\n };\n }\n\n // 备用格式(向后兼容)\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n },\n };\n });\n }\n\n private transformToolChoice(toolChoice: any): any {\n // undefined 或 auto -> 'auto'\n if (toolChoice === undefined || toolChoice === 'auto') {\n return 'auto';\n }\n\n // none -> 'none'\n if (toolChoice === 'none') {\n return 'none';\n }\n\n // required -> 'required' (强制调用至少一个工具)\n if (toolChoice === 'required' || (typeof toolChoice === 'object' && toolChoice.type === 'required')) {\n return 'required';\n }\n\n // 特定工具: { type: 'tool', toolName: 'function_name' }\n if (typeof toolChoice === 'object' && toolChoice.type === 'tool') {\n // DeepSeek API 可能支持的格式\n return {\n type: 'function',\n function: {\n name: toolChoice.toolName,\n },\n };\n }\n\n // 默认: auto\n return 'auto';\n }\n}","// 响应转换器 - 新 AI SDK 格式\n\nimport type {\n LanguageModelV1FinishReason,\n LanguageModelV1CallWarning,\n LanguageModelV1FunctionToolCall,\n LanguageModelV1ContentPart,\n} from '@ai-sdk/provider';\nimport type { DeepSeekResponse } from '../types';\n\n// 新 AI SDK 返回结果类型\nexport interface V1GenerateResult {\n content: LanguageModelV1ContentPart[];\n finishReason: LanguageModelV1FinishReason;\n usage: {\n promptTokens: number;\n completionTokens: number;\n };\n rawCall: {\n rawPrompt: unknown;\n rawSettings: Record<string, unknown>;\n };\n warnings?: LanguageModelV1CallWarning[];\n // 兼容旧格式的字段\n text?: string;\n toolCalls?: LanguageModelV1FunctionToolCall[];\n reasoning?: string;\n}\n\nexport class ResponseTransformer {\n transform(apiResponse: DeepSeekResponse): V1GenerateResult {\n const choice = apiResponse.choices?.[0];\n const message = choice?.message || {};\n\n // 修复 finish_reason\n const finishReason = this.fixFinishReason(\n choice?.finish_reason,\n message.tool_calls\n );\n\n // 转换工具调用\n const toolCalls = this.transformToolCalls(message.tool_calls);\n\n // 构建内容数组\n const content: LanguageModelV1ContentPart[] = [];\n\n // 添加文本内容\n if (message.content) {\n content.push({\n type: 'text',\n text: message.content,\n });\n }\n\n // 添加工具调用\n if (toolCalls.length > 0) {\n content.push(...toolCalls);\n }\n\n return {\n content,\n text: message.content || '', // 兼容旧格式\n finishReason: finishReason as LanguageModelV1FinishReason,\n usage: {\n promptTokens: apiResponse.usage?.prompt_tokens || 0,\n completionTokens: apiResponse.usage?.completion_tokens || 0,\n },\n rawCall: {\n rawPrompt: '',\n rawSettings: {},\n },\n toolCalls, // 兼容旧格式\n warnings: [],\n };\n }\n\n private fixFinishReason(\n originalFinishReason: string | undefined,\n toolCalls: any[] | undefined\n ): string {\n // 如果有 tool_calls 但 finish_reason 是 \"stop\",修复为 \"tool-calls\"\n if (toolCalls && toolCalls.length > 0 && originalFinishReason === 'stop') {\n return 'tool-calls';\n }\n\n // 映射其他 finish_reason 值\n const finishReasonMap: Record<string, string> = {\n 'stop': 'stop',\n 'length': 'length',\n 'content_filter': 'content-filter',\n 'tool_calls': 'tool-calls',\n 'function_call': 'tool-calls',\n };\n\n return finishReasonMap[originalFinishReason || ''] || 'stop';\n }\n\n private transformToolCalls(toolCalls: any[] | undefined): LanguageModelV1FunctionToolCall[] {\n if (!toolCalls || toolCalls.length === 0) {\n return [];\n }\n\n return toolCalls.map((tc: any) => ({\n type: 'tool-call' as const,\n toolCallType: 'function' as const,\n toolCallId: tc.id,\n toolName: tc.function.name,\n args: typeof tc.function.arguments === 'string'\n ? tc.function.arguments\n : JSON.stringify(tc.function.arguments),\n }));\n }\n}\n","// 流解析器\n\nimport type { LanguageModelV1StreamPart } from '@ai-sdk/provider';\nimport type { DeepSeekStreamResponse, DeepSeekUsage } from '../types';\n\ninterface DeepSeekStreamChunk {\n id: string;\n object: string;\n created: number;\n model: string;\n choices: Array<{\n index: number;\n delta: {\n role?: string;\n content?: string;\n tool_calls?: Array<{\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n }>;\n };\n finish_reason?: string;\n }>;\n usage?: DeepSeekUsage;\n}\n\nexport class StreamParser {\n private hasToolCalls: boolean = false;\n\n async *parse(body: ReadableStream<Uint8Array>): AsyncIterable<LanguageModelV1StreamPart> {\n const reader = body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n let partialJson = '';\n this.hasToolCalls = false; // 重置状态\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n if (line.startsWith(':')) continue; // SSE 注释\n\n if (line.startsWith('data: ')) {\n const data = line.slice(6).trim();\n if (data === '[DONE]') {\n yield* this.processPartialJson(partialJson);\n partialJson = '';\n return;\n }\n\n try {\n // 尝试解析 JSON\n const parsed = JSON.parse(data);\n yield* this.processPartialJson(partialJson);\n partialJson = '';\n yield* this.processChunk(parsed);\n } catch (e) {\n // JSON 解析失败,可能是部分数据\n partialJson += data;\n }\n }\n }\n }\n\n // 处理剩余的部分 JSON\n yield* this.processPartialJson(partialJson);\n } finally {\n reader.releaseLock();\n }\n }\n\n private async *processPartialJson(partialJson: string): AsyncIterable<LanguageModelV1StreamPart> {\n if (!partialJson.trim()) return;\n\n try {\n const parsed = JSON.parse(partialJson);\n yield* this.processChunk(parsed);\n } catch (e) {\n // 仍然无法解析,跳过\n console.warn('Failed to parse partial JSON:', partialJson);\n }\n }\n\n private async *processChunk(chunk: DeepSeekStreamChunk): AsyncIterable<LanguageModelV1StreamPart> {\n const delta = chunk.choices?.[0]?.delta;\n\n // 工具调用增量 - JSON in content 格式\n if (delta?.content) {\n const toolCallData = this.tryParseToolCall(delta.content);\n if (toolCallData) {\n this.hasToolCalls = true; // 标记有工具调用\n yield {\n type: 'tool-call-delta',\n toolCallType: 'function',\n toolCallId: toolCallData.id || `tool-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n toolName: toolCallData.name,\n argsTextDelta: JSON.stringify(toolCallData.arguments || {}),\n } as LanguageModelV1StreamPart;\n } else {\n // 普通文本增量\n yield {\n type: 'text-delta',\n textDelta: delta.content,\n } as LanguageModelV1StreamPart;\n }\n }\n\n // 工具调用增量 - 标准 tool_calls 格式\n if (delta?.tool_calls && delta.tool_calls.length > 0) {\n this.hasToolCalls = true; // 标记有工具调用\n for (const toolCall of delta.tool_calls) {\n yield {\n type: 'tool-call-delta',\n toolCallType: 'function',\n toolCallId: toolCall.id,\n toolName: toolCall.function?.name || '',\n argsTextDelta: toolCall.function?.arguments || '',\n } as LanguageModelV1StreamPart;\n }\n }\n\n // 完成信号\n const finishReason = chunk.choices?.[0]?.finish_reason;\n if (finishReason) {\n // V1 API: usage 在 finish 类型的 part 中\n const usage = chunk.usage\n ? {\n promptTokens: chunk.usage.prompt_tokens,\n completionTokens: chunk.usage.completion_tokens,\n }\n : { promptTokens: 0, completionTokens: 0 };\n\n yield {\n type: 'finish',\n finishReason: this.mapFinishReason(finishReason),\n usage,\n } as LanguageModelV1StreamPart;\n }\n }\n\n private mapFinishReason(reason: string): 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other' | 'unknown' {\n // 修复:如果有工具调用但 finish_reason 是 \"stop\",改为 \"tool-calls\"\n if (reason === 'stop' && this.hasToolCalls) {\n return 'tool-calls';\n }\n\n const reasonMap: Record<string, 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other' | 'unknown'> = {\n 'stop': 'stop',\n 'length': 'length',\n 'content_filter': 'content-filter',\n 'tool_calls': 'tool-calls',\n 'function_call': 'tool-calls',\n 'error': 'error',\n };\n return reasonMap[reason] || 'unknown';\n }\n\n private tryParseToolCall(content: string): { id?: string; name: string; arguments: Record<string, unknown> } | null {\n try {\n const parsed = JSON.parse(content);\n // 检查是否是工具调用格式: { name: \"...\", arguments: {...} }\n if (parsed && typeof parsed.name === 'string' && (parsed.arguments === undefined || typeof parsed.arguments === 'object')) {\n return {\n id: parsed.id,\n name: parsed.name,\n arguments: parsed.arguments || {},\n };\n }\n } catch {\n // JSON 解析失败,不是工具调用\n }\n return null;\n }\n}\n\n\n","// DeepSeek Chat 模型实现\n\nimport type {\n LanguageModelV1,\n LanguageModelV1CallOptions,\n} from '@ai-sdk/provider';\nimport type { DeepSeekChatSettings, DeepSeekResponse } from './types';\nimport { validateChatSettings } from './deepseek-chat-settings';\nimport { RequestTransformer } from './utils/request-transformer';\nimport { ResponseTransformer } from './utils/response-transformer';\nimport { StreamParser } from './utils/stream-parser';\n\nexport class DeepSeekChatLanguageModel implements LanguageModelV1 {\n readonly specificationVersion = 'v1' as const;\n readonly provider = 'deepseek' as const;\n readonly modelId: string;\n readonly settings: Required<DeepSeekChatSettings>;\n readonly defaultObjectGenerationMode: 'json' | 'tool' | undefined = undefined;\n\n private baseURL: string;\n private headers: () => Record<string, string>;\n private requestTransformer: RequestTransformer;\n private responseTransformer: ResponseTransformer;\n private streamParser: StreamParser;\n\n constructor(\n modelId: string,\n settings: DeepSeekChatSettings = {},\n config: {\n baseURL: string;\n headers: () => Record<string, string>;\n }\n ) {\n this.modelId = modelId;\n this.settings = validateChatSettings(settings);\n this.baseURL = config.baseURL;\n this.headers = config.headers;\n this.requestTransformer = new RequestTransformer();\n this.responseTransformer = new ResponseTransformer();\n this.streamParser = new StreamParser();\n }\n\n async doGenerate(options: LanguageModelV1CallOptions) {\n const requestBody = this.requestTransformer.transform(this.modelId, options);\n\n const response = await fetch(`${this.baseURL}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.headers(),\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`DeepSeek API error: ${response.status} - ${error}`);\n }\n\n const apiResponse = (await response.json()) as DeepSeekResponse;\n return this.responseTransformer.transform(apiResponse);\n }\n\n async doStream(options: LanguageModelV1CallOptions) {\n const requestBody = {\n ...this.requestTransformer.transform(this.modelId, options),\n stream: true,\n };\n\n const response = await fetch(`${this.baseURL}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'text/event-stream',\n ...this.headers(),\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`DeepSeek API error: ${response.status} - ${error}`);\n }\n\n if (!response.body) {\n throw new Error('Response body is null');\n }\n\n return {\n stream: this.streamParser.parse(response.body) as any,\n rawCall: {\n rawPrompt: requestBody as unknown,\n rawSettings: {},\n },\n warnings: [],\n };\n }\n}","// 公开导出 - 完全兼容官方 @ai-sdk/deepseek\n\n// 主要导出(与官方一致)\nexport { createDeepSeek, deepseek, createProvider } from './deepseek-provider';\n\n// 内部类型和类的导出\nexport { DeepSeekChatLanguageModel } from './deepseek-chat-language-model';\nexport { validateChatSettings } from './deepseek-chat-settings';\n\n// 工具类导出\nexport { RequestTransformer } from './utils/request-transformer';\nexport { ResponseTransformer } from './utils/response-transformer';\nexport { StreamParser } from './utils/stream-parser';\n\n// 类型导出(与官方一致)\nexport type {\n DeepSeekProviderSettings,\n DeepSeekChatSettings,\n DeepSeekMessage,\n DeepSeekToolCall,\n DeepSeekTool,\n DeepSeekRequest,\n DeepSeekChoice,\n DeepSeekUsage,\n DeepSeekResponse,\n DeepSeekStreamChoice,\n DeepSeekStreamResponse,\n} from './types';\n\n// VERSION 常量(与官方一致)\nexport const VERSION = '0.2.0';\n\n// DeepSeekProvider 类型导出\nexport type { DeepSeekProvider } from './deepseek-provider';"],"mappings":";AAEA,SAAS,kBAAkB;;;ACEpB,SAAS,qBAAqB,WAAiC,CAAC,GAAmC;AACxG,SAAO;AAAA,IACL,aAAa,SAAS,eAAe;AAAA,IACrC,MAAM,SAAS,QAAQ;AAAA,IACvB,WAAW,SAAS,aAAa;AAAA,IACjC,iBAAiB,SAAS,mBAAmB;AAAA,IAC7C,kBAAkB,SAAS,oBAAoB;AAAA,EACjD;AACF;;;ACJO,IAAM,qBAAN,MAAyB;AAAA,EAC9B,UAAU,SAAiB,SAAsD;AAC/E,UAAM,cAA+B;AAAA,MACnC,OAAO;AAAA,MACP,UAAU,KAAK,kBAAkB,QAAQ,MAAM;AAAA,MAC/C,QAAQ;AAAA,IACV;AAGA,QAAI,QAAQ,gBAAgB,QAAW;AACrC,kBAAY,cAAc,QAAQ;AAAA,IACpC;AAGA,QAAI,QAAQ,SAAS,QAAW;AAC9B,kBAAY,QAAQ,QAAQ;AAAA,IAC9B;AAGA,QAAI,QAAQ,cAAc,QAAW;AACnC,kBAAY,aAAa,QAAQ;AAAA,IACnC;AAGA,QAAI,QAAQ,oBAAoB,QAAW;AACzC,kBAAY,mBAAmB,QAAQ;AAAA,IACzC;AAGA,QAAI,QAAQ,qBAAqB,QAAW;AAC1C,kBAAY,oBAAoB,QAAQ;AAAA,IAC1C;AAGA,UAAM,OAAO,QAAQ;AACrB,QAAI,aAAyB,CAAC;AAC9B,QAAI;AAGJ,QAAI,QAAQ,KAAK,SAAS,WAAW;AACnC,mBAAa,KAAK,SAAS,CAAC;AAC5B,mBAAa,KAAK;AAAA,IACpB;AAGA,QAAI,WAAW,WAAW,KAAK,QAAQ,SAAS,QAAQ,MAAM,SAAS,GAAG;AACxE,mBAAa,QAAQ;AACrB,mBAAa,QAAQ;AAAA,IACvB;AAEA,QAAI,WAAW,SAAS,GAAG;AACzB,kBAAY,QAAQ,KAAK,eAAe,UAAU;AAClD,kBAAY,cAAc,KAAK,oBAAoB,UAAU;AAAA,IAC/D;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB,UAA6C;AACrE,WAAO,SAAS,IAAI,CAAC,QAAQ;AAC3B,YAAM,cAAmB;AAAA,QACvB,MAAM,IAAI;AAAA,MACZ;AAGA,UAAI,IAAI,WAAW,MAAM,QAAQ,IAAI,OAAO,GAAG;AAC7C,cAAM,eAA2B,CAAC;AAClC,YAAI,eAAe;AACnB,YAAI,iBAA6B,CAAC;AAElC,mBAAW,QAAQ,IAAI,SAAS;AAE9B,cAAI,KAAK,SAAS,QAAQ;AACxB,yBAAa,KAAK,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC;AAAA,UACrD,WAES,KAAK,SAAS,SAAS;AAE9B,kBAAM,YAAY,KAAK;AACvB,gBAAI,OAAO,cAAc,UAAU;AACjC,2BAAa,KAAK,EAAE,MAAM,aAAa,WAAW,EAAE,KAAK,UAAU,EAAE,CAAC;AAAA,YACxE,WAAW,qBAAqB,KAAK;AACnC,2BAAa,KAAK,EAAE,MAAM,aAAa,WAAW,EAAE,KAAK,UAAU,SAAS,EAAE,EAAE,CAAC;AAAA,YACnF;AAAA,UACF,WAES,KAAK,SAAS,aAAa;AAClC,2BAAe;AACf,2BAAe,KAAK;AAAA,cAClB,IAAI,KAAK;AAAA,cACT,MAAM;AAAA,cACN,UAAU;AAAA,gBACR,MAAM,KAAK;AAAA,gBACX,WAAW,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAK,UAAU,KAAK,IAAI;AAAA,cACjF;AAAA,YACF,CAAC;AAAA,UACH,WAES,KAAK,SAAS,eAAe;AAAA,UAGtC,WAES,KAAK,SAAS,eAAe,KAAK,SAAS,sBAAsB;AAGxE,gBAAI,UAAU,QAAQ,KAAK,MAAM;AAC/B,2BAAa,KAAK,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC;AAAA,YACrD;AAAA,UACF,WAES,KAAK,SAAS,QAAQ;AAC7B,yBAAa,KAAK;AAAA,cAChB,MAAM;AAAA,cACN,MAAM,UAAU,KAAK,YAAY,SAAS;AAAA,YAC5C,CAAC;AAAA,UACH,OAEK;AACH,yBAAa,KAAK,IAAI;AAAA,UACxB;AAAA,QACF;AAGA,YAAI,aAAa,SAAS,GAAG;AAC3B,sBAAY,UAAU;AAAA,QACxB;AAGA,YAAI,gBAAgB,eAAe,SAAS,GAAG;AAC7C,sBAAY,aAAa;AAAA,QAC3B;AAAA,MACF,WAAW,OAAO,IAAI,YAAY,UAAU;AAE1C,oBAAY,UAAU,IAAI;AAAA,MAC5B;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEQ,eAAe,OAA+B;AACpD,WAAO,MAAM,IAAI,UAAQ;AAEvB,UAAI,KAAK,SAAS,cAAc,KAAK,UAAU;AAC7C,eAAO;AAAA,UACL,MAAM;AAAA,UACN,UAAU;AAAA,YACR,MAAM,KAAK,SAAS;AAAA,YACpB,aAAa,KAAK,SAAS;AAAA,YAC3B,YAAY,KAAK,SAAS;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AAGA,aAAO;AAAA,QACL,MAAM;AAAA,QACN,UAAU;AAAA,UACR,MAAM,KAAK;AAAA,UACX,aAAa,KAAK;AAAA,UAClB,YAAY,KAAK;AAAA,QACnB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,oBAAoB,YAAsB;AAEhD,QAAI,eAAe,UAAa,eAAe,QAAQ;AACrD,aAAO;AAAA,IACT;AAGA,QAAI,eAAe,QAAQ;AACzB,aAAO;AAAA,IACT;AAGA,QAAI,eAAe,cAAe,OAAO,eAAe,YAAY,WAAW,SAAS,YAAa;AACnG,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,eAAe,YAAY,WAAW,SAAS,QAAQ;AAEhE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,UAAU;AAAA,UACR,MAAM,WAAW;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAGA,WAAO;AAAA,EACT;AACF;;;AChLO,IAAM,sBAAN,MAA0B;AAAA,EAC/B,UAAU,aAAiD;AACzD,UAAM,SAAS,YAAY,UAAU,CAAC;AACtC,UAAM,UAAU,QAAQ,WAAW,CAAC;AAGpC,UAAM,eAAe,KAAK;AAAA,MACxB,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAGA,UAAM,YAAY,KAAK,mBAAmB,QAAQ,UAAU;AAG5D,UAAM,UAAwC,CAAC;AAG/C,QAAI,QAAQ,SAAS;AACnB,cAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QACN,MAAM,QAAQ;AAAA,MAChB,CAAC;AAAA,IACH;AAGA,QAAI,UAAU,SAAS,GAAG;AACxB,cAAQ,KAAK,GAAG,SAAS;AAAA,IAC3B;AAEA,WAAO;AAAA,MACL;AAAA,MACA,MAAM,QAAQ,WAAW;AAAA;AAAA,MACzB;AAAA,MACA,OAAO;AAAA,QACL,cAAc,YAAY,OAAO,iBAAiB;AAAA,QAClD,kBAAkB,YAAY,OAAO,qBAAqB;AAAA,MAC5D;AAAA,MACA,SAAS;AAAA,QACP,WAAW;AAAA,QACX,aAAa,CAAC;AAAA,MAChB;AAAA,MACA;AAAA;AAAA,MACA,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAAA,EAEQ,gBACN,sBACA,WACQ;AAER,QAAI,aAAa,UAAU,SAAS,KAAK,yBAAyB,QAAQ;AACxE,aAAO;AAAA,IACT;AAGA,UAAM,kBAA0C;AAAA,MAC9C,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,kBAAkB;AAAA,MAClB,cAAc;AAAA,MACd,iBAAiB;AAAA,IACnB;AAEA,WAAO,gBAAgB,wBAAwB,EAAE,KAAK;AAAA,EACxD;AAAA,EAEQ,mBAAmB,WAAiE;AAC1F,QAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACxC,aAAO,CAAC;AAAA,IACV;AAEA,WAAO,UAAU,IAAI,CAAC,QAAa;AAAA,MACjC,MAAM;AAAA,MACN,cAAc;AAAA,MACd,YAAY,GAAG;AAAA,MACf,UAAU,GAAG,SAAS;AAAA,MACtB,MAAM,OAAO,GAAG,SAAS,cAAc,WACnC,GAAG,SAAS,YACZ,KAAK,UAAU,GAAG,SAAS,SAAS;AAAA,IAC1C,EAAE;AAAA,EACJ;AACF;;;ACnFO,IAAM,eAAN,MAAmB;AAAA,EAChB,eAAwB;AAAA,EAEhC,OAAO,MAAM,MAA4E;AACvF,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,UAAU,IAAI,YAAY,OAAO;AACvC,QAAI,SAAS;AACb,QAAI,cAAc;AAClB,SAAK,eAAe;AAEpB,QAAI;AACF,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAEV,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,cAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,iBAAS,MAAM,IAAI,KAAK;AAExB,mBAAW,QAAQ,OAAO;AACxB,cAAI,KAAK,KAAK,MAAM,GAAI;AACxB,cAAI,KAAK,WAAW,GAAG,EAAG;AAE1B,cAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,kBAAM,OAAO,KAAK,MAAM,CAAC,EAAE,KAAK;AAChC,gBAAI,SAAS,UAAU;AACrB,qBAAO,KAAK,mBAAmB,WAAW;AAC1C,4BAAc;AACd;AAAA,YACF;AAEA,gBAAI;AAEF,oBAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,qBAAO,KAAK,mBAAmB,WAAW;AAC1C,4BAAc;AACd,qBAAO,KAAK,aAAa,MAAM;AAAA,YACjC,SAAS,GAAG;AAEV,6BAAe;AAAA,YACjB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,aAAO,KAAK,mBAAmB,WAAW;AAAA,IAC5C,UAAE;AACA,aAAO,YAAY;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,OAAe,mBAAmB,aAA+D;AAC/F,QAAI,CAAC,YAAY,KAAK,EAAG;AAEzB,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,WAAW;AACrC,aAAO,KAAK,aAAa,MAAM;AAAA,IACjC,SAAS,GAAG;AAEV,cAAQ,KAAK,iCAAiC,WAAW;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,OAAe,aAAa,OAAsE;AAChG,UAAM,QAAQ,MAAM,UAAU,CAAC,GAAG;AAGlC,QAAI,OAAO,SAAS;AAClB,YAAM,eAAe,KAAK,iBAAiB,MAAM,OAAO;AACxD,UAAI,cAAc;AAChB,aAAK,eAAe;AACpB,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,cAAc;AAAA,UACd,YAAY,aAAa,MAAM,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,UAC5F,UAAU,aAAa;AAAA,UACvB,eAAe,KAAK,UAAU,aAAa,aAAa,CAAC,CAAC;AAAA,QAC5D;AAAA,MACF,OAAO;AAEL,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,WAAW,MAAM;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,OAAO,cAAc,MAAM,WAAW,SAAS,GAAG;AACpD,WAAK,eAAe;AACpB,iBAAW,YAAY,MAAM,YAAY;AACvC,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,cAAc;AAAA,UACd,YAAY,SAAS;AAAA,UACrB,UAAU,SAAS,UAAU,QAAQ;AAAA,UACrC,eAAe,SAAS,UAAU,aAAa;AAAA,QACjD;AAAA,MACF;AAAA,IACF;AAGA,UAAM,eAAe,MAAM,UAAU,CAAC,GAAG;AACzC,QAAI,cAAc;AAEhB,YAAM,QAAQ,MAAM,QAChB;AAAA,QACE,cAAc,MAAM,MAAM;AAAA,QAC1B,kBAAkB,MAAM,MAAM;AAAA,MAChC,IACA,EAAE,cAAc,GAAG,kBAAkB,EAAE;AAE3C,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,cAAc,KAAK,gBAAgB,YAAY;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gBAAgB,QAAqG;AAE3H,QAAI,WAAW,UAAU,KAAK,cAAc;AAC1C,aAAO;AAAA,IACT;AAEA,UAAM,YAAiH;AAAA,MACrH,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,kBAAkB;AAAA,MAClB,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,SAAS;AAAA,IACX;AACA,WAAO,UAAU,MAAM,KAAK;AAAA,EAC9B;AAAA,EAEQ,iBAAiB,SAA2F;AAClH,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,OAAO;AAEjC,UAAI,UAAU,OAAO,OAAO,SAAS,aAAa,OAAO,cAAc,UAAa,OAAO,OAAO,cAAc,WAAW;AACzH,eAAO;AAAA,UACL,IAAI,OAAO;AAAA,UACX,MAAM,OAAO;AAAA,UACb,WAAW,OAAO,aAAa,CAAC;AAAA,QAClC;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AACF;;;AC3KO,IAAM,4BAAN,MAA2D;AAAA,EACvD,uBAAuB;AAAA,EACvB,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,8BAA2D;AAAA,EAE5D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACE,SACA,WAAiC,CAAC,GAClC,QAIA;AACA,SAAK,UAAU;AACf,SAAK,WAAW,qBAAqB,QAAQ;AAC7C,SAAK,UAAU,OAAO;AACtB,SAAK,UAAU,OAAO;AACtB,SAAK,qBAAqB,IAAI,mBAAmB;AACjD,SAAK,sBAAsB,IAAI,oBAAoB;AACnD,SAAK,eAAe,IAAI,aAAa;AAAA,EACvC;AAAA,EAEA,MAAM,WAAW,SAAqC;AACpD,UAAM,cAAc,KAAK,mBAAmB,UAAU,KAAK,SAAS,OAAO;AAE3E,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,qBAAqB;AAAA,MAC/D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG,KAAK,QAAQ;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,WAAW;AAAA,IAClC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,MAAM,KAAK,EAAE;AAAA,IACrE;AAEA,UAAM,cAAe,MAAM,SAAS,KAAK;AACzC,WAAO,KAAK,oBAAoB,UAAU,WAAW;AAAA,EACvD;AAAA,EAEA,MAAM,SAAS,SAAqC;AAClD,UAAM,cAAc;AAAA,MAClB,GAAG,KAAK,mBAAmB,UAAU,KAAK,SAAS,OAAO;AAAA,MAC1D,QAAQ;AAAA,IACV;AAEA,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,qBAAqB;AAAA,MAC/D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,GAAG,KAAK,QAAQ;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,WAAW;AAAA,IAClC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,MAAM,KAAK,EAAE;AAAA,IACrE;AAEA,QAAI,CAAC,SAAS,MAAM;AAClB,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AAEA,WAAO;AAAA,MACL,QAAQ,KAAK,aAAa,MAAM,SAAS,IAAI;AAAA,MAC7C,SAAS;AAAA,QACP,WAAW;AAAA,QACX,aAAa,CAAC;AAAA,MAChB;AAAA,MACA,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AACF;;;AL/DA,eAAsB,eACpB,UAAoC,CAAC,GACV;AAE3B,QAAM,SAAS,MAAM,WAAW;AAAA,IAC9B,QAAQ,QAAQ;AAAA,IAChB,yBAAyB;AAAA,IACzB,aAAa;AAAA,EACf,CAAC;AAED,QAAM,UAAU,QAAQ,WAAW;AAGnC,QAAM,mBAAmB,SACvB,SACA,UAC2B;AAC3B,WAAO,IAAI;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,QACE;AAAA,QACA,SAAS,OAAO;AAAA,UACd,eAAe,UAAU,MAAM;AAAA,UAC/B,GAAI,QAAQ,WAAW,CAAC;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,mBAAiB,gBAAgB;AACjC,mBAAiB,OAAO;AACxB,mBAAiB,qBAAqB,MAAM;AAC1C,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAEA,SAAO;AACT;AAGO,IAAM,WAAW,eAAe;AAGhC,IAAM,iBAAiB;;;AMhDvB,IAAM,UAAU;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hopemyl619/deepseek",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "DeepSeek provider for the Vercel AI SDK with
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "DeepSeek provider for the Vercel AI SDK with automatic finish_reason fix for tool calls",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@ai-sdk/deepseek": "^2.0.11",
|
|
32
32
|
"@types/node": "^20.0.0",
|
|
33
|
+
"dotenv": "^17.2.3",
|
|
33
34
|
"eslint": "^8.0.0",
|
|
34
35
|
"tsup": "^8.0.0",
|
|
35
36
|
"typescript": "^5.0.0",
|
package/src/deepseek-provider.ts
CHANGED
|
@@ -1,37 +1,79 @@
|
|
|
1
|
-
// DeepSeek Provider
|
|
1
|
+
// DeepSeek Provider - 完全兼容官方 @ai-sdk/deepseek 接口
|
|
2
2
|
|
|
3
|
-
import { createDeepSeek as createOfficialProvider } from '@ai-sdk/deepseek';
|
|
4
3
|
import { loadApiKey } from '@ai-sdk/provider-utils';
|
|
5
|
-
import type { DeepSeekProviderSettings } from './types';
|
|
4
|
+
import type { DeepSeekProviderSettings, DeepSeekChatSettings } from './types';
|
|
5
|
+
import { DeepSeekChatLanguageModel } from './deepseek-chat-language-model';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
// Provider 接口定义(兼容官方)
|
|
8
|
+
export interface DeepSeekProvider {
|
|
9
|
+
/**
|
|
10
|
+
* 创建 DeepSeek 模型用于文本生成
|
|
11
|
+
*/
|
|
12
|
+
(modelId: string, settings?: DeepSeekChatSettings): DeepSeekChatLanguageModel;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 创建 DeepSeek 模型用于文本生成
|
|
16
|
+
*/
|
|
17
|
+
languageModel(modelId: string, settings?: DeepSeekChatSettings): DeepSeekChatLanguageModel;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 创建 DeepSeek 聊天模型用于文本生成
|
|
21
|
+
*/
|
|
22
|
+
chat(modelId: string, settings?: DeepSeekChatSettings): DeepSeekChatLanguageModel;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 文本嵌入模型(暂不支持)
|
|
26
|
+
* @deprecated
|
|
27
|
+
*/
|
|
28
|
+
textEmbeddingModel(modelId: string): never;
|
|
12
29
|
}
|
|
13
30
|
|
|
14
|
-
|
|
15
|
-
|
|
31
|
+
/**
|
|
32
|
+
* 创建 DeepSeek Provider
|
|
33
|
+
* 完全兼容官方 @ai-sdk/deepseek 的 createDeepSeek 函数
|
|
34
|
+
*/
|
|
35
|
+
export async function createDeepSeek(
|
|
36
|
+
options: DeepSeekProviderSettings = {}
|
|
37
|
+
): Promise<DeepSeekProvider> {
|
|
38
|
+
// 加载 API Key
|
|
39
|
+
const apiKey = await loadApiKey({
|
|
16
40
|
apiKey: options.apiKey,
|
|
17
|
-
|
|
18
|
-
|
|
41
|
+
environmentVariableName: 'DEEPSEEK_API_KEY',
|
|
42
|
+
description: 'DeepSeek API key',
|
|
19
43
|
});
|
|
20
44
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
const baseURL = options.baseURL || 'https://api.deepseek.com';
|
|
46
|
+
|
|
47
|
+
// 创建 provider 函数
|
|
48
|
+
const providerFunction = function(
|
|
49
|
+
modelId: string,
|
|
50
|
+
settings?: DeepSeekChatSettings
|
|
51
|
+
): DeepSeekChatLanguageModel {
|
|
52
|
+
return new DeepSeekChatLanguageModel(
|
|
53
|
+
modelId,
|
|
54
|
+
settings,
|
|
55
|
+
{
|
|
56
|
+
baseURL,
|
|
57
|
+
headers: () => ({
|
|
58
|
+
Authorization: `Bearer ${apiKey}`,
|
|
59
|
+
...(options.headers || {}),
|
|
60
|
+
}),
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
} as DeepSeekProvider;
|
|
64
|
+
|
|
65
|
+
// 添加方法到 provider 函数对象
|
|
66
|
+
providerFunction.languageModel = providerFunction;
|
|
67
|
+
providerFunction.chat = providerFunction;
|
|
68
|
+
providerFunction.textEmbeddingModel = () => {
|
|
69
|
+
throw new Error('Text embedding models are not supported for DeepSeek');
|
|
32
70
|
};
|
|
33
71
|
|
|
34
|
-
return
|
|
72
|
+
return providerFunction;
|
|
35
73
|
}
|
|
36
74
|
|
|
37
|
-
|
|
75
|
+
// 默认导出的 provider 实例
|
|
76
|
+
export const deepseek = createDeepSeek();
|
|
77
|
+
|
|
78
|
+
// 为了向后兼容,保留 createProvider 作为别名
|
|
79
|
+
export const createProvider = createDeepSeek;
|
package/src/index.ts
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
// 公开导出
|
|
1
|
+
// 公开导出 - 完全兼容官方 @ai-sdk/deepseek
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// 主要导出(与官方一致)
|
|
4
|
+
export { createDeepSeek, deepseek, createProvider } from './deepseek-provider';
|
|
5
|
+
|
|
6
|
+
// 内部类型和类的导出
|
|
4
7
|
export { DeepSeekChatLanguageModel } from './deepseek-chat-language-model';
|
|
5
8
|
export { validateChatSettings } from './deepseek-chat-settings';
|
|
6
|
-
export {
|
|
7
|
-
ChineseParamsPreprocessor,
|
|
8
|
-
} from './utils/chinese-params-preprocessor';
|
|
9
|
-
export {
|
|
10
|
-
RequestTransformer,
|
|
11
|
-
} from './utils/request-transformer';
|
|
12
|
-
export {
|
|
13
|
-
ResponseTransformer,
|
|
14
|
-
} from './utils/response-transformer';
|
|
15
|
-
export {
|
|
16
|
-
StreamParser,
|
|
17
|
-
} from './utils/stream-parser';
|
|
18
9
|
|
|
10
|
+
// 工具类导出
|
|
11
|
+
export { RequestTransformer } from './utils/request-transformer';
|
|
12
|
+
export { ResponseTransformer } from './utils/response-transformer';
|
|
13
|
+
export { StreamParser } from './utils/stream-parser';
|
|
14
|
+
|
|
15
|
+
// 类型导出(与官方一致)
|
|
19
16
|
export type {
|
|
20
17
|
DeepSeekProviderSettings,
|
|
21
18
|
DeepSeekChatSettings,
|
|
@@ -28,4 +25,10 @@ export type {
|
|
|
28
25
|
DeepSeekResponse,
|
|
29
26
|
DeepSeekStreamChoice,
|
|
30
27
|
DeepSeekStreamResponse,
|
|
31
|
-
} from './types';
|
|
28
|
+
} from './types';
|
|
29
|
+
|
|
30
|
+
// VERSION 常量(与官方一致)
|
|
31
|
+
export const VERSION = '0.2.0';
|
|
32
|
+
|
|
33
|
+
// DeepSeekProvider 类型导出
|
|
34
|
+
export type { DeepSeekProvider } from './deepseek-provider';
|
|
@@ -5,15 +5,8 @@ import type {
|
|
|
5
5
|
LanguageModelV1Prompt,
|
|
6
6
|
} from '@ai-sdk/provider';
|
|
7
7
|
import type { DeepSeekRequest } from '../types';
|
|
8
|
-
import { ChineseParamsPreprocessor } from './chinese-params-preprocessor';
|
|
9
8
|
|
|
10
9
|
export class RequestTransformer {
|
|
11
|
-
private preprocessor: ChineseParamsPreprocessor;
|
|
12
|
-
|
|
13
|
-
constructor() {
|
|
14
|
-
this.preprocessor = new ChineseParamsPreprocessor();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
10
|
transform(modelId: string, options: LanguageModelV1CallOptions): DeepSeekRequest {
|
|
18
11
|
const transformed: DeepSeekRequest = {
|
|
19
12
|
model: modelId,
|
|
@@ -57,13 +50,18 @@ export class RequestTransformer {
|
|
|
57
50
|
toolChoice = mode.toolChoice;
|
|
58
51
|
}
|
|
59
52
|
|
|
53
|
+
// 如果没有通过 mode 传递工具,检查直接传递的 tools 参数(向后兼容)
|
|
54
|
+
if (toolsArray.length === 0 && options.tools && options.tools.length > 0) {
|
|
55
|
+
toolsArray = options.tools;
|
|
56
|
+
toolChoice = options.toolChoice;
|
|
57
|
+
}
|
|
58
|
+
|
|
60
59
|
if (toolsArray.length > 0) {
|
|
61
60
|
transformed.tools = this.transformTools(toolsArray);
|
|
62
61
|
transformed.tool_choice = this.transformToolChoice(toolChoice);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
return this.preprocessor.process(transformed);
|
|
64
|
+
return transformed;
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
private transformMessages(messages: LanguageModelV1Prompt): Array<any> {
|
|
@@ -150,34 +148,59 @@ export class RequestTransformer {
|
|
|
150
148
|
}
|
|
151
149
|
|
|
152
150
|
private transformTools(tools: Array<any>): Array<any> {
|
|
153
|
-
return tools.map(tool =>
|
|
154
|
-
type: 'function',
|
|
155
|
-
function
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
151
|
+
return tools.map(tool => {
|
|
152
|
+
// AI SDK V1 格式: { type: 'function', function: { name, description, parameters } }
|
|
153
|
+
if (tool.type === 'function' && tool.function) {
|
|
154
|
+
return {
|
|
155
|
+
type: 'function',
|
|
156
|
+
function: {
|
|
157
|
+
name: tool.function.name,
|
|
158
|
+
description: tool.function.description,
|
|
159
|
+
parameters: tool.function.parameters,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 备用格式(向后兼容)
|
|
165
|
+
return {
|
|
166
|
+
type: 'function',
|
|
167
|
+
function: {
|
|
168
|
+
name: tool.name,
|
|
169
|
+
description: tool.description,
|
|
170
|
+
parameters: tool.parameters,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
});
|
|
161
174
|
}
|
|
162
175
|
|
|
163
|
-
private transformToolChoice(toolChoice: any):
|
|
176
|
+
private transformToolChoice(toolChoice: any): any {
|
|
177
|
+
// undefined 或 auto -> 'auto'
|
|
164
178
|
if (toolChoice === undefined || toolChoice === 'auto') {
|
|
165
179
|
return 'auto';
|
|
166
180
|
}
|
|
181
|
+
|
|
182
|
+
// none -> 'none'
|
|
167
183
|
if (toolChoice === 'none') {
|
|
168
184
|
return 'none';
|
|
169
185
|
}
|
|
170
|
-
|
|
186
|
+
|
|
187
|
+
// required -> 'required' (强制调用至少一个工具)
|
|
188
|
+
if (toolChoice === 'required' || (typeof toolChoice === 'object' && toolChoice.type === 'required')) {
|
|
171
189
|
return 'required';
|
|
172
190
|
}
|
|
191
|
+
|
|
192
|
+
// 特定工具: { type: 'tool', toolName: 'function_name' }
|
|
173
193
|
if (typeof toolChoice === 'object' && toolChoice.type === 'tool') {
|
|
174
|
-
|
|
194
|
+
// DeepSeek API 可能支持的格式
|
|
195
|
+
return {
|
|
175
196
|
type: 'function',
|
|
176
197
|
function: {
|
|
177
198
|
name: toolChoice.toolName,
|
|
178
199
|
},
|
|
179
|
-
}
|
|
200
|
+
};
|
|
180
201
|
}
|
|
202
|
+
|
|
203
|
+
// 默认: auto
|
|
181
204
|
return 'auto';
|
|
182
205
|
}
|
|
183
206
|
}
|
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
// 响应转换器 -
|
|
1
|
+
// 响应转换器 - 新 AI SDK 格式
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
-
LanguageModelV1,
|
|
5
4
|
LanguageModelV1FinishReason,
|
|
6
5
|
LanguageModelV1CallWarning,
|
|
7
6
|
LanguageModelV1FunctionToolCall,
|
|
7
|
+
LanguageModelV1ContentPart,
|
|
8
8
|
} from '@ai-sdk/provider';
|
|
9
9
|
import type { DeepSeekResponse } from '../types';
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// 新 AI SDK 返回结果类型
|
|
12
12
|
export interface V1GenerateResult {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
content: LanguageModelV1ContentPart[];
|
|
14
|
+
finishReason: LanguageModelV1FinishReason;
|
|
15
15
|
usage: {
|
|
16
16
|
promptTokens: number;
|
|
17
17
|
completionTokens: number;
|
|
18
18
|
};
|
|
19
|
-
finishReason: LanguageModelV1FinishReason;
|
|
20
|
-
toolCalls?: LanguageModelV1FunctionToolCall[];
|
|
21
19
|
rawCall: {
|
|
22
20
|
rawPrompt: unknown;
|
|
23
21
|
rawSettings: Record<string, unknown>;
|
|
24
22
|
};
|
|
25
23
|
warnings?: LanguageModelV1CallWarning[];
|
|
24
|
+
// 兼容旧格式的字段
|
|
25
|
+
text?: string;
|
|
26
|
+
toolCalls?: LanguageModelV1FunctionToolCall[];
|
|
27
|
+
reasoning?: string;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
export class ResponseTransformer {
|
|
@@ -36,8 +38,28 @@ export class ResponseTransformer {
|
|
|
36
38
|
message.tool_calls
|
|
37
39
|
);
|
|
38
40
|
|
|
41
|
+
// 转换工具调用
|
|
42
|
+
const toolCalls = this.transformToolCalls(message.tool_calls);
|
|
43
|
+
|
|
44
|
+
// 构建内容数组
|
|
45
|
+
const content: LanguageModelV1ContentPart[] = [];
|
|
46
|
+
|
|
47
|
+
// 添加文本内容
|
|
48
|
+
if (message.content) {
|
|
49
|
+
content.push({
|
|
50
|
+
type: 'text',
|
|
51
|
+
text: message.content,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 添加工具调用
|
|
56
|
+
if (toolCalls.length > 0) {
|
|
57
|
+
content.push(...toolCalls);
|
|
58
|
+
}
|
|
59
|
+
|
|
39
60
|
return {
|
|
40
|
-
|
|
61
|
+
content,
|
|
62
|
+
text: message.content || '', // 兼容旧格式
|
|
41
63
|
finishReason: finishReason as LanguageModelV1FinishReason,
|
|
42
64
|
usage: {
|
|
43
65
|
promptTokens: apiResponse.usage?.prompt_tokens || 0,
|
|
@@ -47,7 +69,7 @@ export class ResponseTransformer {
|
|
|
47
69
|
rawPrompt: '',
|
|
48
70
|
rawSettings: {},
|
|
49
71
|
},
|
|
50
|
-
toolCalls
|
|
72
|
+
toolCalls, // 兼容旧格式
|
|
51
73
|
warnings: [],
|
|
52
74
|
};
|
|
53
75
|
}
|
|
@@ -79,6 +101,7 @@ export class ResponseTransformer {
|
|
|
79
101
|
}
|
|
80
102
|
|
|
81
103
|
return toolCalls.map((tc: any) => ({
|
|
104
|
+
type: 'tool-call' as const,
|
|
82
105
|
toolCallType: 'function' as const,
|
|
83
106
|
toolCallId: tc.id,
|
|
84
107
|
toolName: tc.function.name,
|
|
@@ -87,4 +110,4 @@ export class ResponseTransformer {
|
|
|
87
110
|
: JSON.stringify(tc.function.arguments),
|
|
88
111
|
}));
|
|
89
112
|
}
|
|
90
|
-
}
|
|
113
|
+
}
|
|
@@ -28,11 +28,14 @@ interface DeepSeekStreamChunk {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export class StreamParser {
|
|
31
|
+
private hasToolCalls: boolean = false;
|
|
32
|
+
|
|
31
33
|
async *parse(body: ReadableStream<Uint8Array>): AsyncIterable<LanguageModelV1StreamPart> {
|
|
32
34
|
const reader = body.getReader();
|
|
33
35
|
const decoder = new TextDecoder('utf-8');
|
|
34
36
|
let buffer = '';
|
|
35
37
|
let partialJson = '';
|
|
38
|
+
this.hasToolCalls = false; // 重置状态
|
|
36
39
|
|
|
37
40
|
try {
|
|
38
41
|
while (true) {
|
|
@@ -95,6 +98,7 @@ export class StreamParser {
|
|
|
95
98
|
if (delta?.content) {
|
|
96
99
|
const toolCallData = this.tryParseToolCall(delta.content);
|
|
97
100
|
if (toolCallData) {
|
|
101
|
+
this.hasToolCalls = true; // 标记有工具调用
|
|
98
102
|
yield {
|
|
99
103
|
type: 'tool-call-delta',
|
|
100
104
|
toolCallType: 'function',
|
|
@@ -113,6 +117,7 @@ export class StreamParser {
|
|
|
113
117
|
|
|
114
118
|
// 工具调用增量 - 标准 tool_calls 格式
|
|
115
119
|
if (delta?.tool_calls && delta.tool_calls.length > 0) {
|
|
120
|
+
this.hasToolCalls = true; // 标记有工具调用
|
|
116
121
|
for (const toolCall of delta.tool_calls) {
|
|
117
122
|
yield {
|
|
118
123
|
type: 'tool-call-delta',
|
|
@@ -144,6 +149,11 @@ export class StreamParser {
|
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
private mapFinishReason(reason: string): 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other' | 'unknown' {
|
|
152
|
+
// 修复:如果有工具调用但 finish_reason 是 "stop",改为 "tool-calls"
|
|
153
|
+
if (reason === 'stop' && this.hasToolCalls) {
|
|
154
|
+
return 'tool-calls';
|
|
155
|
+
}
|
|
156
|
+
|
|
147
157
|
const reasonMap: Record<string, 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other' | 'unknown'> = {
|
|
148
158
|
'stop': 'stop',
|
|
149
159
|
'length': 'length',
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
// 中文参数预处理器
|
|
2
|
-
|
|
3
|
-
import type { DeepSeekRequest } from '../types';
|
|
4
|
-
|
|
5
|
-
export class ChineseParamsPreprocessor {
|
|
6
|
-
private cityMap: Record<string, string> = {
|
|
7
|
-
// 中国城市
|
|
8
|
-
'北京': 'Beijing',
|
|
9
|
-
'上海': 'Shanghai',
|
|
10
|
-
'广州': 'Guangzhou',
|
|
11
|
-
'深圳': 'Shenzhen',
|
|
12
|
-
'杭州': 'Hangzhou',
|
|
13
|
-
'南京': 'Nanjing',
|
|
14
|
-
'成都': 'Chengdu',
|
|
15
|
-
'武汉': 'Wuhan',
|
|
16
|
-
'西安': 'Xi\'an',
|
|
17
|
-
'重庆': 'Chongqing',
|
|
18
|
-
'天津': 'Tianjin',
|
|
19
|
-
'苏州': 'Suzhou',
|
|
20
|
-
'长沙': 'Changsha',
|
|
21
|
-
'青岛': 'Qingdao',
|
|
22
|
-
'大连': 'Dalian',
|
|
23
|
-
'厦门': 'Xiamen',
|
|
24
|
-
'宁波': 'Ningbo',
|
|
25
|
-
'无锡': 'Wuxi',
|
|
26
|
-
'佛山': 'Foshan',
|
|
27
|
-
'东莞': 'Dongguan',
|
|
28
|
-
'合肥': 'Hefei',
|
|
29
|
-
'郑州': 'Zhengzhou',
|
|
30
|
-
'福州': 'Fuzhou',
|
|
31
|
-
'济南': 'Jinan',
|
|
32
|
-
'昆明': 'Kunming',
|
|
33
|
-
'沈阳': 'Shenyang',
|
|
34
|
-
'长春': 'Changchun',
|
|
35
|
-
'哈尔滨': 'Harbin',
|
|
36
|
-
'石家庄': 'Shijiazhuang',
|
|
37
|
-
'太原': 'Taiyuan',
|
|
38
|
-
'南昌': 'Nanchang',
|
|
39
|
-
'南宁': 'Nanning',
|
|
40
|
-
'贵阳': 'Guiyang',
|
|
41
|
-
'兰州': 'Lanzhou',
|
|
42
|
-
'海口': 'Haikou',
|
|
43
|
-
'呼和浩特': 'Hohhot',
|
|
44
|
-
'银川': 'Yinchuan',
|
|
45
|
-
'西宁': 'Xining',
|
|
46
|
-
'乌鲁木齐': 'Urumqi',
|
|
47
|
-
'拉萨': 'Lhasa',
|
|
48
|
-
// 国际城市
|
|
49
|
-
'伦敦': 'London',
|
|
50
|
-
'纽约': 'New York',
|
|
51
|
-
'东京': 'Tokyo',
|
|
52
|
-
'巴黎': 'Paris',
|
|
53
|
-
'柏林': 'Berlin',
|
|
54
|
-
'悉尼': 'Sydney',
|
|
55
|
-
'洛杉矶': 'Los Angeles',
|
|
56
|
-
'多伦多': 'Toronto',
|
|
57
|
-
'新加坡': 'Singapore',
|
|
58
|
-
'香港': 'Hong Kong',
|
|
59
|
-
'台北': 'Taipei',
|
|
60
|
-
'首尔': 'Seoul',
|
|
61
|
-
'曼谷': 'Bangkok',
|
|
62
|
-
'迪拜': 'Dubai',
|
|
63
|
-
'莫斯科': 'Moscow',
|
|
64
|
-
'旧金山': 'San Francisco',
|
|
65
|
-
'波士顿': 'Boston',
|
|
66
|
-
'芝加哥': 'Chicago',
|
|
67
|
-
'华盛顿': 'Washington',
|
|
68
|
-
'休斯顿': 'Houston',
|
|
69
|
-
'费城': 'Philadelphia',
|
|
70
|
-
'凤凰城': 'Phoenix',
|
|
71
|
-
'圣迭戈': 'San Diego',
|
|
72
|
-
'达拉斯': 'Dallas',
|
|
73
|
-
'圣何塞': 'San Jose',
|
|
74
|
-
'奥斯汀': 'Austin',
|
|
75
|
-
'温哥华': 'Vancouver',
|
|
76
|
-
'蒙特利尔': 'Montreal',
|
|
77
|
-
'卡尔加里': 'Calgary',
|
|
78
|
-
'渥太华': 'Ottawa',
|
|
79
|
-
'魁北克': 'Quebec',
|
|
80
|
-
'埃德蒙顿': 'Edmonton',
|
|
81
|
-
'温尼伯': 'Winnipeg',
|
|
82
|
-
'哈利法克斯': 'Halifax',
|
|
83
|
-
'维多利亚': 'Victoria',
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
process(request: DeepSeekRequest): DeepSeekRequest {
|
|
87
|
-
const processed = JSON.parse(JSON.stringify(request));
|
|
88
|
-
|
|
89
|
-
// 处理消息内容
|
|
90
|
-
if (processed.messages) {
|
|
91
|
-
processed.messages = this.processMessages(processed.messages);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// 处理工具参数
|
|
95
|
-
if (processed.tools) {
|
|
96
|
-
processed.tools = this.processTools(processed.tools);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return processed;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private processMessages(messages: any[]): any[] {
|
|
103
|
-
return messages.map(msg => {
|
|
104
|
-
if (msg.content && typeof msg.content === 'string') {
|
|
105
|
-
msg.content = this.replaceCityNames(msg.content);
|
|
106
|
-
} else if (Array.isArray(msg.content)) {
|
|
107
|
-
msg.content = msg.content.map((part: any) => {
|
|
108
|
-
if (part.type === 'text' && part.text) {
|
|
109
|
-
part.text = this.replaceCityNames(part.text);
|
|
110
|
-
}
|
|
111
|
-
return part;
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
return msg;
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private processTools(tools: any[]): any[] {
|
|
119
|
-
return tools.map(tool => {
|
|
120
|
-
if (tool.function?.parameters?.properties) {
|
|
121
|
-
this.processProperties(tool.function.parameters.properties);
|
|
122
|
-
}
|
|
123
|
-
if (tool.function?.description) {
|
|
124
|
-
tool.function.description = this.replaceCityNames(tool.function.description);
|
|
125
|
-
}
|
|
126
|
-
return tool;
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private processProperties(properties: any): void {
|
|
131
|
-
for (const key in properties) {
|
|
132
|
-
if (properties[key].description) {
|
|
133
|
-
properties[key].description = this.replaceCityNames(properties[key].description);
|
|
134
|
-
}
|
|
135
|
-
if (properties[key].example) {
|
|
136
|
-
const exampleStr = JSON.stringify(properties[key].example);
|
|
137
|
-
properties[key].example = JSON.parse(this.replaceCityNames(exampleStr));
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
private replaceCityNames(text: string): string {
|
|
143
|
-
let result = text;
|
|
144
|
-
for (const [chinese, english] of Object.entries(this.cityMap)) {
|
|
145
|
-
// 使用正则表达式替换,避免替换部分匹配的词
|
|
146
|
-
const regex = new RegExp(`\\b${chinese}\\b`, 'g');
|
|
147
|
-
result = result.replace(regex, english);
|
|
148
|
-
}
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 添加自定义城市映射
|
|
153
|
-
addCityMapping(chinese: string, english: string): void {
|
|
154
|
-
this.cityMap[chinese] = english;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// 批量添加城市映射
|
|
158
|
-
addCityMappings(mappings: Record<string, string>): void {
|
|
159
|
-
Object.assign(this.cityMap, mappings);
|
|
160
|
-
}
|
|
161
|
-
}
|