Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/). 中文版见 [CHANGELOG_ZH.md](./CHANGELOG_ZH.md).

## [Unreleased]

### Added

- **Claude cost estimation** — built-in Anthropic Claude official API standard rates (USD per 1M tokens, verified 2026-11-05 against https://platform.claude.com/docs/en/about-claude/pricing): Fable 5.1 / 5, Mythos 5.1 / 5, Opus 5.5 / 5 / 4.8 / 4.7 / 4.6 / 4.5 / 4.1 / 4, Sonnet 5.5 / 5 / 4.6 / 4.5 / 4, Haiku 4.5. Flat across peak/off-peak; CNY converted at the fixed 6.76 rate. Claude Haiku 5.5 is intentionally not listed (prompt-length tiered pricing cannot be determined from per-round totals).
- **Separate cache-write pricing** — `BucketPrices` gains an optional `cacheWrite` rate (5-minute TTL write price for Claude); `pricing.json` accepts it too. When absent, cache writes are still billed at the cache-miss rate (DeepSeek behavior unchanged).
- **Model-id normalization** — `normalizeModelId` lower-cases, strips the `anthropic/` prefix and rewrites dotted Claude versions (`claude-opus-5.5` → `claude-opus-5-5`); used by the host resolver, `pricing.json` keys and the client snapshot lookup.
- **Unpriced rounds** — `RoundCost` / `ChartCost` / resolver results gain `unpriced`. Session totals that include unpriced rounds are shown as `≥` (lower bound) with a panel note; the current-model price line is hidden instead of showing `$0/1M`; compaction cost is left blank instead of `$0`.

### Changed

- **Unlisted Claude models are no longer billed at the DeepSeek fallback rate** — any model id containing `claude` (including Bedrock ids such as `anthropic.claude-…` / `us.anthropic.claude-…` and display names) that has no price resolves to zero rates and is marked unpriced, instead of the `deepseek-flash` fallback estimate that understated them by tens of times. DeepSeek models and a missing model name keep the flash fallback. This also changes the exported `pricingFor()` / `estimateCost()`: for such models they now return `UNPRICED_PRICING` / `0` (still `estimated: true`).
- **Longest-key price matching** — price-key lookup (`matchPricingKey`, shared by builtin, `pricing.json` and the client snapshot) now picks the exact key, else the longest matching prefix regardless of insertion order, so `claude-opus-5-5-20261101` resolves to Opus 5.5 rather than Opus 5. Claude keys only match the exact id or the id plus a dated snapshot suffix (`-YYYYMMDD` / `-latest`), so an unlisted newer version (e.g. `claude-opus-5-6`) is unpriced instead of borrowing a sibling's rate. Non-Claude keys keep the lenient prefix semantics.

### Fixed

- **Anomaly detection** skips unpriced rounds, so their zero cost no longer drags the baseline down and causes later priced rounds to be flagged as spikes.

### Compatibility

- Checked against DSH 0.2.2-rc.1 (installed app bundle): the peer-range admission check passes (`includePrerelease`), the missing `dsh-client-ui-slots` package is skipped by `dsh.client.inject`, both slots and their standard props are unchanged, and the fold handles 0.2.2-rc.1 session logs. DeepSeek model ids and list prices are unchanged (`deepseek-flash` = DeepSeek-V4.1-Flash-1017, `deepseek-v4-pro` = DeepSeek-V4-Pro-0813).

## [1.1.8] - 2026-10-22

### Fixed
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,28 @@
本文件记录本项目所有重要变更。格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。英文版见 [CHANGELOG.md](./CHANGELOG.md)。

## [未发布]

### 新增

- **Claude 成本估算**——内置 Anthropic Claude 官方 API 标准价(美元 / 1M tokens,2026-11-05 对照 https://platform.claude.com/docs/en/about-claude/pricing 核验):Fable 5.1 / 5、Mythos 5.1 / 5、Opus 5.5 / 5 / 4.8 / 4.7 / 4.6 / 4.5 / 4.1 / 4、Sonnet 5.5 / 5 / 4.6 / 4.5 / 4、Haiku 4.5。不分高峰/空闲;人民币按固定汇率 6.76 折算。Claude Haiku 5.5 暂不收录(按请求输入长度分档,按轮汇总无法判定档位)。
- **写缓存单独计价**——`BucketPrices` 新增可选 `cacheWrite`(Claude 取 5 分钟 TTL 写入价),`pricing.json` 同样支持;缺省时写缓存仍按「缓存未命中」价计(DeepSeek 行为不变)。
- **模型 ID 归一化**——`normalizeModelId` 转小写、去掉 `anthropic/` 前缀、把 Claude 点号版本改为连字符(`claude-opus-5.5` → `claude-opus-5-5`);宿主解析、`pricing.json` 键与 client 快照查找共用。
- **未定价轮次**——`RoundCost` / `ChartCost` / 解析结果新增 `unpriced`。会话合计含未定价轮次时显示为 `≥`(下限)并在面板提示;当前模型未定价时不再显示「$0/1M」刊例价行;压缩成本留空而非显示 `$0`。

### 变更

- **未收录的 Claude 模型不再按 DeepSeek 回退价估算**——型号名含 `claude` 且未定价的模型(含 Bedrock 写法 `anthropic.claude-…` / `us.anthropic.claude-…` 与显示名)解析为全零单价并标记未定价,不再套用会低估数十倍的 `deepseek-flash` 回退价;DeepSeek 系列与模型名缺失仍按 flash 回退估算。导出的 `pricingFor()` / `estimateCost()` 随之变化:此类模型现返回 `UNPRICED_PRICING` / `0`(仍为 `estimated: true`)。
- **价格键最长匹配**——价格键查找(`matchPricingKey`,内置表、`pricing.json` 与 client 快照共用)改为精确优先、其次最长前缀,与键的插入顺序无关:`claude-opus-5-5-20261101` 命中 Opus 5.5 而非 Opus 5。Claude 键只接受精确 ID 或「ID + 日期快照后缀」(`-YYYYMMDD` / `-latest`),未收录的新版本(如 `claude-opus-5-6`)显示为未定价,不借用相近型号的价格;非 Claude 键保持宽松前缀语义。

### 修复

- **成本异常检测**跳过未定价轮次,其零成本不再拉低基线、导致后续正常计价的轮次被误报为突增。

### 兼容性

- 对照已安装的 DSH 0.2.2-rc.1 应用包检查:peer 范围准入通过(`includePrerelease`);`dsh.client.inject` 中已不存在的 `dsh-client-ui-slots` 会被跳过;两个槽位及其标准 props 未变;fold 能处理 0.2.2-rc.1 会话日志。DeepSeek 模型 ID 与刊例价未变(`deepseek-flash` = DeepSeek-V4.1-Flash-1017,`deepseek-v4-pro` = DeepSeek-V4-Pro-0813)。

## [1.1.8] - 2026-10-22

### 修复
Expand Down
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Click ▸ to open the dashboard panel:

- **Session usage summary** — Input (uncached/cached), output, cache-hit percentage, and context occupancy (derived from official adapter `tokenUsage` / `contextPressure` projections).
- **Context breakdown & compaction diagnostics (v1.1.0)** — Official `contextBreakdown` projection breakdown (System prompt / Tools schema / Message history token counts and percentage with a 3-segment color bar, annotated as heuristic approximations); Host folds `compaction/*` events (which round was compacted, how many tokens were freed, model used, and summarize call cost); provides proactive suggestions (≥75% / ≥90% occupancy) to start a new session or reduce large file injections.
- **Cost estimation** — Estimated from official list prices (CNY/USD dual-currency per 1M tokens, peak/off-peak tiers) with verified source date; supports user override via `pricing.json`; unpriced models are explicitly tagged.
- **Cost estimation** — Estimated from official list prices (CNY/USD dual-currency per 1M tokens, peak/off-peak tiers) with verified source date; supports user override via `pricing.json`; built-in Anthropic Claude official API standard rates (USD); unpriced models are explicitly tagged.
- **Session-cost aggregation (v1.1.7)** — Adds the host's per-round costs using each round's model and billing tier. While a new round is in progress, the indicator and panel share the fetched history plus a marked estimate for new tokens, then refresh the history after token updates pause. The model label follows the same current-history/live-node priority in both places.
- **DSH 0.1.2+ and themed docks (v1.1.7)** — Reads conversation nodes from the independent `chat` source on newer DSH versions, with a legacy session-snapshot fallback; keeps the expanded panel anchored when a theme creates a fixed-position containing block.
- **DSH 0.2.x client-SDK compatibility (v1.1.8)** — Declares client peer ranges spanning both DSH 0.1.x and 0.2.x (tested against 0.2.1-rc.2) so DSH 0.2.x's plugin admission gate accepts the plugin at startup; the retired `@deepseek-ai/dsh-client-runtime` peer is gone, and the assistant-node model identity now also reads the 0.2.x `providerMetadata` field (0.1.x `provenance` still preferred when present, `requestConfig` kept as the last fallback).
Expand Down Expand Up @@ -165,11 +165,26 @@ Costs are resolved with priority **user override file > builtin list price > fal
}
```

Unit prices are **dual-currency (CNY + USD) per 1M tokens**: `peak` covers peak hours (Beijing time Monday–Friday 09:00–12:00 and 14:00–18:00, charged at 2×), `offPeak` covers the rest (including weekends). Unpriced models are explicitly marked "Unpriced model" in the UI.
Unit prices are **dual-currency (CNY + USD) per 1M tokens**: `peak` covers peak hours (Beijing time Monday–Friday 09:00–12:00 and 14:00–18:00, charged at 2×), `offPeak` covers the rest (including weekends). Prices may also carry an optional `cacheWrite` (cache-write rate); when omitted, cache writes are billed at the cache-miss rate.

**Models that are not listed** are explicitly marked "Unpriced model" in the UI:

- DeepSeek models (and a missing model name) are **estimated** at the `deepseek-flash` list price, shown with `≈`;
- models whose id contains `claude` (including Bedrock ids such as `anthropic.claude-…` and display names such as `Claude Opus 5.5`) are **not estimated**: their rates are zero and their cost is excluded, so they are never billed at DeepSeek rates (which would understate them by tens of times). A session total that includes such rounds is shown as `≥` (a lower bound) with a note in the panel; the cost badge and compaction cost do not show `$0`, and anomaly detection skips these rounds.

#### Claude models

Built-in standard rates from the [Anthropic pricing page](https://platform.claude.com/docs/en/about-claude/pricing) (USD per 1M tokens, verified 2026-11-05) cover Fable 5.1 / 5, Mythos 5.1 / 5, Opus 5.5 / 5 / 4.8 / 4.7 / 4.6 / 4.5 / 4.1 / 4, Sonnet 5.5 / 5 / 4.6 / 4.5 / 4 and Haiku 4.5:

- No peak/off-peak tiers; cache writes use the 5-minute TTL rate (usage cannot distinguish 1-hour TTL writes);
- Model-id matching normalizes the `anthropic/` prefix and dotted versions (`claude-opus-5.5`); ids with a dated snapshot suffix (`-20261101` / `-latest`) are priced as that model; any other variant (an unlisted newer version, `-fast`, `-batch`, Bedrock ids, …) is treated as unpriced and never borrows a similar model's rate;
- **Claude Haiku 5.5 is not listed yet**: it is priced by per-request prompt length (≤100K / >100K), which a per-round total cannot determine;
- Not included: batch discounts, regional / `inference_geo` premiums, Fast mode, tool fees;
- Anthropic only quotes USD; CNY amounts are converted at a **fixed rate of 6.76** (informational; they do not follow `cnyPerUsd` or the live rate).

### Display currency and live FX rate (v0.3+ / v1.0.1 official dual-currency)

Costs are computed with the **official list price of the selected currency** (CNY quote from the Chinese pricing page, USD quote from the English pricing page — **no FX conversion**, consistent with the official bill). The cost section has a one-click **CNY/USD** toggle (remembered in the browser); the indicator, panel, chart and badge all follow it. `config.cnyPerUsd` (default 6.76) and the "Refresh rate" button (via Host `/dsh-usage-chart/rate` proxy) are used only for the informational "1 USD ≈ X CNY" note:
Costs are computed with the **official list price of the selected currency** (CNY quote from the Chinese pricing page, USD quote from the English pricing page — **no FX conversion**, consistent with the official bill; the exception is the USD-only Claude models, whose CNY amounts use the fixed 6.76 rate described above). The cost section has a one-click **CNY/USD** toggle (remembered in the browser); the indicator, panel, chart and badge all follow it. `config.cnyPerUsd` (default 6.76) and the "Refresh rate" button (via Host `/dsh-usage-chart/rate` proxy) are used only for the informational "1 USD ≈ X CNY" note:

- **Multi-source fallback**: when the custom source (`config.fxUrl`) is unreachable, a built-in fallback source (frankfurter.dev) is tried;
- **Offline resilience**: the last successful rate is persisted, so a refresh while offline keeps the last real rate instead of the fixed default;
Expand Down
28 changes: 25 additions & 3 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

- **会话用量汇总** — 输入(未命中/命中)、输出、缓存命中率、上下文占用(均来自官方 adapter 上报的 `tokenUsage` / `contextPressure` 投影)
- **上下文构成与压缩诊断(v1.1.0)** — 官方 `contextBreakdown` 投影拆解(系统提示 / 工具定义 / 历史消息 Token 占比与分段条,标注启发式近似);宿主折叠 `compaction/*` 事件流(哪一轮被压缩、释放了多少 Token、生成摘要花费了多少成本与对应模型);结合上下文容量占比(≥75% / ≥90%)给出开新会话或精简大文件注入的优化建议
- **成本估算** — 按官方刊例价(CNY/USD 双币种 /1M tokens,高峰/空闲双时段)估算并标注来源与核验日期;支持用户覆盖 `pricing.json`;未定价模型显式标记「未定价模型」
- **成本估算** — 按官方刊例价(CNY/USD 双币种 /1M tokens,高峰/空闲双时段)估算并标注来源与核验日期;支持用户覆盖 `pricing.json`;内置 Anthropic Claude 官方 API 标准价(美元);未定价模型显式标记「未定价模型」
- **会话成本按轮汇总(v1.1.7)** — 按每轮实际模型和计费时段累加宿主成本;新轮进行中,指示器和面板共用“已读取历史+新增 token 的估算”,实时用量暂停更新后刷新宿主历史。两处模型名称采用相同的历史/实时来源顺序。
- **DSH 0.1.2+ 与皮肤兼容(v1.1.7)** — 新版从独立 `chat` 源读取会话节点,旧版回退到会话快照;皮肤创建 fixed 定位包含块时,展开面板仍贴近指示器。
- **兼容 DSH 0.2.x client SDK(v1.1.8)** — client peer 范围同时覆盖 DSH 0.1.x 与 0.2.x(已在 0.2.1-rc.2 上验证),DSH 0.2.x 的插件准入校验在启动时即可通过;已移除退役的 `@deepseek-ai/dsh-client-runtime` peer,助手节点模型标识新增读取 0.2.x 的 `providerMetadata` 字段(存在 0.1.x 的 `provenance` 时仍优先,`requestConfig` 保留为最后回退)。
Expand Down Expand Up @@ -190,12 +190,34 @@ dsh web --profile web
`offPeak` 为空闲时段(其余时间及周末全天)。兼容旧格式:平铺
`{ "cacheMissInput": …, "cacheHitInput": …, "output": … }` 视为高峰/空闲同价、
人民币报价(美元按默认汇率 6.76 折算)。`verifiedAt`(epoch 毫秒)可选,用于面板
展示核验日期;未收录的模型会在 UI 中显式标记「未定价模型」,不会静默按 0 计。
展示核验日期。单价可选 `cacheWrite`(写缓存价),缺省按「缓存未命中」价计。

**未收录的模型**会在 UI 中显式标记「未定价模型」:

- DeepSeek 系列(及模型名缺失)按 `deepseek-flash` 刊例价**回退估算**,金额带 `≈`;
- 型号名含 `claude` 的模型(含 Bedrock 写法 `anthropic.claude-…`、`Claude Opus 5.5` 等显示名)
**不估算**:单价记为 0、成本不计入,避免套用 DeepSeek 价造成数十倍低估。会话合计含此类
轮次时显示为 `≥`(下限)并在面板提示;成本徽章与压缩成本不显示 `$0`,成本异常检测跳过这些轮次。

#### Claude 系列

内置 [Anthropic 官方价格页](https://platform.claude.com/docs/en/about-claude/pricing) 的标准价
(美元 / 1M tokens,2026-11-05 核验),覆盖 Fable 5.1 / 5、Mythos 5.1 / 5、Opus 5.5 / 5 / 4.8 / 4.7 /
4.6 / 4.5 / 4.1 / 4、Sonnet 5.5 / 5 / 4.6 / 4.5 / 4、Haiku 4.5:

- 不分高峰/空闲;写缓存按 5 分钟 TTL 价计(用量无法区分 1 小时 TTL);
- 模型名匹配:`anthropic/` 前缀与点号版本(`claude-opus-5.5`)会归一化;带日期快照后缀
(`-20261101` / `-latest`)的 ID 按对应型号计价;其余变体(未收录的新版本、`-fast`、`-batch`、
Bedrock 写法等)一律视为未定价,不会被套上相近型号的价格;
- **Claude Haiku 5.5 暂不收录**:其价格按单次请求的输入长度分档(≤100K / >100K),按轮汇总无法判定档位;
- 不计入:批处理折扣、地区 / `inference_geo` 溢价、Fast mode、工具调用费;
- 官方只有美元报价,人民币金额按**固定汇率 6.76** 折算(参考值,不跟随 `cnyPerUsd` 与实时汇率)。

### 币种与汇率(v0.3+ / v1.0.1 官方双币种)

成本按**所选币种的官方刊例价**直接计算(中文定价页 CNY 报价 / 英文定价页 USD 报价,
**不做汇率换算**,与官方账单口径一致),面板成本区可一键切换 **CNY/USD**(选择在
**不做汇率换算**,与官方账单口径一致;例外:只有美元报价的 Claude 系列,人民币金额按固定汇率
6.76 折算,见上文),面板成本区可一键切换 **CNY/USD**(选择在
浏览器记住),指示器、面板、图表与成本徽章全部跟随。`config.cnyPerUsd`(默认 6.76)
与「刷新汇率」按钮(经宿主 `/dsh-usage-chart/rate` 代理)仅用于「1 USD ≈ X CNY」
参考注记:
Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Client 半区(浏览器):src/client/
| 模块 | 接口(小) | 实现(深) | 接缝 / 适配器 |
|---|---|---|---|
| **RoundFold**(`usage/rounds.ts`) | `foldRounds(events) → { totals, rounds }`,`Round = { turn, buckets, model, startedAt, endedAt, durationMs, ttftMs, outputTps, endReason, userSource, cost }` | 四桶 + 轮次耗时/来源/模型/成本;0.2.x 读取 message/attempt 的 usage 与 stream,TTFT 取首 token,TPS 分母为各次流式生成时长之和;旧日志保留 chunk/usage 回退(详见 2.5) | 纯函数,无 IO;测试喂合成事件流 |
| **PricingResolver**(`pricing/resolve.ts`) | `resolve(model) → { pricing, source, verifiedAt, estimated, known }` | 优先级解析(覆盖>内置>回退)、峰谷时段、未知模型标记、来源/时效标注 | **接缝:PricingSource**(见 2.3) |
| **PricingResolver**(`pricing/resolve.ts`) | `resolve(model) → { pricing, source, verifiedAt, estimated, known, unpriced }` | 优先级解析(覆盖>内置>回退)、峰谷时段、未知模型标记、来源/时效标注;键匹配走 `matchPricingKey`(精确 > 最长前缀,Claude 仅接受日期快照后缀);未收录的 Claude 不套 DeepSeek 回退价(`unpriced`,单价全零) | **接缝:PricingSource**(见 2.3) |
| **PricingCalc**(`pricing/calc.ts`) | `estimateCost / formatTokens / buckets 数学` | 纯共享计算,两个半区 bundle 同一份 | 无 IO;不解析来源 |
| **HostRoutes**(`src/index.ts`) | 注册 `/usage` `/balance` `/pricing` `/meta` `/rate` | 编排 RoundFold + PricingResolver + 安全守卫(沿用 `isTrustedRequest`) | 适配器:`webServer` 接缝 |
| **HistoryStore**(`history/store.ts`,v1.2) | `appendSample(round)` / `queryRange(from, to) → rows` | 聚合/按天落盘、索引、一键清除、导出 | **接缝:历史存储**(2.3) |
Expand Down
Loading
Loading