deepseeker-code 1.0.57 → 1.0.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +153 -22
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -539,7 +539,7 @@ var init_config = __esm({
|
|
|
539
539
|
* - 'allow':照常明文备份(隐私差,谨慎使用)。
|
|
540
540
|
*/
|
|
541
541
|
undoBackupSensitive: "skip",
|
|
542
|
-
/** web_search 搜索后端:环境变量 SEARCH_PROVIDER 可强制 "tavily"|"bing"|"ddg";不设则自动——有 TAVILY_API_KEY 用 Tavily,否则用 Bing(免注册,中国/全球可达)。 */
|
|
542
|
+
/** web_search 搜索后端:环境变量 SEARCH_PROVIDER 可强制 "deepseek"|"tavily"|"bing"|"ddg";不设则自动——有 DEEP_SEEK_API_KEY 用 DeepSeek 自家搜索(¥0.005/次进结算单),否则有 TAVILY_API_KEY 用 Tavily,否则用 Bing(免注册,中国/全球可达)。 */
|
|
543
543
|
searchProvider: process.env.SEARCH_PROVIDER || "",
|
|
544
544
|
/** Tavily 搜索 API 密钥(可选升级后端)。从环境变量 TAVILY_API_KEY 读取;未配置时 web_search 自动回退到免注册的 DuckDuckGo。 */
|
|
545
545
|
tavilyApiKey: process.env.TAVILY_API_KEY || "",
|
|
@@ -1132,10 +1132,10 @@ var init_batchStrings = __esm({
|
|
|
1132
1132
|
const money = c.costYuan !== null ? `\xA5${c.costYuan.toFixed(4)}` : "\uFF08\u65E0\u4EF7\u6A21\u578B\uFF0C\u4E0D\u8BA1\u94B1\uFF09";
|
|
1133
1133
|
const hit = c.promptTokens > 0 ? Math.round(c.cachedTokens / c.promptTokens * 100) : 0;
|
|
1134
1134
|
const mins = Math.round(c.durationMs / 6e3) / 10;
|
|
1135
|
-
return `${c.rounds} \u8F6E \xB7 ${money} \xB7 \u7F13\u5B58\u547D\u4E2D ${hit}% \xB7 ${mins}min${c.partialPrice ? "\uFF08\u90E8\u5206\u8BB0\u5F55\u65E0\u4EF7\uFF0C\u94B1\u4E3A\u90E8\u5206\u548C\uFF09" : ""}${c.subRuns > 0 ? ` \xB7 \u5B50 run ${c.subRuns} \u4E2A\u5DF2\u8BA1\u5165` : ""}`;
|
|
1135
|
+
return `${c.rounds} \u8F6E \xB7 ${money} \xB7 \u7F13\u5B58\u547D\u4E2D ${hit}% \xB7 ${mins}min${c.partialPrice ? "\uFF08\u90E8\u5206\u8BB0\u5F55\u65E0\u4EF7\uFF0C\u94B1\u4E3A\u90E8\u5206\u548C\uFF09" : ""}${c.subRuns > 0 ? ` \xB7 \u5B50 run ${c.subRuns} \u4E2A\u5DF2\u8BA1\u5165` : ""}${c.toolCostYuan > 0 ? ` \xB7 \u8054\u7F51 \xA5${c.toolCostYuan.toFixed(4)}` : ""}`;
|
|
1136
1136
|
},
|
|
1137
1137
|
noReceipt: "\uFF08\u65E0\u7ED3\u7B97\u5355\u2014\u2014run \u672A\u5230\u6536\u5C3E\u5373\u88AB\u622A\u65AD\uFF0C\u82B1\u8D39\u4EE5\u4E0A\u65B9 usageLog \u805A\u5408\u4E3A\u51C6\uFF09",
|
|
1138
|
-
receiptLine: (r) => `${r.rounds} \u8F6E \xB7 ${r.costYuan !== null ? `\xA5${r.costYuan.toFixed(4)}` : "\u65E0\u4EF7"} \xB7 \u7F13\u5B58\u547D\u4E2D ${Math.round(r.cacheHitRate * 100)}% \xB7 ${(r.durationMs / 1e3).toFixed(0)}s`,
|
|
1138
|
+
receiptLine: (r) => `${r.rounds} \u8F6E \xB7 ${r.costYuan !== null ? `\xA5${r.costYuan.toFixed(4)}` : "\u65E0\u4EF7"} \xB7 \u7F13\u5B58\u547D\u4E2D ${Math.round(r.cacheHitRate * 100)}% \xB7 ${(r.durationMs / 1e3).toFixed(0)}s${r.toolCostYuan ? ` \xB7 \u8054\u7F51 \xA5${r.toolCostYuan.toFixed(4)}` : ""}`,
|
|
1139
1139
|
// —— 报告骨架 ——
|
|
1140
1140
|
rejectedTitle: "# \u6302\u673A\u4EFB\u52A1\u88AB\u62D2",
|
|
1141
1141
|
reportTitle: (title) => `# \u6302\u673A\u4EFB\u52A1\u62A5\u544A\uFF1A${title}`,
|
|
@@ -1232,10 +1232,10 @@ changes are harvested onto an isolated git worktree (temp branch), kept for manu
|
|
|
1232
1232
|
const money = c.costYuan !== null ? `\xA5${c.costYuan.toFixed(4)}` : "(unpriced model, no money counted)";
|
|
1233
1233
|
const hit = c.promptTokens > 0 ? Math.round(c.cachedTokens / c.promptTokens * 100) : 0;
|
|
1234
1234
|
const mins = Math.round(c.durationMs / 6e3) / 10;
|
|
1235
|
-
return `${c.rounds} rounds \xB7 ${money} \xB7 cache hit ${hit}% \xB7 ${mins}min${c.partialPrice ? " (some records unpriced; money is a partial sum)" : ""}${c.subRuns > 0 ? ` \xB7 ${c.subRuns} sub-runs included` : ""}`;
|
|
1235
|
+
return `${c.rounds} rounds \xB7 ${money} \xB7 cache hit ${hit}% \xB7 ${mins}min${c.partialPrice ? " (some records unpriced; money is a partial sum)" : ""}${c.subRuns > 0 ? ` \xB7 ${c.subRuns} sub-runs included` : ""}${c.toolCostYuan > 0 ? ` \xB7 web \xA5${c.toolCostYuan.toFixed(4)}` : ""}`;
|
|
1236
1236
|
},
|
|
1237
1237
|
noReceipt: "(no receipt \u2014 the run was truncated before finishing; cost per the usageLog aggregate above)",
|
|
1238
|
-
receiptLine: (r) => `${r.rounds} rounds \xB7 ${r.costYuan !== null ? `\xA5${r.costYuan.toFixed(4)}` : "unpriced"} \xB7 cache hit ${Math.round(r.cacheHitRate * 100)}% \xB7 ${(r.durationMs / 1e3).toFixed(0)}s`,
|
|
1238
|
+
receiptLine: (r) => `${r.rounds} rounds \xB7 ${r.costYuan !== null ? `\xA5${r.costYuan.toFixed(4)}` : "unpriced"} \xB7 cache hit ${Math.round(r.cacheHitRate * 100)}% \xB7 ${(r.durationMs / 1e3).toFixed(0)}s${r.toolCostYuan ? ` \xB7 web \xA5${r.toolCostYuan.toFixed(4)}` : ""}`,
|
|
1239
1239
|
rejectedTitle: "# Batch task rejected",
|
|
1240
1240
|
reportTitle: (title) => `# Batch task report: ${title}`,
|
|
1241
1241
|
statusEntry: (v) => `- Status: ${v}`,
|
|
@@ -8335,12 +8335,56 @@ function decodeEntities(s) {
|
|
|
8335
8335
|
return cp > 0 && cp <= 1114111 && !(cp >= 55296 && cp <= 57343) ? String.fromCodePoint(cp) : "";
|
|
8336
8336
|
}).replace(/&[a-z#0-9]+;/gi, (e) => named[e.toLowerCase()] ?? e);
|
|
8337
8337
|
}
|
|
8338
|
+
async function searchDeepseek(query, maxResults, signal) {
|
|
8339
|
+
const apiKey = dsApiKey();
|
|
8340
|
+
if (!apiKey) throw new Error("\u672A\u914D\u7F6E DEEP_SEEK_API_KEY\uFF08\u4E0E LLM \u8C03\u7528\u540C key\uFF0CDeepSeek \u63A7\u5236\u53F0\u7533\u8BF7\uFF09");
|
|
8341
|
+
const res = await fetch(`${dsToolsBase()}/tools/search`, {
|
|
8342
|
+
method: "POST",
|
|
8343
|
+
signal,
|
|
8344
|
+
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
8345
|
+
body: JSON.stringify({ query, count: Math.max(1, Math.min(maxResults, 50)) })
|
|
8346
|
+
});
|
|
8347
|
+
if (!res.ok) {
|
|
8348
|
+
const t = await res.text().catch(() => "");
|
|
8349
|
+
throw new Error(`DeepSeek Search HTTP ${res.status} ${res.statusText}${t ? ` | ${t.slice(0, 200)}` : ""}`);
|
|
8350
|
+
}
|
|
8351
|
+
const data = await res.json();
|
|
8352
|
+
const results = [];
|
|
8353
|
+
let budget = DS_SNIPPET_BUDGET_CHARS;
|
|
8354
|
+
for (const r of Array.isArray(data?.results) ? data.results : []) {
|
|
8355
|
+
const title = (r?.title ?? "").toString().trim();
|
|
8356
|
+
const url = (r?.url ?? "").toString().trim();
|
|
8357
|
+
if (!title || !url) continue;
|
|
8358
|
+
const snippet = (r?.summary ?? r?.snippet ?? "").toString().trim();
|
|
8359
|
+
if (results.length > 0 && snippet.length > budget) break;
|
|
8360
|
+
results.push({ title, url, snippet });
|
|
8361
|
+
budget -= snippet.length;
|
|
8362
|
+
}
|
|
8363
|
+
return { answer: "", results };
|
|
8364
|
+
}
|
|
8365
|
+
async function fetchDeepseek(url, signal) {
|
|
8366
|
+
const apiKey = dsApiKey();
|
|
8367
|
+
if (!apiKey) throw new Error("\u672A\u914D\u7F6E DEEP_SEEK_API_KEY\uFF08\u4E0E LLM \u8C03\u7528\u540C key\uFF0CDeepSeek \u63A7\u5236\u53F0\u7533\u8BF7\uFF09");
|
|
8368
|
+
const res = await fetch(`${dsToolsBase()}/tools/fetch`, {
|
|
8369
|
+
method: "POST",
|
|
8370
|
+
signal,
|
|
8371
|
+
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
8372
|
+
body: JSON.stringify({ url })
|
|
8373
|
+
});
|
|
8374
|
+
if (!res.ok) {
|
|
8375
|
+
const t = await res.text().catch(() => "");
|
|
8376
|
+
throw new Error(`DeepSeek Fetch HTTP ${res.status} ${res.statusText}${t ? ` | ${t.slice(0, 200)}` : ""}`);
|
|
8377
|
+
}
|
|
8378
|
+
const data = await res.json();
|
|
8379
|
+
return { title: (data?.title ?? "").toString().trim(), content: (data?.content ?? "").toString() };
|
|
8380
|
+
}
|
|
8338
8381
|
function pickSearchProvider() {
|
|
8339
8382
|
const forced = (process.env.SEARCH_PROVIDER || "").toLowerCase();
|
|
8383
|
+
if (forced === "deepseek" && dsApiKey()) return "deepseek";
|
|
8340
8384
|
if (forced === "tavily" && appConfig.tavilyApiKey) return "tavily";
|
|
8341
8385
|
if (forced === "ddg" || forced === "duckduckgo") return "duckduckgo";
|
|
8342
8386
|
if (forced === "bing") return "bing";
|
|
8343
|
-
return appConfig.tavilyApiKey ? "tavily" : "bing";
|
|
8387
|
+
return dsApiKey() ? "deepseek" : appConfig.tavilyApiKey ? "tavily" : "bing";
|
|
8344
8388
|
}
|
|
8345
8389
|
async function searchTavily(query, maxResults, signal) {
|
|
8346
8390
|
const apiKey = appConfig.tavilyApiKey;
|
|
@@ -8419,10 +8463,18 @@ async function searchDuckDuckGo(query, maxResults, signal) {
|
|
|
8419
8463
|
return { answer: "", results };
|
|
8420
8464
|
}
|
|
8421
8465
|
function formatSearchResults(query, provider, resp) {
|
|
8422
|
-
if (resp.results.length === 0)
|
|
8466
|
+
if (resp.results.length === 0) {
|
|
8467
|
+
const siteArg = query.match(/site:(\S+)/i)?.[1];
|
|
8468
|
+
if (siteArg?.includes("/")) {
|
|
8469
|
+
const host = siteArg.split("/")[0];
|
|
8470
|
+
return `[web_search | "${query}" | ${provider}]\uFF1A0 \u547D\u4E2D\u2014\u2014site: \u540E\u5E26\u4E86\u8DEF\u5F84\uFF08site: \u53EA\u63A5\u57DF\u540D\uFF0C\u5E26\u8DEF\u5F84\u6052 0 \u6761\uFF09\u3002\u6539\u7528\uFF1Asite:${host} \u9875\u9762\u6807\u9898\u6216\u4E3B\u9898\u5173\u952E\u8BCD`;
|
|
8471
|
+
}
|
|
8472
|
+
return `[web_search | "${query}" | ${provider}]\uFF1A\u672A\u627E\u5230\u76F8\u5173\u7ED3\u679C\u3002`;
|
|
8473
|
+
}
|
|
8474
|
+
const snippetCap = provider === "deepseek" ? DS_SUMMARY_SLICE_CHARS : 240;
|
|
8423
8475
|
const lines = resp.results.map((r, i) => `${i + 1}. ${r.title}
|
|
8424
8476
|
${r.url}
|
|
8425
|
-
${r.snippet.slice(0,
|
|
8477
|
+
${r.snippet.slice(0, snippetCap)}`);
|
|
8426
8478
|
const body = (resp.answer ? `\u{1F4A1} \u6458\u8981: ${resp.answer}
|
|
8427
8479
|
|
|
8428
8480
|
` : "") + lines.join("\n\n");
|
|
@@ -8473,7 +8525,7 @@ async function safeFetchFollow(startUrl, baseHeaders, signals, allowPrivate = fa
|
|
|
8473
8525
|
return res;
|
|
8474
8526
|
}
|
|
8475
8527
|
}
|
|
8476
|
-
var FETCH_TIMEOUT_MS2, SEARCH_TIMEOUT_MS, DEFAULT_MAX_CHARS, USER_AGENT, BROWSER_UA, TAVILY_ENDPOINT, formatHostBlockMessage, MAX_REDIRECTS, pinnedSsrfDispatcher, pinnedMetadataGuardDispatcher, readBodyCapped, webTools;
|
|
8528
|
+
var FETCH_TIMEOUT_MS2, SEARCH_TIMEOUT_MS, DEFAULT_MAX_CHARS, USER_AGENT, BROWSER_UA, TAVILY_ENDPOINT, formatHostBlockMessage, TOOL_CALL_PRICE_YUAN, dsToolsBase, dsApiKey, DS_SNIPPET_BUDGET_CHARS, DS_FETCH_TIMEOUT_MS, DS_SUMMARY_SLICE_CHARS, MAX_REDIRECTS, pinnedSsrfDispatcher, pinnedMetadataGuardDispatcher, readBodyCapped, webTools;
|
|
8477
8529
|
var init_web = __esm({
|
|
8478
8530
|
"../core/src/tool/registry/web.ts"() {
|
|
8479
8531
|
"use strict";
|
|
@@ -8503,6 +8555,12 @@ var init_web = __esm({
|
|
|
8503
8555
|
return `\u76EE\u6807\u4E3B\u673A ${h} DNS \u89E3\u6790\u5931\u8D25\uFF08${v.detail || "\u672A\u77E5\u9519\u8BEF"}\uFF09\uFF0C\u975E SSRF \u62E6\u622A\uFF1B\u5EFA\u8BAE\u68C0\u67E5\u7F51\u7EDC/DNS \u6216\u6539\u7528 web_search`;
|
|
8504
8556
|
}
|
|
8505
8557
|
};
|
|
8558
|
+
TOOL_CALL_PRICE_YUAN = { search: 5e-3, fetch: 5e-3 };
|
|
8559
|
+
dsToolsBase = () => (process.env.DEEP_SEEK_API_URL || "https://api.deepseek.com").replace(/\/+$/, "");
|
|
8560
|
+
dsApiKey = () => (process.env.DEEP_SEEK_API_KEY || "").trim();
|
|
8561
|
+
DS_SNIPPET_BUDGET_CHARS = 14e3;
|
|
8562
|
+
DS_FETCH_TIMEOUT_MS = 3e4;
|
|
8563
|
+
DS_SUMMARY_SLICE_CHARS = 3e3;
|
|
8506
8564
|
MAX_REDIRECTS = 5;
|
|
8507
8565
|
pinnedSsrfDispatcher = new Agent({
|
|
8508
8566
|
connect: {
|
|
@@ -8583,13 +8641,14 @@ var init_web = __esm({
|
|
|
8583
8641
|
planAllowed: true,
|
|
8584
8642
|
primaryArg: "url",
|
|
8585
8643
|
autoApproval: "aggressive",
|
|
8586
|
-
description:
|
|
8644
|
+
description: '\u6293\u53D6\u6307\u5B9A\u516C\u5F00 URL \u7684\u7F51\u9875\u5185\u5BB9\u5E76\u8F6C\u4E3A\u5E72\u51C0\u7684 Markdown \u6587\u672C\uFF0C\u7528\u4E8E\u67E5\u9605 API \u6587\u6863\u3001\u62A5\u9519\u8BF4\u660E\u3001\u5B98\u65B9 changelog \u7B49\u5916\u90E8\u8D44\u6599\u3002\u4EC5\u652F\u6301 http/https\uFF0C\u9ED8\u8BA4\u62E6\u622A\u5185\u7F51/\u56DE\u73AF/\u94FE\u8DEF\u672C\u5730\u5730\u5740\uFF08\u9632 SSRF\uFF09\uFF1B\u672C\u5730\u5F00\u53D1/\u81EA\u52A8\u5316\u6D4B\u8BD5\u9700\u6293 localhost \u670D\u52A1\u6216\u5185\u7F51\u9875\u9762\u65F6\uFF0C\u4F20 allow_private=true \u653E\u884C\uFF08\u4E91\u5143\u6570\u636E\u7AEF\u70B9\u4ECD\u62E6\uFF09\u3002\u53EF\u9009 backend="deepseek" \u8D70 DeepSeek \u670D\u52A1\u7AEF\u6293\u53D6\uFF08\u8FD4\u56DE markdown \u6B63\u6587\uFF1B\u8BE5\u540E\u7AEF\u4E0B allow_private \u65E0\u6548\u2014\u2014\u6293\u53D6\u4E0D\u7ECF\u8FC7\u672C\u673A\u7F51\u7EDC\uFF0CSSRF \u9632\u62A4\u662F\u672C\u673A\u8BED\u4E49\uFF09\u3002',
|
|
8587
8645
|
parameters: {
|
|
8588
8646
|
type: "object",
|
|
8589
8647
|
properties: {
|
|
8590
8648
|
url: { type: "string", description: "\u8981\u6293\u53D6\u7684\u5B8C\u6574 http(s) URL" },
|
|
8649
|
+
backend: { type: "string", enum: ["local", "deepseek"], description: "\u6293\u53D6\u540E\u7AEF\uFF1Alocal=\u672C\u673A\u76F4\u6293\uFF08\u7F3A\u7701\uFF0C\u5E26\u5168\u5957 SSRF \u9632\u62A4\uFF09\uFF1Bdeepseek=DeepSeek \u670D\u52A1\u7AEF\u6293\u53D6\uFF08\u53CD\u722C\u53D7\u9650\uFF0C\u5931\u8D25\u65F6\u53EF\u8BD5 web_search \u7528 site: \u8BED\u6CD5\u4ECE\u7D22\u5F15\u4FA7\u62FF\u6B63\u6587\uFF09\u3002" },
|
|
8591
8650
|
max_length: { type: "number", description: `\u8FD4\u56DE\u5185\u5BB9\u7684\u6700\u5927\u5B57\u7B26\u6570\uFF08\u9ED8\u8BA4 ${DEFAULT_MAX_CHARS}\uFF0C\u8D85\u51FA\u81EA\u52A8\u622A\u65AD\uFF09` },
|
|
8592
|
-
allow_private: { type: "boolean", description: "\u662F\u5426\u5141\u8BB8\u8BBF\u95EE\u5185\u7F51/\u56DE\u73AF\u5730\u5740\uFF08\u5982 localhost:5173 \u672C\u5730\u670D\u52A1\u3001\u5185\u7F51\u6587\u6863\uFF09\u3002\u9ED8\u8BA4 false\u3002\u4E5F\u53EF\u7528\u73AF\u5883\u53D8\u91CF WEB_FETCH_ALLOW_PRIVATE=1 \u5168\u5C40\u5F00\u542F\u3002\u5373\u4FBF\u5F00\u542F\u4ECD\u62E6\u622A\u4E91\u5143\u6570\u636E\u7AEF\u70B9\uFF08169.254.169.254 \u7B49\uFF09\u3002" }
|
|
8651
|
+
allow_private: { type: "boolean", description: "\u662F\u5426\u5141\u8BB8\u8BBF\u95EE\u5185\u7F51/\u56DE\u73AF\u5730\u5740\uFF08\u5982 localhost:5173 \u672C\u5730\u670D\u52A1\u3001\u5185\u7F51\u6587\u6863\uFF09\u3002\u9ED8\u8BA4 false\u3002\u4E5F\u53EF\u7528\u73AF\u5883\u53D8\u91CF WEB_FETCH_ALLOW_PRIVATE=1 \u5168\u5C40\u5F00\u542F\u3002\u5373\u4FBF\u5F00\u542F\u4ECD\u62E6\u622A\u4E91\u5143\u6570\u636E\u7AEF\u70B9\uFF08169.254.169.254 \u7B49\uFF09\u3002\u4EC5 local \u540E\u7AEF\u6709\u6548\uFF1Bbackend=deepseek \u65F6\u5FFD\u7565\u3002" }
|
|
8593
8652
|
},
|
|
8594
8653
|
required: ["url"]
|
|
8595
8654
|
},
|
|
@@ -8602,6 +8661,44 @@ var init_web = __esm({
|
|
|
8602
8661
|
\uFF08\u5C06\u53D1\u8D77\u5BF9\u5916\u7F51\u7EDC\u8BF7\u6C42\uFF0C\u4E14\u6293\u53D6\u5230\u7684\u5185\u5BB9\u4F1A\u8FDB\u5165\u4E91\u7AEF\u6A21\u578B\u4E0A\u4E0B\u6587\uFF1B\u8BF7\u786E\u8BA4 URL \u6765\u6E90\u53EF\u4FE1\u3001\u4E0D\u542B\u654F\u611F\u56DE\u4F20\u6570\u636E\uFF09`,
|
|
8603
8662
|
async execute(args, ctx) {
|
|
8604
8663
|
const maxChars = args.max_length && args.max_length > 0 ? args.max_length : DEFAULT_MAX_CHARS;
|
|
8664
|
+
if (args.backend === "deepseek") {
|
|
8665
|
+
let dsUrl;
|
|
8666
|
+
try {
|
|
8667
|
+
dsUrl = new URL(args.url);
|
|
8668
|
+
} catch {
|
|
8669
|
+
return toolFailure(`[\u6293\u53D6\u5931\u8D25]\uFF1AURL \u683C\u5F0F\u4E0D\u5408\u6CD5\uFF1A${args.url}`);
|
|
8670
|
+
}
|
|
8671
|
+
if (dsUrl.protocol !== "http:" && dsUrl.protocol !== "https:") {
|
|
8672
|
+
return toolFailure(`[\u5B89\u5168\u7194\u65AD]\uFF1A\u4EC5\u5141\u8BB8 http/https \u534F\u8BAE\uFF0C\u62D2\u7EDD ${dsUrl.protocol}`);
|
|
8673
|
+
}
|
|
8674
|
+
const dsSignals = [AbortSignal.timeout(DS_FETCH_TIMEOUT_MS)];
|
|
8675
|
+
if (ctx?.abortSignal) dsSignals.push(ctx.abortSignal);
|
|
8676
|
+
try {
|
|
8677
|
+
const { title, content } = await fetchDeepseek(dsUrl.href, AbortSignal.any(dsSignals));
|
|
8678
|
+
ctx?.toolCostSink?.(TOOL_CALL_PRICE_YUAN.fetch);
|
|
8679
|
+
const body = title ? `# ${title}
|
|
8680
|
+
|
|
8681
|
+
${content}` : content;
|
|
8682
|
+
if (body.length > maxChars) {
|
|
8683
|
+
return [
|
|
8684
|
+
`[web_fetch | deepseek | ${dsUrl.href} | \u5DF2\u622A\u65AD\u524D ${maxChars} \u5B57\u7B26\uFF0C\u539F\u6587\u5171 ${body.length} \u5B57\u7B26]`,
|
|
8685
|
+
body.slice(0, maxChars),
|
|
8686
|
+
`
|
|
8687
|
+
[... \u26A0\uFE0F \u5185\u5BB9\u8FC7\u957F\uFF0C\u5DF2\u9690\u85CF\u5269\u4F59 ${body.length - maxChars} \u5B57\u7B26\uFF0C\u53EF\u8C03\u5927 max_length ...]`
|
|
8688
|
+
].join("\n");
|
|
8689
|
+
}
|
|
8690
|
+
return `[web_fetch | deepseek | ${dsUrl.href}]
|
|
8691
|
+
${body}`;
|
|
8692
|
+
} catch (error) {
|
|
8693
|
+
if (error?.name === "TimeoutError") {
|
|
8694
|
+
return toolFailure(`[\u6293\u53D6\u8D85\u65F6]\uFF1A${DS_FETCH_TIMEOUT_MS / 1e3}s \u5185\u672A\u54CD\u5E94\uFF1A${dsUrl.href}`);
|
|
8695
|
+
}
|
|
8696
|
+
if (error?.name === "AbortError") {
|
|
8697
|
+
return `\u23F9\uFE0F [\u5DF2\u4E2D\u6B62]\uFF1A\u7528\u6237\u4E2D\u65AD\u4E86\u6293\u53D6\uFF1A${dsUrl.href}`;
|
|
8698
|
+
}
|
|
8699
|
+
return toolFailure(`[\u6293\u53D6\u5931\u8D25 | deepseek]\uFF1A${error.message}\uFF08\u8BE5\u540E\u7AEF\u5BF9\u53CD\u722C/\u56FD\u9645\u7AD9\u70B9\u540C\u6837\u53D7\u9650\uFF1B\u53EF\u6539\u7528 web_search \u4ECE\u7D22\u5F15\u4FA7\u62FF\u6B63\u6587\u2014\u2014site: \u53EA\u63A5\u57DF\u540D\u4E0D\u5E26\u8DEF\u5F84\uFF0C\u4F8B\uFF1Asite:${dsUrl.hostname} \u9875\u9762\u6807\u9898\u6216\u4E3B\u9898\u5173\u952E\u8BCD\uFF09`);
|
|
8700
|
+
}
|
|
8701
|
+
}
|
|
8605
8702
|
const allowPrivate = args.allow_private ?? appConfig.webFetchAllowPrivate;
|
|
8606
8703
|
let parsed;
|
|
8607
8704
|
try {
|
|
@@ -8666,7 +8763,7 @@ ${body}${truncNote}`;
|
|
|
8666
8763
|
planAllowed: true,
|
|
8667
8764
|
primaryArg: "query",
|
|
8668
8765
|
autoApproval: "aggressive",
|
|
8669
|
-
description: "\u8054\u7F51\u641C\u7D22\u5916\u90E8\u8D44\u6599\uFF08API \u6587\u6863\u3001\u62A5\u9519\u89E3\u6CD5\u3001\u5E93\u7528\u6CD5\u3001\u6700\u65B0\u4FE1\u606F\u7B49\uFF09\uFF0C\u8FD4\u56DE\u7ED3\u679C\u5217\u8868\uFF08\u6807\u9898/URL/\
|
|
8766
|
+
description: "\u8054\u7F51\u641C\u7D22\u5916\u90E8\u8D44\u6599\uFF08API \u6587\u6863\u3001\u62A5\u9519\u89E3\u6CD5\u3001\u5E93\u7528\u6CD5\u3001\u6700\u65B0\u4FE1\u606F\u7B49\uFF09\uFF0C\u8FD4\u56DE\u7ED3\u679C\u5217\u8868\uFF08\u6807\u9898/URL/\u6458\u8981\uFF09\u3002\u540E\u7AEF\u81EA\u52A8\u9009\u62E9\uFF1A\u914D\u7F6E\u4E86 DEEP_SEEK_API_KEY\uFF08\u901A\u5E38\u5DF2\u914D\uFF09\u9ED8\u8BA4\u8D70 DeepSeek \u81EA\u5BB6\u641C\u7D22\u5F15\u64CE\uFF08\u957F\u6458\u8981\u8D28\u91CF\u6700\u4F73\uFF0C\xA50.005/\u6B21\u6309\u6B21\u8BA1\u8D39\u8FDB\u7ED3\u7B97\u5355\uFF09\uFF1B\u5426\u5219\u6709 TAVILY_API_KEY \u7528 Tavily\uFF0C\u518D\u5426\u5219 Bing\uFF08\u514D\u6CE8\u518C\uFF09\u3002\u53EF\u7528 SEARCH_PROVIDER=deepseek|tavily|bing|ddg \u5F3A\u5236\u6307\u5B9A\uFF08deepseek \u5F02\u5E38\u65F6\u53EF\u4E34\u65F6\u5207 bing \u56DE\u9000\uFF09\u3002\u67E5\u8BE2\u964C\u751F\u5E93\u6216\u62A5\u9519\u65F6\u4F18\u5148\u7528\u672C\u5DE5\u5177\u66FF\u4EE3\u51ED\u8BB0\u5FC6\u4F5C\u7B54\u3002\u7ED3\u679C\u6309\u957F\u5EA6\u7194\u65AD\u3002",
|
|
8670
8767
|
parameters: {
|
|
8671
8768
|
type: "object",
|
|
8672
8769
|
properties: {
|
|
@@ -8689,7 +8786,17 @@ ${body}${truncNote}`;
|
|
|
8689
8786
|
if (ctx?.abortSignal) signals.push(ctx.abortSignal);
|
|
8690
8787
|
try {
|
|
8691
8788
|
const signal = AbortSignal.any(signals);
|
|
8692
|
-
|
|
8789
|
+
let resp;
|
|
8790
|
+
if (provider === "deepseek") {
|
|
8791
|
+
resp = await searchDeepseek(args.query, maxResults, signal);
|
|
8792
|
+
ctx?.toolCostSink?.(TOOL_CALL_PRICE_YUAN.search);
|
|
8793
|
+
} else if (provider === "tavily") {
|
|
8794
|
+
resp = await searchTavily(args.query, maxResults, signal);
|
|
8795
|
+
} else if (provider === "duckduckgo") {
|
|
8796
|
+
resp = await searchDuckDuckGo(args.query, maxResults, signal);
|
|
8797
|
+
} else {
|
|
8798
|
+
resp = await searchBing(args.query, maxResults, signal);
|
|
8799
|
+
}
|
|
8693
8800
|
return formatSearchResults(args.query, provider, resp);
|
|
8694
8801
|
} catch (error) {
|
|
8695
8802
|
if (error?.name === "TimeoutError") {
|
|
@@ -8698,7 +8805,8 @@ ${body}${truncNote}`;
|
|
|
8698
8805
|
if (error?.name === "AbortError") {
|
|
8699
8806
|
return `\u23F9\uFE0F [\u5DF2\u4E2D\u6B62]\uFF1A\u7528\u6237\u4E2D\u65AD\u4E86\u641C\u7D22\u3002`;
|
|
8700
8807
|
}
|
|
8701
|
-
|
|
8808
|
+
const hint = provider === "deepseek" ? "\uFF08\u53EF\u8BBE SEARCH_PROVIDER=bing \u4E34\u65F6\u5207\u56DE\u672C\u5730\u722C\u866B\u540E\u7AEF\uFF09" : "";
|
|
8809
|
+
return toolFailure(`[web_search \u5931\u8D25 | ${provider}]\uFF1A${error.message}${hint}`);
|
|
8702
8810
|
}
|
|
8703
8811
|
}
|
|
8704
8812
|
}
|
|
@@ -11808,7 +11916,8 @@ var init_toolExecution = __esm({
|
|
|
11808
11916
|
modelWindow,
|
|
11809
11917
|
parentSystemPrompt,
|
|
11810
11918
|
readTracker,
|
|
11811
|
-
reportCost
|
|
11919
|
+
reportCost,
|
|
11920
|
+
toolCostSink
|
|
11812
11921
|
} = ctx;
|
|
11813
11922
|
let calledName = "";
|
|
11814
11923
|
let calledArgs = {};
|
|
@@ -11846,7 +11955,7 @@ var init_toolExecution = __esm({
|
|
|
11846
11955
|
events({ sessionId, eventType: "tool.validation.failed", metadata: { depth, decisionSource: llmDecisionSource, durationMs: performance.now() - startTime, round, tools_id: toolCall.id, toolName: calledName, toolSource: "builtin", ok: false, attempt: round }, payload: { output: note } });
|
|
11847
11956
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: false };
|
|
11848
11957
|
}
|
|
11849
|
-
const toolCtx = { sessionId, cwd: getActiveWorkspaceRoot(), abortSignal: signal, depth, keepRecentUnits, compactRatio, modelWindow, parentSystemPrompt, events, onUIEvent, requestApproval: hostRequestApproval, requestQuestion: hostRequestQuestion, ideAction, emitProgress: (m) => onUIEvent?.({ type: "tool.progress", toolsId: toolCall.id, toolName: calledName, message: m }), permissionMode, readTracker, reportCost };
|
|
11958
|
+
const toolCtx = { sessionId, cwd: getActiveWorkspaceRoot(), abortSignal: signal, depth, keepRecentUnits, compactRatio, modelWindow, parentSystemPrompt, events, onUIEvent, requestApproval: hostRequestApproval, requestQuestion: hostRequestQuestion, ideAction, emitProgress: (m) => onUIEvent?.({ type: "tool.progress", toolsId: toolCall.id, toolName: calledName, message: m }), permissionMode, readTracker, reportCost, toolCostSink };
|
|
11850
11959
|
let result = "";
|
|
11851
11960
|
let resultStatus = "success";
|
|
11852
11961
|
let errorCategory;
|
|
@@ -12833,12 +12942,17 @@ var init_prices = __esm({
|
|
|
12833
12942
|
idle: { input: 1, output: 4, cacheHit: 0.02 },
|
|
12834
12943
|
peak: { input: 2, output: 8, cacheHit: 0.04 }
|
|
12835
12944
|
},
|
|
12945
|
+
// 官网脚注明示旧名按 Flash 价格计费(2026-10-19 核实),非猜测——与 flash 同价条目
|
|
12946
|
+
"deepseek-flash-vision-exp": {
|
|
12947
|
+
idle: { input: 1, output: 4, cacheHit: 0.02 },
|
|
12948
|
+
peak: { input: 2, output: 8, cacheHit: 0.04 }
|
|
12949
|
+
},
|
|
12836
12950
|
"deepseek-v4-pro": {
|
|
12837
12951
|
idle: { input: 4.5, output: 13.5, cacheHit: 0.15 },
|
|
12838
12952
|
peak: { input: 9, output: 27, cacheHit: 0.3 }
|
|
12839
12953
|
}
|
|
12840
12954
|
};
|
|
12841
|
-
PRICES_VERIFIED_AT = "2026-10-
|
|
12955
|
+
PRICES_VERIFIED_AT = "2026-10-19";
|
|
12842
12956
|
PRICES_STALE_DAYS = 30;
|
|
12843
12957
|
pricesAgeDays = () => Math.max(0, Math.floor((Date.now() - Date.parse(`${PRICES_VERIFIED_AT}T00:00:00Z`)) / 864e5));
|
|
12844
12958
|
isBeijingPeak = (ts2 = /* @__PURE__ */ new Date()) => {
|
|
@@ -12960,6 +13074,13 @@ async function* runAgent(message, options) {
|
|
|
12960
13074
|
budgetSpentYuan += cost;
|
|
12961
13075
|
}
|
|
12962
13076
|
};
|
|
13077
|
+
let toolCostYuanAcc = 0;
|
|
13078
|
+
const addToolCost = (yuan) => {
|
|
13079
|
+
if (!Number.isFinite(yuan) || yuan <= 0) return;
|
|
13080
|
+
toolCostYuanAcc += yuan;
|
|
13081
|
+
budgetSpentYuan += yuan;
|
|
13082
|
+
};
|
|
13083
|
+
const toolCostSink = process.env.DEEP_SEEK_TOOL_COST === "0" ? void 0 : addToolCost;
|
|
12963
13084
|
const toolCounts = {};
|
|
12964
13085
|
await appendEvent(sessionId, { dscEvent: "run.start", runId, depth });
|
|
12965
13086
|
try {
|
|
@@ -13141,7 +13262,10 @@ async function* runAgent(message, options) {
|
|
|
13141
13262
|
// 子 run 结束时把总花费记进本 run 预算累计器——父预算自动继承约束(子花费计入父 spent)。
|
|
13142
13263
|
reportCost: (yuan) => {
|
|
13143
13264
|
if (Number.isFinite(yuan) && yuan > 0) budgetSpentYuan += yuan;
|
|
13144
|
-
}
|
|
13265
|
+
},
|
|
13266
|
+
// ★ 按次计费工具成本上报(DeepSeek Search/Fetch):web 工具经 toolCtx.toolCostSink 拿到闭包,
|
|
13267
|
+
// 成功调用后按次上报进本 run 累计器。
|
|
13268
|
+
toolCostSink
|
|
13145
13269
|
};
|
|
13146
13270
|
const scheduleResult = yield* scheduleToolCalls(assistantMessage, message, toolCallCtx);
|
|
13147
13271
|
if (scheduleResult.kind === "aborted") {
|
|
@@ -13191,12 +13315,15 @@ async function* runAgent(message, options) {
|
|
|
13191
13315
|
totalTokens: usageSum?.total_tokens,
|
|
13192
13316
|
cachedTokens: usageSum?.cached_tokens,
|
|
13193
13317
|
costYuan: costKnown ? Math.round(costYuanAcc * 1e6) / 1e6 : void 0,
|
|
13318
|
+
toolCostYuan: toolCostYuanAcc > 0 ? Math.round(toolCostYuanAcc * 1e6) / 1e6 : void 0,
|
|
13319
|
+
// 按次计费工具花费(Search/Fetch)
|
|
13194
13320
|
tools: toolCounts
|
|
13195
13321
|
});
|
|
13196
13322
|
} catch {
|
|
13197
13323
|
}
|
|
13198
13324
|
try {
|
|
13199
|
-
|
|
13325
|
+
const spentTotal = costYuanAcc + toolCostYuanAcc;
|
|
13326
|
+
if (options.costSink && spentTotal > 0) options.costSink(Math.round(spentTotal * 1e6) / 1e6);
|
|
13200
13327
|
} catch {
|
|
13201
13328
|
}
|
|
13202
13329
|
try {
|
|
@@ -13210,6 +13337,8 @@ async function* runAgent(message, options) {
|
|
|
13210
13337
|
cachedTokens: usageSum.cached_tokens ?? 0,
|
|
13211
13338
|
cacheHitRate: prompt > 0 ? (usageSum.cached_tokens ?? 0) / prompt : 0,
|
|
13212
13339
|
costYuan: costKnown ? Math.round(costYuanAcc * 1e6) / 1e6 : null,
|
|
13340
|
+
toolCostYuan: toolCostYuanAcc > 0 ? Math.round(toolCostYuanAcc * 1e6) / 1e6 : void 0,
|
|
13341
|
+
// 按次计费工具花费(undefined 自动省略)
|
|
13213
13342
|
durationMs: Math.round(performance.now() - startTime),
|
|
13214
13343
|
budgetTruncated: budgetTruncated || void 0
|
|
13215
13344
|
// 预算截断标注(E2;undefined 自动省略)
|
|
@@ -15570,13 +15699,14 @@ var init_useChatState = __esm({
|
|
|
15570
15699
|
const durMs = obj.durationMs ?? 0;
|
|
15571
15700
|
const durText = durMs >= 6e4 ? `${Math.floor(durMs / 6e4)}m${Math.round(durMs % 6e4 / 1e3)}s` : `${(durMs / 1e3).toFixed(1)}s`;
|
|
15572
15701
|
const cost = obj.costYuan;
|
|
15702
|
+
const toolCost = typeof obj.toolCostYuan === "number" && obj.toolCostYuan > 0 ? obj.toolCostYuan : null;
|
|
15573
15703
|
const tokTotal = promptT + completionT;
|
|
15574
15704
|
const tokText = tokTotal >= 1e4 ? `${(tokTotal / 1e3).toFixed(1)}k` : String(tokTotal);
|
|
15575
15705
|
const costText = typeof cost === "number" ? `\xA5${cost.toFixed(cost < 5e-3 ? 4 : 3)}` : `${tokText} tok`;
|
|
15576
15706
|
setRows((prev) => [...prev, {
|
|
15577
15707
|
id: newRowId(),
|
|
15578
15708
|
kind: "meta",
|
|
15579
|
-
text: `\u{1F4B0} \u672C\u6B21 ${rounds} \u8F6E \xB7 ${costText} \xB7 \u7F13\u5B58\u547D\u4E2D ${hitPct}% \xB7 ${durText}${obj.budgetTruncated ? " \xB7 \u9884\u7B97\u622A\u65AD" : ""}`
|
|
15709
|
+
text: `\u{1F4B0} \u672C\u6B21 ${rounds} \u8F6E \xB7 ${costText}${toolCost != null ? ` \xB7 \u8054\u7F51 \xA5${toolCost.toFixed(3)}` : ""} \xB7 \u7F13\u5B58\u547D\u4E2D ${hitPct}% \xB7 ${durText}${obj.budgetTruncated ? " \xB7 \u9884\u7B97\u622A\u65AD" : ""}`
|
|
15580
15710
|
}]);
|
|
15581
15711
|
lastRunCostRef.current = typeof cost === "number" ? cost : void 0;
|
|
15582
15712
|
sessionCostRef.current = typeof cost === "number" ? (sessionCostRef.current ?? 0) + cost : sessionCostRef.current;
|
|
@@ -18267,7 +18397,7 @@ ${lines.slice(-ACCEPT_TAIL_LINES).join("\n")}` : text;
|
|
|
18267
18397
|
};
|
|
18268
18398
|
collectSessionCost = async (sessionId) => {
|
|
18269
18399
|
const recs = (await readUsageRecords(2)).filter((r) => r.sessionId === sessionId);
|
|
18270
|
-
const c = { rounds: 0, mainRounds: 0, subRuns: 0, promptTokens: 0, completionTokens: 0, cachedTokens: 0, costYuan: null, partialPrice: false, durationMs: 0 };
|
|
18400
|
+
const c = { rounds: 0, mainRounds: 0, subRuns: 0, promptTokens: 0, completionTokens: 0, cachedTokens: 0, costYuan: null, toolCostYuan: 0, partialPrice: false, durationMs: 0 };
|
|
18271
18401
|
for (const r of recs) {
|
|
18272
18402
|
c.rounds += r.rounds || 0;
|
|
18273
18403
|
if (r.depth === 0) c.mainRounds += r.rounds || 0;
|
|
@@ -18276,6 +18406,7 @@ ${lines.slice(-ACCEPT_TAIL_LINES).join("\n")}` : text;
|
|
|
18276
18406
|
c.completionTokens += r.completionTokens ?? 0;
|
|
18277
18407
|
c.cachedTokens += r.cachedTokens ?? 0;
|
|
18278
18408
|
c.durationMs += r.durationMs || 0;
|
|
18409
|
+
c.toolCostYuan += r.toolCostYuan ?? 0;
|
|
18279
18410
|
if (typeof r.costYuan === "number") c.costYuan = (c.costYuan ?? 0) + r.costYuan;
|
|
18280
18411
|
else c.partialPrice = true;
|
|
18281
18412
|
}
|
|
@@ -18341,7 +18472,7 @@ ${diff}
|
|
|
18341
18472
|
const source = await fs49.promises.readFile(task.path, "utf-8");
|
|
18342
18473
|
const parsed = parseBatchTicket(source, getLocale());
|
|
18343
18474
|
if (!parsed.ok) {
|
|
18344
|
-
const cost2 = { rounds: 0, mainRounds: 0, subRuns: 0, promptTokens: 0, completionTokens: 0, cachedTokens: 0, costYuan: 0, partialPrice: false, durationMs: 0 };
|
|
18475
|
+
const cost2 = { rounds: 0, mainRounds: 0, subRuns: 0, promptTokens: 0, completionTokens: 0, cachedTokens: 0, costYuan: 0, toolCostYuan: 0, partialPrice: false, durationMs: 0 };
|
|
18345
18476
|
await finishTicket(task.id, `---
|
|
18346
18477
|
id: ${task.id}
|
|
18347
18478
|
title: ${task.id}
|