deepseeker-code 1.0.56 → 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 +223 -31
- package/package.json +4 -3
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 || "",
|
|
@@ -913,10 +913,11 @@ var init_ticket = __esm({
|
|
|
913
913
|
}
|
|
914
914
|
const tools = fm["tools"] !== void 0 ? parseToolsValue(fm["tools"]) : void 0;
|
|
915
915
|
if (tools && tools.length === 0) return { ok: false, error: ticketMsg(locale2, "badTools") };
|
|
916
|
+
const setup = (fm["setup"] ?? "").trim() || void 0;
|
|
916
917
|
const body = bodyRaw.trim();
|
|
917
918
|
if (!body) return { ok: false, error: ticketMsg(locale2, "emptyBody") };
|
|
918
919
|
const title = (fm["title"] ?? "").trim() || body.split(/\r?\n/).find((l) => l.trim())?.slice(0, 40) || ticketMsg(locale2, "untitled");
|
|
919
|
-
return { ok: true, ticket: { title, accept, budgetYuan, timeoutMin, tools: tools && tools.length > 0 ? tools : void 0, body } };
|
|
920
|
+
return { ok: true, ticket: { title, accept, setup, budgetYuan, timeoutMin, tools: tools && tools.length > 0 ? tools : void 0, body } };
|
|
920
921
|
};
|
|
921
922
|
readBatchTicket = async (filePath, locale2 = "zh") => {
|
|
922
923
|
let source;
|
|
@@ -1069,6 +1070,7 @@ var init_batchStrings = __esm({
|
|
|
1069
1070
|
---
|
|
1070
1071
|
title: \u4FEE\u590D\u65E5\u671F\u89E3\u6790 bug
|
|
1071
1072
|
accept: npm test
|
|
1073
|
+
setup: pnpm install # \u53EF\u9009\uFF1Aagent \u524D\u5728 worktree \u5185\u5907\u73AF\u5883\uFF08\u5E72\u51C0\u68C0\u51FA\u65E0 node_modules\uFF0C\u9A8C\u6536\u4F9D\u8D56\u73AF\u5883\u65F6\u5148\u88C5\uFF09
|
|
1072
1074
|
budget-yuan: 0.5 # \u53EF\u9009\uFF1A\u672C\u4EFB\u52A1\u82B1\u8D39\u4E0A\u9650\uFF08\u5143\uFF09
|
|
1073
1075
|
timeout-min: 30 # \u53EF\u9009\uFF1Aagent \u9636\u6BB5\u8D85\u65F6\uFF08\u5206\u949F\uFF0C\u7F3A\u7701 30\uFF09
|
|
1074
1076
|
tools: run_command # \u53EF\u9009\uFF1A\u663E\u5F0F\u89E3\u9501\u9AD8\u5371\u5DE5\u5177\uFF08\u7F3A\u7701\u7981 run_command/delete_path\uFF09
|
|
@@ -1091,6 +1093,8 @@ var init_batchStrings = __esm({
|
|
|
1091
1093
|
// —— batchRunner 控制台进度 ——
|
|
1092
1094
|
ticketRejected: (id, err) => `\u{1F6AB} [${id}] \u5DE5\u5355\u88AB\u62D2\uFF1A${err}`,
|
|
1093
1095
|
taskMeta: (budget, timeoutMin, accept) => ` \u9884\u7B97 ${budget !== void 0 ? `\xA5${budget}` : "\u4E0D\u9650"} \xB7 \u8D85\u65F6 ${timeoutMin}min \xB7 \u9A8C\u6536 \`${accept}\``,
|
|
1096
|
+
setupLine: (cmd) => `\u{1F6E0}\uFE0F setup\uFF1A\`${cmd}\`\uFF08worktree \u5185\u5907\u73AF\u5883\uFF09`,
|
|
1097
|
+
setupFail: (cmd, code) => `\u73AF\u5883\u51C6\u5907\u5931\u8D25\uFF08setup \`${cmd}\` exit ${code ?? "null"}\uFF09\u2014\u2014\u8DF3\u8FC7 agent \u9636\u6BB5\uFF0C\u4EFB\u52A1\u8BB0\u5931\u8D25`,
|
|
1094
1098
|
roundLine: (ts2, round) => ` [${ts2}] \u8F6E ${round}`,
|
|
1095
1099
|
wtCreateFail: (e) => `\u521B\u5EFA worktree \u5931\u8D25\uFF08\u9700\u8981\u4E3B\u5DE5\u4F5C\u533A\u662F git \u4ED3\u5E93\uFF09\uFF1A${e}`,
|
|
1096
1100
|
agentErrorLine: (id, err) => `\u{1F4A5} [${id}] agent \u5F02\u5E38\uFF1A${err}`,
|
|
@@ -1114,6 +1118,7 @@ var init_batchStrings = __esm({
|
|
|
1114
1118
|
"accept-failed": "\u274C \u9A8C\u6536\u672A\u8FC7",
|
|
1115
1119
|
timeout: "\u23F1\uFE0F \u8D85\u65F6\u622A\u65AD",
|
|
1116
1120
|
error: "\u{1F4A5} agent \u5F02\u5E38",
|
|
1121
|
+
"setup-failed": "\u{1F6E0}\uFE0F \u73AF\u5883\u51C6\u5907\u5931\u8D25",
|
|
1117
1122
|
rejected: "\u{1F6AB} \u5DE5\u5355\u88AB\u62D2"
|
|
1118
1123
|
})[s],
|
|
1119
1124
|
// —— 验收命令执行(输出嵌入报告) ——
|
|
@@ -1127,10 +1132,10 @@ var init_batchStrings = __esm({
|
|
|
1127
1132
|
const money = c.costYuan !== null ? `\xA5${c.costYuan.toFixed(4)}` : "\uFF08\u65E0\u4EF7\u6A21\u578B\uFF0C\u4E0D\u8BA1\u94B1\uFF09";
|
|
1128
1133
|
const hit = c.promptTokens > 0 ? Math.round(c.cachedTokens / c.promptTokens * 100) : 0;
|
|
1129
1134
|
const mins = Math.round(c.durationMs / 6e3) / 10;
|
|
1130
|
-
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)}` : ""}`;
|
|
1131
1136
|
},
|
|
1132
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",
|
|
1133
|
-
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)}` : ""}`,
|
|
1134
1139
|
// —— 报告骨架 ——
|
|
1135
1140
|
rejectedTitle: "# \u6302\u673A\u4EFB\u52A1\u88AB\u62D2",
|
|
1136
1141
|
reportTitle: (title) => `# \u6302\u673A\u4EFB\u52A1\u62A5\u544A\uFF1A${title}`,
|
|
@@ -1168,6 +1173,7 @@ Ticket format (Markdown; frontmatter \`accept\` is required \u2014 no acceptance
|
|
|
1168
1173
|
---
|
|
1169
1174
|
title: Fix date parsing bug
|
|
1170
1175
|
accept: npm test # required: acceptance command (exit 0 = pass)
|
|
1176
|
+
setup: pnpm install # optional: prep env inside the worktree before the agent (fresh checkout has no node_modules)
|
|
1171
1177
|
budget-yuan: 0.5 # optional: per-task cost cap (yuan)
|
|
1172
1178
|
timeout-min: 30 # optional: agent-phase timeout (minutes, default 30)
|
|
1173
1179
|
tools: run_command # optional: unlock risky tools (run_command/delete_path denied by default)
|
|
@@ -1190,6 +1196,8 @@ changes are harvested onto an isolated git worktree (temp branch), kept for manu
|
|
|
1190
1196
|
reportMissing: "(report missing)",
|
|
1191
1197
|
ticketRejected: (id, err) => `\u{1F6AB} [${id}] Ticket rejected: ${err}`,
|
|
1192
1198
|
taskMeta: (budget, timeoutMin, accept) => ` Budget ${budget !== void 0 ? `\xA5${budget}` : "uncapped"} \xB7 timeout ${timeoutMin}min \xB7 accept \`${accept}\``,
|
|
1199
|
+
setupLine: (cmd) => `\u{1F6E0}\uFE0F setup: \`${cmd}\` (preparing the environment inside the worktree)`,
|
|
1200
|
+
setupFail: (cmd, code) => `Setup failed (\`${cmd}\` exit ${code ?? "null"}) \u2014 agent phase skipped, task marked failed`,
|
|
1193
1201
|
roundLine: (ts2, round) => ` [${ts2}] round ${round}`,
|
|
1194
1202
|
wtCreateFail: (e) => `Failed to create worktree (the main workspace must be a git repo): ${e}`,
|
|
1195
1203
|
agentErrorLine: (id, err) => `\u{1F4A5} [${id}] agent error: ${err}`,
|
|
@@ -1212,6 +1220,7 @@ changes are harvested onto an isolated git worktree (temp branch), kept for manu
|
|
|
1212
1220
|
"accept-failed": "\u274C acceptance failed",
|
|
1213
1221
|
timeout: "\u23F1\uFE0F timed out",
|
|
1214
1222
|
error: "\u{1F4A5} agent error",
|
|
1223
|
+
"setup-failed": "\u{1F6E0}\uFE0F setup failed",
|
|
1215
1224
|
rejected: "\u{1F6AB} ticket rejected"
|
|
1216
1225
|
})[s],
|
|
1217
1226
|
spawnFail: (e) => `Spawn failed: ${e}`,
|
|
@@ -1223,10 +1232,10 @@ changes are harvested onto an isolated git worktree (temp branch), kept for manu
|
|
|
1223
1232
|
const money = c.costYuan !== null ? `\xA5${c.costYuan.toFixed(4)}` : "(unpriced model, no money counted)";
|
|
1224
1233
|
const hit = c.promptTokens > 0 ? Math.round(c.cachedTokens / c.promptTokens * 100) : 0;
|
|
1225
1234
|
const mins = Math.round(c.durationMs / 6e3) / 10;
|
|
1226
|
-
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)}` : ""}`;
|
|
1227
1236
|
},
|
|
1228
1237
|
noReceipt: "(no receipt \u2014 the run was truncated before finishing; cost per the usageLog aggregate above)",
|
|
1229
|
-
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)}` : ""}`,
|
|
1230
1239
|
rejectedTitle: "# Batch task rejected",
|
|
1231
1240
|
reportTitle: (title) => `# Batch task report: ${title}`,
|
|
1232
1241
|
statusEntry: (v) => `- Status: ${v}`,
|
|
@@ -8326,12 +8335,56 @@ function decodeEntities(s) {
|
|
|
8326
8335
|
return cp > 0 && cp <= 1114111 && !(cp >= 55296 && cp <= 57343) ? String.fromCodePoint(cp) : "";
|
|
8327
8336
|
}).replace(/&[a-z#0-9]+;/gi, (e) => named[e.toLowerCase()] ?? e);
|
|
8328
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
|
+
}
|
|
8329
8381
|
function pickSearchProvider() {
|
|
8330
8382
|
const forced = (process.env.SEARCH_PROVIDER || "").toLowerCase();
|
|
8383
|
+
if (forced === "deepseek" && dsApiKey()) return "deepseek";
|
|
8331
8384
|
if (forced === "tavily" && appConfig.tavilyApiKey) return "tavily";
|
|
8332
8385
|
if (forced === "ddg" || forced === "duckduckgo") return "duckduckgo";
|
|
8333
8386
|
if (forced === "bing") return "bing";
|
|
8334
|
-
return appConfig.tavilyApiKey ? "tavily" : "bing";
|
|
8387
|
+
return dsApiKey() ? "deepseek" : appConfig.tavilyApiKey ? "tavily" : "bing";
|
|
8335
8388
|
}
|
|
8336
8389
|
async function searchTavily(query, maxResults, signal) {
|
|
8337
8390
|
const apiKey = appConfig.tavilyApiKey;
|
|
@@ -8410,10 +8463,18 @@ async function searchDuckDuckGo(query, maxResults, signal) {
|
|
|
8410
8463
|
return { answer: "", results };
|
|
8411
8464
|
}
|
|
8412
8465
|
function formatSearchResults(query, provider, resp) {
|
|
8413
|
-
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;
|
|
8414
8475
|
const lines = resp.results.map((r, i) => `${i + 1}. ${r.title}
|
|
8415
8476
|
${r.url}
|
|
8416
|
-
${r.snippet.slice(0,
|
|
8477
|
+
${r.snippet.slice(0, snippetCap)}`);
|
|
8417
8478
|
const body = (resp.answer ? `\u{1F4A1} \u6458\u8981: ${resp.answer}
|
|
8418
8479
|
|
|
8419
8480
|
` : "") + lines.join("\n\n");
|
|
@@ -8464,7 +8525,7 @@ async function safeFetchFollow(startUrl, baseHeaders, signals, allowPrivate = fa
|
|
|
8464
8525
|
return res;
|
|
8465
8526
|
}
|
|
8466
8527
|
}
|
|
8467
|
-
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;
|
|
8468
8529
|
var init_web = __esm({
|
|
8469
8530
|
"../core/src/tool/registry/web.ts"() {
|
|
8470
8531
|
"use strict";
|
|
@@ -8494,6 +8555,12 @@ var init_web = __esm({
|
|
|
8494
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`;
|
|
8495
8556
|
}
|
|
8496
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;
|
|
8497
8564
|
MAX_REDIRECTS = 5;
|
|
8498
8565
|
pinnedSsrfDispatcher = new Agent({
|
|
8499
8566
|
connect: {
|
|
@@ -8574,13 +8641,14 @@ var init_web = __esm({
|
|
|
8574
8641
|
planAllowed: true,
|
|
8575
8642
|
primaryArg: "url",
|
|
8576
8643
|
autoApproval: "aggressive",
|
|
8577
|
-
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',
|
|
8578
8645
|
parameters: {
|
|
8579
8646
|
type: "object",
|
|
8580
8647
|
properties: {
|
|
8581
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" },
|
|
8582
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` },
|
|
8583
|
-
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" }
|
|
8584
8652
|
},
|
|
8585
8653
|
required: ["url"]
|
|
8586
8654
|
},
|
|
@@ -8593,6 +8661,44 @@ var init_web = __esm({
|
|
|
8593
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`,
|
|
8594
8662
|
async execute(args, ctx) {
|
|
8595
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
|
+
}
|
|
8596
8702
|
const allowPrivate = args.allow_private ?? appConfig.webFetchAllowPrivate;
|
|
8597
8703
|
let parsed;
|
|
8598
8704
|
try {
|
|
@@ -8657,7 +8763,7 @@ ${body}${truncNote}`;
|
|
|
8657
8763
|
planAllowed: true,
|
|
8658
8764
|
primaryArg: "query",
|
|
8659
8765
|
autoApproval: "aggressive",
|
|
8660
|
-
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",
|
|
8661
8767
|
parameters: {
|
|
8662
8768
|
type: "object",
|
|
8663
8769
|
properties: {
|
|
@@ -8680,7 +8786,17 @@ ${body}${truncNote}`;
|
|
|
8680
8786
|
if (ctx?.abortSignal) signals.push(ctx.abortSignal);
|
|
8681
8787
|
try {
|
|
8682
8788
|
const signal = AbortSignal.any(signals);
|
|
8683
|
-
|
|
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
|
+
}
|
|
8684
8800
|
return formatSearchResults(args.query, provider, resp);
|
|
8685
8801
|
} catch (error) {
|
|
8686
8802
|
if (error?.name === "TimeoutError") {
|
|
@@ -8689,7 +8805,8 @@ ${body}${truncNote}`;
|
|
|
8689
8805
|
if (error?.name === "AbortError") {
|
|
8690
8806
|
return `\u23F9\uFE0F [\u5DF2\u4E2D\u6B62]\uFF1A\u7528\u6237\u4E2D\u65AD\u4E86\u641C\u7D22\u3002`;
|
|
8691
8807
|
}
|
|
8692
|
-
|
|
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}`);
|
|
8693
8810
|
}
|
|
8694
8811
|
}
|
|
8695
8812
|
}
|
|
@@ -11799,7 +11916,8 @@ var init_toolExecution = __esm({
|
|
|
11799
11916
|
modelWindow,
|
|
11800
11917
|
parentSystemPrompt,
|
|
11801
11918
|
readTracker,
|
|
11802
|
-
reportCost
|
|
11919
|
+
reportCost,
|
|
11920
|
+
toolCostSink
|
|
11803
11921
|
} = ctx;
|
|
11804
11922
|
let calledName = "";
|
|
11805
11923
|
let calledArgs = {};
|
|
@@ -11837,7 +11955,7 @@ var init_toolExecution = __esm({
|
|
|
11837
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 } });
|
|
11838
11956
|
return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: false };
|
|
11839
11957
|
}
|
|
11840
|
-
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 };
|
|
11841
11959
|
let result = "";
|
|
11842
11960
|
let resultStatus = "success";
|
|
11843
11961
|
let errorCategory;
|
|
@@ -12815,13 +12933,34 @@ var init_usageLog = __esm({
|
|
|
12815
12933
|
});
|
|
12816
12934
|
|
|
12817
12935
|
// ../core/src/config/prices.ts
|
|
12818
|
-
var MODEL_PRICES, envPrice, ENV_OVERRIDE, priceFor, calcCostYuan;
|
|
12936
|
+
var MODEL_PRICES, PRICES_VERIFIED_AT, PRICES_STALE_DAYS, pricesAgeDays, isBeijingPeak, envPrice, ENV_OVERRIDE, priceFor, calcCostYuan;
|
|
12819
12937
|
var init_prices = __esm({
|
|
12820
12938
|
"../core/src/config/prices.ts"() {
|
|
12821
12939
|
"use strict";
|
|
12822
12940
|
MODEL_PRICES = {
|
|
12823
|
-
"deepseek-flash": {
|
|
12824
|
-
|
|
12941
|
+
"deepseek-flash": {
|
|
12942
|
+
idle: { input: 1, output: 4, cacheHit: 0.02 },
|
|
12943
|
+
peak: { input: 2, output: 8, cacheHit: 0.04 }
|
|
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
|
+
},
|
|
12950
|
+
"deepseek-v4-pro": {
|
|
12951
|
+
idle: { input: 4.5, output: 13.5, cacheHit: 0.15 },
|
|
12952
|
+
peak: { input: 9, output: 27, cacheHit: 0.3 }
|
|
12953
|
+
}
|
|
12954
|
+
};
|
|
12955
|
+
PRICES_VERIFIED_AT = "2026-10-19";
|
|
12956
|
+
PRICES_STALE_DAYS = 30;
|
|
12957
|
+
pricesAgeDays = () => Math.max(0, Math.floor((Date.now() - Date.parse(`${PRICES_VERIFIED_AT}T00:00:00Z`)) / 864e5));
|
|
12958
|
+
isBeijingPeak = (ts2 = /* @__PURE__ */ new Date()) => {
|
|
12959
|
+
const bj = new Date(ts2.getTime() + 8 * 36e5);
|
|
12960
|
+
const day = bj.getUTCDay();
|
|
12961
|
+
if (day === 0 || day === 6) return false;
|
|
12962
|
+
const h = bj.getUTCHours();
|
|
12963
|
+
return h >= 9 && h < 12 || h >= 14 && h < 18;
|
|
12825
12964
|
};
|
|
12826
12965
|
envPrice = (name) => {
|
|
12827
12966
|
const raw = process.env[name];
|
|
@@ -12836,8 +12975,9 @@ var init_prices = __esm({
|
|
|
12836
12975
|
if (input === void 0 && output === void 0 && cacheHit === void 0) return null;
|
|
12837
12976
|
return { input, output, cacheHit };
|
|
12838
12977
|
})();
|
|
12839
|
-
priceFor = (model) => {
|
|
12840
|
-
const
|
|
12978
|
+
priceFor = (model, ts2) => {
|
|
12979
|
+
const tier = MODEL_PRICES[model];
|
|
12980
|
+
const base = tier ? isBeijingPeak(ts2 ?? /* @__PURE__ */ new Date()) ? tier.peak : tier.idle : void 0;
|
|
12841
12981
|
if (!ENV_OVERRIDE) return base ?? null;
|
|
12842
12982
|
const input = ENV_OVERRIDE.input ?? base?.input;
|
|
12843
12983
|
const output = ENV_OVERRIDE.output ?? base?.output;
|
|
@@ -12845,8 +12985,8 @@ var init_prices = __esm({
|
|
|
12845
12985
|
if (input === void 0 || output === void 0 || cacheHit === void 0) return null;
|
|
12846
12986
|
return { input, output, cacheHit };
|
|
12847
12987
|
};
|
|
12848
|
-
calcCostYuan = (model, u) => {
|
|
12849
|
-
const p = priceFor(model);
|
|
12988
|
+
calcCostYuan = (model, u, ts2) => {
|
|
12989
|
+
const p = priceFor(model, ts2);
|
|
12850
12990
|
if (!p) return null;
|
|
12851
12991
|
const cached2 = Math.max(0, u.cachedTokens ?? 0);
|
|
12852
12992
|
const miss = Math.max(0, (u.promptTokens ?? 0) - cached2);
|
|
@@ -12934,6 +13074,13 @@ async function* runAgent(message, options) {
|
|
|
12934
13074
|
budgetSpentYuan += cost;
|
|
12935
13075
|
}
|
|
12936
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;
|
|
12937
13084
|
const toolCounts = {};
|
|
12938
13085
|
await appendEvent(sessionId, { dscEvent: "run.start", runId, depth });
|
|
12939
13086
|
try {
|
|
@@ -13115,7 +13262,10 @@ async function* runAgent(message, options) {
|
|
|
13115
13262
|
// 子 run 结束时把总花费记进本 run 预算累计器——父预算自动继承约束(子花费计入父 spent)。
|
|
13116
13263
|
reportCost: (yuan) => {
|
|
13117
13264
|
if (Number.isFinite(yuan) && yuan > 0) budgetSpentYuan += yuan;
|
|
13118
|
-
}
|
|
13265
|
+
},
|
|
13266
|
+
// ★ 按次计费工具成本上报(DeepSeek Search/Fetch):web 工具经 toolCtx.toolCostSink 拿到闭包,
|
|
13267
|
+
// 成功调用后按次上报进本 run 累计器。
|
|
13268
|
+
toolCostSink
|
|
13119
13269
|
};
|
|
13120
13270
|
const scheduleResult = yield* scheduleToolCalls(assistantMessage, message, toolCallCtx);
|
|
13121
13271
|
if (scheduleResult.kind === "aborted") {
|
|
@@ -13165,12 +13315,15 @@ async function* runAgent(message, options) {
|
|
|
13165
13315
|
totalTokens: usageSum?.total_tokens,
|
|
13166
13316
|
cachedTokens: usageSum?.cached_tokens,
|
|
13167
13317
|
costYuan: costKnown ? Math.round(costYuanAcc * 1e6) / 1e6 : void 0,
|
|
13318
|
+
toolCostYuan: toolCostYuanAcc > 0 ? Math.round(toolCostYuanAcc * 1e6) / 1e6 : void 0,
|
|
13319
|
+
// 按次计费工具花费(Search/Fetch)
|
|
13168
13320
|
tools: toolCounts
|
|
13169
13321
|
});
|
|
13170
13322
|
} catch {
|
|
13171
13323
|
}
|
|
13172
13324
|
try {
|
|
13173
|
-
|
|
13325
|
+
const spentTotal = costYuanAcc + toolCostYuanAcc;
|
|
13326
|
+
if (options.costSink && spentTotal > 0) options.costSink(Math.round(spentTotal * 1e6) / 1e6);
|
|
13174
13327
|
} catch {
|
|
13175
13328
|
}
|
|
13176
13329
|
try {
|
|
@@ -13184,6 +13337,8 @@ async function* runAgent(message, options) {
|
|
|
13184
13337
|
cachedTokens: usageSum.cached_tokens ?? 0,
|
|
13185
13338
|
cacheHitRate: prompt > 0 ? (usageSum.cached_tokens ?? 0) / prompt : 0,
|
|
13186
13339
|
costYuan: costKnown ? Math.round(costYuanAcc * 1e6) / 1e6 : null,
|
|
13340
|
+
toolCostYuan: toolCostYuanAcc > 0 ? Math.round(toolCostYuanAcc * 1e6) / 1e6 : void 0,
|
|
13341
|
+
// 按次计费工具花费(undefined 自动省略)
|
|
13187
13342
|
durationMs: Math.round(performance.now() - startTime),
|
|
13188
13343
|
budgetTruncated: budgetTruncated || void 0
|
|
13189
13344
|
// 预算截断标注(E2;undefined 自动省略)
|
|
@@ -15544,13 +15699,14 @@ var init_useChatState = __esm({
|
|
|
15544
15699
|
const durMs = obj.durationMs ?? 0;
|
|
15545
15700
|
const durText = durMs >= 6e4 ? `${Math.floor(durMs / 6e4)}m${Math.round(durMs % 6e4 / 1e3)}s` : `${(durMs / 1e3).toFixed(1)}s`;
|
|
15546
15701
|
const cost = obj.costYuan;
|
|
15702
|
+
const toolCost = typeof obj.toolCostYuan === "number" && obj.toolCostYuan > 0 ? obj.toolCostYuan : null;
|
|
15547
15703
|
const tokTotal = promptT + completionT;
|
|
15548
15704
|
const tokText = tokTotal >= 1e4 ? `${(tokTotal / 1e3).toFixed(1)}k` : String(tokTotal);
|
|
15549
15705
|
const costText = typeof cost === "number" ? `\xA5${cost.toFixed(cost < 5e-3 ? 4 : 3)}` : `${tokText} tok`;
|
|
15550
15706
|
setRows((prev) => [...prev, {
|
|
15551
15707
|
id: newRowId(),
|
|
15552
15708
|
kind: "meta",
|
|
15553
|
-
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" : ""}`
|
|
15554
15710
|
}]);
|
|
15555
15711
|
lastRunCostRef.current = typeof cost === "number" ? cost : void 0;
|
|
15556
15712
|
sessionCostRef.current = typeof cost === "number" ? (sessionCostRef.current ?? 0) + cost : sessionCostRef.current;
|
|
@@ -17163,6 +17319,7 @@ var init_inspect = __esm({
|
|
|
17163
17319
|
usageTopTools: (tools) => ` \u5E38\u7528\u5DE5\u5177: ${tools.join("\u3001") || "\uFF08\u65E0\uFF09"}`,
|
|
17164
17320
|
usageWeekCost: (cost, saved, unpriced) => ` \u8FD1 7 \u5929\u82B1\u8D39 \xA5${cost}\uFF08\u7F13\u5B58\u547D\u4E2D\u5DF2\u7701 \xA5${saved}\uFF09${unpriced > 0 ? ` \xB7 ${unpriced} \u6761\u65E0\u4EF7\u8BB0\u5F55\u672A\u8BA1` : ""}`,
|
|
17165
17321
|
usageTopSessions: (tops) => ` \u8D39\u7528 top \u4F1A\u8BDD: ${tops}`,
|
|
17322
|
+
usagePriceStale: (days, at) => ` \u26A0\uFE0F \u4EF7\u683C\u8868 ${at} \u6838\u5B9E\u540E\u5DF2 ${days} \u5929\u672A\u590D\u6838\u2014\u2014\u5B98\u7F51\u82E5\u5DF2\u8C03\u4EF7\uFF0C\u4E0A\u65B9\u82B1\u8D39\u4F1A\u5931\u771F\uFF08\u53EF\u8BBE DEEP_SEEK_PRICE_* \u4E34\u65F6\u6821\u51C6\uFF09\u3002`,
|
|
17166
17323
|
usageTip: " \u63D0\u793A\uFF1A\u5E76\u884C workflow \u4F1A\u653E\u5927\u5B50 agent \u7528\u91CF\uFF1B\u7F13\u5B58\u547D\u4E2D\u7387\u8D8A\u9AD8\uFF0C\u8F93\u5165\u6210\u672C\u8D8A\u4F4E\u3002",
|
|
17167
17324
|
ctxHead: "\u{1F9E0} \u4E0A\u4E0B\u6587\u6CBB\u7406",
|
|
17168
17325
|
ctxWindow: (window, threshold, ratio, keep) => ` \u7A97\u53E3\u4E0A\u9650: ${window} | \u538B\u7F29\u9608\u503C: ${threshold}\uFF08${ratio}\xD7\uFF09 | \u4FDD\u7559\u6700\u8FD1: ${keep} \u5BF9\u8BDD\u5355\u5143`,
|
|
@@ -17209,6 +17366,7 @@ var init_inspect = __esm({
|
|
|
17209
17366
|
usageTopTools: (tools) => ` Top tools: ${tools.join(", ") || "(none)"}`,
|
|
17210
17367
|
usageWeekCost: (cost, saved, unpriced) => ` 7-day spend \xA5${cost} (cache hits saved \xA5${saved})${unpriced > 0 ? ` \xB7 ${unpriced} unpriced records excluded` : ""}`,
|
|
17211
17368
|
usageTopSessions: (tops) => ` Costliest sessions: ${tops}`,
|
|
17369
|
+
usagePriceStale: (days, at) => ` \u26A0\uFE0F Price table verified on ${at}, ${days} days ago \u2014 if official pricing changed, costs above may drift (set DEEP_SEEK_PRICE_* to correct).`,
|
|
17212
17370
|
usageTip: " Tip: parallel workflows multiply sub-agent usage; higher cache hit rate means lower input cost.",
|
|
17213
17371
|
ctxHead: "\u{1F9E0} Context governance",
|
|
17214
17372
|
ctxWindow: (window, threshold, ratio, keep) => ` Window cap: ${window} | Compact threshold: ${threshold} (${ratio}\xD7) | Keep recent: ${keep} dialogue units`,
|
|
@@ -17319,12 +17477,13 @@ var init_inspect = __esm({
|
|
|
17319
17477
|
const bySession = /* @__PURE__ */ new Map();
|
|
17320
17478
|
let weekCost = 0, weekSaved = 0, pricedRuns = 0;
|
|
17321
17479
|
for (const r of weekRecords) {
|
|
17322
|
-
const
|
|
17480
|
+
const at = Number.isNaN(Date.parse(String(r.ts))) ? void 0 : new Date(r.ts);
|
|
17481
|
+
const c = r.costYuan ?? calcCostYuan(r.model, r, at);
|
|
17323
17482
|
if (c == null) continue;
|
|
17324
17483
|
pricedRuns++;
|
|
17325
17484
|
weekCost += c;
|
|
17326
17485
|
bySession.set(r.sessionId, (bySession.get(r.sessionId) ?? 0) + c);
|
|
17327
|
-
const p = priceFor(r.model);
|
|
17486
|
+
const p = priceFor(r.model, at);
|
|
17328
17487
|
if (p) weekSaved += (r.cachedTokens ?? 0) * (p.input - p.cacheHit) / 1e6;
|
|
17329
17488
|
}
|
|
17330
17489
|
if (pricedRuns > 0) {
|
|
@@ -17334,6 +17493,8 @@ var init_inspect = __esm({
|
|
|
17334
17493
|
if (tops) lines.push(t("usageTopSessions")(tops));
|
|
17335
17494
|
}
|
|
17336
17495
|
}
|
|
17496
|
+
const staleDays = pricesAgeDays();
|
|
17497
|
+
if (staleDays >= PRICES_STALE_DAYS) lines.push(t("usagePriceStale")(staleDays, PRICES_VERIFIED_AT));
|
|
17337
17498
|
lines.push(t("usageTip"));
|
|
17338
17499
|
return lines.join("\n");
|
|
17339
17500
|
};
|
|
@@ -18236,7 +18397,7 @@ ${lines.slice(-ACCEPT_TAIL_LINES).join("\n")}` : text;
|
|
|
18236
18397
|
};
|
|
18237
18398
|
collectSessionCost = async (sessionId) => {
|
|
18238
18399
|
const recs = (await readUsageRecords(2)).filter((r) => r.sessionId === sessionId);
|
|
18239
|
-
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 };
|
|
18240
18401
|
for (const r of recs) {
|
|
18241
18402
|
c.rounds += r.rounds || 0;
|
|
18242
18403
|
if (r.depth === 0) c.mainRounds += r.rounds || 0;
|
|
@@ -18245,6 +18406,7 @@ ${lines.slice(-ACCEPT_TAIL_LINES).join("\n")}` : text;
|
|
|
18245
18406
|
c.completionTokens += r.completionTokens ?? 0;
|
|
18246
18407
|
c.cachedTokens += r.cachedTokens ?? 0;
|
|
18247
18408
|
c.durationMs += r.durationMs || 0;
|
|
18409
|
+
c.toolCostYuan += r.toolCostYuan ?? 0;
|
|
18248
18410
|
if (typeof r.costYuan === "number") c.costYuan = (c.costYuan ?? 0) + r.costYuan;
|
|
18249
18411
|
else c.partialPrice = true;
|
|
18250
18412
|
}
|
|
@@ -18310,7 +18472,7 @@ ${diff}
|
|
|
18310
18472
|
const source = await fs49.promises.readFile(task.path, "utf-8");
|
|
18311
18473
|
const parsed = parseBatchTicket(source, getLocale());
|
|
18312
18474
|
if (!parsed.ok) {
|
|
18313
|
-
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 };
|
|
18314
18476
|
await finishTicket(task.id, `---
|
|
18315
18477
|
id: ${task.id}
|
|
18316
18478
|
title: ${task.id}
|
|
@@ -18357,6 +18519,36 @@ ${parsed.error}`);
|
|
|
18357
18519
|
return { status: "error", cost: cost2, budgetTruncated: false };
|
|
18358
18520
|
}
|
|
18359
18521
|
setSessionWorktree(sessionId, wt);
|
|
18522
|
+
if (t.setup) {
|
|
18523
|
+
emit2(T.setupLine(t.setup));
|
|
18524
|
+
const s = await runAcceptCommand(t.setup, wt.path);
|
|
18525
|
+
if (s.code !== 0 || s.timedOut) {
|
|
18526
|
+
const msg = `${T.setupFail(t.setup, s.code)}${s.timedOut ? T.acceptTimeoutSuffix : ""}
|
|
18527
|
+
|
|
18528
|
+
\`\`\`
|
|
18529
|
+
${s.output}
|
|
18530
|
+
\`\`\``;
|
|
18531
|
+
await killBackgroundTasksUnder(wt.path).catch(() => {
|
|
18532
|
+
});
|
|
18533
|
+
const cost2 = await collectSessionCost(sessionId);
|
|
18534
|
+
await finishTicket(task.id, buildReport({
|
|
18535
|
+
id: task.id,
|
|
18536
|
+
ticket: t,
|
|
18537
|
+
status: "setup-failed",
|
|
18538
|
+
budgetTruncated: false,
|
|
18539
|
+
cost: cost2,
|
|
18540
|
+
receipt: void 0,
|
|
18541
|
+
finalText: "",
|
|
18542
|
+
accept: null,
|
|
18543
|
+
deniedTools: [],
|
|
18544
|
+
diff: T.diffNone,
|
|
18545
|
+
wt,
|
|
18546
|
+
errorMessage: msg
|
|
18547
|
+
}));
|
|
18548
|
+
emit2(`\u{1F6E0}\uFE0F [${task.id}] ${T.setupFail(t.setup, s.code)}`);
|
|
18549
|
+
return { status: "setup-failed", cost: cost2, budgetTruncated: false };
|
|
18550
|
+
}
|
|
18551
|
+
}
|
|
18360
18552
|
const ac = new AbortController();
|
|
18361
18553
|
const timer = setTimeout(() => ac.abort(new Error(T.timeoutAbort(timeoutMin))), timeoutMin * 6e4);
|
|
18362
18554
|
let receipt;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepseeker-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.58",
|
|
4
4
|
"description": "DeepSeeker-Code 终端客户端(React Ink,in-process 直驱 runAgent)",
|
|
5
5
|
"homepage": "https://github.com/xknk/deepSeekCode#readme",
|
|
6
6
|
"repository": {
|
|
@@ -40,10 +40,11 @@
|
|
|
40
40
|
"node": ">=20"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"
|
|
44
|
-
"react": "18",
|
|
43
|
+
"ajv": "^8.20.0",
|
|
45
44
|
"ignore": "^7.0.5",
|
|
45
|
+
"ink": "5",
|
|
46
46
|
"openai": "^6.42.0",
|
|
47
|
+
"react": "18",
|
|
47
48
|
"undici": "^8.8.0",
|
|
48
49
|
"vscode-ripgrep": "^1.13.2"
|
|
49
50
|
},
|