deepseeker-code 1.0.59 → 1.0.60

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +200 -151
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -12803,7 +12803,6 @@ var init_streamInference = __esm({
12803
12803
  payload: { input: msgText(message[message.length - 1].content) }
12804
12804
  // ★ 多模态:trace 只记文本视图
12805
12805
  });
12806
- console.log(`[DSC-DIAG] streamInference round ${round} \u5B8C\u6210: content=${contentBuf.length}chars reasoning=${reasoningBuf.length}chars toolCalls=${toolCallsBuf.size}`);
12807
12806
  return { kind: "completed", assistantMessage, usage: lastUsage };
12808
12807
  } catch (error) {
12809
12808
  if (signal?.aborted) {
@@ -12817,7 +12816,7 @@ var init_streamInference = __esm({
12817
12816
  payload: { input: msgText(message[message.length - 1].content), output: err.message }
12818
12817
  // ★ 多模态:文本视图
12819
12818
  });
12820
- console.log(`[DSC-DIAG] streamInference round ${round} \u2550\u2550\u2550 ERROR: ${err.message}`);
12819
+ console.error(`\u274C \u63A8\u7406\u5931\u8D25\uFF08round ${round}\uFF09\uFF1A${err.message}`);
12821
12820
  return { kind: "error", error: err };
12822
12821
  }
12823
12822
  };
@@ -13074,6 +13073,70 @@ ${PLAN_REJECT_TEXT(planRejectCount)}` };
13074
13073
  }
13075
13074
  });
13076
13075
 
13076
+ // ../core/src/config/prices.ts
13077
+ var MODEL_PRICES, PRICES_VERIFIED_AT, PRICES_STALE_DAYS, pricesAgeDays, isBeijingPeak, envPrice, ENV_OVERRIDE, priceFor, calcCostYuan;
13078
+ var init_prices = __esm({
13079
+ "../core/src/config/prices.ts"() {
13080
+ "use strict";
13081
+ MODEL_PRICES = {
13082
+ "deepseek-flash": {
13083
+ idle: { input: 1, output: 4, cacheHit: 0.02 },
13084
+ peak: { input: 2, output: 8, cacheHit: 0.04 }
13085
+ },
13086
+ // 官网脚注明示旧名按 Flash 价格计费(2026-10-19 核实),非猜测——与 flash 同价条目
13087
+ "deepseek-flash-vision-exp": {
13088
+ idle: { input: 1, output: 4, cacheHit: 0.02 },
13089
+ peak: { input: 2, output: 8, cacheHit: 0.04 }
13090
+ },
13091
+ "deepseek-v4-pro": {
13092
+ idle: { input: 4.5, output: 13.5, cacheHit: 0.15 },
13093
+ peak: { input: 9, output: 27, cacheHit: 0.3 }
13094
+ }
13095
+ };
13096
+ PRICES_VERIFIED_AT = "2026-10-19";
13097
+ PRICES_STALE_DAYS = 30;
13098
+ pricesAgeDays = () => Math.max(0, Math.floor((Date.now() - Date.parse(`${PRICES_VERIFIED_AT}T00:00:00Z`)) / 864e5));
13099
+ isBeijingPeak = (ts2 = /* @__PURE__ */ new Date()) => {
13100
+ const bj = new Date(ts2.getTime() + 8 * 36e5);
13101
+ const day = bj.getUTCDay();
13102
+ if (day === 0 || day === 6) return false;
13103
+ const h = bj.getUTCHours();
13104
+ return h >= 9 && h < 12 || h >= 14 && h < 18;
13105
+ };
13106
+ envPrice = (name) => {
13107
+ const raw = process.env[name];
13108
+ if (!raw) return void 0;
13109
+ const n = Number(raw);
13110
+ return Number.isFinite(n) && n >= 0 ? n : void 0;
13111
+ };
13112
+ ENV_OVERRIDE = (() => {
13113
+ const input = envPrice("DEEP_SEEK_PRICE_INPUT");
13114
+ const output = envPrice("DEEP_SEEK_PRICE_OUTPUT");
13115
+ const cacheHit = envPrice("DEEP_SEEK_PRICE_CACHEHIT");
13116
+ if (input === void 0 && output === void 0 && cacheHit === void 0) return null;
13117
+ return { input, output, cacheHit };
13118
+ })();
13119
+ priceFor = (model, ts2) => {
13120
+ const tier = MODEL_PRICES[model];
13121
+ const base = tier ? isBeijingPeak(ts2 ?? /* @__PURE__ */ new Date()) ? tier.peak : tier.idle : void 0;
13122
+ if (!ENV_OVERRIDE) return base ?? null;
13123
+ const input = ENV_OVERRIDE.input ?? base?.input;
13124
+ const output = ENV_OVERRIDE.output ?? base?.output;
13125
+ const cacheHit = ENV_OVERRIDE.cacheHit ?? base?.cacheHit;
13126
+ if (input === void 0 || output === void 0 || cacheHit === void 0) return null;
13127
+ return { input, output, cacheHit };
13128
+ };
13129
+ calcCostYuan = (model, u, ts2) => {
13130
+ const p = priceFor(model, ts2);
13131
+ if (!p) return null;
13132
+ const cached2 = Math.max(0, u.cachedTokens ?? 0);
13133
+ const miss = Math.max(0, (u.promptTokens ?? 0) - cached2);
13134
+ const completion = Math.max(0, u.completionTokens ?? 0);
13135
+ return (miss * p.input + cached2 * p.cacheHit + completion * p.output) / 1e6;
13136
+ };
13137
+ }
13138
+ });
13139
+
13077
13140
  // ../core/src/agent/costRelay.ts
13078
13141
  var createCostRelay;
13079
13142
  var init_costRelay = __esm({
@@ -13102,6 +13165,99 @@ var init_costRelay = __esm({
13102
13165
  }
13103
13166
  });
13104
13167
 
13168
+ // ../core/src/agent/runLedger.ts
13169
+ var BUDGET_HARD_LIMIT_RATIO, roundYuan6, createRunLedger;
13170
+ var init_runLedger = __esm({
13171
+ "../core/src/agent/runLedger.ts"() {
13172
+ "use strict";
13173
+ init_prices();
13174
+ init_costRelay();
13175
+ init_client();
13176
+ BUDGET_HARD_LIMIT_RATIO = 1.2;
13177
+ roundYuan6 = (y) => Math.round(y * 1e6) / 1e6;
13178
+ createRunLedger = (opts) => {
13179
+ let budgetSpentYuan = 0;
13180
+ let usageSum;
13181
+ let costYuanAcc = 0;
13182
+ let costKnown = true;
13183
+ let toolCostYuanAcc = 0;
13184
+ let auxCostYuanAcc = 0;
13185
+ let subCostYuanAcc = 0;
13186
+ const relay = createCostRelay(opts.costSink);
13187
+ const addUsage = (u) => {
13188
+ if (!u) return;
13189
+ usageSum = {
13190
+ prompt_tokens: (usageSum?.prompt_tokens ?? 0) + (u.prompt_tokens ?? 0),
13191
+ completion_tokens: (usageSum?.completion_tokens ?? 0) + (u.completion_tokens ?? 0),
13192
+ total_tokens: (usageSum?.total_tokens ?? 0) + (u.total_tokens ?? 0),
13193
+ cached_tokens: (usageSum?.cached_tokens ?? 0) + (u.cached_tokens ?? 0)
13194
+ };
13195
+ const cost = calcCostYuan(opts.model, { promptTokens: u.prompt_tokens, completionTokens: u.completion_tokens, cachedTokens: u.cached_tokens });
13196
+ if (cost == null) costKnown = false;
13197
+ else {
13198
+ costYuanAcc += cost;
13199
+ budgetSpentYuan += cost;
13200
+ }
13201
+ };
13202
+ const addToolCost = (yuan) => {
13203
+ if (!Number.isFinite(yuan) || yuan <= 0) return;
13204
+ toolCostYuanAcc += yuan;
13205
+ budgetSpentYuan += yuan;
13206
+ };
13207
+ const reportAuxUsage = (usage, kind) => {
13208
+ if (usage) {
13209
+ const cost = calcCostYuan(AUX_MODEL_NAME, { promptTokens: usage.prompt_tokens, completionTokens: usage.completion_tokens, cachedTokens: usage.cached_tokens });
13210
+ if (cost != null && Number.isFinite(cost) && cost > 0) {
13211
+ auxCostYuanAcc += cost;
13212
+ budgetSpentYuan += cost;
13213
+ }
13214
+ }
13215
+ try {
13216
+ opts.onAuxUsage?.(usage, kind);
13217
+ } catch {
13218
+ }
13219
+ };
13220
+ const reportSubCost = (yuan) => {
13221
+ if (Number.isFinite(yuan) && yuan > 0) {
13222
+ budgetSpentYuan += yuan;
13223
+ subCostYuanAcc += yuan;
13224
+ }
13225
+ };
13226
+ const snapshot = () => opts.budgetYuan != null ? { spent: budgetSpentYuan, budget: opts.budgetYuan } : null;
13227
+ return {
13228
+ addUsage,
13229
+ addToolCost,
13230
+ reportAuxUsage,
13231
+ reportSubCost,
13232
+ /** 预算 soft 判定读数(nudge 管线消费):未武装返回 null。O(1) 闭包读数。 */
13233
+ getBudgetStatus: snapshot,
13234
+ /** 预算硬线判定(E2):spent >= budget×1.2(>= 语义与收拢前逐字节等价,恰 1.2× 即触发)。
13235
+ * 自武装探测(inheritedBudgetCheck 兜底)与轮边界硬截断共用同一判定。 */
13236
+ overHardLimit: () => opts.budgetYuan != null && budgetSpentYuan >= opts.budgetYuan * BUDGET_HARD_LIMIT_RATIO,
13237
+ /** 子 run 成本中继 flush:基数=预算圈实时读数(子树完整口径,文件头★中继段)。主 run 无 sink 时 no-op。 */
13238
+ flushRelay: () => relay.flush(budgetSpentYuan),
13239
+ /** run.end 事件行与 receipt token 段共用的用量合计快照。 */
13240
+ usageSummary: () => usageSum,
13241
+ /** 预算读数快照:硬截断 final 文案金额源。未武装=null(调用方结构上只在已武装分支取,勿 ?? 0 兜底)。 */
13242
+ budgetSnapshot: snapshot,
13243
+ /** usageLog 落盘字段(recordUsageRun 入参金额段;costYuan 无价=undefined、各账 ≤0 省略——自动缺省容错)。 */
13244
+ usageLogFields: () => ({
13245
+ costYuan: costKnown ? roundYuan6(costYuanAcc) : void 0,
13246
+ toolCostYuan: toolCostYuanAcc > 0 ? roundYuan6(toolCostYuanAcc) : void 0,
13247
+ auxCostYuan: auxCostYuanAcc > 0 ? roundYuan6(auxCostYuanAcc) : void 0
13248
+ }),
13249
+ /** run.receipt 结算单金额段:costYuan 无价=null(显式「不知钱」,绝不编数);各账 ≤0 省略字段。 */
13250
+ receiptFields: () => ({
13251
+ costYuan: costKnown ? roundYuan6(costYuanAcc) : null,
13252
+ toolCostYuan: toolCostYuanAcc > 0 ? roundYuan6(toolCostYuanAcc) : void 0,
13253
+ auxCostYuan: auxCostYuanAcc > 0 ? roundYuan6(auxCostYuanAcc) : void 0,
13254
+ subCostYuan: subCostYuanAcc > 0 ? roundYuan6(subCostYuanAcc) : void 0
13255
+ })
13256
+ };
13257
+ };
13258
+ }
13259
+ });
13260
+
13105
13261
  // ../core/src/observability/usageLog.ts
13106
13262
  import fs34 from "fs/promises";
13107
13263
  import path37 from "path";
@@ -13209,70 +13365,6 @@ var init_usageLog = __esm({
13209
13365
  }
13210
13366
  });
13211
13367
 
13212
- // ../core/src/config/prices.ts
13213
- var MODEL_PRICES, PRICES_VERIFIED_AT, PRICES_STALE_DAYS, pricesAgeDays, isBeijingPeak, envPrice, ENV_OVERRIDE, priceFor, calcCostYuan;
13214
- var init_prices = __esm({
13215
- "../core/src/config/prices.ts"() {
13216
- "use strict";
13217
- MODEL_PRICES = {
13218
- "deepseek-flash": {
13219
- idle: { input: 1, output: 4, cacheHit: 0.02 },
13220
- peak: { input: 2, output: 8, cacheHit: 0.04 }
13221
- },
13222
- // 官网脚注明示旧名按 Flash 价格计费(2026-10-19 核实),非猜测——与 flash 同价条目
13223
- "deepseek-flash-vision-exp": {
13224
- idle: { input: 1, output: 4, cacheHit: 0.02 },
13225
- peak: { input: 2, output: 8, cacheHit: 0.04 }
13226
- },
13227
- "deepseek-v4-pro": {
13228
- idle: { input: 4.5, output: 13.5, cacheHit: 0.15 },
13229
- peak: { input: 9, output: 27, cacheHit: 0.3 }
13230
- }
13231
- };
13232
- PRICES_VERIFIED_AT = "2026-10-19";
13233
- PRICES_STALE_DAYS = 30;
13234
- pricesAgeDays = () => Math.max(0, Math.floor((Date.now() - Date.parse(`${PRICES_VERIFIED_AT}T00:00:00Z`)) / 864e5));
13235
- isBeijingPeak = (ts2 = /* @__PURE__ */ new Date()) => {
13236
- const bj = new Date(ts2.getTime() + 8 * 36e5);
13237
- const day = bj.getUTCDay();
13238
- if (day === 0 || day === 6) return false;
13239
- const h = bj.getUTCHours();
13240
- return h >= 9 && h < 12 || h >= 14 && h < 18;
13241
- };
13242
- envPrice = (name) => {
13243
- const raw = process.env[name];
13244
- if (!raw) return void 0;
13245
- const n = Number(raw);
13246
- return Number.isFinite(n) && n >= 0 ? n : void 0;
13247
- };
13248
- ENV_OVERRIDE = (() => {
13249
- const input = envPrice("DEEP_SEEK_PRICE_INPUT");
13250
- const output = envPrice("DEEP_SEEK_PRICE_OUTPUT");
13251
- const cacheHit = envPrice("DEEP_SEEK_PRICE_CACHEHIT");
13252
- if (input === void 0 && output === void 0 && cacheHit === void 0) return null;
13253
- return { input, output, cacheHit };
13254
- })();
13255
- priceFor = (model, ts2) => {
13256
- const tier = MODEL_PRICES[model];
13257
- const base = tier ? isBeijingPeak(ts2 ?? /* @__PURE__ */ new Date()) ? tier.peak : tier.idle : void 0;
13258
- if (!ENV_OVERRIDE) return base ?? null;
13259
- const input = ENV_OVERRIDE.input ?? base?.input;
13260
- const output = ENV_OVERRIDE.output ?? base?.output;
13261
- const cacheHit = ENV_OVERRIDE.cacheHit ?? base?.cacheHit;
13262
- if (input === void 0 || output === void 0 || cacheHit === void 0) return null;
13263
- return { input, output, cacheHit };
13264
- };
13265
- calcCostYuan = (model, u, ts2) => {
13266
- const p = priceFor(model, ts2);
13267
- if (!p) return null;
13268
- const cached2 = Math.max(0, u.cachedTokens ?? 0);
13269
- const miss = Math.max(0, (u.promptTokens ?? 0) - cached2);
13270
- const completion = Math.max(0, u.completionTokens ?? 0);
13271
- return (miss * p.input + cached2 * p.cacheHit + completion * p.output) / 1e6;
13272
- };
13273
- }
13274
- });
13275
-
13276
13368
  // ../core/src/agent/runAgent.ts
13277
13369
  async function* runAgent(message, options) {
13278
13370
  const sessionId = options.sessionId;
@@ -13300,15 +13392,22 @@ async function* runAgent(message, options) {
13300
13392
  let budgetTruncated = false;
13301
13393
  const MAX_AGENT_ROUNDS = 500;
13302
13394
  const firstPrompt = resolveFirstPrompt(message, options);
13303
- let budgetSpentYuan = 0;
13304
- let subCostYuanAcc = 0;
13395
+ const ledger = createRunLedger({
13396
+ model: effectiveModel,
13397
+ budgetYuan: depth === 0 && options.budgetYuan != null && options.budgetYuan > 0 ? options.budgetYuan : void 0,
13398
+ costSink: options.costSink,
13399
+ onAuxUsage: options.onAuxUsage
13400
+ });
13401
+ const reportAuxUsage = ledger.reportAuxUsage;
13402
+ const toolCostSink = process.env.DEEP_SEEK_TOOL_COST === "0" ? void 0 : ledger.addToolCost;
13305
13403
  let runCompactCount = 0;
13306
13404
  const nudges = createNudgeScheduler({
13307
13405
  firstPrompt,
13308
13406
  planMode: !!options.planMode,
13309
13407
  noEarlyFinal: !!options.noEarlyFinal,
13310
13408
  getContextUsage: () => ({ usedTokens: Math.round(estimateTokens(message) * calibRatio + toolsTokens), windowTokens: modelWindow }),
13311
- getBudgetStatus: depth === 0 && options.budgetYuan != null && options.budgetYuan > 0 ? () => ({ spent: budgetSpentYuan, budget: options.budgetYuan }) : void 0
13409
+ getBudgetStatus: ledger.getBudgetStatus
13410
+ // ★ E2 预算 soft 读数(闭包在账本内 O(1) 读数;未武装返回 null,管线自判)
13312
13411
  });
13313
13412
  const readTracker = /* @__PURE__ */ new Map();
13314
13413
  const userDecisionSource = depth > 0 ? "spawn_agent" : "user";
@@ -13330,47 +13429,7 @@ async function* runAgent(message, options) {
13330
13429
  let lastRealPromptTokens = persistedCalib.lastRealPromptTokens;
13331
13430
  let lastCachedTokens = persistedCalib.lastCachedTokens;
13332
13431
  const breaker = createRepeatBreaker({ sessionId, depth, llmDecisionSource, startTime, events });
13333
- let usageSum;
13334
- let costYuanAcc = 0;
13335
- let costKnown = true;
13336
- const addUsage = (u) => {
13337
- if (!u) return;
13338
- usageSum = {
13339
- prompt_tokens: (usageSum?.prompt_tokens ?? 0) + (u.prompt_tokens ?? 0),
13340
- completion_tokens: (usageSum?.completion_tokens ?? 0) + (u.completion_tokens ?? 0),
13341
- total_tokens: (usageSum?.total_tokens ?? 0) + (u.total_tokens ?? 0),
13342
- cached_tokens: (usageSum?.cached_tokens ?? 0) + (u.cached_tokens ?? 0)
13343
- };
13344
- const cost = calcCostYuan(effectiveModel, { promptTokens: u.prompt_tokens, completionTokens: u.completion_tokens, cachedTokens: u.cached_tokens });
13345
- if (cost == null) costKnown = false;
13346
- else {
13347
- costYuanAcc += cost;
13348
- budgetSpentYuan += cost;
13349
- }
13350
- };
13351
- let toolCostYuanAcc = 0;
13352
- const addToolCost = (yuan) => {
13353
- if (!Number.isFinite(yuan) || yuan <= 0) return;
13354
- toolCostYuanAcc += yuan;
13355
- budgetSpentYuan += yuan;
13356
- };
13357
- const toolCostSink = process.env.DEEP_SEEK_TOOL_COST === "0" ? void 0 : addToolCost;
13358
- let auxCostYuanAcc = 0;
13359
- const reportAuxUsage = (usage, kind) => {
13360
- if (usage) {
13361
- const cost = calcCostYuan(AUX_MODEL_NAME, { promptTokens: usage.prompt_tokens, completionTokens: usage.completion_tokens, cachedTokens: usage.cached_tokens });
13362
- if (cost != null && Number.isFinite(cost) && cost > 0) {
13363
- auxCostYuanAcc += cost;
13364
- budgetSpentYuan += cost;
13365
- }
13366
- }
13367
- try {
13368
- options.onAuxUsage?.(usage, kind);
13369
- } catch {
13370
- }
13371
- };
13372
- const costRelay = createCostRelay(options.costSink);
13373
- const inheritedBudgetCheck = options.budgetCheck ?? (depth === 0 && options.budgetYuan != null && options.budgetYuan > 0 ? () => budgetSpentYuan >= options.budgetYuan * 1.2 : void 0);
13432
+ const inheritedBudgetCheck = options.budgetCheck ?? (depth === 0 ? ledger.overHardLimit : void 0);
13374
13433
  let planWriteRej = 0;
13375
13434
  const toolCounts = {};
13376
13435
  await appendEvent(sessionId, { dscEvent: "run.start", runId, depth });
@@ -13401,11 +13460,12 @@ async function* runAgent(message, options) {
13401
13460
  yield { type: "final", text: lastContent || "\uFF08\u5DF2\u4E2D\u6B62\uFF09" };
13402
13461
  return;
13403
13462
  }
13404
- if (depth === 0 && options.budgetYuan != null && options.budgetYuan > 0 && budgetSpentYuan >= options.budgetYuan * 1.2) {
13463
+ if (depth === 0 && ledger.overHardLimit()) {
13464
+ const snap = ledger.budgetSnapshot();
13405
13465
  stopReason = "limit";
13406
13466
  budgetTruncated = true;
13407
13467
  yield { type: "final", text: (lastContent || "") + `
13408
- \uFF08\u{1F4B0} \u9884\u7B97\u622A\u65AD\uFF1A\u672C run \u5DF2\u82B1\u8D39 \xA5${budgetSpentYuan.toFixed(3)} / \u9884\u7B97 \xA5${options.budgetYuan.toFixed(3)}\u3002/budget \u8C03\u6574\u9884\u7B97\u540E\u56DE\u590D"\u7EE7\u7EED"\u5373\u53EF\u63A5\u7EED\u3002\uFF09` };
13468
+ \uFF08\u{1F4B0} \u9884\u7B97\u622A\u65AD\uFF1A\u672C run \u5DF2\u82B1\u8D39 \xA5${snap.spent.toFixed(3)} / \u9884\u7B97 \xA5${snap.budget.toFixed(3)}\u3002/budget \u8C03\u6574\u9884\u7B97\u540E\u56DE\u590D"\u7EE7\u7EED"\u5373\u53EF\u63A5\u7EED\u3002\uFF09` };
13409
13469
  return;
13410
13470
  }
13411
13471
  if (depth > 0 && options.budgetCheck?.()) {
@@ -13494,12 +13554,12 @@ async function* runAgent(message, options) {
13494
13554
  const estAtInfer = estimateTokens(message) + toolsTokens;
13495
13555
  if (estAtInfer > 1e3) {
13496
13556
  const observed = infResult.usage.prompt_tokens / estAtInfer;
13497
- calibRatio = calibRatio * 0.6 + observed * 0.4;
13557
+ calibRatio = calibRatio * CALIB_EMA_KEEP + observed * CALIB_EMA_NEW;
13498
13558
  }
13499
13559
  lastRealPromptTokens = infResult.usage.prompt_tokens;
13500
13560
  lastCachedTokens = infResult.usage.cached_tokens;
13501
13561
  }
13502
- addUsage(infResult.usage);
13562
+ ledger.addUsage(infResult.usage);
13503
13563
  const assistantMessage = infResult.assistantMessage;
13504
13564
  message.push(assistantMessage);
13505
13565
  await appendMessage({ ...assistantMessage, sessionId });
@@ -13509,7 +13569,7 @@ async function* runAgent(message, options) {
13509
13569
  if (!assistantMessage.tool_calls || assistantMessage.tool_calls.length === 0) {
13510
13570
  await appendEvent(sessionId, { dscEvent: "round.end", runId, round, usage: infResult.usage });
13511
13571
  emitContextUsage();
13512
- costRelay.flush(budgetSpentYuan);
13572
+ ledger.flushRelay();
13513
13573
  const finalText = (typeof assistantMessage.content === "string" ? assistantMessage.content : "") || "";
13514
13574
  const intercepted = nudges.interceptFinal(finalText, round);
13515
13575
  if (intercepted) continue;
@@ -13559,14 +13619,9 @@ async function* runAgent(message, options) {
13559
13619
  contextTokensEst: Math.round(estimateTokens(message) * calibRatio + toolsTokens),
13560
13620
  readTracker,
13561
13621
  // ★ P3-8:run 级读取追踪(同一引用透传,跨轮累计)
13562
- // ★ 子 run 成本回灌(成本信任链第二环 E1):runSubagent 经 toolCtx.reportCost 拿到闭包,
13563
- // 子 run 结束时把总花费记进本 run 预算累计器——父预算自动继承约束(子花费计入父 spent)。
13564
- reportCost: (yuan) => {
13565
- if (Number.isFinite(yuan) && yuan > 0) {
13566
- budgetSpentYuan += yuan;
13567
- subCostYuanAcc += yuan;
13568
- }
13569
- },
13622
+ // ★ 子 run 成本回灌(成本信任链第二环 E1):runSubagent 经 toolCtx.reportCost 把子 run 花费
13623
+ // 记进账本预算圈 + 展示账——父预算自动继承约束(守卫与分账语义在 runLedger.reportSubCost)。
13624
+ reportCost: ledger.reportSubCost,
13570
13625
  // ★ 按次计费工具成本上报(DeepSeek Search/Fetch):web 工具经 toolCtx.toolCostSink 拿到闭包,
13571
13626
  // 成功调用后按次上报进本 run 累计器。
13572
13627
  toolCostSink,
@@ -13591,7 +13646,7 @@ async function* runAgent(message, options) {
13591
13646
  }
13592
13647
  await appendEvent(sessionId, { dscEvent: "round.end", runId, round, usage: infResult.usage });
13593
13648
  emitContextUsage();
13594
- costRelay.flush(budgetSpentYuan);
13649
+ ledger.flushRelay();
13595
13650
  if (options.planMode && planWriteRej >= PLAN_REJECT_FORCE_AT) {
13596
13651
  stopReason = "limit";
13597
13652
  yield { type: "final", text: PLAN_REJECT_FORCE_FINAL_TEXT(planWriteRej) };
@@ -13615,10 +13670,11 @@ async function* runAgent(message, options) {
13615
13670
  } catch {
13616
13671
  }
13617
13672
  try {
13618
- await appendEvent(sessionId, { dscEvent: "run.end", runId, stopReason: signal?.aborted ? "aborted" : stopReason, rounds: round, usage: usageSum });
13673
+ await appendEvent(sessionId, { dscEvent: "run.end", runId, stopReason: signal?.aborted ? "aborted" : stopReason, rounds: round, usage: ledger.usageSummary() });
13619
13674
  } catch {
13620
13675
  }
13621
13676
  try {
13677
+ const us = ledger.usageSummary();
13622
13678
  void recordUsageRun({
13623
13679
  v: 1,
13624
13680
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -13629,40 +13685,33 @@ async function* runAgent(message, options) {
13629
13685
  stopReason: signal?.aborted ? "aborted" : stopReason,
13630
13686
  rounds: round,
13631
13687
  durationMs: Math.round(performance.now() - startTime),
13632
- promptTokens: usageSum?.prompt_tokens,
13633
- completionTokens: usageSum?.completion_tokens,
13634
- totalTokens: usageSum?.total_tokens,
13635
- cachedTokens: usageSum?.cached_tokens,
13636
- costYuan: costKnown ? Math.round(costYuanAcc * 1e6) / 1e6 : void 0,
13637
- toolCostYuan: toolCostYuanAcc > 0 ? Math.round(toolCostYuanAcc * 1e6) / 1e6 : void 0,
13638
- // 按次计费工具花费(Search/Fetch)
13639
- auxCostYuan: auxCostYuanAcc > 0 ? Math.round(auxCostYuanAcc * 1e6) / 1e6 : void 0,
13640
- // 辅助模型花费(压缩摘要+风险分类器,P0-2)
13688
+ promptTokens: us?.prompt_tokens,
13689
+ completionTokens: us?.completion_tokens,
13690
+ totalTokens: us?.total_tokens,
13691
+ cachedTokens: us?.cached_tokens,
13692
+ ...ledger.usageLogFields(),
13693
+ // costYuan/toolCostYuan/auxCostYuan(口径与舍入在 runLedger)
13641
13694
  tools: toolCounts
13642
13695
  });
13643
13696
  } catch {
13644
13697
  }
13645
13698
  try {
13646
- costRelay.flush(budgetSpentYuan);
13699
+ ledger.flushRelay();
13647
13700
  } catch {
13648
13701
  }
13649
13702
  try {
13650
- if (depth === 0 && options.onUIEvent && usageSum) {
13651
- const prompt = usageSum.prompt_tokens ?? 0;
13703
+ const us = ledger.usageSummary();
13704
+ if (depth === 0 && options.onUIEvent && us) {
13705
+ const prompt = us.prompt_tokens ?? 0;
13652
13706
  options.onUIEvent({
13653
13707
  type: "run.receipt",
13654
13708
  rounds: round,
13655
13709
  promptTokens: prompt,
13656
- completionTokens: usageSum.completion_tokens ?? 0,
13657
- cachedTokens: usageSum.cached_tokens ?? 0,
13658
- cacheHitRate: prompt > 0 ? (usageSum.cached_tokens ?? 0) / prompt : 0,
13659
- costYuan: costKnown ? Math.round(costYuanAcc * 1e6) / 1e6 : null,
13660
- toolCostYuan: toolCostYuanAcc > 0 ? Math.round(toolCostYuanAcc * 1e6) / 1e6 : void 0,
13661
- // 按次计费工具花费(undefined 自动省略)
13662
- auxCostYuan: auxCostYuanAcc > 0 ? Math.round(auxCostYuanAcc * 1e6) / 1e6 : void 0,
13663
- // 辅助模型花费(压缩摘要+风险分类器;undefined 自动省略)
13664
- subCostYuan: subCostYuanAcc > 0 ? Math.round(subCostYuanAcc * 1e6) / 1e6 : void 0,
13665
- // ★ Q12:子 run 花费并列展示(展示层补偿;undefined 自动省略)
13710
+ completionTokens: us.completion_tokens ?? 0,
13711
+ cachedTokens: us.cached_tokens ?? 0,
13712
+ cacheHitRate: prompt > 0 ? (us.cached_tokens ?? 0) / prompt : 0,
13713
+ ...ledger.receiptFields(),
13714
+ // costYuan(null=无价)/toolCostYuan/auxCostYuan/subCostYuan(口径与舍入在 runLedger)
13666
13715
  durationMs: Math.round(performance.now() - startTime),
13667
13716
  budgetTruncated: budgetTruncated || void 0
13668
13717
  // 预算截断标注(E2;undefined 自动省略)
@@ -13683,7 +13732,7 @@ async function* runAgent(message, options) {
13683
13732
  }
13684
13733
  }
13685
13734
  }
13686
- var resolveFirstPrompt;
13735
+ var CALIB_EMA_KEEP, CALIB_EMA_NEW, resolveFirstPrompt;
13687
13736
  var init_runAgent = __esm({
13688
13737
  "../core/src/agent/runAgent.ts"() {
13689
13738
  "use strict";
@@ -13700,11 +13749,11 @@ var init_runAgent = __esm({
13700
13749
  init_toolScheduling();
13701
13750
  init_streamInference();
13702
13751
  init_agentNudges();
13703
- init_costRelay();
13752
+ init_runLedger();
13704
13753
  init_usageLog();
13705
- init_prices();
13706
13754
  init_createModel();
13707
- init_client();
13755
+ CALIB_EMA_KEEP = 0.6;
13756
+ CALIB_EMA_NEW = 0.4;
13708
13757
  resolveFirstPrompt = (message, options) => {
13709
13758
  if ((options.depth ?? 0) !== 0) return "";
13710
13759
  const explicit = options.currentUserText?.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepseeker-code",
3
- "version": "1.0.59",
3
+ "version": "1.0.60",
4
4
  "description": "DeepSeeker-Code 终端客户端(React Ink,in-process 直驱 runAgent)",
5
5
  "homepage": "https://github.com/xknk/deepSeekCode#readme",
6
6
  "repository": {