@huyooo/ai-chat-core 0.2.3 → 0.2.5
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/package.json +3 -4
- package/dist/index.cjs +0 -2869
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -1434
package/dist/index.cjs
DELETED
|
@@ -1,2869 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var genai = require('@google/genai');
|
|
4
|
-
|
|
5
|
-
// src/agent.ts
|
|
6
|
-
|
|
7
|
-
// src/constants.ts
|
|
8
|
-
var DEFAULT_ARK_URL = "https://ark.cn-beijing.volces.com/api/v3";
|
|
9
|
-
var DEFAULT_QWEN_URL = "https://dashscope.aliyuncs.com/api/v1";
|
|
10
|
-
var DEFAULT_QWEN_NATIVE_URL = "https://dashscope.aliyuncs.com/api/v1";
|
|
11
|
-
var DEFAULT_OPENROUTER_URL = "https://openrouter.ai/api/v1";
|
|
12
|
-
var DOUBAO_SEED_1_8 = {
|
|
13
|
-
id: "doubao-seed-1-8-251215"};
|
|
14
|
-
var DOUBAO_SEED_1_6 = {
|
|
15
|
-
id: "doubao-seed-1-6-250615",
|
|
16
|
-
displayName: "\u8C46\u5305 Seed 1.6",
|
|
17
|
-
provider: "\u8C46\u5305"
|
|
18
|
-
};
|
|
19
|
-
var DOUBAO_SEED_1_6_LATEST = {
|
|
20
|
-
id: "doubao-seed-1-6-251015"};
|
|
21
|
-
var DOUBAO_SEED_1_6_FLASH = {
|
|
22
|
-
id: "doubao-seed-1-6-flash-250617"};
|
|
23
|
-
var DEEPSEEK_V3 = {
|
|
24
|
-
id: "deepseek-v3-1-terminus",
|
|
25
|
-
displayName: "DeepSeek V3",
|
|
26
|
-
provider: "DeepSeek"
|
|
27
|
-
};
|
|
28
|
-
var QWEN_MAX = { id: "qwen-max"};
|
|
29
|
-
var QWEN_MAX_LATEST = { id: "qwen-max-latest"};
|
|
30
|
-
var QWEN_PLUS = { id: "qwen-plus"};
|
|
31
|
-
var QWEN_PLUS_LATEST = { id: "qwen-plus-latest"};
|
|
32
|
-
var QWEN_TURBO = { id: "qwen-turbo"};
|
|
33
|
-
var QWEN_TURBO_LATEST = { id: "qwen-turbo-latest"};
|
|
34
|
-
var QWEN3_235B = { id: "qwen3-235b-a22b"};
|
|
35
|
-
var QWEN3_MAX_PREVIEW = {
|
|
36
|
-
id: "qwen3-max-preview",
|
|
37
|
-
displayName: "\u901A\u4E49\u5343\u95EE 3 Max",
|
|
38
|
-
provider: "\u901A\u4E49\u5343\u95EE"
|
|
39
|
-
};
|
|
40
|
-
var GEMINI_2_5_FLASH = { id: "gemini-2.5-flash-preview-05-20"};
|
|
41
|
-
var GEMINI_2_5_PRO = { id: "gemini-2.5-pro-preview-05-06"};
|
|
42
|
-
var GEMINI_2_0_FLASH = { id: "gemini-2.0-flash"};
|
|
43
|
-
var GEMINI_2_0_FLASH_LITE = { id: "gemini-2.0-flash-lite"};
|
|
44
|
-
var GEMINI_3_PRO = {
|
|
45
|
-
id: "gemini-3-pro-preview",
|
|
46
|
-
displayName: "Gemini 3 Pro",
|
|
47
|
-
provider: "Gemini"
|
|
48
|
-
};
|
|
49
|
-
var GEMINI_IMAGE_MODEL = "gemini-2.0-flash";
|
|
50
|
-
var GEMINI_IMAGE_GEN_MODEL = "gemini-3-pro-image-preview";
|
|
51
|
-
var OR_GEMINI_2_5_FLASH = {
|
|
52
|
-
id: "google/gemini-2.5-flash-preview"};
|
|
53
|
-
var OR_GEMINI_2_5_PRO = {
|
|
54
|
-
id: "google/gemini-2.5-pro-preview"};
|
|
55
|
-
var OR_GEMINI_2_0_FLASH = {
|
|
56
|
-
id: "google/gemini-2.0-flash-001"};
|
|
57
|
-
var OR_GEMINI_3_PRO = {
|
|
58
|
-
id: "google/gemini-3-pro-preview",
|
|
59
|
-
displayName: "Gemini 3 Pro",
|
|
60
|
-
isOpenRouter: true,
|
|
61
|
-
provider: "Gemini"
|
|
62
|
-
};
|
|
63
|
-
var OR_GPT_5_2 = {
|
|
64
|
-
id: "openai/gpt-5.2",
|
|
65
|
-
displayName: "GPT-5.2",
|
|
66
|
-
isOpenRouter: true,
|
|
67
|
-
provider: "OpenAI"
|
|
68
|
-
};
|
|
69
|
-
var OR_CLAUDE_OPUS_4_5 = {
|
|
70
|
-
id: "anthropic/claude-opus-4.5",
|
|
71
|
-
displayName: "Claude Opus 4.5",
|
|
72
|
-
isOpenRouter: true,
|
|
73
|
-
provider: "Anthropic"
|
|
74
|
-
};
|
|
75
|
-
var OR_QWEN3_MAX = {
|
|
76
|
-
id: "qwen/qwen3-max",
|
|
77
|
-
displayName: "\u901A\u4E49\u5343\u95EE Max",
|
|
78
|
-
isOpenRouter: true,
|
|
79
|
-
provider: "\u901A\u4E49\u5343\u95EE"
|
|
80
|
-
};
|
|
81
|
-
var OR_DEEPSEEK_R1 = {
|
|
82
|
-
id: "deepseek/deepseek-r1"};
|
|
83
|
-
var OR_DEEPSEEK_CHAT_V3 = {
|
|
84
|
-
id: "deepseek/deepseek-chat-v3-0324"};
|
|
85
|
-
var OR_DEEPSEEK_V3_2 = {
|
|
86
|
-
id: "deepseek/deepseek-v3.2",
|
|
87
|
-
displayName: "DeepSeek V3.2",
|
|
88
|
-
isOpenRouter: true,
|
|
89
|
-
provider: "DeepSeek"
|
|
90
|
-
};
|
|
91
|
-
var DISPLAY_MODELS = [
|
|
92
|
-
// 原生模型
|
|
93
|
-
DOUBAO_SEED_1_6,
|
|
94
|
-
DEEPSEEK_V3,
|
|
95
|
-
QWEN3_MAX_PREVIEW,
|
|
96
|
-
GEMINI_3_PRO,
|
|
97
|
-
// OpenRouter 模型
|
|
98
|
-
OR_GPT_5_2,
|
|
99
|
-
OR_CLAUDE_OPUS_4_5,
|
|
100
|
-
OR_GEMINI_3_PRO,
|
|
101
|
-
OR_QWEN3_MAX,
|
|
102
|
-
OR_DEEPSEEK_V3_2
|
|
103
|
-
];
|
|
104
|
-
var DEFAULT_MODEL = DOUBAO_SEED_1_6.id;
|
|
105
|
-
var PLAN_MODE_PROMPT = "\u5206\u6790\u9700\u6C42\u5E76\u5236\u5B9A\u6267\u884C\u8BA1\u5212\uFF0C\u4EE5 Markdown \u683C\u5F0F\u8F93\u51FA\u6B65\u9AA4\uFF0C\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u518D\u6267\u884C\u3002";
|
|
106
|
-
var AGENT_MODE_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684 AI \u52A9\u624B\u3002\u8BF7\u9075\u5FAA\u4EE5\u4E0B\u89C4\u5219\uFF1A
|
|
107
|
-
- \u8FD4\u56DE\u7684\u5185\u5BB9\u5C3D\u91CF\u4E0D\u8981\u4F7F\u7528\u8868\u60C5\u7B26\u53F7\uFF08emoji\uFF09\uFF0C\u9664\u975E\u7528\u6237\u8981\u6C42\u4F7F\u7528
|
|
108
|
-
- \u4F7F\u7528 Markdown \u683C\u5F0F\u7EC4\u7EC7\u5185\u5BB9
|
|
109
|
-
- \u4EE3\u7801\u5757\u4F7F\u7528\u6B63\u786E\u7684\u8BED\u8A00\u6807\u8BC6`;
|
|
110
|
-
|
|
111
|
-
// src/types.ts
|
|
112
|
-
var MODELS = DISPLAY_MODELS.map((m) => ({
|
|
113
|
-
modelId: m.id,
|
|
114
|
-
displayName: m.displayName,
|
|
115
|
-
group: m.isOpenRouter ? "OpenRouter" : "\u539F\u751F\u6A21\u578B",
|
|
116
|
-
// 后端决定分组
|
|
117
|
-
isOpenRouter: m.isOpenRouter,
|
|
118
|
-
provider: m.provider
|
|
119
|
-
}));
|
|
120
|
-
function getNativeModels() {
|
|
121
|
-
return MODELS.filter((m) => !m.isOpenRouter);
|
|
122
|
-
}
|
|
123
|
-
function getOpenRouterModels() {
|
|
124
|
-
return MODELS.filter((m) => m.isOpenRouter);
|
|
125
|
-
}
|
|
126
|
-
function getModelByModelId(modelId) {
|
|
127
|
-
return MODELS.find((m) => m.modelId === modelId);
|
|
128
|
-
}
|
|
129
|
-
function tool(t) {
|
|
130
|
-
return { tools: [t] };
|
|
131
|
-
}
|
|
132
|
-
function tools(ts) {
|
|
133
|
-
return { tools: ts };
|
|
134
|
-
}
|
|
135
|
-
async function resolveTools(items) {
|
|
136
|
-
const tools2 = [];
|
|
137
|
-
for (const item of items) {
|
|
138
|
-
const resolved = await item;
|
|
139
|
-
if ("tools" in resolved && Array.isArray(resolved.tools)) {
|
|
140
|
-
tools2.push(...resolved.tools);
|
|
141
|
-
} else {
|
|
142
|
-
console.warn("\u5DE5\u5177\u914D\u7F6E\u9879\u5FC5\u987B\u662F ToolPlugin \u5F62\u5F0F:", resolved);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return tools2;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// src/events.ts
|
|
149
|
-
function createThinkingStart() {
|
|
150
|
-
return {
|
|
151
|
-
type: "thinking_start",
|
|
152
|
-
data: { startedAt: Date.now() }
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
function createThinkingDelta(content) {
|
|
156
|
-
return {
|
|
157
|
-
type: "thinking_delta",
|
|
158
|
-
data: { content }
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
function createThinkingEnd(startedAt) {
|
|
162
|
-
const endedAt = Date.now();
|
|
163
|
-
return {
|
|
164
|
-
type: "thinking_end",
|
|
165
|
-
data: {
|
|
166
|
-
endedAt,
|
|
167
|
-
duration: endedAt - startedAt
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
function createSearchStart(query) {
|
|
172
|
-
return {
|
|
173
|
-
type: "search_start",
|
|
174
|
-
data: { query, startedAt: Date.now() }
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
function createSearchResult(results, startedAt) {
|
|
178
|
-
const endedAt = Date.now();
|
|
179
|
-
return {
|
|
180
|
-
type: "search_result",
|
|
181
|
-
data: {
|
|
182
|
-
results,
|
|
183
|
-
endedAt,
|
|
184
|
-
duration: endedAt - startedAt
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
function createSearchEnd(success, startedAt, error) {
|
|
189
|
-
const endedAt = Date.now();
|
|
190
|
-
return {
|
|
191
|
-
type: "search_end",
|
|
192
|
-
data: {
|
|
193
|
-
success,
|
|
194
|
-
error,
|
|
195
|
-
endedAt,
|
|
196
|
-
duration: endedAt - startedAt
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
function createToolCallStart(id, name, args) {
|
|
201
|
-
return {
|
|
202
|
-
type: "tool_call_start",
|
|
203
|
-
data: { id, name, args, startedAt: Date.now() }
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
function createToolCallResult(id, name, result, success, startedAt, error, sideEffects) {
|
|
207
|
-
const endedAt = Date.now();
|
|
208
|
-
return {
|
|
209
|
-
type: "tool_call_result",
|
|
210
|
-
data: {
|
|
211
|
-
id,
|
|
212
|
-
name,
|
|
213
|
-
result,
|
|
214
|
-
success,
|
|
215
|
-
error,
|
|
216
|
-
endedAt,
|
|
217
|
-
duration: endedAt - startedAt,
|
|
218
|
-
sideEffects
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
function createTextDelta(content) {
|
|
223
|
-
return {
|
|
224
|
-
type: "text_delta",
|
|
225
|
-
data: { content }
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
function createStreamStart(model, requestId) {
|
|
229
|
-
return {
|
|
230
|
-
type: "stream_start",
|
|
231
|
-
data: {
|
|
232
|
-
model,
|
|
233
|
-
requestId,
|
|
234
|
-
startedAt: Date.now()
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
function createDone(text, usage, duration) {
|
|
239
|
-
return {
|
|
240
|
-
type: "done",
|
|
241
|
-
data: { text, usage, duration }
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
function createError(details) {
|
|
245
|
-
return {
|
|
246
|
-
type: "error",
|
|
247
|
-
data: details
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
function createApiError(message, options = {}) {
|
|
251
|
-
return createError({
|
|
252
|
-
category: "api",
|
|
253
|
-
message,
|
|
254
|
-
...options
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
function createRateLimitError(message, retryAfter, context) {
|
|
258
|
-
return createError({
|
|
259
|
-
category: "rate_limit",
|
|
260
|
-
message,
|
|
261
|
-
code: "RATE_LIMIT",
|
|
262
|
-
statusCode: 429,
|
|
263
|
-
retryable: true,
|
|
264
|
-
retryAfter,
|
|
265
|
-
context
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
function createToolError(message, toolName, cause) {
|
|
269
|
-
return createError({
|
|
270
|
-
category: "tool",
|
|
271
|
-
message,
|
|
272
|
-
code: "TOOL_ERROR",
|
|
273
|
-
context: toolName,
|
|
274
|
-
cause,
|
|
275
|
-
retryable: false
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
function createTimeoutError(message, context) {
|
|
279
|
-
return createError({
|
|
280
|
-
category: "timeout",
|
|
281
|
-
message,
|
|
282
|
-
code: "TIMEOUT",
|
|
283
|
-
retryable: true,
|
|
284
|
-
context
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
function createParseError(message, cause) {
|
|
288
|
-
return createError({
|
|
289
|
-
category: "parse",
|
|
290
|
-
message,
|
|
291
|
-
code: "PARSE_ERROR",
|
|
292
|
-
cause,
|
|
293
|
-
retryable: false
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
function createAbort(reason) {
|
|
297
|
-
return {
|
|
298
|
-
type: "abort",
|
|
299
|
-
data: {
|
|
300
|
-
reason,
|
|
301
|
-
abortedAt: Date.now()
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
function createStepStart(stepNumber, description) {
|
|
306
|
-
return {
|
|
307
|
-
type: "step_start",
|
|
308
|
-
data: { stepNumber, description, startedAt: Date.now() }
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
function createStepEnd(stepNumber, startedAt) {
|
|
312
|
-
const endedAt = Date.now();
|
|
313
|
-
return {
|
|
314
|
-
type: "step_end",
|
|
315
|
-
data: {
|
|
316
|
-
stepNumber,
|
|
317
|
-
endedAt,
|
|
318
|
-
duration: endedAt - startedAt
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
function createImage(options) {
|
|
323
|
-
return {
|
|
324
|
-
type: "image",
|
|
325
|
-
data: options
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
function createVideo(path) {
|
|
329
|
-
return {
|
|
330
|
-
type: "video",
|
|
331
|
-
data: { path }
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
function isThinkingEvent(event) {
|
|
335
|
-
return event.type.startsWith("thinking_");
|
|
336
|
-
}
|
|
337
|
-
function isSearchEvent(event) {
|
|
338
|
-
return event.type.startsWith("search_");
|
|
339
|
-
}
|
|
340
|
-
function isToolEvent(event) {
|
|
341
|
-
return event.type.startsWith("tool_");
|
|
342
|
-
}
|
|
343
|
-
function isTextEvent(event) {
|
|
344
|
-
return event.type === "text_delta";
|
|
345
|
-
}
|
|
346
|
-
function isMediaEvent(event) {
|
|
347
|
-
return event.type === "image" || event.type === "video";
|
|
348
|
-
}
|
|
349
|
-
function isStatusEvent(event) {
|
|
350
|
-
return event.type === "stream_start" || event.type === "done" || event.type === "error" || event.type === "abort";
|
|
351
|
-
}
|
|
352
|
-
function isErrorEvent(event) {
|
|
353
|
-
return event.type === "error";
|
|
354
|
-
}
|
|
355
|
-
function isAbortEvent(event) {
|
|
356
|
-
return event.type === "abort";
|
|
357
|
-
}
|
|
358
|
-
function isStepEvent(event) {
|
|
359
|
-
return event.type.startsWith("step_");
|
|
360
|
-
}
|
|
361
|
-
function isRetryableError(event) {
|
|
362
|
-
if (event.type !== "error") return false;
|
|
363
|
-
return event.data.retryable === true;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// src/tools.ts
|
|
367
|
-
var DANGEROUS_COMMANDS = [
|
|
368
|
-
"rm -rf /",
|
|
369
|
-
"rm -rf ~",
|
|
370
|
-
"format",
|
|
371
|
-
"mkfs",
|
|
372
|
-
"dd if=",
|
|
373
|
-
"shutdown",
|
|
374
|
-
"reboot",
|
|
375
|
-
"sudo rm",
|
|
376
|
-
"sudo format"
|
|
377
|
-
];
|
|
378
|
-
function isDangerousCommand(command) {
|
|
379
|
-
const lowerCommand = command.toLowerCase().trim();
|
|
380
|
-
return DANGEROUS_COMMANDS.some(
|
|
381
|
-
(dangerous) => lowerCommand.includes(dangerous.toLowerCase())
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
function createDefaultToolExecutor(defaultCwd = process.cwd()) {
|
|
385
|
-
return {
|
|
386
|
-
async executeCommand(command, cwd, signal) {
|
|
387
|
-
if (signal?.aborted) {
|
|
388
|
-
return { success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88" };
|
|
389
|
-
}
|
|
390
|
-
if (isDangerousCommand(command)) {
|
|
391
|
-
return { success: false, error: "\u8BE5\u547D\u4EE4\u88AB\u5B89\u5168\u7B56\u7565\u963B\u6B62" };
|
|
392
|
-
}
|
|
393
|
-
try {
|
|
394
|
-
const { spawn } = await import('child_process');
|
|
395
|
-
return new Promise((resolve) => {
|
|
396
|
-
let stdout = "";
|
|
397
|
-
let stderr = "";
|
|
398
|
-
let killed = false;
|
|
399
|
-
const child = spawn("sh", ["-c", command], {
|
|
400
|
-
cwd: cwd || defaultCwd,
|
|
401
|
-
env: process.env
|
|
402
|
-
});
|
|
403
|
-
const timeout = setTimeout(() => {
|
|
404
|
-
if (!killed) {
|
|
405
|
-
killed = true;
|
|
406
|
-
child.kill("SIGTERM");
|
|
407
|
-
resolve({ success: false, error: "\u547D\u4EE4\u6267\u884C\u8D85\u65F6\uFF0830\u79D2\uFF09" });
|
|
408
|
-
}
|
|
409
|
-
}, 3e4);
|
|
410
|
-
const abortHandler = () => {
|
|
411
|
-
if (!killed) {
|
|
412
|
-
killed = true;
|
|
413
|
-
child.kill("SIGTERM");
|
|
414
|
-
clearTimeout(timeout);
|
|
415
|
-
resolve({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88" });
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
signal?.addEventListener("abort", abortHandler);
|
|
419
|
-
child.stdout?.on("data", (data) => {
|
|
420
|
-
stdout += data.toString();
|
|
421
|
-
});
|
|
422
|
-
child.stderr?.on("data", (data) => {
|
|
423
|
-
stderr += data.toString();
|
|
424
|
-
});
|
|
425
|
-
child.on("close", (code) => {
|
|
426
|
-
clearTimeout(timeout);
|
|
427
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
428
|
-
if (killed) return;
|
|
429
|
-
const output = stdout.trim();
|
|
430
|
-
const errOutput = stderr.trim();
|
|
431
|
-
if (code === 0) {
|
|
432
|
-
resolve({ success: true, output: output || errOutput || "\u6267\u884C\u6210\u529F" });
|
|
433
|
-
} else {
|
|
434
|
-
if (output) {
|
|
435
|
-
const warning = errOutput ? `
|
|
436
|
-
[\u8B66\u544A: ${errOutput}]` : "";
|
|
437
|
-
resolve({ success: true, output: output + warning });
|
|
438
|
-
} else if (errOutput) {
|
|
439
|
-
resolve({ success: false, error: errOutput });
|
|
440
|
-
} else {
|
|
441
|
-
resolve({ success: false, error: `\u547D\u4EE4\u9000\u51FA\u7801: ${code}` });
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
child.on("error", (err) => {
|
|
446
|
-
clearTimeout(timeout);
|
|
447
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
448
|
-
if (!killed) {
|
|
449
|
-
resolve({ success: false, error: err.message });
|
|
450
|
-
}
|
|
451
|
-
});
|
|
452
|
-
});
|
|
453
|
-
} catch (error) {
|
|
454
|
-
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// src/router.ts
|
|
461
|
-
var MODEL_ROUTES = [
|
|
462
|
-
// === 高优先级:OpenRouter 格式(包含 /)===
|
|
463
|
-
// 所有包含 / 的模型名都路由到 OpenRouter
|
|
464
|
-
// 例如:qwen/qwen3-max, anthropic/claude-opus-4.5, openai/gpt-5.2
|
|
465
|
-
{
|
|
466
|
-
type: "contains",
|
|
467
|
-
pattern: "/",
|
|
468
|
-
provider: "openrouter",
|
|
469
|
-
priority: 100,
|
|
470
|
-
description: "OpenRouter \u683C\u5F0F\u6A21\u578B\uFF08vendor/model\uFF09"
|
|
471
|
-
},
|
|
472
|
-
// === 中优先级:原生 Provider 前缀匹配 ===
|
|
473
|
-
{
|
|
474
|
-
type: "prefix",
|
|
475
|
-
pattern: "qwen",
|
|
476
|
-
provider: "qwen",
|
|
477
|
-
priority: 50,
|
|
478
|
-
description: "Qwen (DashScope) \u539F\u751F\u6A21\u578B"
|
|
479
|
-
},
|
|
480
|
-
{
|
|
481
|
-
type: "prefix",
|
|
482
|
-
pattern: "gemini",
|
|
483
|
-
provider: "gemini",
|
|
484
|
-
priority: 50,
|
|
485
|
-
description: "Gemini (Google AI) \u539F\u751F\u6A21\u578B"
|
|
486
|
-
},
|
|
487
|
-
// === 低优先级:ARK 火山引擎模型 ===
|
|
488
|
-
{
|
|
489
|
-
type: "prefix",
|
|
490
|
-
pattern: "doubao",
|
|
491
|
-
provider: "ark",
|
|
492
|
-
priority: 30,
|
|
493
|
-
description: "\u8C46\u5305\u6A21\u578B\uFF08\u706B\u5C71\u5F15\u64CE\uFF09"
|
|
494
|
-
},
|
|
495
|
-
{
|
|
496
|
-
type: "prefix",
|
|
497
|
-
pattern: "deepseek",
|
|
498
|
-
provider: "ark",
|
|
499
|
-
priority: 30,
|
|
500
|
-
description: "DeepSeek \u6A21\u578B\uFF08\u706B\u5C71\u5F15\u64CE\uFF09"
|
|
501
|
-
}
|
|
502
|
-
];
|
|
503
|
-
var DEFAULT_PROVIDER = "ark";
|
|
504
|
-
var sortedRulesCache = null;
|
|
505
|
-
function getSortedRules() {
|
|
506
|
-
if (!sortedRulesCache) {
|
|
507
|
-
sortedRulesCache = [...MODEL_ROUTES].sort((a, b) => b.priority - a.priority);
|
|
508
|
-
}
|
|
509
|
-
return sortedRulesCache;
|
|
510
|
-
}
|
|
511
|
-
function matchRule(model, rule) {
|
|
512
|
-
const lowerPattern = rule.pattern.toLowerCase();
|
|
513
|
-
switch (rule.type) {
|
|
514
|
-
case "exact":
|
|
515
|
-
return model === lowerPattern;
|
|
516
|
-
case "prefix":
|
|
517
|
-
return model.startsWith(lowerPattern);
|
|
518
|
-
case "contains":
|
|
519
|
-
return model.includes(lowerPattern);
|
|
520
|
-
case "regex":
|
|
521
|
-
return new RegExp(rule.pattern, "i").test(model);
|
|
522
|
-
default:
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
function routeModelToProvider(model) {
|
|
527
|
-
return routeModelWithDetails(model).provider;
|
|
528
|
-
}
|
|
529
|
-
function routeModelWithDetails(model) {
|
|
530
|
-
const lowerModel = model.toLowerCase();
|
|
531
|
-
const sortedRules = getSortedRules();
|
|
532
|
-
for (const rule of sortedRules) {
|
|
533
|
-
if (matchRule(lowerModel, rule)) {
|
|
534
|
-
return {
|
|
535
|
-
provider: rule.provider,
|
|
536
|
-
matchedRule: rule,
|
|
537
|
-
isDefault: false
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
return {
|
|
542
|
-
provider: DEFAULT_PROVIDER,
|
|
543
|
-
isDefault: true
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
function getRouteRules() {
|
|
547
|
-
return MODEL_ROUTES;
|
|
548
|
-
}
|
|
549
|
-
function getDefaultProvider() {
|
|
550
|
-
return DEFAULT_PROVIDER;
|
|
551
|
-
}
|
|
552
|
-
function isModelForProvider(model, provider) {
|
|
553
|
-
return routeModelToProvider(model) === provider;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// src/providers/orchestrator.ts
|
|
557
|
-
var DEFAULT_MAX_ITERATIONS = 10;
|
|
558
|
-
var ChatOrchestrator = class {
|
|
559
|
-
config;
|
|
560
|
-
constructor(config) {
|
|
561
|
-
this.config = {
|
|
562
|
-
maxIterations: DEFAULT_MAX_ITERATIONS,
|
|
563
|
-
...config
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
567
|
-
* 执行聊天
|
|
568
|
-
*
|
|
569
|
-
* @param adapter Provider 适配器
|
|
570
|
-
* @param message 用户消息
|
|
571
|
-
* @param context Orchestrator 上下文
|
|
572
|
-
* @param options 选项
|
|
573
|
-
*/
|
|
574
|
-
async *chat(adapter, message, context, options) {
|
|
575
|
-
const startedAt = Date.now();
|
|
576
|
-
const maxIterations = this.config.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
577
|
-
const messages = this.buildMessages(context, message);
|
|
578
|
-
let iterations = 0;
|
|
579
|
-
let finalText = "";
|
|
580
|
-
let thinkingText = "";
|
|
581
|
-
let thinkingStartedAt = 0;
|
|
582
|
-
let thinkingComplete = !options.enableThinking;
|
|
583
|
-
let searchResults = [];
|
|
584
|
-
let searchStartedAt = 0;
|
|
585
|
-
let searchStarted = false;
|
|
586
|
-
if (options.enableThinking) {
|
|
587
|
-
thinkingStartedAt = Date.now();
|
|
588
|
-
yield createThinkingStart();
|
|
589
|
-
}
|
|
590
|
-
while (iterations < maxIterations) {
|
|
591
|
-
if (context.signal.aborted) {
|
|
592
|
-
yield createAbort("\u8BF7\u6C42\u5DF2\u53D6\u6D88");
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
iterations++;
|
|
596
|
-
try {
|
|
597
|
-
const pendingToolCalls = [];
|
|
598
|
-
let hasToolCalls = false;
|
|
599
|
-
const stream = adapter.streamOnce(messages, context.tools, {
|
|
600
|
-
model: options.model,
|
|
601
|
-
enableThinking: options.enableThinking && iterations === 1,
|
|
602
|
-
// 只在第一轮启用思考
|
|
603
|
-
enableSearch: options.enableSearch && iterations === 1,
|
|
604
|
-
signal: context.signal
|
|
605
|
-
});
|
|
606
|
-
for await (const chunk of stream) {
|
|
607
|
-
switch (chunk.type) {
|
|
608
|
-
case "text":
|
|
609
|
-
if (chunk.text) {
|
|
610
|
-
if (!thinkingComplete) {
|
|
611
|
-
thinkingComplete = true;
|
|
612
|
-
yield createThinkingEnd(thinkingStartedAt);
|
|
613
|
-
}
|
|
614
|
-
finalText += chunk.text;
|
|
615
|
-
yield createTextDelta(chunk.text);
|
|
616
|
-
}
|
|
617
|
-
break;
|
|
618
|
-
case "thinking":
|
|
619
|
-
if (chunk.thinking) {
|
|
620
|
-
thinkingText += chunk.thinking;
|
|
621
|
-
yield createThinkingDelta(chunk.thinking);
|
|
622
|
-
}
|
|
623
|
-
break;
|
|
624
|
-
case "thinking_done":
|
|
625
|
-
if (!thinkingComplete) {
|
|
626
|
-
thinkingComplete = true;
|
|
627
|
-
yield createThinkingEnd(thinkingStartedAt);
|
|
628
|
-
}
|
|
629
|
-
break;
|
|
630
|
-
case "tool_call":
|
|
631
|
-
if (chunk.toolCall) {
|
|
632
|
-
pendingToolCalls.push(chunk.toolCall);
|
|
633
|
-
hasToolCalls = true;
|
|
634
|
-
}
|
|
635
|
-
break;
|
|
636
|
-
case "search_result":
|
|
637
|
-
if (chunk.searchResults) {
|
|
638
|
-
if (!searchStarted) {
|
|
639
|
-
searchStarted = true;
|
|
640
|
-
searchStartedAt = Date.now();
|
|
641
|
-
yield createSearchStart(message);
|
|
642
|
-
}
|
|
643
|
-
searchResults = chunk.searchResults;
|
|
644
|
-
yield createSearchResult(searchResults, searchStartedAt);
|
|
645
|
-
}
|
|
646
|
-
break;
|
|
647
|
-
case "done":
|
|
648
|
-
if (chunk.finishReason === "tool_calls") {
|
|
649
|
-
hasToolCalls = true;
|
|
650
|
-
}
|
|
651
|
-
break;
|
|
652
|
-
case "error":
|
|
653
|
-
yield createApiError(chunk.error ?? "\u672A\u77E5\u9519\u8BEF");
|
|
654
|
-
return;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
if (!thinkingComplete) {
|
|
658
|
-
thinkingComplete = true;
|
|
659
|
-
yield createThinkingEnd(thinkingStartedAt);
|
|
660
|
-
}
|
|
661
|
-
if (hasToolCalls && pendingToolCalls.length > 0) {
|
|
662
|
-
const assistantMessage = {
|
|
663
|
-
role: "assistant",
|
|
664
|
-
content: finalText,
|
|
665
|
-
toolCalls: pendingToolCalls
|
|
666
|
-
};
|
|
667
|
-
messages.push(assistantMessage);
|
|
668
|
-
for (const toolCall of pendingToolCalls) {
|
|
669
|
-
const toolStartedAt = Date.now();
|
|
670
|
-
let args;
|
|
671
|
-
try {
|
|
672
|
-
args = JSON.parse(toolCall.arguments || "{}");
|
|
673
|
-
} catch {
|
|
674
|
-
messages.push({
|
|
675
|
-
role: "tool",
|
|
676
|
-
content: "\u53C2\u6570\u89E3\u6790\u9519\u8BEF",
|
|
677
|
-
toolCallId: toolCall.id
|
|
678
|
-
});
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
const autoRunConfig = this.config.getAutoRunConfig ? await this.config.getAutoRunConfig() : options.autoRunConfig || this.config.autoRunConfig;
|
|
682
|
-
console.log("[Orchestrator] \u68C0\u67E5\u5DE5\u5177\u6279\u51C6:", {
|
|
683
|
-
toolName: toolCall.name,
|
|
684
|
-
autoRunConfigMode: autoRunConfig?.mode,
|
|
685
|
-
hasCallback: !!this.config.onToolApprovalRequest
|
|
686
|
-
});
|
|
687
|
-
if (autoRunConfig?.mode === "manual" && this.config.onToolApprovalRequest) {
|
|
688
|
-
console.log("[Orchestrator] \u53D1\u9001\u5DE5\u5177\u6279\u51C6\u8BF7\u6C42:", toolCall.name);
|
|
689
|
-
const approvalRequest = {
|
|
690
|
-
type: "tool_approval_request",
|
|
691
|
-
data: {
|
|
692
|
-
id: toolCall.id,
|
|
693
|
-
name: toolCall.name,
|
|
694
|
-
args,
|
|
695
|
-
requestedAt: Date.now()
|
|
696
|
-
}
|
|
697
|
-
};
|
|
698
|
-
yield approvalRequest;
|
|
699
|
-
const approved = await this.config.onToolApprovalRequest({
|
|
700
|
-
id: toolCall.id,
|
|
701
|
-
name: toolCall.name,
|
|
702
|
-
args
|
|
703
|
-
});
|
|
704
|
-
if (!approved) {
|
|
705
|
-
const result2 = JSON.stringify({ skipped: true, message: "\u7528\u6237\u8DF3\u8FC7\u4E86\u6B64\u5DE5\u5177" });
|
|
706
|
-
yield createToolCallResult(toolCall.id, toolCall.name, result2, false, toolStartedAt);
|
|
707
|
-
messages.push({
|
|
708
|
-
role: "tool",
|
|
709
|
-
content: result2,
|
|
710
|
-
toolCallId: toolCall.id,
|
|
711
|
-
toolName: toolCall.name
|
|
712
|
-
});
|
|
713
|
-
continue;
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
yield createToolCallStart(toolCall.id, toolCall.name, args);
|
|
717
|
-
let result;
|
|
718
|
-
let dynamicSideEffects;
|
|
719
|
-
let success = true;
|
|
720
|
-
try {
|
|
721
|
-
const executeResult = await this.config.executeTool(toolCall.name, args, context.signal);
|
|
722
|
-
if (typeof executeResult === "string") {
|
|
723
|
-
result = executeResult;
|
|
724
|
-
} else {
|
|
725
|
-
result = executeResult.result;
|
|
726
|
-
dynamicSideEffects = executeResult.sideEffects;
|
|
727
|
-
}
|
|
728
|
-
} catch (error) {
|
|
729
|
-
success = false;
|
|
730
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
731
|
-
result = `\u9519\u8BEF: ${errorMessage}`;
|
|
732
|
-
}
|
|
733
|
-
const tool2 = this.config.tools?.get(toolCall.name);
|
|
734
|
-
const sideEffects = dynamicSideEffects ?? tool2?.sideEffects;
|
|
735
|
-
yield createToolCallResult(toolCall.id, toolCall.name, result, success, toolStartedAt, void 0, sideEffects);
|
|
736
|
-
messages.push({
|
|
737
|
-
role: "tool",
|
|
738
|
-
content: result,
|
|
739
|
-
toolCallId: toolCall.id,
|
|
740
|
-
toolName: toolCall.name
|
|
741
|
-
// Gemini 需要工具名称
|
|
742
|
-
});
|
|
743
|
-
if (context.signal.aborted) {
|
|
744
|
-
yield createAbort("\u8BF7\u6C42\u5DF2\u53D6\u6D88");
|
|
745
|
-
return;
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
finalText = "";
|
|
749
|
-
continue;
|
|
750
|
-
}
|
|
751
|
-
break;
|
|
752
|
-
} catch (error) {
|
|
753
|
-
if (context.signal.aborted) {
|
|
754
|
-
yield createAbort("\u8BF7\u6C42\u5DF2\u53D6\u6D88");
|
|
755
|
-
} else {
|
|
756
|
-
yield createApiError(error instanceof Error ? error.message : String(error));
|
|
757
|
-
}
|
|
758
|
-
return;
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
if (searchStarted) {
|
|
762
|
-
yield createSearchEnd(true, searchStartedAt);
|
|
763
|
-
}
|
|
764
|
-
const duration = Date.now() - startedAt;
|
|
765
|
-
yield createDone(finalText, void 0, duration);
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* 构建标准化消息列表
|
|
769
|
-
*/
|
|
770
|
-
buildMessages(context, message) {
|
|
771
|
-
const messages = [];
|
|
772
|
-
if (context.systemPrompt) {
|
|
773
|
-
messages.push({
|
|
774
|
-
role: "system",
|
|
775
|
-
content: context.systemPrompt
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
for (const msg of context.history) {
|
|
779
|
-
const standardMsg = {
|
|
780
|
-
role: msg.role,
|
|
781
|
-
content: msg.content
|
|
782
|
-
};
|
|
783
|
-
if (msg.tool_calls) {
|
|
784
|
-
standardMsg.toolCalls = msg.tool_calls.map((tc) => ({
|
|
785
|
-
id: tc.id,
|
|
786
|
-
name: tc.function.name,
|
|
787
|
-
arguments: tc.function.arguments
|
|
788
|
-
}));
|
|
789
|
-
}
|
|
790
|
-
messages.push(standardMsg);
|
|
791
|
-
}
|
|
792
|
-
messages.push({
|
|
793
|
-
role: "user",
|
|
794
|
-
content: message,
|
|
795
|
-
images: context.images
|
|
796
|
-
});
|
|
797
|
-
return messages;
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
function createOrchestrator(config) {
|
|
801
|
-
return new ChatOrchestrator(config);
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// src/providers/adapters/ark.ts
|
|
805
|
-
var ARK_MODELS = [
|
|
806
|
-
DOUBAO_SEED_1_8.id,
|
|
807
|
-
DOUBAO_SEED_1_6.id,
|
|
808
|
-
DOUBAO_SEED_1_6_LATEST.id,
|
|
809
|
-
DOUBAO_SEED_1_6_FLASH.id,
|
|
810
|
-
"doubao-1-5-pro-32k-250115",
|
|
811
|
-
"doubao-1-5-pro-256k-250115",
|
|
812
|
-
"doubao-1-5-lite-32k-250115"
|
|
813
|
-
];
|
|
814
|
-
var ArkAdapter = class {
|
|
815
|
-
name = "ark";
|
|
816
|
-
supportedModels = ARK_MODELS;
|
|
817
|
-
apiKey;
|
|
818
|
-
apiUrl;
|
|
819
|
-
constructor(config) {
|
|
820
|
-
this.apiKey = config.apiKey;
|
|
821
|
-
this.apiUrl = config.apiUrl ?? DEFAULT_ARK_URL;
|
|
822
|
-
}
|
|
823
|
-
supportsModel(model) {
|
|
824
|
-
return this.supportedModels.some((m) => model.includes(m) || m.includes(model));
|
|
825
|
-
}
|
|
826
|
-
/**
|
|
827
|
-
* 单次流式调用
|
|
828
|
-
*/
|
|
829
|
-
async *streamOnce(messages, tools2, options) {
|
|
830
|
-
const input = this.convertMessages(messages);
|
|
831
|
-
const requestBody = {
|
|
832
|
-
model: options.model,
|
|
833
|
-
stream: true,
|
|
834
|
-
max_output_tokens: 32768,
|
|
835
|
-
input
|
|
836
|
-
};
|
|
837
|
-
const apiTools = [];
|
|
838
|
-
if (options.enableSearch) {
|
|
839
|
-
apiTools.push({ type: "web_search", max_keyword: 5, limit: 20 });
|
|
840
|
-
}
|
|
841
|
-
if (tools2.length > 0) {
|
|
842
|
-
for (const t of tools2) {
|
|
843
|
-
apiTools.push({
|
|
844
|
-
type: "function",
|
|
845
|
-
name: t.name,
|
|
846
|
-
description: t.description,
|
|
847
|
-
parameters: t.parameters
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
if (apiTools.length > 0) {
|
|
852
|
-
requestBody.tools = apiTools;
|
|
853
|
-
}
|
|
854
|
-
if (options.enableThinking) {
|
|
855
|
-
requestBody.thinking = { type: "enabled" };
|
|
856
|
-
}
|
|
857
|
-
const response = await fetch(`${this.apiUrl}/responses`, {
|
|
858
|
-
method: "POST",
|
|
859
|
-
headers: {
|
|
860
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
861
|
-
"Content-Type": "application/json"
|
|
862
|
-
},
|
|
863
|
-
body: JSON.stringify(requestBody),
|
|
864
|
-
signal: options.signal
|
|
865
|
-
});
|
|
866
|
-
if (!response.ok) {
|
|
867
|
-
const errorText = await response.text();
|
|
868
|
-
yield { type: "error", error: `ARK API \u9519\u8BEF: ${response.status} - ${errorText}` };
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
const reader = response.body?.getReader();
|
|
872
|
-
if (!reader) {
|
|
873
|
-
yield { type: "error", error: "\u65E0\u6CD5\u83B7\u53D6\u54CD\u5E94\u6D41" };
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
yield* this.parseStream(reader);
|
|
877
|
-
}
|
|
878
|
-
/**
|
|
879
|
-
* 转换标准消息为 ARK Responses API 格式
|
|
880
|
-
*/
|
|
881
|
-
convertMessages(messages) {
|
|
882
|
-
const input = [];
|
|
883
|
-
for (const msg of messages) {
|
|
884
|
-
switch (msg.role) {
|
|
885
|
-
case "system":
|
|
886
|
-
input.push({ role: "system", content: msg.content });
|
|
887
|
-
break;
|
|
888
|
-
case "user": {
|
|
889
|
-
const content = [{ type: "input_text", text: msg.content }];
|
|
890
|
-
if (msg.images?.length) {
|
|
891
|
-
for (const img of msg.images) {
|
|
892
|
-
content.push({
|
|
893
|
-
type: "input_image",
|
|
894
|
-
image_url: img.startsWith("data:") ? img : `data:image/jpeg;base64,${img}`
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
input.push({ role: "user", content });
|
|
899
|
-
break;
|
|
900
|
-
}
|
|
901
|
-
case "assistant":
|
|
902
|
-
if (msg.toolCalls?.length) {
|
|
903
|
-
for (const tc of msg.toolCalls) {
|
|
904
|
-
input.push({
|
|
905
|
-
type: "function_call",
|
|
906
|
-
call_id: tc.id,
|
|
907
|
-
name: tc.name,
|
|
908
|
-
arguments: tc.arguments
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
} else {
|
|
912
|
-
input.push({
|
|
913
|
-
role: "developer",
|
|
914
|
-
content: `[\u4E0A\u4E00\u8F6EAI\u56DE\u590D]: ${msg.content}`
|
|
915
|
-
});
|
|
916
|
-
}
|
|
917
|
-
break;
|
|
918
|
-
case "tool":
|
|
919
|
-
input.push({
|
|
920
|
-
type: "function_call_output",
|
|
921
|
-
call_id: msg.toolCallId,
|
|
922
|
-
output: msg.content
|
|
923
|
-
});
|
|
924
|
-
break;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
return input;
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* 解析 ARK 流式响应
|
|
931
|
-
*/
|
|
932
|
-
async *parseStream(reader) {
|
|
933
|
-
const decoder = new TextDecoder();
|
|
934
|
-
let buffer = "";
|
|
935
|
-
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
936
|
-
let currentFunctionCallId = null;
|
|
937
|
-
const searchResults = [];
|
|
938
|
-
while (true) {
|
|
939
|
-
const { done, value } = await reader.read();
|
|
940
|
-
if (done) break;
|
|
941
|
-
buffer += decoder.decode(value, { stream: true });
|
|
942
|
-
const lines = buffer.split("\n");
|
|
943
|
-
buffer = lines.pop() || "";
|
|
944
|
-
for (const line of lines) {
|
|
945
|
-
if (!line.startsWith("data:")) continue;
|
|
946
|
-
const data = line.slice(5).trim();
|
|
947
|
-
if (data === "[DONE]") {
|
|
948
|
-
if (pendingToolCalls.size > 0) {
|
|
949
|
-
for (const tc of pendingToolCalls.values()) {
|
|
950
|
-
yield { type: "tool_call", toolCall: tc };
|
|
951
|
-
}
|
|
952
|
-
yield { type: "done", finishReason: "tool_calls" };
|
|
953
|
-
} else {
|
|
954
|
-
yield { type: "done", finishReason: "stop" };
|
|
955
|
-
}
|
|
956
|
-
return;
|
|
957
|
-
}
|
|
958
|
-
try {
|
|
959
|
-
const event = JSON.parse(data);
|
|
960
|
-
switch (event.type) {
|
|
961
|
-
case "response.output_item.added": {
|
|
962
|
-
const item = event.item;
|
|
963
|
-
if (item?.type === "function_call") {
|
|
964
|
-
const callId = item.call_id;
|
|
965
|
-
if (!callId) {
|
|
966
|
-
console.warn("[ARK] function_call \u7F3A\u5C11 call_id");
|
|
967
|
-
break;
|
|
968
|
-
}
|
|
969
|
-
currentFunctionCallId = callId;
|
|
970
|
-
pendingToolCalls.set(callId, {
|
|
971
|
-
id: callId,
|
|
972
|
-
name: item.name || "",
|
|
973
|
-
arguments: item.arguments || ""
|
|
974
|
-
});
|
|
975
|
-
}
|
|
976
|
-
break;
|
|
977
|
-
}
|
|
978
|
-
case "response.function_call_arguments.delta": {
|
|
979
|
-
if (currentFunctionCallId) {
|
|
980
|
-
const call = pendingToolCalls.get(currentFunctionCallId);
|
|
981
|
-
if (call) {
|
|
982
|
-
call.arguments += event.delta || "";
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
break;
|
|
986
|
-
}
|
|
987
|
-
case "response.function_call_arguments.done":
|
|
988
|
-
case "response.output_item.done": {
|
|
989
|
-
const item = event.item;
|
|
990
|
-
if (item?.type === "function_call" && item.call_id) {
|
|
991
|
-
const callId = item.call_id;
|
|
992
|
-
const existing = pendingToolCalls.get(callId);
|
|
993
|
-
pendingToolCalls.set(callId, {
|
|
994
|
-
id: callId,
|
|
995
|
-
name: item.name || existing?.name || "",
|
|
996
|
-
arguments: item.arguments || existing?.arguments || "{}"
|
|
997
|
-
});
|
|
998
|
-
}
|
|
999
|
-
break;
|
|
1000
|
-
}
|
|
1001
|
-
case "response.output_text.annotation.added": {
|
|
1002
|
-
const annotation = event.annotation;
|
|
1003
|
-
const isUrlCitation = annotation?.type === "url_citation" || annotation?.type === "citation" || annotation?.url;
|
|
1004
|
-
if (isUrlCitation && annotation?.url) {
|
|
1005
|
-
const exists = searchResults.some((r) => r.url === annotation.url);
|
|
1006
|
-
if (!exists) {
|
|
1007
|
-
searchResults.push({
|
|
1008
|
-
title: annotation.title || annotation.text || "",
|
|
1009
|
-
url: annotation.url,
|
|
1010
|
-
snippet: annotation.summary || annotation.snippet || ""
|
|
1011
|
-
});
|
|
1012
|
-
yield { type: "search_result", searchResults: [...searchResults] };
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
break;
|
|
1016
|
-
}
|
|
1017
|
-
case "response.output_text.delta":
|
|
1018
|
-
if (event.delta) {
|
|
1019
|
-
yield { type: "text", text: event.delta };
|
|
1020
|
-
}
|
|
1021
|
-
break;
|
|
1022
|
-
case "response.reasoning_summary_text.delta":
|
|
1023
|
-
if (event.delta) {
|
|
1024
|
-
yield { type: "thinking", thinking: event.delta };
|
|
1025
|
-
}
|
|
1026
|
-
break;
|
|
1027
|
-
case "response.reasoning_summary_text.done":
|
|
1028
|
-
yield { type: "thinking_done" };
|
|
1029
|
-
break;
|
|
1030
|
-
}
|
|
1031
|
-
} catch {
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
if (pendingToolCalls.size > 0) {
|
|
1036
|
-
for (const tc of pendingToolCalls.values()) {
|
|
1037
|
-
yield { type: "tool_call", toolCall: tc };
|
|
1038
|
-
}
|
|
1039
|
-
yield { type: "done", finishReason: "tool_calls" };
|
|
1040
|
-
} else {
|
|
1041
|
-
yield { type: "done", finishReason: "stop" };
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
};
|
|
1045
|
-
function createArkAdapter(config) {
|
|
1046
|
-
return new ArkAdapter(config);
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
// src/providers/adapters/openrouter.ts
|
|
1050
|
-
var OPENROUTER_MODELS = [
|
|
1051
|
-
OR_GEMINI_2_5_FLASH.id,
|
|
1052
|
-
OR_GEMINI_2_5_PRO.id,
|
|
1053
|
-
OR_GEMINI_2_0_FLASH.id,
|
|
1054
|
-
"anthropic/claude-sonnet-4",
|
|
1055
|
-
"anthropic/claude-3.5-sonnet",
|
|
1056
|
-
"openai/gpt-4o",
|
|
1057
|
-
"openai/gpt-4o-mini",
|
|
1058
|
-
OR_DEEPSEEK_R1.id,
|
|
1059
|
-
OR_DEEPSEEK_CHAT_V3.id
|
|
1060
|
-
];
|
|
1061
|
-
var OpenRouterAdapter = class {
|
|
1062
|
-
name = "openrouter";
|
|
1063
|
-
supportedModels = OPENROUTER_MODELS;
|
|
1064
|
-
apiKey;
|
|
1065
|
-
apiUrl;
|
|
1066
|
-
constructor(config) {
|
|
1067
|
-
this.apiKey = config.apiKey;
|
|
1068
|
-
this.apiUrl = config.apiUrl ?? DEFAULT_OPENROUTER_URL;
|
|
1069
|
-
}
|
|
1070
|
-
supportsModel(model) {
|
|
1071
|
-
return this.supportedModels.some((m) => model.includes(m) || m.includes(model));
|
|
1072
|
-
}
|
|
1073
|
-
/**
|
|
1074
|
-
* 单次流式调用
|
|
1075
|
-
*/
|
|
1076
|
-
async *streamOnce(messages, tools2, options) {
|
|
1077
|
-
const apiMessages = this.convertMessages(messages);
|
|
1078
|
-
const requestBody = {
|
|
1079
|
-
model: options.model,
|
|
1080
|
-
messages: apiMessages,
|
|
1081
|
-
stream: true,
|
|
1082
|
-
max_tokens: 32768
|
|
1083
|
-
};
|
|
1084
|
-
if (tools2.length > 0) {
|
|
1085
|
-
requestBody.tools = tools2.map((t) => ({
|
|
1086
|
-
type: "function",
|
|
1087
|
-
function: {
|
|
1088
|
-
name: t.name,
|
|
1089
|
-
description: t.description,
|
|
1090
|
-
parameters: t.parameters
|
|
1091
|
-
}
|
|
1092
|
-
}));
|
|
1093
|
-
}
|
|
1094
|
-
if (options.model.includes("gemini") && options.enableThinking) {
|
|
1095
|
-
requestBody.reasoning = { effort: "high" };
|
|
1096
|
-
}
|
|
1097
|
-
if (options.model.includes("claude") && options.enableThinking) {
|
|
1098
|
-
requestBody.reasoning = { effort: "high", exclude: false };
|
|
1099
|
-
}
|
|
1100
|
-
if (options.enableSearch) {
|
|
1101
|
-
const isSmallContext = options.model.includes("deepseek") || options.model.includes("qwen");
|
|
1102
|
-
const maxResults = isSmallContext ? 2 : 3;
|
|
1103
|
-
requestBody.plugins = [{ id: "web", max_results: maxResults }];
|
|
1104
|
-
}
|
|
1105
|
-
const response = await fetch(`${this.apiUrl}/chat/completions`, {
|
|
1106
|
-
method: "POST",
|
|
1107
|
-
headers: {
|
|
1108
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
1109
|
-
"Content-Type": "application/json",
|
|
1110
|
-
"HTTP-Referer": "https://ai-chat.local",
|
|
1111
|
-
"X-Title": "AI Chat"
|
|
1112
|
-
},
|
|
1113
|
-
body: JSON.stringify(requestBody),
|
|
1114
|
-
signal: options.signal
|
|
1115
|
-
});
|
|
1116
|
-
if (!response.ok) {
|
|
1117
|
-
const errorText = await response.text();
|
|
1118
|
-
yield { type: "error", error: `OpenRouter API \u9519\u8BEF: ${response.status} - ${errorText}` };
|
|
1119
|
-
return;
|
|
1120
|
-
}
|
|
1121
|
-
const reader = response.body?.getReader();
|
|
1122
|
-
if (!reader) {
|
|
1123
|
-
yield { type: "error", error: "\u65E0\u6CD5\u83B7\u53D6\u54CD\u5E94\u6D41" };
|
|
1124
|
-
return;
|
|
1125
|
-
}
|
|
1126
|
-
yield* this.parseStream(reader);
|
|
1127
|
-
}
|
|
1128
|
-
/**
|
|
1129
|
-
* 转换标准消息为 OpenAI 格式
|
|
1130
|
-
*/
|
|
1131
|
-
convertMessages(messages) {
|
|
1132
|
-
const apiMessages = [];
|
|
1133
|
-
for (const msg of messages) {
|
|
1134
|
-
switch (msg.role) {
|
|
1135
|
-
case "system":
|
|
1136
|
-
apiMessages.push({ role: "system", content: msg.content });
|
|
1137
|
-
break;
|
|
1138
|
-
case "user": {
|
|
1139
|
-
if (msg.images?.length) {
|
|
1140
|
-
const content = [{ type: "text", text: msg.content }];
|
|
1141
|
-
for (const img of msg.images) {
|
|
1142
|
-
content.push({
|
|
1143
|
-
type: "image_url",
|
|
1144
|
-
image_url: { url: img.startsWith("data:") ? img : `data:image/jpeg;base64,${img}` }
|
|
1145
|
-
});
|
|
1146
|
-
}
|
|
1147
|
-
apiMessages.push({ role: "user", content });
|
|
1148
|
-
} else {
|
|
1149
|
-
apiMessages.push({ role: "user", content: msg.content });
|
|
1150
|
-
}
|
|
1151
|
-
break;
|
|
1152
|
-
}
|
|
1153
|
-
case "assistant":
|
|
1154
|
-
if (msg.toolCalls?.length) {
|
|
1155
|
-
apiMessages.push({
|
|
1156
|
-
role: "assistant",
|
|
1157
|
-
content: msg.content || null,
|
|
1158
|
-
tool_calls: msg.toolCalls.map((tc) => ({
|
|
1159
|
-
id: tc.id,
|
|
1160
|
-
type: "function",
|
|
1161
|
-
function: {
|
|
1162
|
-
name: tc.name,
|
|
1163
|
-
arguments: tc.arguments
|
|
1164
|
-
}
|
|
1165
|
-
}))
|
|
1166
|
-
});
|
|
1167
|
-
} else {
|
|
1168
|
-
apiMessages.push({ role: "assistant", content: msg.content });
|
|
1169
|
-
}
|
|
1170
|
-
break;
|
|
1171
|
-
case "tool":
|
|
1172
|
-
apiMessages.push({
|
|
1173
|
-
role: "tool",
|
|
1174
|
-
tool_call_id: msg.toolCallId,
|
|
1175
|
-
content: msg.content
|
|
1176
|
-
});
|
|
1177
|
-
break;
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
return apiMessages;
|
|
1181
|
-
}
|
|
1182
|
-
/**
|
|
1183
|
-
* 解析 OpenAI 兼容流式响应
|
|
1184
|
-
*/
|
|
1185
|
-
async *parseStream(reader) {
|
|
1186
|
-
const decoder = new TextDecoder();
|
|
1187
|
-
let buffer = "";
|
|
1188
|
-
const toolCallsMap = /* @__PURE__ */ new Map();
|
|
1189
|
-
let toolCallCounter = 0;
|
|
1190
|
-
let finishReason = null;
|
|
1191
|
-
const searchResults = [];
|
|
1192
|
-
let hasThinking = false;
|
|
1193
|
-
let thinkingDone = false;
|
|
1194
|
-
while (true) {
|
|
1195
|
-
const { done, value } = await reader.read();
|
|
1196
|
-
if (done) break;
|
|
1197
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1198
|
-
const lines = buffer.split("\n");
|
|
1199
|
-
buffer = lines.pop() || "";
|
|
1200
|
-
for (const line of lines) {
|
|
1201
|
-
if (!line.startsWith("data:")) continue;
|
|
1202
|
-
const data = line.slice(5).trim();
|
|
1203
|
-
if (data === "[DONE]") {
|
|
1204
|
-
if (searchResults.length > 0) {
|
|
1205
|
-
yield { type: "search_result", searchResults: [...searchResults] };
|
|
1206
|
-
}
|
|
1207
|
-
if (toolCallsMap.size > 0) {
|
|
1208
|
-
for (const tc of toolCallsMap.values()) {
|
|
1209
|
-
if (tc.name) {
|
|
1210
|
-
yield { type: "tool_call", toolCall: tc };
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
yield { type: "done", finishReason: "tool_calls" };
|
|
1214
|
-
} else {
|
|
1215
|
-
yield { type: "done", finishReason: "stop" };
|
|
1216
|
-
}
|
|
1217
|
-
return;
|
|
1218
|
-
}
|
|
1219
|
-
try {
|
|
1220
|
-
const json = JSON.parse(data);
|
|
1221
|
-
const choice = json.choices?.[0];
|
|
1222
|
-
const annotations = json.annotations;
|
|
1223
|
-
if (annotations?.length) {
|
|
1224
|
-
for (const annotation of annotations) {
|
|
1225
|
-
if (annotation.type === "url_citation" && annotation.url_citation?.url) {
|
|
1226
|
-
const exists = searchResults.some((r) => r.url === annotation.url_citation.url);
|
|
1227
|
-
if (!exists) {
|
|
1228
|
-
searchResults.push({
|
|
1229
|
-
url: annotation.url_citation.url,
|
|
1230
|
-
title: annotation.url_citation.title || "",
|
|
1231
|
-
snippet: annotation.url_citation.content || ""
|
|
1232
|
-
});
|
|
1233
|
-
yield { type: "search_result", searchResults: [...searchResults] };
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
if (!choice) continue;
|
|
1239
|
-
const delta = choice.delta || {};
|
|
1240
|
-
finishReason = choice.finish_reason;
|
|
1241
|
-
if (delta.reasoning) {
|
|
1242
|
-
hasThinking = true;
|
|
1243
|
-
yield { type: "thinking", thinking: delta.reasoning };
|
|
1244
|
-
}
|
|
1245
|
-
if (delta.content) {
|
|
1246
|
-
if (hasThinking && !thinkingDone) {
|
|
1247
|
-
thinkingDone = true;
|
|
1248
|
-
yield { type: "thinking_done" };
|
|
1249
|
-
}
|
|
1250
|
-
yield { type: "text", text: delta.content };
|
|
1251
|
-
}
|
|
1252
|
-
if (delta.tool_calls?.length) {
|
|
1253
|
-
for (const tc of delta.tool_calls) {
|
|
1254
|
-
const index = tc.index;
|
|
1255
|
-
const existing = toolCallsMap.get(index);
|
|
1256
|
-
if (existing) {
|
|
1257
|
-
if (tc.function?.arguments) {
|
|
1258
|
-
existing.arguments += tc.function.arguments;
|
|
1259
|
-
}
|
|
1260
|
-
if (tc.function?.name) {
|
|
1261
|
-
existing.name = tc.function.name;
|
|
1262
|
-
}
|
|
1263
|
-
if (tc.id) {
|
|
1264
|
-
existing.id = tc.id;
|
|
1265
|
-
}
|
|
1266
|
-
} else {
|
|
1267
|
-
toolCallsMap.set(index, {
|
|
1268
|
-
id: tc.id || `call_${Date.now()}_${toolCallCounter++}`,
|
|
1269
|
-
name: tc.function?.name || "",
|
|
1270
|
-
arguments: tc.function?.arguments || ""
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
if (finishReason === "tool_calls") {
|
|
1276
|
-
for (const tc of toolCallsMap.values()) {
|
|
1277
|
-
if (tc.name) {
|
|
1278
|
-
yield { type: "tool_call", toolCall: tc };
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
yield { type: "done", finishReason: "tool_calls" };
|
|
1282
|
-
return;
|
|
1283
|
-
}
|
|
1284
|
-
} catch {
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
if (searchResults.length > 0) {
|
|
1289
|
-
yield { type: "search_result", searchResults: [...searchResults] };
|
|
1290
|
-
}
|
|
1291
|
-
if (toolCallsMap.size > 0) {
|
|
1292
|
-
for (const tc of toolCallsMap.values()) {
|
|
1293
|
-
if (tc.name) {
|
|
1294
|
-
yield { type: "tool_call", toolCall: tc };
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
yield { type: "done", finishReason: "tool_calls" };
|
|
1298
|
-
} else {
|
|
1299
|
-
yield { type: "done", finishReason: "stop" };
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
};
|
|
1303
|
-
function createOpenRouterAdapter(config) {
|
|
1304
|
-
return new OpenRouterAdapter(config);
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
// src/providers/adapters/qwen.ts
|
|
1308
|
-
var QWEN_MODELS = [
|
|
1309
|
-
QWEN_MAX.id,
|
|
1310
|
-
QWEN_MAX_LATEST.id,
|
|
1311
|
-
QWEN_PLUS.id,
|
|
1312
|
-
QWEN_PLUS_LATEST.id,
|
|
1313
|
-
QWEN_TURBO.id,
|
|
1314
|
-
QWEN_TURBO_LATEST.id,
|
|
1315
|
-
QWEN3_235B.id
|
|
1316
|
-
];
|
|
1317
|
-
var QwenAdapter = class {
|
|
1318
|
-
name = "qwen";
|
|
1319
|
-
supportedModels = QWEN_MODELS;
|
|
1320
|
-
apiKey;
|
|
1321
|
-
apiUrl;
|
|
1322
|
-
constructor(config) {
|
|
1323
|
-
this.apiKey = config.apiKey;
|
|
1324
|
-
this.apiUrl = config.apiUrl ?? DEFAULT_QWEN_URL;
|
|
1325
|
-
}
|
|
1326
|
-
supportsModel(model) {
|
|
1327
|
-
return this.supportedModels.some((m) => model.includes(m) || m.includes(model));
|
|
1328
|
-
}
|
|
1329
|
-
/**
|
|
1330
|
-
* 单次流式调用
|
|
1331
|
-
*/
|
|
1332
|
-
async *streamOnce(messages, tools2, options) {
|
|
1333
|
-
const apiMessages = this.convertMessages(messages);
|
|
1334
|
-
const requestBody = {
|
|
1335
|
-
model: options.model,
|
|
1336
|
-
input: { messages: apiMessages },
|
|
1337
|
-
parameters: {
|
|
1338
|
-
result_format: "message",
|
|
1339
|
-
incremental_output: true,
|
|
1340
|
-
enable_search: options.enableSearch,
|
|
1341
|
-
// 深度思考支持
|
|
1342
|
-
...options.enableThinking && {
|
|
1343
|
-
enable_thinking: true,
|
|
1344
|
-
thinking_budget: 38400
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
};
|
|
1348
|
-
if (tools2.length > 0) {
|
|
1349
|
-
requestBody.parameters = {
|
|
1350
|
-
...requestBody.parameters,
|
|
1351
|
-
tools: tools2.map((t) => ({
|
|
1352
|
-
type: "function",
|
|
1353
|
-
function: {
|
|
1354
|
-
name: t.name,
|
|
1355
|
-
description: t.description,
|
|
1356
|
-
parameters: t.parameters
|
|
1357
|
-
}
|
|
1358
|
-
}))
|
|
1359
|
-
};
|
|
1360
|
-
}
|
|
1361
|
-
const response = await fetch(`${this.apiUrl}/services/aigc/text-generation/generation`, {
|
|
1362
|
-
method: "POST",
|
|
1363
|
-
headers: {
|
|
1364
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
1365
|
-
"Content-Type": "application/json",
|
|
1366
|
-
"X-DashScope-SSE": "enable"
|
|
1367
|
-
},
|
|
1368
|
-
body: JSON.stringify(requestBody),
|
|
1369
|
-
signal: options.signal
|
|
1370
|
-
});
|
|
1371
|
-
if (!response.ok) {
|
|
1372
|
-
const errorText = await response.text();
|
|
1373
|
-
yield { type: "error", error: `Qwen API \u9519\u8BEF: ${response.status} - ${errorText}` };
|
|
1374
|
-
return;
|
|
1375
|
-
}
|
|
1376
|
-
const reader = response.body?.getReader();
|
|
1377
|
-
if (!reader) {
|
|
1378
|
-
yield { type: "error", error: "\u65E0\u6CD5\u83B7\u53D6\u54CD\u5E94\u6D41" };
|
|
1379
|
-
return;
|
|
1380
|
-
}
|
|
1381
|
-
yield* this.parseStream(reader);
|
|
1382
|
-
}
|
|
1383
|
-
/**
|
|
1384
|
-
* 转换标准消息为 Qwen 格式
|
|
1385
|
-
*/
|
|
1386
|
-
convertMessages(messages) {
|
|
1387
|
-
const apiMessages = [];
|
|
1388
|
-
for (const msg of messages) {
|
|
1389
|
-
switch (msg.role) {
|
|
1390
|
-
case "system":
|
|
1391
|
-
apiMessages.push({ role: "system", content: msg.content });
|
|
1392
|
-
break;
|
|
1393
|
-
case "user": {
|
|
1394
|
-
if (msg.images?.length) {
|
|
1395
|
-
const content = [{ type: "text", text: msg.content }];
|
|
1396
|
-
for (const img of msg.images) {
|
|
1397
|
-
content.push({
|
|
1398
|
-
type: "image_url",
|
|
1399
|
-
image_url: { url: img.startsWith("data:") ? img : `data:image/jpeg;base64,${img}` }
|
|
1400
|
-
});
|
|
1401
|
-
}
|
|
1402
|
-
apiMessages.push({ role: "user", content });
|
|
1403
|
-
} else {
|
|
1404
|
-
apiMessages.push({ role: "user", content: msg.content });
|
|
1405
|
-
}
|
|
1406
|
-
break;
|
|
1407
|
-
}
|
|
1408
|
-
case "assistant":
|
|
1409
|
-
if (msg.toolCalls?.length) {
|
|
1410
|
-
apiMessages.push({
|
|
1411
|
-
role: "assistant",
|
|
1412
|
-
content: msg.content || "",
|
|
1413
|
-
tool_calls: msg.toolCalls.map((tc) => ({
|
|
1414
|
-
id: tc.id,
|
|
1415
|
-
type: "function",
|
|
1416
|
-
function: {
|
|
1417
|
-
name: tc.name,
|
|
1418
|
-
arguments: tc.arguments
|
|
1419
|
-
}
|
|
1420
|
-
}))
|
|
1421
|
-
});
|
|
1422
|
-
} else {
|
|
1423
|
-
apiMessages.push({ role: "assistant", content: msg.content });
|
|
1424
|
-
}
|
|
1425
|
-
break;
|
|
1426
|
-
case "tool":
|
|
1427
|
-
apiMessages.push({
|
|
1428
|
-
role: "tool",
|
|
1429
|
-
tool_call_id: msg.toolCallId,
|
|
1430
|
-
content: msg.content
|
|
1431
|
-
});
|
|
1432
|
-
break;
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
return apiMessages;
|
|
1436
|
-
}
|
|
1437
|
-
/**
|
|
1438
|
-
* 解析 Qwen 流式响应
|
|
1439
|
-
*/
|
|
1440
|
-
async *parseStream(reader) {
|
|
1441
|
-
const decoder = new TextDecoder();
|
|
1442
|
-
let buffer = "";
|
|
1443
|
-
const toolCallsMap = /* @__PURE__ */ new Map();
|
|
1444
|
-
let toolCallCounter = 0;
|
|
1445
|
-
const searchResults = [];
|
|
1446
|
-
let hasThinking = false;
|
|
1447
|
-
let thinkingDone = false;
|
|
1448
|
-
while (true) {
|
|
1449
|
-
const { done, value } = await reader.read();
|
|
1450
|
-
if (done) break;
|
|
1451
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1452
|
-
const lines = buffer.split("\n");
|
|
1453
|
-
buffer = lines.pop() || "";
|
|
1454
|
-
for (const line of lines) {
|
|
1455
|
-
if (!line.startsWith("data:")) continue;
|
|
1456
|
-
const data = line.slice(5).trim();
|
|
1457
|
-
if (!data || data === "[DONE]") continue;
|
|
1458
|
-
try {
|
|
1459
|
-
const json = JSON.parse(data);
|
|
1460
|
-
const output = json.output;
|
|
1461
|
-
if (!output) continue;
|
|
1462
|
-
const choice = output.choices?.[0];
|
|
1463
|
-
const message = choice?.message || {};
|
|
1464
|
-
const finishReason = choice?.finish_reason;
|
|
1465
|
-
if (message.reasoning_content) {
|
|
1466
|
-
hasThinking = true;
|
|
1467
|
-
yield { type: "thinking", thinking: message.reasoning_content };
|
|
1468
|
-
}
|
|
1469
|
-
if (message.content) {
|
|
1470
|
-
if (!thinkingDone && hasThinking) {
|
|
1471
|
-
thinkingDone = true;
|
|
1472
|
-
yield { type: "thinking_done" };
|
|
1473
|
-
}
|
|
1474
|
-
yield { type: "text", text: message.content };
|
|
1475
|
-
}
|
|
1476
|
-
const searchInfo = json.output?.search_info;
|
|
1477
|
-
if (searchInfo?.search_results?.length) {
|
|
1478
|
-
for (const result of searchInfo.search_results) {
|
|
1479
|
-
const exists = searchResults.some((r) => r.url === result.url);
|
|
1480
|
-
if (!exists) {
|
|
1481
|
-
searchResults.push({
|
|
1482
|
-
title: result.title || "",
|
|
1483
|
-
url: result.url || "",
|
|
1484
|
-
snippet: result.snippet || ""
|
|
1485
|
-
});
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
yield { type: "search_result", searchResults: [...searchResults] };
|
|
1489
|
-
}
|
|
1490
|
-
if (message.tool_calls?.length) {
|
|
1491
|
-
for (const tc of message.tool_calls) {
|
|
1492
|
-
const index = toolCallsMap.size;
|
|
1493
|
-
const existing = toolCallsMap.get(index);
|
|
1494
|
-
if (existing) {
|
|
1495
|
-
if (tc.function?.arguments) {
|
|
1496
|
-
existing.arguments += tc.function.arguments;
|
|
1497
|
-
}
|
|
1498
|
-
} else {
|
|
1499
|
-
toolCallsMap.set(index, {
|
|
1500
|
-
id: tc.id || `call_${Date.now()}_${toolCallCounter++}`,
|
|
1501
|
-
name: tc.function.name,
|
|
1502
|
-
arguments: tc.function.arguments
|
|
1503
|
-
});
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
if (finishReason === "stop" || finishReason === "length" || finishReason === "tool_calls") {
|
|
1508
|
-
if (toolCallsMap.size > 0) {
|
|
1509
|
-
for (const tc of toolCallsMap.values()) {
|
|
1510
|
-
yield { type: "tool_call", toolCall: tc };
|
|
1511
|
-
}
|
|
1512
|
-
yield { type: "done", finishReason: "tool_calls" };
|
|
1513
|
-
} else {
|
|
1514
|
-
yield { type: "done", finishReason: "stop" };
|
|
1515
|
-
}
|
|
1516
|
-
return;
|
|
1517
|
-
}
|
|
1518
|
-
} catch {
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
if (toolCallsMap.size > 0) {
|
|
1523
|
-
for (const tc of toolCallsMap.values()) {
|
|
1524
|
-
yield { type: "tool_call", toolCall: tc };
|
|
1525
|
-
}
|
|
1526
|
-
yield { type: "done", finishReason: "tool_calls" };
|
|
1527
|
-
} else {
|
|
1528
|
-
yield { type: "done", finishReason: "stop" };
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
};
|
|
1532
|
-
function createQwenAdapter(config) {
|
|
1533
|
-
return new QwenAdapter(config);
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
// src/providers/adapters/gemini.ts
|
|
1537
|
-
var GEMINI_MODELS = [
|
|
1538
|
-
GEMINI_2_5_FLASH.id,
|
|
1539
|
-
GEMINI_2_5_PRO.id,
|
|
1540
|
-
GEMINI_2_0_FLASH.id,
|
|
1541
|
-
GEMINI_2_0_FLASH_LITE.id,
|
|
1542
|
-
GEMINI_3_PRO.id
|
|
1543
|
-
];
|
|
1544
|
-
var GeminiAdapter = class {
|
|
1545
|
-
name = "gemini";
|
|
1546
|
-
supportedModels = GEMINI_MODELS;
|
|
1547
|
-
client = null;
|
|
1548
|
-
apiKey;
|
|
1549
|
-
constructor(config) {
|
|
1550
|
-
this.apiKey = config.apiKey;
|
|
1551
|
-
}
|
|
1552
|
-
/** 懒加载客户端 */
|
|
1553
|
-
async getClient() {
|
|
1554
|
-
if (!this.client) {
|
|
1555
|
-
const { GoogleGenAI: GoogleGenAI2 } = await import('@google/genai');
|
|
1556
|
-
this.client = new GoogleGenAI2({ apiKey: this.apiKey });
|
|
1557
|
-
}
|
|
1558
|
-
return this.client;
|
|
1559
|
-
}
|
|
1560
|
-
supportsModel(model) {
|
|
1561
|
-
return this.supportedModels.some((m) => model.includes(m) || m.includes(model)) || model.startsWith("gemini-");
|
|
1562
|
-
}
|
|
1563
|
-
/**
|
|
1564
|
-
* 单次流式调用
|
|
1565
|
-
*/
|
|
1566
|
-
async *streamOnce(messages, tools2, options) {
|
|
1567
|
-
const client = await this.getClient();
|
|
1568
|
-
const geminiMessages = this.convertMessages(messages);
|
|
1569
|
-
const generateConfig = {};
|
|
1570
|
-
const toolsConfig = [];
|
|
1571
|
-
if (tools2.length > 0) {
|
|
1572
|
-
toolsConfig.push({
|
|
1573
|
-
functionDeclarations: tools2.map((t) => ({
|
|
1574
|
-
name: t.name,
|
|
1575
|
-
description: t.description,
|
|
1576
|
-
parameters: t.parameters
|
|
1577
|
-
}))
|
|
1578
|
-
});
|
|
1579
|
-
}
|
|
1580
|
-
if (options.enableSearch) {
|
|
1581
|
-
toolsConfig.push({ googleSearch: {} });
|
|
1582
|
-
}
|
|
1583
|
-
if (toolsConfig.length > 0) {
|
|
1584
|
-
generateConfig.tools = toolsConfig;
|
|
1585
|
-
}
|
|
1586
|
-
if (options.enableThinking) {
|
|
1587
|
-
generateConfig.thinkingConfig = {
|
|
1588
|
-
thinkingLevel: "high",
|
|
1589
|
-
includeThoughts: true
|
|
1590
|
-
};
|
|
1591
|
-
}
|
|
1592
|
-
try {
|
|
1593
|
-
const streamResponse = await client.models.generateContentStream({
|
|
1594
|
-
model: options.model,
|
|
1595
|
-
contents: geminiMessages,
|
|
1596
|
-
config: generateConfig
|
|
1597
|
-
});
|
|
1598
|
-
const pendingToolCalls = [];
|
|
1599
|
-
let toolCallCounter = 0;
|
|
1600
|
-
let hasThinking = false;
|
|
1601
|
-
let thinkingDone = false;
|
|
1602
|
-
for await (const chunk of streamResponse) {
|
|
1603
|
-
if (options.signal.aborted) {
|
|
1604
|
-
yield { type: "error", error: "\u8BF7\u6C42\u5DF2\u53D6\u6D88" };
|
|
1605
|
-
return;
|
|
1606
|
-
}
|
|
1607
|
-
const candidate = chunk.candidates?.[0];
|
|
1608
|
-
if (!candidate) continue;
|
|
1609
|
-
const parts = candidate.content?.parts || [];
|
|
1610
|
-
for (const part of parts) {
|
|
1611
|
-
if (part.thought && part.text) {
|
|
1612
|
-
hasThinking = true;
|
|
1613
|
-
yield { type: "thinking", thinking: part.text };
|
|
1614
|
-
continue;
|
|
1615
|
-
}
|
|
1616
|
-
if (part.text && !part.thought) {
|
|
1617
|
-
if (hasThinking && !thinkingDone) {
|
|
1618
|
-
thinkingDone = true;
|
|
1619
|
-
yield { type: "thinking_done" };
|
|
1620
|
-
}
|
|
1621
|
-
yield { type: "text", text: part.text };
|
|
1622
|
-
}
|
|
1623
|
-
if (part.functionCall && part.functionCall.name) {
|
|
1624
|
-
pendingToolCalls.push({
|
|
1625
|
-
id: `call_${Date.now()}_${toolCallCounter++}`,
|
|
1626
|
-
name: part.functionCall.name,
|
|
1627
|
-
arguments: JSON.stringify(part.functionCall.args || {})
|
|
1628
|
-
});
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
if (pendingToolCalls.length > 0) {
|
|
1633
|
-
for (const tc of pendingToolCalls) {
|
|
1634
|
-
yield { type: "tool_call", toolCall: tc };
|
|
1635
|
-
}
|
|
1636
|
-
yield { type: "done", finishReason: "tool_calls" };
|
|
1637
|
-
} else {
|
|
1638
|
-
yield { type: "done", finishReason: "stop" };
|
|
1639
|
-
}
|
|
1640
|
-
} catch (error) {
|
|
1641
|
-
const errorStr = String(error);
|
|
1642
|
-
if (errorStr.includes("User location is not supported") || errorStr.includes("FAILED_PRECONDITION")) {
|
|
1643
|
-
yield {
|
|
1644
|
-
type: "error",
|
|
1645
|
-
error: "Gemini API \u4E0D\u652F\u6301\u5F53\u524D\u5730\u533A\uFF08\u4E2D\u56FD\u5927\u9646\u65E0\u6CD5\u8BBF\u95EE\uFF09\u3002\u8BF7\u4F7F\u7528\u5176\u4ED6\u6A21\u578B\u3002"
|
|
1646
|
-
};
|
|
1647
|
-
} else {
|
|
1648
|
-
yield { type: "error", error: errorStr };
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
/**
|
|
1653
|
-
* 转换标准消息为 Gemini 格式
|
|
1654
|
-
*/
|
|
1655
|
-
convertMessages(messages) {
|
|
1656
|
-
const geminiMessages = [];
|
|
1657
|
-
for (const msg of messages) {
|
|
1658
|
-
switch (msg.role) {
|
|
1659
|
-
case "system":
|
|
1660
|
-
geminiMessages.push(
|
|
1661
|
-
{ role: "user", parts: [{ text: msg.content }] },
|
|
1662
|
-
{ role: "model", parts: [{ text: "OK" }] }
|
|
1663
|
-
);
|
|
1664
|
-
break;
|
|
1665
|
-
case "user": {
|
|
1666
|
-
const parts = [{ text: msg.content }];
|
|
1667
|
-
if (msg.images?.length) {
|
|
1668
|
-
for (const img of msg.images) {
|
|
1669
|
-
const base64 = img.startsWith("data:") ? img.split(",")[1] : img;
|
|
1670
|
-
parts.push({
|
|
1671
|
-
inlineData: {
|
|
1672
|
-
mimeType: "image/jpeg",
|
|
1673
|
-
data: base64
|
|
1674
|
-
}
|
|
1675
|
-
});
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
geminiMessages.push({ role: "user", parts });
|
|
1679
|
-
break;
|
|
1680
|
-
}
|
|
1681
|
-
case "assistant":
|
|
1682
|
-
if (msg.toolCalls?.length) {
|
|
1683
|
-
const parts = [];
|
|
1684
|
-
if (msg.content) {
|
|
1685
|
-
parts.push({ text: msg.content });
|
|
1686
|
-
}
|
|
1687
|
-
for (const tc of msg.toolCalls) {
|
|
1688
|
-
parts.push({
|
|
1689
|
-
functionCall: {
|
|
1690
|
-
name: tc.name,
|
|
1691
|
-
args: JSON.parse(tc.arguments || "{}")
|
|
1692
|
-
}
|
|
1693
|
-
});
|
|
1694
|
-
}
|
|
1695
|
-
geminiMessages.push({ role: "model", parts });
|
|
1696
|
-
} else {
|
|
1697
|
-
geminiMessages.push({
|
|
1698
|
-
role: "model",
|
|
1699
|
-
parts: [{ text: msg.content }]
|
|
1700
|
-
});
|
|
1701
|
-
}
|
|
1702
|
-
break;
|
|
1703
|
-
case "tool":
|
|
1704
|
-
geminiMessages.push({
|
|
1705
|
-
role: "user",
|
|
1706
|
-
parts: [{
|
|
1707
|
-
functionResponse: {
|
|
1708
|
-
name: msg.toolName || "unknown_tool",
|
|
1709
|
-
response: { result: msg.content }
|
|
1710
|
-
}
|
|
1711
|
-
}]
|
|
1712
|
-
});
|
|
1713
|
-
break;
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
return geminiMessages;
|
|
1717
|
-
}
|
|
1718
|
-
};
|
|
1719
|
-
function createGeminiAdapter(config) {
|
|
1720
|
-
return new GeminiAdapter(config);
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
// src/agent.ts
|
|
1724
|
-
var HybridAgent = class {
|
|
1725
|
-
config;
|
|
1726
|
-
adapters = /* @__PURE__ */ new Map();
|
|
1727
|
-
orchestrator;
|
|
1728
|
-
geminiClient;
|
|
1729
|
-
toolExecutor;
|
|
1730
|
-
abortController = null;
|
|
1731
|
-
/** 已注册的工具 */
|
|
1732
|
-
tools = /* @__PURE__ */ new Map();
|
|
1733
|
-
/** 工具配置(用于异步初始化) */
|
|
1734
|
-
toolConfig;
|
|
1735
|
-
constructor(config, toolExecutor) {
|
|
1736
|
-
this.config = {
|
|
1737
|
-
arkApiKey: config.arkApiKey,
|
|
1738
|
-
arkApiUrl: config.arkApiUrl || DEFAULT_ARK_URL,
|
|
1739
|
-
qwenApiKey: config.qwenApiKey || "",
|
|
1740
|
-
qwenApiUrl: config.qwenApiUrl || DEFAULT_QWEN_NATIVE_URL,
|
|
1741
|
-
openrouterApiKey: config.openrouterApiKey || "",
|
|
1742
|
-
openrouterApiUrl: config.openrouterApiUrl || DEFAULT_OPENROUTER_URL,
|
|
1743
|
-
geminiApiKey: config.geminiApiKey,
|
|
1744
|
-
cwd: config.cwd || process.cwd(),
|
|
1745
|
-
planPrompt: config.planPrompt || PLAN_MODE_PROMPT
|
|
1746
|
-
};
|
|
1747
|
-
this.geminiClient = new genai.GoogleGenAI({ apiKey: this.config.geminiApiKey });
|
|
1748
|
-
this.toolExecutor = toolExecutor || createDefaultToolExecutor(this.config.cwd);
|
|
1749
|
-
this.toolConfig = config.tools;
|
|
1750
|
-
this.tools = /* @__PURE__ */ new Map();
|
|
1751
|
-
this.initializeAdapters();
|
|
1752
|
-
this.orchestrator = new ChatOrchestrator({
|
|
1753
|
-
maxIterations: 10,
|
|
1754
|
-
executeTool: this.executeTool.bind(this),
|
|
1755
|
-
tools: this.tools,
|
|
1756
|
-
// 传入工具列表,用于获取 sideEffects
|
|
1757
|
-
// autoRunConfig 在每次 chat 调用时通过 options 传递
|
|
1758
|
-
onToolApprovalRequest: config.onToolApprovalRequest,
|
|
1759
|
-
// 传递工具批准回调
|
|
1760
|
-
getAutoRunConfig: config.getAutoRunConfig
|
|
1761
|
-
// 传递动态获取配置回调
|
|
1762
|
-
});
|
|
1763
|
-
}
|
|
1764
|
-
/** 异步初始化工具(在第一次 chat 前调用) */
|
|
1765
|
-
async asyncInit() {
|
|
1766
|
-
if (this.toolConfig && this.tools.size === 0) {
|
|
1767
|
-
const resolvedTools = await resolveTools(this.toolConfig);
|
|
1768
|
-
for (const tool2 of resolvedTools) {
|
|
1769
|
-
this.tools.set(tool2.name, tool2);
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
/** 初始化所有 Adapter */
|
|
1774
|
-
initializeAdapters() {
|
|
1775
|
-
if (this.config.arkApiKey) {
|
|
1776
|
-
this.adapters.set("ark", new ArkAdapter({
|
|
1777
|
-
apiKey: this.config.arkApiKey,
|
|
1778
|
-
apiUrl: this.config.arkApiUrl
|
|
1779
|
-
}));
|
|
1780
|
-
}
|
|
1781
|
-
if (this.config.qwenApiKey) {
|
|
1782
|
-
this.adapters.set("qwen", new QwenAdapter({
|
|
1783
|
-
apiKey: this.config.qwenApiKey,
|
|
1784
|
-
apiUrl: this.config.qwenApiUrl
|
|
1785
|
-
}));
|
|
1786
|
-
}
|
|
1787
|
-
if (this.config.geminiApiKey) {
|
|
1788
|
-
this.adapters.set("gemini", new GeminiAdapter({
|
|
1789
|
-
apiKey: this.config.geminiApiKey
|
|
1790
|
-
}));
|
|
1791
|
-
}
|
|
1792
|
-
if (this.config.openrouterApiKey) {
|
|
1793
|
-
this.adapters.set("openrouter", new OpenRouterAdapter({
|
|
1794
|
-
apiKey: this.config.openrouterApiKey,
|
|
1795
|
-
apiUrl: this.config.openrouterApiUrl
|
|
1796
|
-
}));
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
/**
|
|
1800
|
-
* 判断模型提供商
|
|
1801
|
-
*/
|
|
1802
|
-
getModelProvider(model) {
|
|
1803
|
-
return routeModelToProvider(model);
|
|
1804
|
-
}
|
|
1805
|
-
/** 获取 Adapter */
|
|
1806
|
-
getAdapter(model) {
|
|
1807
|
-
const providerName = this.getModelProvider(model);
|
|
1808
|
-
return this.adapters.get(providerName);
|
|
1809
|
-
}
|
|
1810
|
-
/**
|
|
1811
|
-
* 调试:获取模型路由信息
|
|
1812
|
-
*/
|
|
1813
|
-
getModelRouteInfo(model) {
|
|
1814
|
-
const result = routeModelWithDetails(model);
|
|
1815
|
-
return {
|
|
1816
|
-
...result,
|
|
1817
|
-
available: this.adapters.has(result.provider)
|
|
1818
|
-
};
|
|
1819
|
-
}
|
|
1820
|
-
/** 构建系统提示词 */
|
|
1821
|
-
buildSystemPrompt(options) {
|
|
1822
|
-
if (options.mode === "plan") {
|
|
1823
|
-
return this.config.planPrompt;
|
|
1824
|
-
}
|
|
1825
|
-
return AGENT_MODE_PROMPT;
|
|
1826
|
-
}
|
|
1827
|
-
/** 获取默认深度思考模式 */
|
|
1828
|
-
getDefaultThinkingMode() {
|
|
1829
|
-
return "disabled";
|
|
1830
|
-
}
|
|
1831
|
-
/** 创建工具执行上下文 */
|
|
1832
|
-
createToolContext(signal) {
|
|
1833
|
-
return {
|
|
1834
|
-
cwd: this.config.cwd,
|
|
1835
|
-
geminiClient: this.geminiClient,
|
|
1836
|
-
executeCommand: (command, cwd) => this.toolExecutor.executeCommand(command, cwd || this.config.cwd, signal),
|
|
1837
|
-
signal
|
|
1838
|
-
};
|
|
1839
|
-
}
|
|
1840
|
-
/** 执行工具 */
|
|
1841
|
-
async executeTool(name, args, signal) {
|
|
1842
|
-
const tool2 = this.tools.get(name);
|
|
1843
|
-
if (!tool2) {
|
|
1844
|
-
return `\u672A\u77E5\u5DE5\u5177: ${name}`;
|
|
1845
|
-
}
|
|
1846
|
-
return await tool2.execute(args, this.createToolContext(signal));
|
|
1847
|
-
}
|
|
1848
|
-
/** 获取工具定义列表 */
|
|
1849
|
-
getToolDefinitions() {
|
|
1850
|
-
return Array.from(this.tools.values()).map((tool2) => ({
|
|
1851
|
-
name: tool2.name,
|
|
1852
|
-
description: tool2.description,
|
|
1853
|
-
parameters: tool2.parameters
|
|
1854
|
-
}));
|
|
1855
|
-
}
|
|
1856
|
-
/**
|
|
1857
|
-
* 聊天入口
|
|
1858
|
-
*
|
|
1859
|
-
* 使用 ChatOrchestrator 统一处理所有 Provider 的工具调用循环
|
|
1860
|
-
*/
|
|
1861
|
-
async *chat(message, options = {}, images) {
|
|
1862
|
-
await this.asyncInit();
|
|
1863
|
-
this.abortController = new AbortController();
|
|
1864
|
-
const signal = this.abortController.signal;
|
|
1865
|
-
const model = options.model || DEFAULT_MODEL;
|
|
1866
|
-
const adapter = this.getAdapter(model);
|
|
1867
|
-
if (!adapter) {
|
|
1868
|
-
const providerName = this.getModelProvider(model);
|
|
1869
|
-
yield createApiError(`\u7F3A\u5C11 ${providerName} Provider \u7684 API Key`, { code: "MISSING_API_KEY" });
|
|
1870
|
-
return;
|
|
1871
|
-
}
|
|
1872
|
-
const thinkingMode = options.thinkingMode ?? this.getDefaultThinkingMode();
|
|
1873
|
-
const systemPrompt = this.buildSystemPrompt(options);
|
|
1874
|
-
const tools2 = options.mode === "ask" ? [] : this.getToolDefinitions();
|
|
1875
|
-
const history = options.history || [];
|
|
1876
|
-
const context = {
|
|
1877
|
-
systemPrompt,
|
|
1878
|
-
history,
|
|
1879
|
-
tools: tools2,
|
|
1880
|
-
signal,
|
|
1881
|
-
images
|
|
1882
|
-
};
|
|
1883
|
-
try {
|
|
1884
|
-
yield* this.orchestrator.chat(adapter, message, context, {
|
|
1885
|
-
model,
|
|
1886
|
-
enableThinking: thinkingMode === "enabled",
|
|
1887
|
-
enableSearch: options.enableWebSearch,
|
|
1888
|
-
autoRunConfig: options.autoRunConfig
|
|
1889
|
-
});
|
|
1890
|
-
} finally {
|
|
1891
|
-
this.abortController = null;
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
/** 中断当前请求 */
|
|
1895
|
-
abort() {
|
|
1896
|
-
if (this.abortController) {
|
|
1897
|
-
this.abortController.abort();
|
|
1898
|
-
}
|
|
1899
|
-
}
|
|
1900
|
-
/** 设置当前工作目录 */
|
|
1901
|
-
setCwd(dir) {
|
|
1902
|
-
this.config.cwd = dir;
|
|
1903
|
-
}
|
|
1904
|
-
/** 获取当前配置 */
|
|
1905
|
-
getConfig() {
|
|
1906
|
-
return { ...this.config };
|
|
1907
|
-
}
|
|
1908
|
-
/** 获取所有支持的模型 */
|
|
1909
|
-
getSupportedModels() {
|
|
1910
|
-
return MODELS;
|
|
1911
|
-
}
|
|
1912
|
-
};
|
|
1913
|
-
|
|
1914
|
-
// src/builtin-tools/get-cwd.ts
|
|
1915
|
-
function getCwdTool() {
|
|
1916
|
-
return tool({
|
|
1917
|
-
name: "get_cwd",
|
|
1918
|
-
description: "\u83B7\u53D6\u7528\u6237\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u7684\u7EDD\u5BF9\u8DEF\u5F84\u3002\u5F53\u4F60\u9700\u8981\u77E5\u9053\u7528\u6237\u5728\u54EA\u4E2A\u76EE\u5F55\u4E0B\u5DE5\u4F5C\u65F6\u4F7F\u7528\u3002",
|
|
1919
|
-
parameters: {
|
|
1920
|
-
type: "object",
|
|
1921
|
-
properties: {},
|
|
1922
|
-
required: []
|
|
1923
|
-
},
|
|
1924
|
-
execute: async (_args, context) => {
|
|
1925
|
-
return JSON.stringify({ cwd: context.cwd });
|
|
1926
|
-
}
|
|
1927
|
-
});
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1930
|
-
// src/builtin-tools/get-platform.ts
|
|
1931
|
-
function getPlatformTool() {
|
|
1932
|
-
return tool({
|
|
1933
|
-
name: "get_platform",
|
|
1934
|
-
description: "\u83B7\u53D6\u64CD\u4F5C\u7CFB\u7EDF\u4FE1\u606F\uFF08macOS/Windows/Linux\uFF09\u3002\u5F53\u4F60\u9700\u8981\u786E\u5B9A\u4F7F\u7528\u54EA\u79CD\u547D\u4EE4\u8BED\u6CD5\u65F6\u8C03\u7528\uFF08\u5982 ls vs dir\uFF09\u3002",
|
|
1935
|
-
parameters: {
|
|
1936
|
-
type: "object",
|
|
1937
|
-
properties: {},
|
|
1938
|
-
required: []
|
|
1939
|
-
},
|
|
1940
|
-
execute: async () => {
|
|
1941
|
-
const os = await import('os');
|
|
1942
|
-
const platform = os.default.platform();
|
|
1943
|
-
const platformName = platform === "darwin" ? "macOS" : platform === "win32" ? "Windows" : "Linux";
|
|
1944
|
-
const shell = platform === "win32" ? "powershell" : "bash/zsh";
|
|
1945
|
-
const pathSeparator = platform === "win32" ? "\\" : "/";
|
|
1946
|
-
return JSON.stringify({
|
|
1947
|
-
platform,
|
|
1948
|
-
platformName,
|
|
1949
|
-
shell,
|
|
1950
|
-
pathSeparator
|
|
1951
|
-
});
|
|
1952
|
-
}
|
|
1953
|
-
});
|
|
1954
|
-
}
|
|
1955
|
-
|
|
1956
|
-
// src/builtin-tools/execute-command.ts
|
|
1957
|
-
function executeCommandTool() {
|
|
1958
|
-
return tool({
|
|
1959
|
-
name: "execute_command",
|
|
1960
|
-
description: "\u6267\u884C shell \u547D\u4EE4\u3002\u6267\u884C\u524D\u5EFA\u8BAE\u5148\u7528 get_cwd \u83B7\u53D6\u5F53\u524D\u76EE\u5F55\u3001get_platform \u83B7\u53D6\u7CFB\u7EDF\u7C7B\u578B\uFF0C\u4EE5\u786E\u4FDD\u4F7F\u7528\u6B63\u786E\u7684\u8DEF\u5F84\u548C\u547D\u4EE4\u8BED\u6CD5\u3002",
|
|
1961
|
-
parameters: {
|
|
1962
|
-
type: "object",
|
|
1963
|
-
properties: {
|
|
1964
|
-
command: { type: "string", description: "\u8981\u6267\u884C\u7684\u547D\u4EE4" },
|
|
1965
|
-
cwd: { type: "string", description: "\u6267\u884C\u547D\u4EE4\u7684\u76EE\u5F55\uFF08\u4E0D\u4F20\u5219\u4F7F\u7528\u7528\u6237\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF09" }
|
|
1966
|
-
},
|
|
1967
|
-
required: ["command"]
|
|
1968
|
-
},
|
|
1969
|
-
execute: async (args, context) => {
|
|
1970
|
-
const cwd = args.cwd || context.cwd;
|
|
1971
|
-
const result = await context.executeCommand(args.command, cwd);
|
|
1972
|
-
if (result.success) {
|
|
1973
|
-
return result.output || "\u6267\u884C\u6210\u529F";
|
|
1974
|
-
}
|
|
1975
|
-
if (result.error === "\u64CD\u4F5C\u5DF2\u53D6\u6D88") {
|
|
1976
|
-
return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88", cancelled: true });
|
|
1977
|
-
}
|
|
1978
|
-
return `\u9519\u8BEF: ${result.error}`;
|
|
1979
|
-
}
|
|
1980
|
-
});
|
|
1981
|
-
}
|
|
1982
|
-
|
|
1983
|
-
// src/gemini.ts
|
|
1984
|
-
function getMimeType(ext) {
|
|
1985
|
-
const types = {
|
|
1986
|
-
".jpg": "image/jpeg",
|
|
1987
|
-
".jpeg": "image/jpeg",
|
|
1988
|
-
".png": "image/png",
|
|
1989
|
-
".gif": "image/gif",
|
|
1990
|
-
".webp": "image/webp"
|
|
1991
|
-
};
|
|
1992
|
-
return types[ext] || "image/jpeg";
|
|
1993
|
-
}
|
|
1994
|
-
function getVideoMimeType(ext) {
|
|
1995
|
-
const types = {
|
|
1996
|
-
".mp4": "video/mp4",
|
|
1997
|
-
".mov": "video/quicktime",
|
|
1998
|
-
".avi": "video/x-msvideo",
|
|
1999
|
-
".webm": "video/webm"
|
|
2000
|
-
};
|
|
2001
|
-
return types[ext] || "video/mp4";
|
|
2002
|
-
}
|
|
2003
|
-
async function analyzeImage(geminiClient, imagePath, question, signal) {
|
|
2004
|
-
try {
|
|
2005
|
-
if (signal?.aborted) {
|
|
2006
|
-
return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88", cancelled: true });
|
|
2007
|
-
}
|
|
2008
|
-
const fs = await import('fs/promises');
|
|
2009
|
-
const path = await import('path');
|
|
2010
|
-
const imageData = await fs.readFile(imagePath);
|
|
2011
|
-
const base64 = imageData.toString("base64");
|
|
2012
|
-
const ext = path.extname(imagePath).toLowerCase();
|
|
2013
|
-
const mimeType = getMimeType(ext);
|
|
2014
|
-
const response = await geminiClient.models.generateContent({
|
|
2015
|
-
model: GEMINI_IMAGE_MODEL,
|
|
2016
|
-
contents: [{
|
|
2017
|
-
role: "user",
|
|
2018
|
-
parts: [
|
|
2019
|
-
{ text: question || "\u8BF7\u8BE6\u7EC6\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9" },
|
|
2020
|
-
{ inlineData: { mimeType, data: base64 } }
|
|
2021
|
-
]
|
|
2022
|
-
}],
|
|
2023
|
-
config: { abortSignal: signal }
|
|
2024
|
-
});
|
|
2025
|
-
return response.text || "\u65E0\u6CD5\u5206\u6790\u56FE\u7247";
|
|
2026
|
-
} catch (error) {
|
|
2027
|
-
if (signal?.aborted) return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88", cancelled: true });
|
|
2028
|
-
return `\u56FE\u7247\u5206\u6790\u5931\u8D25: ${error}`;
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
async function generateImage(geminiClient, cwd, prompt, outputPath, signal) {
|
|
2032
|
-
try {
|
|
2033
|
-
if (signal?.aborted) {
|
|
2034
|
-
return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88" });
|
|
2035
|
-
}
|
|
2036
|
-
const response = await geminiClient.models.generateContent({
|
|
2037
|
-
model: GEMINI_IMAGE_GEN_MODEL,
|
|
2038
|
-
contents: [{ role: "user", parts: [{ text: prompt }] }],
|
|
2039
|
-
config: { abortSignal: signal }
|
|
2040
|
-
});
|
|
2041
|
-
for (const part of response.candidates?.[0]?.content?.parts || []) {
|
|
2042
|
-
if (part.inlineData) {
|
|
2043
|
-
const imageData = Buffer.from(part.inlineData.data, "base64");
|
|
2044
|
-
const mimeType = part.inlineData.mimeType || "image/png";
|
|
2045
|
-
const ext = mimeType === "image/jpeg" ? ".jpg" : mimeType === "image/webp" ? ".webp" : ".png";
|
|
2046
|
-
const fs = await import('fs/promises');
|
|
2047
|
-
const savePath = outputPath || `${cwd}/generated_${Date.now()}${ext}`;
|
|
2048
|
-
await fs.writeFile(savePath, imageData);
|
|
2049
|
-
return JSON.stringify({
|
|
2050
|
-
success: true,
|
|
2051
|
-
path: savePath,
|
|
2052
|
-
format: mimeType
|
|
2053
|
-
});
|
|
2054
|
-
}
|
|
2055
|
-
}
|
|
2056
|
-
return JSON.stringify({ success: false, error: "\u56FE\u7247\u751F\u6210\u5931\u8D25" });
|
|
2057
|
-
} catch (error) {
|
|
2058
|
-
if (signal?.aborted) {
|
|
2059
|
-
return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88", cancelled: true });
|
|
2060
|
-
}
|
|
2061
|
-
return JSON.stringify({ success: false, error: `\u56FE\u7247\u751F\u6210\u5931\u8D25: ${error}` });
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
async function analyzeVideo(geminiClient, videoPath, question, signal) {
|
|
2065
|
-
try {
|
|
2066
|
-
if (signal?.aborted) {
|
|
2067
|
-
return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88", cancelled: true });
|
|
2068
|
-
}
|
|
2069
|
-
const fs = await import('fs/promises');
|
|
2070
|
-
const path = await import('path');
|
|
2071
|
-
const videoData = await fs.readFile(videoPath);
|
|
2072
|
-
const base64 = videoData.toString("base64");
|
|
2073
|
-
const ext = path.extname(videoPath).toLowerCase();
|
|
2074
|
-
const mimeType = getVideoMimeType(ext);
|
|
2075
|
-
const response = await geminiClient.models.generateContent({
|
|
2076
|
-
model: GEMINI_IMAGE_MODEL,
|
|
2077
|
-
contents: [{
|
|
2078
|
-
role: "user",
|
|
2079
|
-
parts: [
|
|
2080
|
-
{ text: question || "\u8BF7\u8BE6\u7EC6\u63CF\u8FF0\u8FD9\u4E2A\u89C6\u9891\u7684\u5185\u5BB9" },
|
|
2081
|
-
{ inlineData: { mimeType, data: base64 } }
|
|
2082
|
-
]
|
|
2083
|
-
}],
|
|
2084
|
-
config: { abortSignal: signal }
|
|
2085
|
-
});
|
|
2086
|
-
return response.text || "\u65E0\u6CD5\u5206\u6790\u89C6\u9891";
|
|
2087
|
-
} catch (error) {
|
|
2088
|
-
if (signal?.aborted) return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88", cancelled: true });
|
|
2089
|
-
return `\u89C6\u9891\u5206\u6790\u5931\u8D25: ${error}`;
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
|
|
2093
|
-
// src/builtin-tools/analyze-image.ts
|
|
2094
|
-
function analyzeImageTool() {
|
|
2095
|
-
return tool({
|
|
2096
|
-
name: "analyze_image",
|
|
2097
|
-
description: "\u5206\u6790\u56FE\u7247\u5185\u5BB9\uFF08\u8BC6\u522B\u7269\u4F53\u3001\u573A\u666F\u3001\u6587\u5B57\u7B49\uFF09",
|
|
2098
|
-
parameters: {
|
|
2099
|
-
type: "object",
|
|
2100
|
-
properties: {
|
|
2101
|
-
imagePath: { type: "string", description: "\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84" },
|
|
2102
|
-
question: { type: "string", description: "\u5173\u4E8E\u56FE\u7247\u7684\u95EE\u9898\uFF08\u53EF\u9009\uFF09" }
|
|
2103
|
-
},
|
|
2104
|
-
required: ["imagePath"]
|
|
2105
|
-
},
|
|
2106
|
-
execute: async (args, context) => {
|
|
2107
|
-
if (!context.geminiClient) {
|
|
2108
|
-
return "\u9519\u8BEF: \u672A\u914D\u7F6E Gemini API Key\uFF0C\u65E0\u6CD5\u4F7F\u7528\u56FE\u7247\u5206\u6790\u529F\u80FD";
|
|
2109
|
-
}
|
|
2110
|
-
return await analyzeImage(
|
|
2111
|
-
context.geminiClient,
|
|
2112
|
-
args.imagePath,
|
|
2113
|
-
args.question,
|
|
2114
|
-
context.signal
|
|
2115
|
-
);
|
|
2116
|
-
}
|
|
2117
|
-
});
|
|
2118
|
-
}
|
|
2119
|
-
|
|
2120
|
-
// src/builtin-tools/generate-image.ts
|
|
2121
|
-
function generateImageTool() {
|
|
2122
|
-
return tool({
|
|
2123
|
-
name: "generate_image",
|
|
2124
|
-
description: "\u6839\u636E\u6587\u5B57\u63CF\u8FF0\u751F\u6210\u56FE\u7247\u5E76\u4FDD\u5B58\u5230\u672C\u5730\u3002\u8FD4\u56DE\u4FDD\u5B58\u8DEF\u5F84\u3002",
|
|
2125
|
-
parameters: {
|
|
2126
|
-
type: "object",
|
|
2127
|
-
properties: {
|
|
2128
|
-
prompt: { type: "string", description: "\u56FE\u7247\u63CF\u8FF0\uFF0C\u4F7F\u7528\u8BE6\u7EC6\u7684\u82F1\u6587\u63CF\u8FF0\u6548\u679C\u66F4\u597D" },
|
|
2129
|
-
outputPath: { type: "string", description: "\u4FDD\u5B58\u8DEF\u5F84\uFF08\u53EF\u9009\uFF09" }
|
|
2130
|
-
},
|
|
2131
|
-
required: ["prompt"]
|
|
2132
|
-
},
|
|
2133
|
-
// 图片生成完成后通知用户
|
|
2134
|
-
sideEffects: [{ type: "notification", success: true, message: "\u{1F3A8} \u56FE\u7247\u751F\u6210\u5B8C\u6210" }],
|
|
2135
|
-
execute: async (args, context) => {
|
|
2136
|
-
if (!context.geminiClient) {
|
|
2137
|
-
return "\u9519\u8BEF: \u672A\u914D\u7F6E Gemini API Key\uFF0C\u65E0\u6CD5\u4F7F\u7528\u56FE\u7247\u751F\u6210\u529F\u80FD";
|
|
2138
|
-
}
|
|
2139
|
-
return await generateImage(
|
|
2140
|
-
context.geminiClient,
|
|
2141
|
-
context.cwd,
|
|
2142
|
-
args.prompt,
|
|
2143
|
-
args.outputPath,
|
|
2144
|
-
context.signal
|
|
2145
|
-
);
|
|
2146
|
-
}
|
|
2147
|
-
});
|
|
2148
|
-
}
|
|
2149
|
-
|
|
2150
|
-
// src/builtin-tools/analyze-video.ts
|
|
2151
|
-
function analyzeVideoTool() {
|
|
2152
|
-
return tool({
|
|
2153
|
-
name: "analyze_video",
|
|
2154
|
-
description: "\u5206\u6790\u89C6\u9891\u5185\u5BB9\uFF08\u8BC6\u522B\u573A\u666F\u3001\u52A8\u4F5C\u3001\u7269\u4F53\u7B49\uFF09",
|
|
2155
|
-
parameters: {
|
|
2156
|
-
type: "object",
|
|
2157
|
-
properties: {
|
|
2158
|
-
videoPath: { type: "string", description: "\u89C6\u9891\u6587\u4EF6\u8DEF\u5F84" },
|
|
2159
|
-
question: { type: "string", description: "\u5173\u4E8E\u89C6\u9891\u7684\u95EE\u9898\uFF08\u53EF\u9009\uFF09" }
|
|
2160
|
-
},
|
|
2161
|
-
required: ["videoPath"]
|
|
2162
|
-
},
|
|
2163
|
-
execute: async (args, context) => {
|
|
2164
|
-
if (!context.geminiClient) {
|
|
2165
|
-
return "\u9519\u8BEF: \u672A\u914D\u7F6E Gemini API Key\uFF0C\u65E0\u6CD5\u4F7F\u7528\u89C6\u9891\u5206\u6790\u529F\u80FD";
|
|
2166
|
-
}
|
|
2167
|
-
return await analyzeVideo(
|
|
2168
|
-
context.geminiClient,
|
|
2169
|
-
args.videoPath,
|
|
2170
|
-
args.question,
|
|
2171
|
-
context.signal
|
|
2172
|
-
);
|
|
2173
|
-
}
|
|
2174
|
-
});
|
|
2175
|
-
}
|
|
2176
|
-
|
|
2177
|
-
// src/builtin-tools/weather/city-adcodes.ts
|
|
2178
|
-
var CITY_ADCODE_MAP = {
|
|
2179
|
-
// 直辖市
|
|
2180
|
-
"\u5317\u4EAC": "110000",
|
|
2181
|
-
"\u5929\u6D25": "120000",
|
|
2182
|
-
"\u4E0A\u6D77": "310000",
|
|
2183
|
-
"\u91CD\u5E86": "500000",
|
|
2184
|
-
// 河北省
|
|
2185
|
-
"\u77F3\u5BB6\u5E84": "130100",
|
|
2186
|
-
"\u5510\u5C71": "130200",
|
|
2187
|
-
"\u79E6\u7687\u5C9B": "130300",
|
|
2188
|
-
"\u90AF\u90F8": "130400",
|
|
2189
|
-
"\u90A2\u53F0": "130500",
|
|
2190
|
-
"\u4FDD\u5B9A": "130600",
|
|
2191
|
-
"\u5F20\u5BB6\u53E3": "130700",
|
|
2192
|
-
"\u627F\u5FB7": "130800",
|
|
2193
|
-
"\u6CA7\u5DDE": "130900",
|
|
2194
|
-
"\u5ECA\u574A": "131000",
|
|
2195
|
-
"\u8861\u6C34": "131100",
|
|
2196
|
-
// 山西省
|
|
2197
|
-
"\u592A\u539F": "140100",
|
|
2198
|
-
"\u5927\u540C": "140200",
|
|
2199
|
-
"\u9633\u6CC9": "140300",
|
|
2200
|
-
"\u957F\u6CBB": "140400",
|
|
2201
|
-
"\u664B\u57CE": "140500",
|
|
2202
|
-
"\u6714\u5DDE": "140600",
|
|
2203
|
-
"\u664B\u4E2D": "140700",
|
|
2204
|
-
"\u8FD0\u57CE": "140800",
|
|
2205
|
-
"\u5FFB\u5DDE": "140900",
|
|
2206
|
-
"\u4E34\u6C7E": "141000",
|
|
2207
|
-
"\u5415\u6881": "141100",
|
|
2208
|
-
// 内蒙古自治区
|
|
2209
|
-
"\u547C\u548C\u6D69\u7279": "150100",
|
|
2210
|
-
"\u5305\u5934": "150200",
|
|
2211
|
-
"\u4E4C\u6D77": "150300",
|
|
2212
|
-
"\u8D64\u5CF0": "150400",
|
|
2213
|
-
"\u901A\u8FBD": "150500",
|
|
2214
|
-
"\u9102\u5C14\u591A\u65AF": "150600",
|
|
2215
|
-
"\u547C\u4F26\u8D1D\u5C14": "150700",
|
|
2216
|
-
"\u5DF4\u5F66\u6DD6\u5C14": "150800",
|
|
2217
|
-
"\u4E4C\u5170\u5BDF\u5E03": "150900",
|
|
2218
|
-
"\u5174\u5B89\u76DF": "152200",
|
|
2219
|
-
"\u9521\u6797\u90ED\u52D2\u76DF": "152500",
|
|
2220
|
-
"\u963F\u62C9\u5584\u76DF": "152900",
|
|
2221
|
-
// 辽宁省
|
|
2222
|
-
"\u6C88\u9633": "210100",
|
|
2223
|
-
"\u5927\u8FDE": "210200",
|
|
2224
|
-
"\u978D\u5C71": "210300",
|
|
2225
|
-
"\u629A\u987A": "210400",
|
|
2226
|
-
"\u672C\u6EAA": "210500",
|
|
2227
|
-
"\u4E39\u4E1C": "210600",
|
|
2228
|
-
"\u9526\u5DDE": "210700",
|
|
2229
|
-
"\u8425\u53E3": "210800",
|
|
2230
|
-
"\u961C\u65B0": "210900",
|
|
2231
|
-
"\u8FBD\u9633": "211000",
|
|
2232
|
-
"\u76D8\u9526": "211100",
|
|
2233
|
-
"\u94C1\u5CAD": "211200",
|
|
2234
|
-
"\u671D\u9633": "211300",
|
|
2235
|
-
"\u846B\u82A6\u5C9B": "211400",
|
|
2236
|
-
// 吉林省
|
|
2237
|
-
"\u957F\u6625": "220100",
|
|
2238
|
-
"\u5409\u6797": "220200",
|
|
2239
|
-
"\u56DB\u5E73": "220300",
|
|
2240
|
-
"\u8FBD\u6E90": "220400",
|
|
2241
|
-
"\u901A\u5316": "220500",
|
|
2242
|
-
"\u767D\u5C71": "220600",
|
|
2243
|
-
"\u677E\u539F": "220700",
|
|
2244
|
-
"\u767D\u57CE": "220800",
|
|
2245
|
-
"\u5EF6\u8FB9\u671D\u9C9C\u65CF\u81EA\u6CBB\u5DDE": "222400",
|
|
2246
|
-
// 黑龙江省
|
|
2247
|
-
"\u54C8\u5C14\u6EE8": "230100",
|
|
2248
|
-
"\u9F50\u9F50\u54C8\u5C14": "230200",
|
|
2249
|
-
"\u9E21\u897F": "230300",
|
|
2250
|
-
"\u9E64\u5C97": "230400",
|
|
2251
|
-
"\u53CC\u9E2D\u5C71": "230500",
|
|
2252
|
-
"\u5927\u5E86": "230600",
|
|
2253
|
-
"\u4F0A\u6625": "230700",
|
|
2254
|
-
"\u4F73\u6728\u65AF": "230800",
|
|
2255
|
-
"\u4E03\u53F0\u6CB3": "230900",
|
|
2256
|
-
"\u7261\u4E39\u6C5F": "231000",
|
|
2257
|
-
"\u9ED1\u6CB3": "231100",
|
|
2258
|
-
"\u7EE5\u5316": "231200",
|
|
2259
|
-
"\u5927\u5174\u5B89\u5CAD\u5730\u533A": "232700",
|
|
2260
|
-
// 江苏省
|
|
2261
|
-
"\u5357\u4EAC": "320100",
|
|
2262
|
-
"\u65E0\u9521": "320200",
|
|
2263
|
-
"\u5F90\u5DDE": "320300",
|
|
2264
|
-
"\u5E38\u5DDE": "320400",
|
|
2265
|
-
"\u82CF\u5DDE": "320500",
|
|
2266
|
-
"\u5357\u901A": "320600",
|
|
2267
|
-
"\u8FDE\u4E91\u6E2F": "320700",
|
|
2268
|
-
"\u6DEE\u5B89": "320800",
|
|
2269
|
-
"\u76D0\u57CE": "320900",
|
|
2270
|
-
"\u626C\u5DDE": "321000",
|
|
2271
|
-
"\u9547\u6C5F": "321100",
|
|
2272
|
-
"\u6CF0\u5DDE": "321200",
|
|
2273
|
-
"\u5BBF\u8FC1": "321300",
|
|
2274
|
-
// 浙江省
|
|
2275
|
-
"\u676D\u5DDE": "330100",
|
|
2276
|
-
"\u5B81\u6CE2": "330200",
|
|
2277
|
-
"\u6E29\u5DDE": "330300",
|
|
2278
|
-
"\u5609\u5174": "330400",
|
|
2279
|
-
"\u6E56\u5DDE": "330500",
|
|
2280
|
-
"\u7ECD\u5174": "330600",
|
|
2281
|
-
"\u91D1\u534E": "330700",
|
|
2282
|
-
"\u8862\u5DDE": "330800",
|
|
2283
|
-
"\u821F\u5C71": "330900",
|
|
2284
|
-
"\u53F0\u5DDE": "331000",
|
|
2285
|
-
"\u4E3D\u6C34": "331100",
|
|
2286
|
-
// 安徽省
|
|
2287
|
-
"\u5408\u80A5": "340100",
|
|
2288
|
-
"\u829C\u6E56": "340200",
|
|
2289
|
-
"\u868C\u57E0": "340300",
|
|
2290
|
-
"\u6DEE\u5357": "340400",
|
|
2291
|
-
"\u9A6C\u978D\u5C71": "340500",
|
|
2292
|
-
"\u6DEE\u5317": "340600",
|
|
2293
|
-
"\u94DC\u9675": "340700",
|
|
2294
|
-
"\u5B89\u5E86": "340800",
|
|
2295
|
-
"\u9EC4\u5C71": "341000",
|
|
2296
|
-
"\u6EC1\u5DDE": "341100",
|
|
2297
|
-
"\u961C\u9633": "341200",
|
|
2298
|
-
"\u5BBF\u5DDE": "341300",
|
|
2299
|
-
"\u516D\u5B89": "341500",
|
|
2300
|
-
"\u4EB3\u5DDE": "341600",
|
|
2301
|
-
"\u6C60\u5DDE": "341700",
|
|
2302
|
-
"\u5BA3\u57CE": "341800",
|
|
2303
|
-
// 福建省
|
|
2304
|
-
"\u798F\u5DDE": "350100",
|
|
2305
|
-
"\u53A6\u95E8": "350200",
|
|
2306
|
-
"\u8386\u7530": "350300",
|
|
2307
|
-
"\u4E09\u660E": "350400",
|
|
2308
|
-
"\u6CC9\u5DDE": "350500",
|
|
2309
|
-
"\u6F33\u5DDE": "350600",
|
|
2310
|
-
"\u5357\u5E73": "350700",
|
|
2311
|
-
"\u9F99\u5CA9": "350800",
|
|
2312
|
-
"\u5B81\u5FB7": "350900",
|
|
2313
|
-
// 江西省
|
|
2314
|
-
"\u5357\u660C": "360100",
|
|
2315
|
-
"\u666F\u5FB7\u9547": "360200",
|
|
2316
|
-
"\u840D\u4E61": "360300",
|
|
2317
|
-
"\u4E5D\u6C5F": "360400",
|
|
2318
|
-
"\u65B0\u4F59": "360500",
|
|
2319
|
-
"\u9E70\u6F6D": "360600",
|
|
2320
|
-
"\u8D63\u5DDE": "360700",
|
|
2321
|
-
"\u5409\u5B89": "360800",
|
|
2322
|
-
"\u5B9C\u6625": "360900",
|
|
2323
|
-
"\u629A\u5DDE": "361000",
|
|
2324
|
-
"\u4E0A\u9976": "361100",
|
|
2325
|
-
// 山东省
|
|
2326
|
-
"\u6D4E\u5357": "370100",
|
|
2327
|
-
"\u9752\u5C9B": "370200",
|
|
2328
|
-
"\u6DC4\u535A": "370300",
|
|
2329
|
-
"\u67A3\u5E84": "370400",
|
|
2330
|
-
"\u4E1C\u8425": "370500",
|
|
2331
|
-
"\u70DF\u53F0": "370600",
|
|
2332
|
-
"\u6F4D\u574A": "370700",
|
|
2333
|
-
"\u6D4E\u5B81": "370800",
|
|
2334
|
-
"\u6CF0\u5B89": "370900",
|
|
2335
|
-
"\u5A01\u6D77": "371000",
|
|
2336
|
-
"\u65E5\u7167": "371100",
|
|
2337
|
-
"\u4E34\u6C82": "371300",
|
|
2338
|
-
"\u5FB7\u5DDE": "371400",
|
|
2339
|
-
"\u804A\u57CE": "371500",
|
|
2340
|
-
"\u6EE8\u5DDE": "371600",
|
|
2341
|
-
"\u83CF\u6CFD": "371700",
|
|
2342
|
-
// 河南省
|
|
2343
|
-
"\u90D1\u5DDE": "410100",
|
|
2344
|
-
"\u5F00\u5C01": "410200",
|
|
2345
|
-
"\u6D1B\u9633": "410300",
|
|
2346
|
-
"\u5E73\u9876\u5C71": "410400",
|
|
2347
|
-
"\u5B89\u9633": "410500",
|
|
2348
|
-
"\u9E64\u58C1": "410600",
|
|
2349
|
-
"\u65B0\u4E61": "410700",
|
|
2350
|
-
"\u7126\u4F5C": "410800",
|
|
2351
|
-
"\u6FEE\u9633": "410900",
|
|
2352
|
-
"\u8BB8\u660C": "411000",
|
|
2353
|
-
"\u6F2F\u6CB3": "411100",
|
|
2354
|
-
"\u4E09\u95E8\u5CE1": "411200",
|
|
2355
|
-
"\u5357\u9633": "411300",
|
|
2356
|
-
"\u5546\u4E18": "411400",
|
|
2357
|
-
"\u4FE1\u9633": "411500",
|
|
2358
|
-
"\u5468\u53E3": "411600",
|
|
2359
|
-
"\u9A7B\u9A6C\u5E97": "411700",
|
|
2360
|
-
// 湖北省
|
|
2361
|
-
"\u6B66\u6C49": "420100",
|
|
2362
|
-
"\u9EC4\u77F3": "420200",
|
|
2363
|
-
"\u5341\u5830": "420300",
|
|
2364
|
-
"\u5B9C\u660C": "420500",
|
|
2365
|
-
"\u8944\u9633": "420600",
|
|
2366
|
-
"\u9102\u5DDE": "420700",
|
|
2367
|
-
"\u8346\u95E8": "420800",
|
|
2368
|
-
"\u5B5D\u611F": "420900",
|
|
2369
|
-
"\u8346\u5DDE": "421000",
|
|
2370
|
-
"\u9EC4\u5188": "421100",
|
|
2371
|
-
"\u54B8\u5B81": "421200",
|
|
2372
|
-
"\u968F\u5DDE": "421300",
|
|
2373
|
-
"\u6069\u65BD\u571F\u5BB6\u65CF\u82D7\u65CF\u81EA\u6CBB\u5DDE": "422800",
|
|
2374
|
-
// 湖南省
|
|
2375
|
-
"\u957F\u6C99": "430100",
|
|
2376
|
-
"\u682A\u6D32": "430200",
|
|
2377
|
-
"\u6E58\u6F6D": "430300",
|
|
2378
|
-
"\u8861\u9633": "430400",
|
|
2379
|
-
"\u90B5\u9633": "430500",
|
|
2380
|
-
"\u5CB3\u9633": "430600",
|
|
2381
|
-
"\u5E38\u5FB7": "430700",
|
|
2382
|
-
"\u5F20\u5BB6\u754C": "430800",
|
|
2383
|
-
"\u76CA\u9633": "430900",
|
|
2384
|
-
"\u90F4\u5DDE": "431000",
|
|
2385
|
-
"\u6C38\u5DDE": "431100",
|
|
2386
|
-
"\u6000\u5316": "431200",
|
|
2387
|
-
"\u5A04\u5E95": "431300",
|
|
2388
|
-
"\u6E58\u897F\u571F\u5BB6\u65CF\u82D7\u65CF\u81EA\u6CBB\u5DDE": "433100",
|
|
2389
|
-
// 广东省
|
|
2390
|
-
"\u5E7F\u5DDE": "440100",
|
|
2391
|
-
"\u97F6\u5173": "440200",
|
|
2392
|
-
"\u6DF1\u5733": "440300",
|
|
2393
|
-
"\u73E0\u6D77": "440400",
|
|
2394
|
-
"\u6C55\u5934": "440500",
|
|
2395
|
-
"\u4F5B\u5C71": "440600",
|
|
2396
|
-
"\u6C5F\u95E8": "440700",
|
|
2397
|
-
"\u6E5B\u6C5F": "440800",
|
|
2398
|
-
"\u8302\u540D": "440900",
|
|
2399
|
-
"\u8087\u5E86": "441200",
|
|
2400
|
-
"\u60E0\u5DDE": "441300",
|
|
2401
|
-
"\u6885\u5DDE": "441400",
|
|
2402
|
-
"\u6C55\u5C3E": "441500",
|
|
2403
|
-
"\u6CB3\u6E90": "441600",
|
|
2404
|
-
"\u9633\u6C5F": "441700",
|
|
2405
|
-
"\u6E05\u8FDC": "441800",
|
|
2406
|
-
"\u4E1C\u839E": "441900",
|
|
2407
|
-
"\u4E2D\u5C71": "442000",
|
|
2408
|
-
"\u6F6E\u5DDE": "445100",
|
|
2409
|
-
"\u63ED\u9633": "445200",
|
|
2410
|
-
"\u4E91\u6D6E": "445300",
|
|
2411
|
-
// 广西壮族自治区
|
|
2412
|
-
"\u5357\u5B81": "450100",
|
|
2413
|
-
"\u67F3\u5DDE": "450200",
|
|
2414
|
-
"\u6842\u6797": "450300",
|
|
2415
|
-
"\u68A7\u5DDE": "450400",
|
|
2416
|
-
"\u5317\u6D77": "450500",
|
|
2417
|
-
"\u9632\u57CE\u6E2F": "450600",
|
|
2418
|
-
"\u94A6\u5DDE": "450700",
|
|
2419
|
-
"\u8D35\u6E2F": "450800",
|
|
2420
|
-
"\u7389\u6797": "450900",
|
|
2421
|
-
"\u767E\u8272": "451000",
|
|
2422
|
-
"\u8D3A\u5DDE": "451100",
|
|
2423
|
-
"\u6CB3\u6C60": "451200",
|
|
2424
|
-
"\u6765\u5BBE": "451300",
|
|
2425
|
-
"\u5D07\u5DE6": "451400",
|
|
2426
|
-
// 海南省
|
|
2427
|
-
"\u6D77\u53E3": "460100",
|
|
2428
|
-
"\u4E09\u4E9A": "460200",
|
|
2429
|
-
"\u4E09\u6C99": "460300",
|
|
2430
|
-
"\u510B\u5DDE": "460400",
|
|
2431
|
-
// 四川省
|
|
2432
|
-
"\u6210\u90FD": "510100",
|
|
2433
|
-
"\u81EA\u8D21": "510300",
|
|
2434
|
-
"\u6500\u679D\u82B1": "510400",
|
|
2435
|
-
"\u6CF8\u5DDE": "510500",
|
|
2436
|
-
"\u5FB7\u9633": "510600",
|
|
2437
|
-
"\u7EF5\u9633": "510700",
|
|
2438
|
-
"\u5E7F\u5143": "510800",
|
|
2439
|
-
"\u9042\u5B81": "510900",
|
|
2440
|
-
"\u5185\u6C5F": "511000",
|
|
2441
|
-
"\u4E50\u5C71": "511100",
|
|
2442
|
-
"\u5357\u5145": "511300",
|
|
2443
|
-
"\u7709\u5C71": "511400",
|
|
2444
|
-
"\u5B9C\u5BBE": "511500",
|
|
2445
|
-
"\u5E7F\u5B89": "511600",
|
|
2446
|
-
"\u8FBE\u5DDE": "511700",
|
|
2447
|
-
"\u96C5\u5B89": "511800",
|
|
2448
|
-
"\u5DF4\u4E2D": "511900",
|
|
2449
|
-
"\u8D44\u9633": "512000",
|
|
2450
|
-
"\u963F\u575D\u85CF\u65CF\u7F8C\u65CF\u81EA\u6CBB\u5DDE": "513200",
|
|
2451
|
-
"\u7518\u5B5C\u85CF\u65CF\u81EA\u6CBB\u5DDE": "513300",
|
|
2452
|
-
"\u51C9\u5C71\u5F5D\u65CF\u81EA\u6CBB\u5DDE": "513400",
|
|
2453
|
-
// 贵州省
|
|
2454
|
-
"\u8D35\u9633": "520100",
|
|
2455
|
-
"\u516D\u76D8\u6C34": "520200",
|
|
2456
|
-
"\u9075\u4E49": "520300",
|
|
2457
|
-
"\u5B89\u987A": "520400",
|
|
2458
|
-
"\u6BD5\u8282": "520500",
|
|
2459
|
-
"\u94DC\u4EC1": "520600",
|
|
2460
|
-
"\u9ED4\u897F\u5357\u5E03\u4F9D\u65CF\u82D7\u65CF\u81EA\u6CBB\u5DDE": "522300",
|
|
2461
|
-
"\u9ED4\u4E1C\u5357\u82D7\u65CF\u4F97\u65CF\u81EA\u6CBB\u5DDE": "522600",
|
|
2462
|
-
"\u9ED4\u5357\u5E03\u4F9D\u65CF\u82D7\u65CF\u81EA\u6CBB\u5DDE": "522700",
|
|
2463
|
-
// 云南省
|
|
2464
|
-
"\u6606\u660E": "530100",
|
|
2465
|
-
"\u66F2\u9756": "530300",
|
|
2466
|
-
"\u7389\u6EAA": "530400",
|
|
2467
|
-
"\u4FDD\u5C71": "530500",
|
|
2468
|
-
"\u662D\u901A": "530600",
|
|
2469
|
-
"\u4E3D\u6C5F": "530700",
|
|
2470
|
-
"\u666E\u6D31": "530800",
|
|
2471
|
-
"\u4E34\u6CA7": "530900",
|
|
2472
|
-
"\u695A\u96C4\u5F5D\u65CF\u81EA\u6CBB\u5DDE": "532300",
|
|
2473
|
-
"\u7EA2\u6CB3\u54C8\u5C3C\u65CF\u5F5D\u65CF\u81EA\u6CBB\u5DDE": "532500",
|
|
2474
|
-
"\u6587\u5C71\u58EE\u65CF\u82D7\u65CF\u81EA\u6CBB\u5DDE": "532600",
|
|
2475
|
-
"\u897F\u53CC\u7248\u7EB3\u50A3\u65CF\u81EA\u6CBB\u5DDE": "532800",
|
|
2476
|
-
"\u5927\u7406\u767D\u65CF\u81EA\u6CBB\u5DDE": "532900",
|
|
2477
|
-
"\u5FB7\u5B8F\u50A3\u65CF\u666F\u9887\u65CF\u81EA\u6CBB\u5DDE": "533100",
|
|
2478
|
-
"\u6012\u6C5F\u5088\u50F3\u65CF\u81EA\u6CBB\u5DDE": "533300",
|
|
2479
|
-
"\u8FEA\u5E86\u85CF\u65CF\u81EA\u6CBB\u5DDE": "533400",
|
|
2480
|
-
// 西藏自治区
|
|
2481
|
-
"\u62C9\u8428": "540100",
|
|
2482
|
-
"\u65E5\u5580\u5219": "540200",
|
|
2483
|
-
"\u660C\u90FD": "540300",
|
|
2484
|
-
"\u6797\u829D": "540400",
|
|
2485
|
-
"\u5C71\u5357": "540500",
|
|
2486
|
-
"\u90A3\u66F2": "540600",
|
|
2487
|
-
"\u963F\u91CC\u5730\u533A": "542500",
|
|
2488
|
-
// 陕西省
|
|
2489
|
-
"\u897F\u5B89": "610100",
|
|
2490
|
-
"\u94DC\u5DDD": "610200",
|
|
2491
|
-
"\u5B9D\u9E21": "610300",
|
|
2492
|
-
"\u54B8\u9633": "610400",
|
|
2493
|
-
"\u6E2D\u5357": "610500",
|
|
2494
|
-
"\u5EF6\u5B89": "610600",
|
|
2495
|
-
"\u6C49\u4E2D": "610700",
|
|
2496
|
-
"\u6986\u6797": "610800",
|
|
2497
|
-
"\u5B89\u5EB7": "610900",
|
|
2498
|
-
"\u5546\u6D1B": "611000",
|
|
2499
|
-
// 甘肃省
|
|
2500
|
-
"\u5170\u5DDE": "620100",
|
|
2501
|
-
"\u5609\u5CEA\u5173": "620200",
|
|
2502
|
-
"\u91D1\u660C": "620300",
|
|
2503
|
-
"\u767D\u94F6": "620400",
|
|
2504
|
-
"\u5929\u6C34": "620500",
|
|
2505
|
-
"\u6B66\u5A01": "620600",
|
|
2506
|
-
"\u5F20\u6396": "620700",
|
|
2507
|
-
"\u5E73\u51C9": "620800",
|
|
2508
|
-
"\u9152\u6CC9": "620900",
|
|
2509
|
-
"\u5E86\u9633": "621000",
|
|
2510
|
-
"\u5B9A\u897F": "621100",
|
|
2511
|
-
"\u9647\u5357": "621200",
|
|
2512
|
-
"\u4E34\u590F\u56DE\u65CF\u81EA\u6CBB\u5DDE": "622900",
|
|
2513
|
-
"\u7518\u5357\u85CF\u65CF\u81EA\u6CBB\u5DDE": "623000",
|
|
2514
|
-
// 青海省
|
|
2515
|
-
"\u897F\u5B81": "630100",
|
|
2516
|
-
"\u6D77\u4E1C": "630200",
|
|
2517
|
-
"\u6D77\u5317\u85CF\u65CF\u81EA\u6CBB\u5DDE": "632200",
|
|
2518
|
-
"\u9EC4\u5357\u85CF\u65CF\u81EA\u6CBB\u5DDE": "632300",
|
|
2519
|
-
"\u6D77\u5357\u85CF\u65CF\u81EA\u6CBB\u5DDE": "632500",
|
|
2520
|
-
"\u679C\u6D1B\u85CF\u65CF\u81EA\u6CBB\u5DDE": "632600",
|
|
2521
|
-
"\u7389\u6811\u85CF\u65CF\u81EA\u6CBB\u5DDE": "632700",
|
|
2522
|
-
"\u6D77\u897F\u8499\u53E4\u65CF\u85CF\u65CF\u81EA\u6CBB\u5DDE": "632800",
|
|
2523
|
-
// 宁夏回族自治区
|
|
2524
|
-
"\u94F6\u5DDD": "640100",
|
|
2525
|
-
"\u77F3\u5634\u5C71": "640200",
|
|
2526
|
-
"\u5434\u5FE0": "640300",
|
|
2527
|
-
"\u56FA\u539F": "640400",
|
|
2528
|
-
"\u4E2D\u536B": "640500",
|
|
2529
|
-
// 新疆维吾尔自治区
|
|
2530
|
-
"\u4E4C\u9C81\u6728\u9F50": "650100",
|
|
2531
|
-
"\u514B\u62C9\u739B\u4F9D": "650200",
|
|
2532
|
-
"\u5410\u9C81\u756A": "650400",
|
|
2533
|
-
"\u54C8\u5BC6": "650500",
|
|
2534
|
-
"\u660C\u5409\u56DE\u65CF\u81EA\u6CBB\u5DDE": "652300",
|
|
2535
|
-
"\u535A\u5C14\u5854\u62C9\u8499\u53E4\u81EA\u6CBB\u5DDE": "652700",
|
|
2536
|
-
"\u5DF4\u97F3\u90ED\u695E\u8499\u53E4\u81EA\u6CBB\u5DDE": "652800",
|
|
2537
|
-
"\u963F\u514B\u82CF\u5730\u533A": "652900",
|
|
2538
|
-
"\u514B\u5B5C\u52D2\u82CF\u67EF\u5C14\u514B\u5B5C\u81EA\u6CBB\u5DDE": "653000",
|
|
2539
|
-
"\u5580\u4EC0\u5730\u533A": "653100",
|
|
2540
|
-
"\u548C\u7530\u5730\u533A": "653200",
|
|
2541
|
-
"\u4F0A\u7281\u54C8\u8428\u514B\u81EA\u6CBB\u5DDE": "654000",
|
|
2542
|
-
"\u5854\u57CE\u5730\u533A": "654200",
|
|
2543
|
-
"\u963F\u52D2\u6CF0\u5730\u533A": "654300"
|
|
2544
|
-
};
|
|
2545
|
-
function getCityAdcode(cityName) {
|
|
2546
|
-
if (CITY_ADCODE_MAP[cityName]) {
|
|
2547
|
-
return CITY_ADCODE_MAP[cityName];
|
|
2548
|
-
}
|
|
2549
|
-
const normalized = cityName.replace(/[市省区]$/, "");
|
|
2550
|
-
if (CITY_ADCODE_MAP[normalized]) {
|
|
2551
|
-
return CITY_ADCODE_MAP[normalized];
|
|
2552
|
-
}
|
|
2553
|
-
for (const [name, code] of Object.entries(CITY_ADCODE_MAP)) {
|
|
2554
|
-
if (name.startsWith(cityName) || cityName.startsWith(name.slice(0, 2))) {
|
|
2555
|
-
return code;
|
|
2556
|
-
}
|
|
2557
|
-
}
|
|
2558
|
-
return null;
|
|
2559
|
-
}
|
|
2560
|
-
|
|
2561
|
-
// src/builtin-tools/weather/get-weather.ts
|
|
2562
|
-
var AMAP_KEY = "16924e39cfd78c645f0035c1bc290961";
|
|
2563
|
-
function getWeatherTool() {
|
|
2564
|
-
return tool({
|
|
2565
|
-
name: "get_weather",
|
|
2566
|
-
description: "\u83B7\u53D6\u6307\u5B9A\u57CE\u5E02\u7684\u5B9E\u65F6\u5929\u6C14\u4FE1\u606F\u3002\u652F\u6301\u5168\u56FD 337 \u4E2A\u5730\u7EA7\u5E02\uFF0C\u5305\u62EC\uFF1A\u5317\u4EAC\u3001\u4E0A\u6D77\u3001\u5E7F\u5DDE\u3001\u6DF1\u5733\u3001\u676D\u5DDE\u3001\u6210\u90FD\u3001\u6B66\u6C49\u3001\u897F\u5B89\u3001\u5357\u4EAC\u3001\u82CF\u5DDE\u3001\u91CD\u5E86\u3001\u5929\u6D25\u7B49\u3002\u8FD4\u56DE\u6E29\u5EA6\u3001\u5929\u6C14\u72B6\u51B5\u3001\u6E7F\u5EA6\u3001\u98CE\u5411\u98CE\u529B\u7B49\u4FE1\u606F\u3002",
|
|
2567
|
-
parameters: {
|
|
2568
|
-
type: "object",
|
|
2569
|
-
properties: {
|
|
2570
|
-
city: {
|
|
2571
|
-
type: "string",
|
|
2572
|
-
description: '\u57CE\u5E02\u540D\u79F0\uFF0C\u5982 "\u5317\u4EAC"\u3001"\u4E0A\u6D77"\u3001"\u6DF1\u5733"\u3001"\u676D\u5DDE"'
|
|
2573
|
-
}
|
|
2574
|
-
},
|
|
2575
|
-
required: ["city"]
|
|
2576
|
-
},
|
|
2577
|
-
execute: async (args, context) => {
|
|
2578
|
-
const city = args.city;
|
|
2579
|
-
if (context.signal?.aborted) {
|
|
2580
|
-
return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88", cancelled: true });
|
|
2581
|
-
}
|
|
2582
|
-
const adcode = getCityAdcode(city);
|
|
2583
|
-
if (!adcode) {
|
|
2584
|
-
return JSON.stringify({
|
|
2585
|
-
error: `\u4E0D\u652F\u6301\u7684\u57CE\u5E02: ${city}`,
|
|
2586
|
-
tip: "\u8BF7\u8F93\u5165\u5730\u7EA7\u5E02\u540D\u79F0\uFF0C\u5982\uFF1A\u5317\u4EAC\u3001\u4E0A\u6D77\u3001\u5E7F\u5DDE\u3001\u6DF1\u5733"
|
|
2587
|
-
});
|
|
2588
|
-
}
|
|
2589
|
-
try {
|
|
2590
|
-
const url = `https://restapi.amap.com/v3/weather/weatherInfo?key=${AMAP_KEY}&city=${adcode}&extensions=base&output=JSON`;
|
|
2591
|
-
const response = await fetch(url, { signal: context.signal });
|
|
2592
|
-
if (!response.ok) {
|
|
2593
|
-
return JSON.stringify({ error: `\u5929\u6C14\u670D\u52A1\u8BF7\u6C42\u5931\u8D25: ${response.status}` });
|
|
2594
|
-
}
|
|
2595
|
-
const data = await response.json();
|
|
2596
|
-
if (data.status !== "1" || data.infocode !== "10000") {
|
|
2597
|
-
return JSON.stringify({ error: `\u5929\u6C14\u670D\u52A1\u8FD4\u56DE\u9519\u8BEF: ${data.info}` });
|
|
2598
|
-
}
|
|
2599
|
-
if (!data.lives?.length) {
|
|
2600
|
-
return JSON.stringify({ error: "\u672A\u83B7\u53D6\u5230\u5929\u6C14\u6570\u636E" });
|
|
2601
|
-
}
|
|
2602
|
-
const live = data.lives[0];
|
|
2603
|
-
return JSON.stringify({
|
|
2604
|
-
city: live.city,
|
|
2605
|
-
temperature: parseInt(live.temperature, 10),
|
|
2606
|
-
condition: live.weather,
|
|
2607
|
-
humidity: parseInt(live.humidity, 10),
|
|
2608
|
-
wind: `${live.winddirection}\u98CE ${live.windpower}\u7EA7`,
|
|
2609
|
-
reportTime: live.reporttime,
|
|
2610
|
-
province: live.province
|
|
2611
|
-
});
|
|
2612
|
-
} catch (error) {
|
|
2613
|
-
if (context.signal?.aborted) {
|
|
2614
|
-
return JSON.stringify({ success: false, error: "\u64CD\u4F5C\u5DF2\u53D6\u6D88", cancelled: true });
|
|
2615
|
-
}
|
|
2616
|
-
return JSON.stringify({
|
|
2617
|
-
success: false,
|
|
2618
|
-
error: `\u83B7\u53D6\u5929\u6C14\u5931\u8D25: ${error instanceof Error ? error.message : "\u7F51\u7EDC\u9519\u8BEF"}`
|
|
2619
|
-
});
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
});
|
|
2623
|
-
}
|
|
2624
|
-
|
|
2625
|
-
// src/builtin-tools/ui-actions.ts
|
|
2626
|
-
function showToastTool() {
|
|
2627
|
-
return tool({
|
|
2628
|
-
name: "show_toast",
|
|
2629
|
-
description: "\u5728\u7528\u6237\u754C\u9762\u4E0A\u663E\u793A\u4E00\u6761Toast \u901A\u77E5\u6D88\u606F\uFF0C\u7528\u4E8E\u544A\u77E5\u7528\u6237\u64CD\u4F5C\u7ED3\u679C\u6216\u91CD\u8981\u63D0\u793A\u4FE1\u606F\uFF0C\u6D88\u606F\u4F1A\u5728\u51E0\u79D2\u540E\u81EA\u52A8\u6D88\u5931",
|
|
2630
|
-
parameters: {
|
|
2631
|
-
type: "object",
|
|
2632
|
-
properties: {
|
|
2633
|
-
message: { type: "string", description: "\u8981\u663E\u793A\u7ED9\u7528\u6237\u7684\u901A\u77E5\u5185\u5BB9" }
|
|
2634
|
-
},
|
|
2635
|
-
required: ["message"]
|
|
2636
|
-
},
|
|
2637
|
-
execute: async (args) => {
|
|
2638
|
-
const message = args.message;
|
|
2639
|
-
return {
|
|
2640
|
-
result: JSON.stringify({ success: true }),
|
|
2641
|
-
sideEffects: [{ type: "notification", success: true, message }]
|
|
2642
|
-
};
|
|
2643
|
-
}
|
|
2644
|
-
});
|
|
2645
|
-
}
|
|
2646
|
-
function openConfirmDialogTool() {
|
|
2647
|
-
return tool({
|
|
2648
|
-
name: "open_confirm_dialog",
|
|
2649
|
-
description: "\u5728\u7528\u6237\u754C\u9762\u4E0A\u5F39\u51FA\u4E00\u4E2A\u6A21\u6001\u786E\u8BA4\u5BF9\u8BDD\u6846\u3002",
|
|
2650
|
-
parameters: {
|
|
2651
|
-
type: "object",
|
|
2652
|
-
properties: {
|
|
2653
|
-
title: { type: "string", description: "\u5BF9\u8BDD\u6846\u6807\u9898\uFF0C\u7B80\u8981\u8BF4\u660E\u786E\u8BA4\u7684\u64CD\u4F5C" },
|
|
2654
|
-
message: { type: "string", description: "\u8BE6\u7EC6\u63CF\u8FF0\u9700\u8981\u7528\u6237\u786E\u8BA4\u7684\u5185\u5BB9" },
|
|
2655
|
-
confirmText: { type: "string", description: '\u786E\u8BA4\u6309\u94AE\u6587\u5B57\uFF0C\u9ED8\u8BA4\u4E3A"\u786E\u8BA4"' },
|
|
2656
|
-
cancelText: { type: "string", description: '\u53D6\u6D88\u6309\u94AE\u6587\u5B57\uFF0C\u9ED8\u8BA4\u4E3A"\u53D6\u6D88"' }
|
|
2657
|
-
},
|
|
2658
|
-
required: ["title", "message"]
|
|
2659
|
-
},
|
|
2660
|
-
execute: async (args) => {
|
|
2661
|
-
return {
|
|
2662
|
-
result: JSON.stringify({ success: true }),
|
|
2663
|
-
sideEffects: [{
|
|
2664
|
-
type: "ui:confirm_dialog",
|
|
2665
|
-
success: true,
|
|
2666
|
-
data: {
|
|
2667
|
-
title: args.title,
|
|
2668
|
-
message: args.message,
|
|
2669
|
-
confirmText: args.confirmText || "\u786E\u8BA4",
|
|
2670
|
-
cancelText: args.cancelText || "\u53D6\u6D88"
|
|
2671
|
-
}
|
|
2672
|
-
}]
|
|
2673
|
-
};
|
|
2674
|
-
}
|
|
2675
|
-
});
|
|
2676
|
-
}
|
|
2677
|
-
function openFilePreviewTool() {
|
|
2678
|
-
return tool({
|
|
2679
|
-
name: "open_file_preview",
|
|
2680
|
-
description: "\u5728\u7528\u6237\u754C\u9762\u4E0A\u6253\u5F00\u6587\u4EF6\u9884\u89C8\u7A97\u53E3\uFF0C\u8BA9\u7528\u6237\u67E5\u770B\u6307\u5B9A\u6587\u4EF6\u7684\u5185\u5BB9\uFF0C\u652F\u6301\u6587\u672C\u3001\u56FE\u7247\u7B49\u5E38\u89C1\u683C\u5F0F",
|
|
2681
|
-
parameters: {
|
|
2682
|
-
type: "object",
|
|
2683
|
-
properties: {
|
|
2684
|
-
path: { type: "string", description: "\u8981\u9884\u89C8\u7684\u6587\u4EF6\u7684\u5B8C\u6574\u8DEF\u5F84" }
|
|
2685
|
-
},
|
|
2686
|
-
required: ["path"]
|
|
2687
|
-
},
|
|
2688
|
-
execute: async (args) => {
|
|
2689
|
-
return {
|
|
2690
|
-
result: JSON.stringify({ success: true, path: args.path }),
|
|
2691
|
-
sideEffects: [{
|
|
2692
|
-
type: "ui:file_preview",
|
|
2693
|
-
success: true,
|
|
2694
|
-
data: { path: args.path }
|
|
2695
|
-
}]
|
|
2696
|
-
};
|
|
2697
|
-
}
|
|
2698
|
-
});
|
|
2699
|
-
}
|
|
2700
|
-
function navigateToDirectoryTool() {
|
|
2701
|
-
return tool({
|
|
2702
|
-
name: "navigate_to_directory",
|
|
2703
|
-
description: "\u63A7\u5236\u7528\u6237\u754C\u9762\u5DE6\u4FA7\u7684\u6587\u4EF6\u6D4F\u89C8\u5668\u8DF3\u8F6C\u5230\u6307\u5B9A\u76EE\u5F55\uFF0C\u8BA9\u7528\u6237\u53EF\u4EE5\u76F4\u63A5\u770B\u5230\u8BE5\u76EE\u5F55\u4E0B\u7684\u6587\u4EF6\u5217\u8868",
|
|
2704
|
-
parameters: {
|
|
2705
|
-
type: "object",
|
|
2706
|
-
properties: {
|
|
2707
|
-
path: { type: "string", description: "\u8981\u8DF3\u8F6C\u5230\u7684\u76EE\u5F55\u7684\u5B8C\u6574\u8DEF\u5F84" }
|
|
2708
|
-
},
|
|
2709
|
-
required: ["path"]
|
|
2710
|
-
},
|
|
2711
|
-
execute: async (args) => {
|
|
2712
|
-
return {
|
|
2713
|
-
result: JSON.stringify({ success: true, path: args.path }),
|
|
2714
|
-
sideEffects: [{
|
|
2715
|
-
type: "ui:navigate",
|
|
2716
|
-
success: true,
|
|
2717
|
-
data: { path: args.path }
|
|
2718
|
-
}]
|
|
2719
|
-
};
|
|
2720
|
-
}
|
|
2721
|
-
});
|
|
2722
|
-
}
|
|
2723
|
-
var uiActionTools = [
|
|
2724
|
-
showToastTool(),
|
|
2725
|
-
openConfirmDialogTool(),
|
|
2726
|
-
openFilePreviewTool(),
|
|
2727
|
-
navigateToDirectoryTool()
|
|
2728
|
-
];
|
|
2729
|
-
|
|
2730
|
-
// src/builtin-tools/search-documents.ts
|
|
2731
|
-
var aiSearchModule = null;
|
|
2732
|
-
async function loadAiSearch() {
|
|
2733
|
-
if (aiSearchModule) return aiSearchModule;
|
|
2734
|
-
try {
|
|
2735
|
-
const dynamicRequire = new Function(
|
|
2736
|
-
"moduleName",
|
|
2737
|
-
"return import(moduleName)"
|
|
2738
|
-
);
|
|
2739
|
-
const mod = await dynamicRequire("@huyooo/ai-search");
|
|
2740
|
-
aiSearchModule = mod;
|
|
2741
|
-
return aiSearchModule;
|
|
2742
|
-
} catch {
|
|
2743
|
-
return null;
|
|
2744
|
-
}
|
|
2745
|
-
}
|
|
2746
|
-
async function createDocumentSearchTools(options) {
|
|
2747
|
-
const mod = await loadAiSearch();
|
|
2748
|
-
if (!mod) {
|
|
2749
|
-
return [createPlaceholderTool()];
|
|
2750
|
-
}
|
|
2751
|
-
const dataDir = options?.dataDir || "./.search-data";
|
|
2752
|
-
const plugin = await mod.searchPlugin({
|
|
2753
|
-
dataDir,
|
|
2754
|
-
// 如果配置了默认目录且自动索引,使用第一个目录作为工作空间
|
|
2755
|
-
workspace: options?.autoIndex && options?.defaultDirectories?.length ? expandPath(options.defaultDirectories[0]) : void 0
|
|
2756
|
-
});
|
|
2757
|
-
return plugin.tools;
|
|
2758
|
-
}
|
|
2759
|
-
function createPlaceholderTool() {
|
|
2760
|
-
return {
|
|
2761
|
-
name: "search_local_documents",
|
|
2762
|
-
description: "\u641C\u7D22\u672C\u5730\u6587\u6863\uFF08\u9700\u8981\u5B89\u88C5 @huyooo/ai-search\uFF09",
|
|
2763
|
-
parameters: {
|
|
2764
|
-
type: "object",
|
|
2765
|
-
properties: {
|
|
2766
|
-
query: {
|
|
2767
|
-
type: "string",
|
|
2768
|
-
description: "\u641C\u7D22\u5185\u5BB9"
|
|
2769
|
-
}
|
|
2770
|
-
},
|
|
2771
|
-
required: ["query"]
|
|
2772
|
-
},
|
|
2773
|
-
execute: async () => {
|
|
2774
|
-
return JSON.stringify({
|
|
2775
|
-
error: "\u6587\u6863\u641C\u7D22\u529F\u80FD\u672A\u542F\u7528",
|
|
2776
|
-
solution: "\u8BF7\u5B89\u88C5 @huyooo/ai-search: npm install @huyooo/ai-search"
|
|
2777
|
-
});
|
|
2778
|
-
}
|
|
2779
|
-
};
|
|
2780
|
-
}
|
|
2781
|
-
function expandPath(p) {
|
|
2782
|
-
if (p.startsWith("~")) {
|
|
2783
|
-
return p.replace("~", process.env.HOME || "");
|
|
2784
|
-
}
|
|
2785
|
-
return p;
|
|
2786
|
-
}
|
|
2787
|
-
async function getDocumentSearchInstance(dataDir = "./.search-data", workspace) {
|
|
2788
|
-
const mod = await loadAiSearch();
|
|
2789
|
-
if (!mod) return null;
|
|
2790
|
-
return await mod.searchPlugin({ dataDir, workspace });
|
|
2791
|
-
}
|
|
2792
|
-
|
|
2793
|
-
exports.ARK_MODELS = ARK_MODELS;
|
|
2794
|
-
exports.ArkAdapter = ArkAdapter;
|
|
2795
|
-
exports.ChatOrchestrator = ChatOrchestrator;
|
|
2796
|
-
exports.DEFAULT_MODEL = DEFAULT_MODEL;
|
|
2797
|
-
exports.GEMINI_MODELS = GEMINI_MODELS;
|
|
2798
|
-
exports.GeminiAdapter = GeminiAdapter;
|
|
2799
|
-
exports.HybridAgent = HybridAgent;
|
|
2800
|
-
exports.MODELS = MODELS;
|
|
2801
|
-
exports.OPENROUTER_MODELS = OPENROUTER_MODELS;
|
|
2802
|
-
exports.OpenRouterAdapter = OpenRouterAdapter;
|
|
2803
|
-
exports.QWEN_MODELS = QWEN_MODELS;
|
|
2804
|
-
exports.QwenAdapter = QwenAdapter;
|
|
2805
|
-
exports.analyzeImageTool = analyzeImageTool;
|
|
2806
|
-
exports.analyzeVideoTool = analyzeVideoTool;
|
|
2807
|
-
exports.createAbort = createAbort;
|
|
2808
|
-
exports.createApiError = createApiError;
|
|
2809
|
-
exports.createArkAdapter = createArkAdapter;
|
|
2810
|
-
exports.createDefaultToolExecutor = createDefaultToolExecutor;
|
|
2811
|
-
exports.createDocumentSearchTools = createDocumentSearchTools;
|
|
2812
|
-
exports.createDone = createDone;
|
|
2813
|
-
exports.createError = createError;
|
|
2814
|
-
exports.createGeminiAdapter = createGeminiAdapter;
|
|
2815
|
-
exports.createImage = createImage;
|
|
2816
|
-
exports.createOpenRouterAdapter = createOpenRouterAdapter;
|
|
2817
|
-
exports.createOrchestrator = createOrchestrator;
|
|
2818
|
-
exports.createParseError = createParseError;
|
|
2819
|
-
exports.createQwenAdapter = createQwenAdapter;
|
|
2820
|
-
exports.createRateLimitError = createRateLimitError;
|
|
2821
|
-
exports.createSearchEnd = createSearchEnd;
|
|
2822
|
-
exports.createSearchResult = createSearchResult;
|
|
2823
|
-
exports.createSearchStart = createSearchStart;
|
|
2824
|
-
exports.createStepEnd = createStepEnd;
|
|
2825
|
-
exports.createStepStart = createStepStart;
|
|
2826
|
-
exports.createStreamStart = createStreamStart;
|
|
2827
|
-
exports.createTextDelta = createTextDelta;
|
|
2828
|
-
exports.createThinkingDelta = createThinkingDelta;
|
|
2829
|
-
exports.createThinkingEnd = createThinkingEnd;
|
|
2830
|
-
exports.createThinkingStart = createThinkingStart;
|
|
2831
|
-
exports.createTimeoutError = createTimeoutError;
|
|
2832
|
-
exports.createToolCallResult = createToolCallResult;
|
|
2833
|
-
exports.createToolCallStart = createToolCallStart;
|
|
2834
|
-
exports.createToolError = createToolError;
|
|
2835
|
-
exports.createVideo = createVideo;
|
|
2836
|
-
exports.executeCommandTool = executeCommandTool;
|
|
2837
|
-
exports.generateImageTool = generateImageTool;
|
|
2838
|
-
exports.getCwdTool = getCwdTool;
|
|
2839
|
-
exports.getDefaultProvider = getDefaultProvider;
|
|
2840
|
-
exports.getDocumentSearchInstance = getDocumentSearchInstance;
|
|
2841
|
-
exports.getModelByModelId = getModelByModelId;
|
|
2842
|
-
exports.getNativeModels = getNativeModels;
|
|
2843
|
-
exports.getOpenRouterModels = getOpenRouterModels;
|
|
2844
|
-
exports.getPlatformTool = getPlatformTool;
|
|
2845
|
-
exports.getRouteRules = getRouteRules;
|
|
2846
|
-
exports.getWeatherTool = getWeatherTool;
|
|
2847
|
-
exports.isAbortEvent = isAbortEvent;
|
|
2848
|
-
exports.isErrorEvent = isErrorEvent;
|
|
2849
|
-
exports.isMediaEvent = isMediaEvent;
|
|
2850
|
-
exports.isModelForProvider = isModelForProvider;
|
|
2851
|
-
exports.isRetryableError = isRetryableError;
|
|
2852
|
-
exports.isSearchEvent = isSearchEvent;
|
|
2853
|
-
exports.isStatusEvent = isStatusEvent;
|
|
2854
|
-
exports.isStepEvent = isStepEvent;
|
|
2855
|
-
exports.isTextEvent = isTextEvent;
|
|
2856
|
-
exports.isThinkingEvent = isThinkingEvent;
|
|
2857
|
-
exports.isToolEvent = isToolEvent;
|
|
2858
|
-
exports.navigateToDirectoryTool = navigateToDirectoryTool;
|
|
2859
|
-
exports.openConfirmDialogTool = openConfirmDialogTool;
|
|
2860
|
-
exports.openFilePreviewTool = openFilePreviewTool;
|
|
2861
|
-
exports.resolveTools = resolveTools;
|
|
2862
|
-
exports.routeModelToProvider = routeModelToProvider;
|
|
2863
|
-
exports.routeModelWithDetails = routeModelWithDetails;
|
|
2864
|
-
exports.showToastTool = showToastTool;
|
|
2865
|
-
exports.tool = tool;
|
|
2866
|
-
exports.tools = tools;
|
|
2867
|
-
exports.uiActionTools = uiActionTools;
|
|
2868
|
-
//# sourceMappingURL=index.cjs.map
|
|
2869
|
-
//# sourceMappingURL=index.cjs.map
|