@gamegeek-saikel/dsh-cost-meter 0.3.0-alpha.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/README.zh-CN.md +5 -4
- package/lib/client.js +93 -36
- package/lib/client.js.map +1 -1
- package/lib/index.js +103 -14
- package/lib/types/client/CostView.d.ts.map +1 -1
- package/lib/types/client/CostView.js +21 -8
- package/lib/types/client/SessionCostLine.d.ts.map +1 -1
- package/lib/types/client/SessionCostLine.js +15 -6
- package/lib/types/client/SessionCostPill.d.ts.map +1 -1
- package/lib/types/client/SessionCostPill.js +11 -5
- package/lib/types/client/cost-math.d.ts +27 -3
- package/lib/types/client/cost-math.d.ts.map +1 -1
- package/lib/types/client/cost-math.js +37 -7
- package/lib/types/client/locales.d.ts +1 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +2 -0
- package/lib/types/index.d.ts +4 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +8 -4
- package/lib/types/subagent-cost.d.ts +46 -14
- package/lib/types/subagent-cost.d.ts.map +1 -1
- package/lib/types/subagent-cost.js +127 -25
- package/lib/types/types.d.ts +16 -1
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/client/CostView.module.css +7 -0
- package/src/client/CostView.tsx +34 -16
- package/src/client/SessionCostLine.tsx +15 -6
- package/src/client/SessionCostPill.tsx +11 -5
- package/src/client/cost-math.ts +47 -6
- package/src/client/locales.ts +2 -0
- package/src/index.ts +13 -4
- package/src/subagent-cost.ts +163 -26
- package/src/types.ts +16 -1
package/README.md
CHANGED
|
@@ -47,7 +47,8 @@ Chat costs in DeepSeek pricing change over time (list prices, USD→CNY exchange
|
|
|
47
47
|
| Peak pricing | 2026-08-17 00:00 Beijing rollout; peak windows apply Monday–Friday only (the zh and en pages may state different timezones; fallback 09:00–12:00 / 14:00–18:00 Beijing), so Saturdays, Sundays, and all other hours are off-peak at half price |
|
|
48
48
|
| Cost formula | Uncached input + cache reads (hit rate) + cache writes (billed at uncached input rate) + output, per 1M tokens, CNY |
|
|
49
49
|
| Account balance | Official `GET /user/balance`, cached 60 s, single in-flight request, trust-fenced route |
|
|
50
|
-
| Subagent support | BFS over the live agent tree
|
|
50
|
+
| Subagent support | Enumerates the conversation's durable subagent tree through `subagents.listDescendants` (nested delegations, settled children, and cold subagent sessions included, with no depth cap); falls back to a BFS over the live agent tree when that service is not mounted |
|
|
51
|
+
| Conversation total | Main session + every descendant subagent (any depth); subagent totals still render while the main session's own ledger is not materialized |
|
|
51
52
|
| UI surfaces | Composer dock · Cost tab · per-reply chip · header pill (live estimate) · settings card |
|
|
52
53
|
| Locale | Simplified Chinese (source) + English |
|
|
53
54
|
| Complexity | Fully synchronous fold; O(1) price lookups via in-memory mirror |
|
|
@@ -59,7 +60,7 @@ Once installed, the plugin contributes five browser surfaces (all text shown in
|
|
|
59
60
|
| Surface | Slot | Description |
|
|
60
61
|
|---|---|---|
|
|
61
62
|
| Composer dock readout | `conversation.composer.dock` | Anchored session spend + account balance, refreshed every minute; hover for the category breakdown and snapshot info |
|
|
62
|
-
| Cost view tab | `conversation.view` | Whole-conversation totals (main +
|
|
63
|
+
| Cost view tab | `conversation.view` | Whole-conversation totals (main + every subagent nesting level), category totals, the per-subagent list with its depth, and the per-reply anchored ledger |
|
|
63
64
|
| Per-reply cost chip | `conversation.chat.assistant-actions` | The anchored cost of one finalized reply as the row's own stat capsule — the same trigger + anchored dialog the shipped 用量 and 用时 capsules use (28px pill, hover fill, `aria-expanded` dialog above the trigger). It closes the row's stat run: after 用量 and 用时, before the timestamp, spaced by the row's own gap, and coloured by the band that priced it (green off-peak, red peak). The dialog lists the three billed categories, the band with its multiplier, the model, and the snapshot version; the slot hands over the message id, which the `sessionCostIndex` projection resolves to ledger coordinates (dash `—` when unpriced) |
|
|
64
65
|
| Header pill | `conversation.session.header.utilities` | Anchored total, or a live `≈ ¥x.xx (estimate)` while streaming; click for the detail panel |
|
|
65
66
|
| Plugin card | `settings.plugin.item` | Per-model overrides, OpenRouter aliases, cache-read discount, FX mode, toggles, and manual refresh |
|
|
@@ -85,7 +86,7 @@ src/
|
|
|
85
86
|
pricebook.ts # Append-only snapshots, priority chain, storage domain
|
|
86
87
|
session-cost-projection.ts # sessionCost projection (immutable per-step ledger)
|
|
87
88
|
session-cost-index.ts # sessionCostIndex: message id → ledger coordinates
|
|
88
|
-
subagent-cost.ts #
|
|
89
|
+
subagent-cost.ts # Subagent cost aggregation (durable tree + live-registry fallback)
|
|
89
90
|
invariant.ts # Route-disposer symmetry invariant companion
|
|
90
91
|
client/ # Browser half: 5 slot components + math/format/locales
|
|
91
92
|
shared/
|
|
@@ -104,7 +105,7 @@ pnpm test # vitest run (hermetic, network stubbed)
|
|
|
104
105
|
pnpm build # tsc -b && tsdown (lib/ + lib/client.js)
|
|
105
106
|
```
|
|
106
107
|
|
|
107
|
-
The test suites are fully offline: pricing-page HTML, OpenRouter models, and the FX endpoint are all stubbed. Tests cover the trust fence, balance parsing, the pricebook priority chain and snapshot selection, the immutable ledger fold (including same-step replacement and peak/off-peak band selection at the *event* time), subagent
|
|
108
|
+
The test suites are fully offline: pricing-page HTML, OpenRouter models, and the FX endpoint are all stubbed. Tests cover the trust fence, balance parsing, the pricebook priority chain and snapshot selection, the immutable ledger fold (including same-step replacement and peak/off-peak band selection at the *event* time), the subagent aggregation (nested and cold children, listing-failure fallback, and a multi-level chain over a real `SessionStore` plus projection registry), and the client surfaces (jsdom).
|
|
108
109
|
|
|
109
110
|
## Documentation
|
|
110
111
|
|
package/README.zh-CN.md
CHANGED
|
@@ -47,7 +47,8 @@ DeepSeek 的价格随时间变化(官方价目表、USD→CNY 汇率、2026-08
|
|
|
47
47
|
| 峰值定价 | 2026-08-17 00:00 北京生效;高峰窗口仅周一至周五(中英文页面时区可能不同,缺省 09:00–12:00 / 14:00–18:00 北京),因此周六、周日全天及其余时段均为半价闲时 |
|
|
48
48
|
| 成本公式 | 未命中输入 + 缓存命中(命中价)+ 缓存写入(按未命中输入价计)+ 输出,每百万 tokens,CNY |
|
|
49
49
|
| 账户余额 | 官方 `GET /user/balance`,缓存 60 秒,单飞请求,路由带信任围栏 |
|
|
50
|
-
| 子代理支持 |
|
|
50
|
+
| 子代理支持 | 沿 `subagents.listDescendants` 枚举本会话持久子代理树(子代理再派生的孙代理、已结束或已冷启动的子会话都计入,无层数上限);未挂载该服务时回退到活跃代理树 BFS |
|
|
51
|
+
| 对话总花费 | 主会话 + 全部后代子代理(任意层数);主会话自身账本尚未就绪时仍展示子代理合计 |
|
|
51
52
|
| UI 表面 | 输入框读数 · 花费标签页 · 回复小标签 · 头部胶囊(实时估算)· 设置卡 |
|
|
52
53
|
| 本地化 | 简体中文(键源)+ 英文 |
|
|
53
54
|
| 复杂度 | 全同步折叠;经内存镜像 O(1) 查价 |
|
|
@@ -59,7 +60,7 @@ DeepSeek 的价格随时间变化(官方价目表、USD→CNY 汇率、2026-08
|
|
|
59
60
|
| 表面 | 插槽 | 说明 |
|
|
60
61
|
|---|---|---|
|
|
61
62
|
| 输入框下方读数 | `conversation.composer.dock` | 锚定的本会话花费 + 账户余额,每分钟刷新;悬停查看分类明细与快照信息 |
|
|
62
|
-
| 花费标签页 | `conversation.view` | 全对话总花费(主会话 +
|
|
63
|
+
| 花费标签页 | `conversation.view` | 全对话总花费(主会话 + 任意层级的子代理)、分类小计、带层级的子代理列表与逐回复锚定账本 |
|
|
63
64
|
| 每条回复成本小标签 | `conversation.chat.assistant-actions` | 单条已定稿回复的锚定成本,做成与官方「用量」「用时」完全同形的统计胶囊(28px 药丸、悬停底色、`aria-expanded` 展开锚定在触发件上方的对话框);位置收在统计串末:在「用量」「用时」之后、末尾时刻文本之前,间距沿用行自身的 gap;按计价档位着色(闲时绿、高峰红);对话框列出三类计费、档位与倍率、模型与快照版本;插槽只给出消息 id,由 `sessionCostIndex` 投影解析为账本坐标(无价格时显示 `—`) |
|
|
64
65
|
| 头部胶囊 | `conversation.session.header.utilities` | 锚定总花费;流式中显示 `预计 ¥x.xx(估算)`;点击展开详情面板 |
|
|
65
66
|
| 插件配置卡 | `settings.plugin.item` | 按模型覆盖价、OpenRouter 别名、缓存折扣、汇率模式、开关与立即刷新 |
|
|
@@ -85,7 +86,7 @@ src/
|
|
|
85
86
|
pricebook.ts # 只追加快照、优先级链、存储域
|
|
86
87
|
session-cost-projection.ts # sessionCost 投影(不可变逐步账本)
|
|
87
88
|
session-cost-index.ts # sessionCostIndex:消息 id → 账本坐标
|
|
88
|
-
subagent-cost.ts #
|
|
89
|
+
subagent-cost.ts # 子代理成本聚合(持久子代理树 + 活跃代理树回退)
|
|
89
90
|
invariant.ts # 路由释放对称性 invariant 伴生插件
|
|
90
91
|
client/ # 浏览器半区:5 个插槽组件 + 数学/格式化/本地化
|
|
91
92
|
shared/
|
|
@@ -104,7 +105,7 @@ pnpm test # vitest run(封闭式,网络 stub)
|
|
|
104
105
|
pnpm build # tsc -b && tsdown(lib/ + lib/client.js)
|
|
105
106
|
```
|
|
106
107
|
|
|
107
|
-
测试套件完全离线:价格页 HTML、OpenRouter 模型目录与汇率接口全部 stub
|
|
108
|
+
测试套件完全离线:价格页 HTML、OpenRouter 模型目录与汇率接口全部 stub。覆盖:信任围栏、余额解析、价格簿优先级链与快照选取、不可变账本折叠(含同一步替换与按*事件时间*选峰值/闲时档)、子代理聚合(持久子代理树的嵌套/冷会话/失败回退,以及真实 `SessionStore` + 投影注册表上的多层链路),以及客户端表面(jsdom)。
|
|
108
109
|
|
|
109
110
|
## 文档
|
|
110
111
|
|
package/lib/client.js
CHANGED
|
@@ -37,6 +37,7 @@ window.__ModuleLoader__.load({
|
|
|
37
37
|
"line.cacheRead": "缓存输入 {amount}",
|
|
38
38
|
"line.output": "输出 {amount}",
|
|
39
39
|
"line.subagent": "子代理 {amount}",
|
|
40
|
+
"subagent.depth": "第 {depth} 层",
|
|
40
41
|
"pill.label": "花费 {amount}",
|
|
41
42
|
"pill.estimate": "预计 {amount}",
|
|
42
43
|
"pill.estimateNote": "估算",
|
|
@@ -111,6 +112,7 @@ window.__ModuleLoader__.load({
|
|
|
111
112
|
"line.cacheRead": "Cached input {amount}",
|
|
112
113
|
"line.output": "Output {amount}",
|
|
113
114
|
"line.subagent": "Subagents {amount}",
|
|
115
|
+
"subagent.depth": "level {depth}",
|
|
114
116
|
"pill.label": "Cost {amount}",
|
|
115
117
|
"pill.estimate": "≈ {amount}",
|
|
116
118
|
"pill.estimateNote": "estimate",
|
|
@@ -246,23 +248,46 @@ window.__ModuleLoader__.load({
|
|
|
246
248
|
}
|
|
247
249
|
return sum;
|
|
248
250
|
}
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
/**
|
|
252
|
+
* Select the conversation's main ledger, the host-aggregated subagent rows,
|
|
253
|
+
* and their combined totals together, so no surface has to remember which
|
|
254
|
+
* pointer to compare against which total.
|
|
255
|
+
*
|
|
256
|
+
* All three are derived consistently: `combined` sums the main ledger with
|
|
257
|
+
* EVERY subagent row the host served — including nested ones — and is defined
|
|
258
|
+
* whenever either side has data. A conversation whose own ledger is not
|
|
259
|
+
* materialized yet (a session switch mid-flight, or a host that serves no main
|
|
260
|
+
* ledger) therefore still totals its subagents instead of rendering nothing.
|
|
261
|
+
*
|
|
262
|
+
* `main` is `null` when the main ledger is absent, in which case `mainSpend`
|
|
263
|
+
* is unknown (the dock shows 0 for a session with no spend of its own).
|
|
264
|
+
* @param main - the main session's projection totals, or undefined.
|
|
265
|
+
* @param subagents - the host-aggregated subagent rows.
|
|
266
|
+
* @returns the main readout, the subagent rows, combined totals, and both spend figures.
|
|
267
|
+
*/
|
|
268
|
+
function costLookupFor(main, subagents) {
|
|
269
|
+
const rows = subagents ?? [];
|
|
270
|
+
return {
|
|
271
|
+
main,
|
|
272
|
+
subagents: rows,
|
|
273
|
+
combined: combineTotals(main, rows),
|
|
274
|
+
mainSpend: main?.cost ?? 0,
|
|
275
|
+
subagentTotal: sumTotals(rows.map((entry) => entry.totals)).cost
|
|
276
|
+
};
|
|
253
277
|
}
|
|
254
278
|
/**
|
|
255
279
|
* The conversation-wide totals: the main session's ledger plus every
|
|
256
|
-
* subagent's ledger (host-aggregated). Undefined
|
|
257
|
-
*
|
|
280
|
+
* subagent's ledger (host-aggregated, all nesting levels). Undefined only when
|
|
281
|
+
* neither side carries a ledger.
|
|
258
282
|
* @param main - the main session's projection totals.
|
|
259
283
|
* @param subagents - the host-aggregated subagent totals.
|
|
260
|
-
* @returns the combined totals, or undefined.
|
|
284
|
+
* @returns the combined totals, or undefined without any ledger.
|
|
261
285
|
*/
|
|
262
286
|
function combineTotals(main, subagents) {
|
|
263
|
-
|
|
264
|
-
if (
|
|
265
|
-
|
|
287
|
+
const rows = subagents ?? [];
|
|
288
|
+
if (main === void 0) return rows.length === 0 ? void 0 : sumTotals(rows.map((entry) => entry.totals));
|
|
289
|
+
if (rows.length === 0) return main;
|
|
290
|
+
return sumTotals([main, ...rows.map((entry) => entry.totals)]);
|
|
266
291
|
}
|
|
267
292
|
/**
|
|
268
293
|
* The price band in effect at one instant (mirror of the host helper). The
|
|
@@ -507,10 +532,10 @@ window.__ModuleLoader__.load({
|
|
|
507
532
|
}, [sessionId, currency]);
|
|
508
533
|
const balance = response?.balance;
|
|
509
534
|
const balanceEnabled = response?.pricebook?.balanceEnabled !== false;
|
|
510
|
-
const
|
|
511
|
-
const combined =
|
|
512
|
-
const subSpend =
|
|
513
|
-
const mainSpend =
|
|
535
|
+
const lookup = costLookupFor(cost?.totals, response?.subagents);
|
|
536
|
+
const combined = lookup.combined;
|
|
537
|
+
const subSpend = lookup.subagentTotal;
|
|
538
|
+
const mainSpend = lookup.mainSpend;
|
|
514
539
|
const parts = [];
|
|
515
540
|
try {
|
|
516
541
|
const symbol = currencySymbol(currency);
|
|
@@ -526,10 +551,15 @@ window.__ModuleLoader__.load({
|
|
|
526
551
|
} catch {}
|
|
527
552
|
if (parts.length === 0) return null;
|
|
528
553
|
const model = cost?.model?.model;
|
|
554
|
+
const subagents = lookup.subagents;
|
|
529
555
|
const tooltipParts = (0, react.useMemo)(() => {
|
|
530
556
|
const rows = [];
|
|
531
557
|
try {
|
|
532
558
|
rows.push(...costDetail(cost, model, t, currency));
|
|
559
|
+
for (const subagent of subagents) {
|
|
560
|
+
const label = subagent.depth > 1 ? `${subagent.sessionId.slice(0, 8)} (${t("subagent.depth", { depth: String(subagent.depth) })})` : subagent.sessionId.slice(0, 8);
|
|
561
|
+
rows.push(`${label} ${currencySymbol(currency)}${formatMoney(subagent.totals?.cost ?? 0)}`);
|
|
562
|
+
}
|
|
533
563
|
if (subSpend > 0) rows.push(t("line.subagent", { amount: `${currencySymbol(currency)}${formatMoney(subSpend)}` }));
|
|
534
564
|
const pricebook = response?.pricebook;
|
|
535
565
|
if (pricebook !== void 0 && pricebook.current !== null) {
|
|
@@ -548,6 +578,7 @@ window.__ModuleLoader__.load({
|
|
|
548
578
|
balanceEnabled,
|
|
549
579
|
response,
|
|
550
580
|
subSpend,
|
|
581
|
+
subagents,
|
|
551
582
|
currency
|
|
552
583
|
]);
|
|
553
584
|
const line = parts.join(" · ");
|
|
@@ -570,7 +601,7 @@ window.__ModuleLoader__.load({
|
|
|
570
601
|
});
|
|
571
602
|
//#endregion
|
|
572
603
|
//#region \0dsh-css:/home/runner/work/dsh-cost-meter/dsh-cost-meter/src/client/CostView.module.css.mjs
|
|
573
|
-
const css$3 = ".fZF-xq_root{max-width:var(--dsh-chat-content-width);box-sizing:border-box;width:100%;color:var(--dsw-alias-label-primary);flex-direction:column;gap:16px;margin:0 auto;padding:16px 24px;font-size:13px;line-height:20px;display:flex}.fZF-xq_summary{flex-direction:column;gap:8px;display:flex}.fZF-xq_totalRow{justify-content:space-between;align-items:baseline;display:flex}.fZF-xq_totalLabel{font-size:15px;font-weight:600}.fZF-xq_totalValue{font-variant-numeric:tabular-nums;font-size:18px;font-weight:700}.fZF-xq_categories{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;gap:4px 16px;font-size:12px;display:flex}.fZF-xq_unpricedNote{color:var(--dsw-alias-label-secondary);opacity:.75;font-size:12px}.fZF-xq_steps{flex-direction:column;gap:8px;display:flex}.fZF-xq_stepsTitle{margin:0;font-size:13px;font-weight:600}.fZF-xq_stepList{flex-direction:column;gap:6px;margin:0;padding:0;list-style:none;display:flex}.fZF-xq_step{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:8px;flex-direction:column;gap:2px;padding:8px 10px;display:flex}.fZF-xq_step[data-band=peak]{border-color:var(--dsw-alias-state-error-secondary)}.fZF-xq_step[data-band=offPeak]{border-color:var(--dsw-alias-state-success-secondary)}.fZF-xq_step[data-band=peak] .fZF-xq_stepCost{color:var(--dsw-alias-state-error-primary)}.fZF-xq_step[data-band=offPeak] .fZF-xq_stepCost{color:var(--dsw-alias-state-success-primary)}.fZF-xq_stepHead{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.fZF-xq_stepTurn{font-weight:600}.fZF-xq_stepModel{color:var(--dsw-alias-label-secondary);font-size:12px}.fZF-xq_stepTime{color:var(--dsw-alias-label-secondary);opacity:.75;font-size:12px}.fZF-xq_stepCost{font-variant-numeric:tabular-nums;align-items:baseline;gap:6px;margin-left:auto;font-weight:600;display:inline-flex}.fZF-xq_stepBody{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;gap:12px;font-size:12px;display:flex}.fZF-xq_stepMeta{color:var(--dsw-alias-label-secondary);opacity:.75}";
|
|
604
|
+
const css$3 = ".fZF-xq_root{max-width:var(--dsh-chat-content-width);box-sizing:border-box;width:100%;color:var(--dsw-alias-label-primary);flex-direction:column;gap:16px;margin:0 auto;padding:16px 24px;font-size:13px;line-height:20px;display:flex}.fZF-xq_summary{flex-direction:column;gap:8px;display:flex}.fZF-xq_totalRow{justify-content:space-between;align-items:baseline;display:flex}.fZF-xq_totalLabel{font-size:15px;font-weight:600}.fZF-xq_totalValue{font-variant-numeric:tabular-nums;font-size:18px;font-weight:700}.fZF-xq_categories{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;gap:4px 16px;font-size:12px;display:flex}.fZF-xq_unpricedNote{color:var(--dsw-alias-label-secondary);opacity:.75;font-size:12px}.fZF-xq_steps{flex-direction:column;gap:8px;display:flex}.fZF-xq_subagents{flex-direction:column;gap:8px;margin-top:4px;display:flex}.fZF-xq_stepsTitle{margin:0;font-size:13px;font-weight:600}.fZF-xq_stepList{flex-direction:column;gap:6px;margin:0;padding:0;list-style:none;display:flex}.fZF-xq_step{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:8px;flex-direction:column;gap:2px;padding:8px 10px;display:flex}.fZF-xq_step[data-band=peak]{border-color:var(--dsw-alias-state-error-secondary)}.fZF-xq_step[data-band=offPeak]{border-color:var(--dsw-alias-state-success-secondary)}.fZF-xq_step[data-band=peak] .fZF-xq_stepCost{color:var(--dsw-alias-state-error-primary)}.fZF-xq_step[data-band=offPeak] .fZF-xq_stepCost{color:var(--dsw-alias-state-success-primary)}.fZF-xq_stepHead{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.fZF-xq_stepTurn{font-weight:600}.fZF-xq_stepModel{color:var(--dsw-alias-label-secondary);font-size:12px}.fZF-xq_stepTime{color:var(--dsw-alias-label-secondary);opacity:.75;font-size:12px}.fZF-xq_stepCost{font-variant-numeric:tabular-nums;align-items:baseline;gap:6px;margin-left:auto;font-weight:600;display:inline-flex}.fZF-xq_stepBody{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;gap:12px;font-size:12px;display:flex}.fZF-xq_stepMeta{color:var(--dsw-alias-label-secondary);opacity:.75}";
|
|
574
605
|
const tagId$3 = "@gamegeek-saikel/dsh-cost-meter/CostView.module.css";
|
|
575
606
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
|
|
576
607
|
const tag = document.createElement("style");
|
|
@@ -593,6 +624,7 @@ window.__ModuleLoader__.load({
|
|
|
593
624
|
"stepTurn": "fZF-xq_stepTurn",
|
|
594
625
|
"steps": "fZF-xq_steps",
|
|
595
626
|
"stepsTitle": "fZF-xq_stepsTitle",
|
|
627
|
+
"subagents": "fZF-xq_subagents",
|
|
596
628
|
"summary": "fZF-xq_summary",
|
|
597
629
|
"totalLabel": "fZF-xq_totalLabel",
|
|
598
630
|
"totalRow": "fZF-xq_totalRow",
|
|
@@ -616,6 +648,14 @@ window.__ModuleLoader__.load({
|
|
|
616
648
|
function reasonText(step, t) {
|
|
617
649
|
return t(`reason.${step.unpricedReason ?? "NO_PRICE"}`);
|
|
618
650
|
}
|
|
651
|
+
/**
|
|
652
|
+
* Indent a subagent row by its root-relative depth, so the nested delegation
|
|
653
|
+
* chain reads as a chain. Depth `-1` (`0`) marks a row the runtime fallback
|
|
654
|
+
* discovered, which states no distance: it keeps the top-level inset.
|
|
655
|
+
*/
|
|
656
|
+
function subagentIndent(depth) {
|
|
657
|
+
return { paddingLeft: `${Math.max(0, depth - 1) * 14}px` };
|
|
658
|
+
}
|
|
619
659
|
const CostView = (0, react.memo)(function CostView({ useProjection, sessionId, t }) {
|
|
620
660
|
const currency = displayCurrency(t);
|
|
621
661
|
const costCny = useProjection("sessionCost");
|
|
@@ -633,15 +673,18 @@ window.__ModuleLoader__.load({
|
|
|
633
673
|
alive = false;
|
|
634
674
|
};
|
|
635
675
|
}, [sessionId, currency]);
|
|
636
|
-
|
|
676
|
+
const rows = cost?.steps ?? [];
|
|
677
|
+
const lookup = costLookupFor(cost?.totals, response?.subagents);
|
|
678
|
+
const subagents = lookup.subagents;
|
|
679
|
+
const combined = lookup.combined;
|
|
680
|
+
const subSpend = lookup.subagentTotal;
|
|
681
|
+
const money = (value) => value === null ? "—" : `${symbol}${formatMoney(value)}`;
|
|
682
|
+
if (combined === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
637
683
|
className: CostView_module_css_default.root,
|
|
638
684
|
"data-testid": "cost-view-empty",
|
|
639
685
|
children: t("view.empty")
|
|
640
686
|
});
|
|
641
|
-
const
|
|
642
|
-
const totals = combineTotals(cost.totals, response?.subagents) ?? cost.totals;
|
|
643
|
-
const subSpend = subagentSpend(response?.subagents);
|
|
644
|
-
const money = (value) => value === null ? "—" : `${symbol}${formatMoney(value)}`;
|
|
687
|
+
const totals = combined;
|
|
645
688
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
646
689
|
className: CostView_module_css_default.root,
|
|
647
690
|
"data-testid": "cost-view",
|
|
@@ -682,7 +725,7 @@ window.__ModuleLoader__.load({
|
|
|
682
725
|
className: CostView_module_css_default.unpricedNote,
|
|
683
726
|
children: t("view.unpriced", { count: String(totals.unpricedSteps) })
|
|
684
727
|
}),
|
|
685
|
-
|
|
728
|
+
subagents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
686
729
|
className: CostView_module_css_default.subagents,
|
|
687
730
|
"data-testid": "cost-view-subagents",
|
|
688
731
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -690,34 +733,48 @@ window.__ModuleLoader__.load({
|
|
|
690
733
|
children: t("line.subagent", { amount: `${symbol}${formatMoney(subSpend)}` })
|
|
691
734
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
|
|
692
735
|
className: CostView_module_css_default.stepList,
|
|
693
|
-
children:
|
|
736
|
+
children: subagents.map((sub) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
694
737
|
className: CostView_module_css_default.step,
|
|
738
|
+
"data-testid": "cost-subagent",
|
|
739
|
+
"data-depth": String(sub.depth),
|
|
695
740
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
696
741
|
className: CostView_module_css_default.stepHead,
|
|
697
|
-
children: [
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
742
|
+
children: [
|
|
743
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
744
|
+
className: CostView_module_css_default.stepTurn,
|
|
745
|
+
style: subagentIndent(sub.depth),
|
|
746
|
+
children: sub.sessionId.slice(0, 8)
|
|
747
|
+
}),
|
|
748
|
+
sub.depth > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
749
|
+
className: CostView_module_css_default.stepModel,
|
|
750
|
+
children: t("subagent.depth", { depth: String(sub.depth) })
|
|
751
|
+
}),
|
|
752
|
+
sub.label !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
753
|
+
className: CostView_module_css_default.stepModel,
|
|
754
|
+
children: sub.label
|
|
755
|
+
}),
|
|
756
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
757
|
+
className: CostView_module_css_default.stepCost,
|
|
758
|
+
children: money(sub.totals?.cost ?? null)
|
|
759
|
+
})
|
|
760
|
+
]
|
|
704
761
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
705
762
|
className: CostView_module_css_default.stepBody,
|
|
706
763
|
children: [
|
|
707
764
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
708
765
|
t("view.uncached"),
|
|
709
766
|
": ",
|
|
710
|
-
money(sub.totals
|
|
767
|
+
money(sub.totals?.uncachedCost ?? null)
|
|
711
768
|
] }),
|
|
712
769
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
713
770
|
t("view.cacheRead"),
|
|
714
771
|
": ",
|
|
715
|
-
money(sub.totals
|
|
772
|
+
money(sub.totals?.cacheReadCost ?? null)
|
|
716
773
|
] }),
|
|
717
774
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
718
775
|
t("view.output"),
|
|
719
776
|
": ",
|
|
720
|
-
money(sub.totals
|
|
777
|
+
money(sub.totals?.outputCost ?? null)
|
|
721
778
|
] })
|
|
722
779
|
]
|
|
723
780
|
})]
|
|
@@ -1069,9 +1126,9 @@ window.__ModuleLoader__.load({
|
|
|
1069
1126
|
const model = projection?.model ?? null;
|
|
1070
1127
|
const snapshot = response?.pricebook.current ?? null;
|
|
1071
1128
|
const schedule = response?.pricebook.schedule;
|
|
1072
|
-
const
|
|
1073
|
-
const combined =
|
|
1074
|
-
const subSpend =
|
|
1129
|
+
const lookup = costLookupFor(projection?.totals, response?.subagents);
|
|
1130
|
+
const combined = lookup.combined;
|
|
1131
|
+
const subSpend = lookup.subagentTotal;
|
|
1075
1132
|
const symbol = currencySymbol(currency);
|
|
1076
1133
|
const estimate = (0, react.useMemo)(() => {
|
|
1077
1134
|
if (!running || projection === void 0) return null;
|
|
@@ -1090,7 +1147,7 @@ window.__ModuleLoader__.load({
|
|
|
1090
1147
|
partial,
|
|
1091
1148
|
currency
|
|
1092
1149
|
]);
|
|
1093
|
-
if (
|
|
1150
|
+
if (combined === void 0 && estimate === null) return null;
|
|
1094
1151
|
const total = combined?.cost ?? 0;
|
|
1095
1152
|
const label = estimate !== null ? t("pill.estimate", { amount: `${symbol}${formatMoney(estimate)}` }) : t("pill.label", { amount: `${symbol}${formatMoney(total)}` });
|
|
1096
1153
|
const last = projection?.steps.length !== void 0 && projection.steps.length > 0 ? projection.steps[projection.steps.length - 1] : void 0;
|