Skip to content

feat(desktop,mobile): 算不出模型报价时消息底部回退显示本轮 token - #1211

Merged
MagicLizi merged 2 commits into
mainfrom
dash/turn-token-fallback
Aug 1, 2026
Merged

feat(desktop,mobile): 算不出模型报价时消息底部回退显示本轮 token#1211
MagicLizi merged 2 commits into
mainfrom
dash/turn-token-fallback

Conversation

@dashhuang

@dashhuang dashhuang commented Jul 31, 2026

Copy link
Copy Markdown
Member

这次改了什么

摘要

消息底部原本只在能算出金额时显示费用;上游没有下发模型价格时,该位置会完全消失。现在 Desktop 与 Mobile 都会在没有金额但有本轮用量时回退显示紧凑 token 数,例如 2.1M tokens

本 PR 已按 review 收窄:不再沿用历史报价,不修改价格缓存,也不引入价格缓存锁。 有金额仍显示金额;没有金额才显示 token。

变更类型

  • feat 新功能
  • fix 缺陷修复
  • refactor / perf 重构或性能优化
  • docs / test / chore 文档、测试或工程维护
  • 其他:

范围

  • 关联 Issue / 需求:消息底部费用提示在价格不可用时消失
  • 本 PR 包含:
    • Desktop main 在费用为空时把现成的 TurnUsageDetails 写入消息 agent_meta,并复用现有 usage:message-turn-cost 推送。
    • Desktop 实时与历史消息分别读取金额、用户轮累计金额和 token 用量;金额优先,无金额才回退 token。
    • Mobile 实时与历史路径采用同一口径,并显示相同的 compact token 格式。
    • formatCompactTokens 下沉到 @cindy/maker-shared,Desktop 与 Mobile 复用。
    • 自动续跑多 segment 时,若收尾 segment 无价,仍保留前序 segment 已产生的用户轮累计金额,不被 token fallback 覆盖。
  • 明确不包含:
    • 沿用最后已知报价、approximate/reference-price 金额。
    • 价格快照、跨进程价格缓存锁、陈旧锁回收和缓存 verdict。
    • 服务端 /models 缺少价格字段的根因修复。
    • 跨轮聚合位置(TodaySpendChip / 首页仪表盘)的 token fallback。
  • 用户可见变化:无金额时,消息底部显示 2.1M tokens;有金额时维持原金额展示。
  • 是否存在 breaking change:无。复用现有推送 channel;payload 金额字段改为可选,旧消费方仍可忽略新增的 usage-only payload。

UI 变化

  • token fallback 复用原金额格的位置、12px 次要文本和现有语义颜色,不新增布局或颜色体系。
  • 引用的设计规范:
    • docs/design-rules/DESIGN.md §3 Typography Rules:沿用 Small 12px / weight 400。
    • docs/design-rules/DESIGN.md §5 Spacing System:沿用金额格既有间距和 24px 行高。
    • docs/design-rules/DESIGN.md §10 Light / Dark Dual-Mode Delivery Gate:Desktop 颜色继续使用既有语义 token;Mobile 复用既有 themed action metadata 样式,无硬编码单模式颜色。

怎么验证的

自动验证

Desktop 定向:5 files / 81 tests passed
Mobile 定向:4 files / 157 tests passed
maker-shared 定向:1 file / 6 tests passed
Desktop / Mobile / maker-shared typecheck:通过
pnpm check:i18n:通过(仅仓库既有非阻塞 warning)
pnpm check:i18n-glossary:通过
pnpm check:dco:通过(PR 共 2 个签名提交)
git diff --check origin/main...HEAD:通过

git skill 完整 unit gate:GATE_EXIT=0;
apps/desktop、apps/mobile、packages/maker-shared 及其余适用 workspace 全部 PASS。

手工验证

未执行。

未执行的验证

  • Light / Dark 实机目检均未执行;本次实现复用既有 themed 样式,但不把它表述为双模式已目检。
  • Mobile 未做模拟器 / 真机验证,无 Metro 与 build label 证据。

风险

风险分类

  • 无已知风险
  • SQLite / migration
  • system prompt
  • 协议兼容
  • 权限 / 安全 / 用户数据
  • 存量插件兼容(批准状态 / 指纹 / manifest 校验 / 安装布局 / 包格式)
  • 原生层 / fingerprint / OTA
  • 跨平台差异
  • 其他:

影响与回滚

  • 影响范围:仅消息级用量展示与现有 agent_meta JSON patch;不改数据库 schema,不写近似金额,不触碰计费账本。
  • Mobile 只改 TS/TSX 与 i18n,不修改 runtime fingerprint 输入,不触发冷更。
  • SSH 远程工作区不涉及 workdir 文件或远端执行;设备互联复用既有 allowlist 中的 usage:message-turn-cost push;Mobile 已同步适配实时与历史路径。
  • 回滚 / 降级方式:回滚本提交即可;已落库的 turnUsageDetails 对旧版本是可忽略的附加 JSON 字段。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s
  • UI 改动已注明设计规范章节
  • 未提交凭证、令牌或授权文件
  • 已确认测试结果或说明未执行原因

Copilot AI review requested due to automatic review settings July 31, 2026 10:04
@dashhuang
dashhuang requested a review from a team as a code owner July 31, 2026 10:04
@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

本 PR 在 Desktop 与 Mobile 的消息费用区域增加无金额时的本轮 token 用量回退展示。

  • Desktop main 将无可用金额时的 turnUsageDetails 持久化到消息元数据并通过现有用量频道广播,同时保留同一用户轮此前已产生的累计金额。
  • Desktop renderer 与 Mobile 同步支持实时推送和历史消息中的用量数据,并统一采用金额优先、token 回退的展示顺序。
  • formatCompactTokens 下沉至 @cindy/maker-shared,供两端复用紧凑 token 格式。

Confidence Score: 5/5

当前变更看起来可以安全合并。

当前 HEAD 已不包含此前报价缓存与跨进程判定相关的改动,先前线程所针对的失效机制不再存在,且本轮未发现仍需阻止合并的失败。

Important Files Changed

Filename Overview
apps/desktop/src/main/turnCostBroadcaster.ts 新增无金额时的消息级用量持久化与广播,并在存在前序 segment 金额时保留用户轮累计金额。
apps/desktop/src/main/maker-ipc/register.ts 将 Claude 与 Codex 的无报价完成路径接入 usage-only 消息记录流程,不改变费用账本口径。
apps/desktop/src/renderer/lib/makerChatStore.ts 扩展实时用量事件处理,使消息状态可独立接收金额和 token 明细。
apps/desktop/src/renderer/components/chat/MessageActionBar.tsx 消息操作栏改为金额优先,并在无金额时展示紧凑 token 数。
apps/mobile/src/session/remoteSessionStore.ts Mobile 实时消息存储接入 usage-only 推送并合并消息用量元数据。
apps/mobile/src/session/messageNormalize.ts Mobile 历史消息规范化新增 token 总量投影,同时保留结构化金额优先级。
apps/mobile/src/session/messageActions.ts Mobile 消息操作元数据增加共享 compact token 格式的回退展示。
packages/maker-shared/src/usageFormat.ts 提供 Desktop 与 Mobile 共用的紧凑 token 格式化函数。

Sequence Diagram

sequenceDiagram
    participant Agent as Agent turn
    participant Main as Desktop main
    participant DB as Message agent_meta
    participant Desktop as Desktop renderer
    participant Mobile as Mobile client
    Agent->>Main: turn completed with usage
    alt Amount available
        Main->>DB: Persist amount and usage
        Main-->>Desktop: Broadcast amount and usage
        Main-->>Mobile: Push amount and usage
        Desktop->>Desktop: Display amount
        Mobile->>Mobile: Display amount
    else Amount unavailable
        Main->>DB: Persist turnUsageDetails
        Main-->>Desktop: Broadcast usage-only payload
        Main-->>Mobile: Push usage-only payload
        Desktop->>Desktop: Display compact tokens
        Mobile->>Mobile: Display compact tokens
    end
Loading

Reviews (37): Last reviewed commit: "fix(mobile): canonicalize turn estimate ..." | Re-trigger Greptile

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a18ab6143

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated
Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 针对「模型报价缺失导致消息底部费用格为空、计费链路静默归零」的问题,在 desktop + mobile 两端把 TurnUsageDetails(token/缓存等用量事实) 从“依附金额”的分支中解耦出来:当金额不可得时,消息底部同一位置回退显示 X.XM tokens,并在 tooltip 中明确提示“取不到报价”,避免被误读为“免费”。

Changes:

  • 新增并共享 token 紧凑格式化口径 formatCompactTokens(maker-shared),desktop 侧改为 re-export、mobile 直接引用,保证两端展示一致
  • mobile / desktop 渲染层:当金额缺席且本轮 token > 0 时,消息操作条费用格回退显示 token,并补齐 turn 完成态判据与历史加载挂载
  • main 侧:新增 usage-only 的落库/广播路径;并在 XD 网关目录“整体无价”时补充告警与“保留上次已知报价(标 approximate)”的兜底

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/maker-shared/src/usageFormat.ts 新增共享的 token 紧凑格式化函数,供 desktop/mobile 共用
packages/maker-shared/src/tests/usageFormat.test.ts 新增对 token 紧凑格式化函数的单测覆盖
packages/maker-shared/package.json 增加 ./usage-format export,供外部包按路径导入
apps/mobile/src/session/remoteSessionStore.ts 支持从 payload 中独立写入 turnUsageDetails(无金额也可 patch)
apps/mobile/src/session/MessageRenderer.tsx 操作条金额缺席时回退渲染 token,并将 token 纳入 action bar 布局判定
apps/mobile/src/session/messageNormalize.ts agentMeta.turnUsageDetails.totalTokens 提取 turnTotalTokens,并把其作为 turn 收尾信号之一
apps/mobile/src/session/messageActions.ts 新增 formatMessageTurnTokens,复用共享 formatCompactTokens + i18n 输出
apps/mobile/src/i18n/locales/zh-CN/message.json 新增 turn token 回退展示与无障碍 label 所需文案
apps/mobile/src/i18n/locales/ko/message.json 同上(韩语)
apps/mobile/src/i18n/locales/ja/message.json 同上(日语)
apps/mobile/src/i18n/locales/en/message.json 同上(英文)
apps/mobile/src/tests/messageNormalize.test.ts 覆盖“无报价轮只落用量也应被视为 turn completed + 可提取 token”
apps/mobile/src/tests/messageActions.test.ts 覆盖 token 回退文案输出与边界输入
apps/desktop/src/renderer/lib/usageFormat.ts 改为从 maker-shared re-export formatCompactTokens,保持既有 import 路径不变
apps/desktop/src/renderer/lib/turnUsageTooltip.ts 无金额时在 tooltip 末尾追加“取不到报价”说明行
apps/desktop/src/renderer/lib/makerChatStore.ts 广播无金额但有用量时也更新消息状态;历史映射将 turnUsageDetails 作为收尾信号并独立挂载
apps/desktop/src/renderer/lib/tests/turnUsageTooltip.test.ts 新增无金额 tooltip 行为的单测覆盖
apps/desktop/src/renderer/i18n/locales/zh-CN/common.json 新增 tooltip 的 priceUnavailable 与 action bar token 文案
apps/desktop/src/renderer/i18n/locales/ko/common.json 同上(韩语)
apps/desktop/src/renderer/i18n/locales/ja/common.json 同上(日语)
apps/desktop/src/renderer/i18n/locales/en/common.json 同上(英文)
apps/desktop/src/renderer/components/chat/MessageStream.tsx turnUsageDetails 纳入 “completed assistant message” 判据
apps/desktop/src/renderer/components/chat/MessageActionBar.tsx 金额缺席时回退显示 token,并复用同一排版 className;tooltip 复用用量明细构建
apps/desktop/src/renderer/components/chat/tests/MessageActionBar.test.tsx 覆盖“无金额→token 回退”“金额为 0 视同无金额”等渲染逻辑
apps/desktop/src/main/usage/modelPricing.ts 目录整体无价时保留上次快照中仍在清单内的报价并标 approximate;补充 warn
apps/desktop/src/main/usage/tests/modelPricing.test.ts 覆盖“目录无价保留旧报价”“不复活下架模型”“不跨账号复用”等行为
apps/desktop/src/main/turnCostBroadcaster.ts MessageTurnCostPayload 金额字段改为可选;新增 recordTurnUsageOnMessage(usage-only 落库+广播)
apps/desktop/src/main/model-access/index.ts 目录整体无价时补充专门 warn(避免 0<0 静默)
apps/desktop/src/main/maker-ipc/register.ts Claude/Codex 多条无金额出口补入 usage-only 落库,确保 UI 可回退显示 token
apps/desktop/src/main/tests/turnCostBroadcaster.test.ts 覆盖 usage-only 路径“不碰账本字段/不带金额广播/patch 失败不广播”等

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/maker-shared/src/__tests__/usageFormat.test.ts
Comment thread packages/maker-shared/src/usageFormat.ts
Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated
dashhuang added a commit that referenced this pull request Jul 31, 2026
处理 #1211 首轮 review 的 6 条反馈,按底层不变量归成两族。

## 族一:retained 报价缺少边界与一致的持久化语义(4 条)

一句话不变量:**retained 报价是内存态的降级兜底 —— 只在目录本身可信但确实一个
priced model 都没有时启用,有最大年龄,且绝不写入磁盘缓存。**

原实现只判「投影为空」就沿用旧价,三个面都漏了:

- **写盘会自毁**(copilot / codex):retained quote 标 approximate=true,而同文件
  validateQuote 明确要求 approximate === false。写进磁盘后,下次冷启动 hydrate
  会把整份判无效(entries > 0 但全不通过 → validateCatalog 返回 null),重启即回到
  「无价 = 全链归零」;更糟的是它还覆盖掉了磁盘上最后一份**精确**快照。
  改为 retained 轮跳过写盘 —— 磁盘上留着精确快照,重启后 hydrate 正好恢复它。
- **陈旧价无限续期**(greptile P1):原来每个无价轮都会刷新 cacheAt 并重新保留,
  没有年龄上限,价格调整后仍会持续按旧价累计进 daily_spend / 会话总额 / 模型用量。
  新增 lastPricedAt(与 cacheAt 分开,只有真实报价才推进;冷启动由磁盘 fetchedAt
  播种,重启不重置)+ 24h 上限。超龄后钱不再记,token 回退仍保证可见性。
- **绕过混币目录的整份拒绝**(codex):混币目录(declared.size > 1)同样让
  gatewayPricingCatalog 返回 {},那是刻意保护 —— 混币 catalog 会被账本守卫按模型
  选择性丢弃,比整份没有报价更难发现。判据从「投影为空」改成
  「一个 priced model 都没有」(复用 isPricedGatewayModel),混币时维持整份拒绝。

## 族二:formatCompactTokens 跨档舍入(2 条)

999_999 曾输出 "1000.0k" —— 量级已经是 M、单位却还停在 k,自相矛盾。改为从小到大
选第一个「四舍五入后仍不满 1000」的单位,命中阈值即进档:999_999 → "1.0M"。
同步修正我自己那条把 "1000.0k" 当成期望值的测试断言。

验证:pnpm test:unit 全绿(GATE_EXIT=0,零 FAIL);desktop typecheck 与
maker-shared lint 通过。新增用例覆盖三条新边界(混币仍整份拒绝、超龄不再沿用且
retained 轮不续期、retained 轮不覆盖磁盘精确快照且冷启动能恢复它)与进位边界
(999_999 / 999_950 → 上一档、999_949_999 仍留本档、超出最大档继续用 B)。

Signed-off-by: Dash <dashhuang@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>
Copilot AI review requested due to automatic review settings July 31, 2026 10:30

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3c22b6910f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated no new comments.

dashhuang added a commit that referenced this pull request Jul 31, 2026
处理 #1211 第二轮 review 的 P1(codex):显式全 0 的免费目录会被误判成故障态。

`isPricedGatewayModel` 的语义是「会不会产出报价」,对「字段齐全但全为 0」的免费
模型返回 false。上一轮用它当兜底判据,于是「模型从付费调成免费」这件**有效的调价**
被当成「服务端没下发价格」,回退去沿用上一份付费报价 —— 已经免费的模型还会在消息
和账本里继续产生费用,最长 24 小时。

判据换成「目录是否**下发了**价格字段」:

- 新增 `declaresGatewayTokenPrice`(shared/modelPriceQuote.ts):任一标准 token 单价
  字段存在即为 true。与 `isPricedGatewayModel` 在全 0 目录上刻意分叉 —— 前者 true
  (确实下发了)、后者 false(产不出报价),注释写明了两者的分工。
- 只有「字段整体缺失」才是故障态,才允许启用兜底。显式 0、以及只下发部分字段的
  形状变化,都不再启用(宁可不记,不要错记)。

同时把混币判据收成单一来源:抽出 `hasMixedGatewayCurrencies`,由
`gatewayPricingCatalog`(整份拒绝)与计费兜底(拒绝启用)共用,不再两处各写一份。
顺带修掉上一轮借道 `isPricedGatewayModel` 判混币的漏洞 —— 「混币且无价」时它为
false,兜底会误启用。

验证:pnpm test:unit 全绿(GATE_EXIT=0,零 FAIL);desktop typecheck 通过。
新增 3 条用例:显式全 0 免费目录不复活付费报价、只下发部分价格字段不启用兜底、
混币且无价同样不启用。

Signed-off-by: Dash <dashhuang@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>
Copilot AI review requested due to automatic review settings July 31, 2026 10:53
@dashhuang

dashhuang commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

计费兜底的不变量清单(给后续 review 当锚点)

已随第七轮 review 更新(f2b89edd):年龄闸也收敛进共用判据,并补上「磁盘写入」一节。第六轮起本文档描述「当前结构」而非变更日志。

一句话不变量

retainKnownGatewayQuotes 产出的报价是内存态的降级兜底:仅当「目录可信 + 一个价格字段都没下发 + 币种与旧报价同源 + 未超龄 + 该模型仍在清单」全部成立时启用。磁盘上永远只存精确快照;只要 scope 处于无价故障态,对外给出的报价一律经同一处投影标为近似。

结构:一个状态 + 一处投影

「沿用最后已知报价」有三条路径,此前各自判断、各自标记(漏洞就出在这里):

路径 现在怎么做
内存 → 内存(retainKnownGatewayQuotes 取旧报价后交给 asApproximateQuotes()
磁盘 → 内存(hydrateFromDisk 恢复精确快照;若 unpricedFailureScope === scope,同样交给 asApproximateQuotes() 得到工作副本,磁盘不改写
内存 → 磁盘(writeDiskCache(preserveDiskQuotes) 磁盘已有精确快照时整份保留,一个字段都不动
  • unpricedFailureScope —— 唯一的「当前处于网关不下发价格故障态」标记,在 replaceGatewayModelPricing 里进入/清除(目录恢复正常、换 scope、登出都清)。
  • asApproximateQuotes() —— 唯一的「标近似」实现。approximate 是下游唯一的降级信号源(→ estimateReasons: ['reference-price'] → 两端 UI 的 ~ 前缀与来源说明),所以标记点唯一 ⇒ 展示口径唯一
  • isRetainablePricingAge() —— 唯一的年龄闸(不变量 b)实现,同样两条路径共用。第七轮补上:此前它只在内存路径,磁盘沿用路径完全没查年龄,离线数天后开机 / 断网期跨重启会拿陈旧价记账。
  • 同源三件套 —— 报价、accountCurrencyfetchedAt(年龄基准)必须来自同一份快照:要么整份换、要么整份留,绝不混搭。

判据同样都是单一来源:混币 → hasMixedGatewayCurrencies;单一币种声明 → declaredSingleGatewayCurrency;是否下发价格 → declaresGatewayTokenPrice(与「是否产出报价」的 isPricedGatewayModel 刻意分家 —— 显式全 0 是有效免费声明,字段缺失才是故障)。

启用条件:全部对称路径

目录状态 启用兜底? 判据 用例
空目录(登出 / clear) models.length === 0 never revives quotes for models that left the catalog
scope 变化(换号 / 换区 / 换 key) cacheScope !== scope does not carry retained quotes across accounts
混币 有价 hasMixedGatewayCurrencies keeps rejecting mixed-currency catalogs...
混币 无价 同上 does not fall back for a mixed-currency catalog even when it carries no prices
显式全 0(付费改免费) declaresGatewayTokenPrice never revives paid quotes for a catalog that explicitly prices everything at zero
只下发部分价格字段 同上(宁可不记,不要错记) does not fall back when only some price fields are present
显式声明了另一种币种 declaredSingleGatewayCurrency ≠ 旧报价币种 does not reuse retained quotes when the catalog switches currency
字段整体缺失 + 有旧报价 + 未超龄 全条件满足 retains last known quotes for models still listed when the catalog drops all prices
字段整体缺失 + 超龄(>24h) lastPricedAt 判据 stops reusing retained quotes once the last real pricing is too old
字段整体缺失 + 内存无旧报价(冷启动竞态) ✗(但磁盘可恢复) !cache?.xd;随后由迟到的 hydrate 补上 lets a late hydrate recover the disk snapshot after an unpriced cold-start sync
旧快照里有、本次已下架的模型 ✗(逐条过滤) 按本次清单过滤 never revives quotes for models that left the catalog

时序与持久化

  • retained 轮不续期:年龄基准 lastPricedAtcacheAt 分开,只有真实报价才推进;冷启动由磁盘 fetchedAt 播种,重启不重新给陈旧价 24 小时。
  • 故障轮不覆盖、不阻断磁盘:不标 hydratedScopes(否则迟到的 prewarm 被 getModelPricing / hydrateFromDisk 短路挡住,永远读不回精确快照);getModelPricing 的短路条件是「内存已有报价 已确认过磁盘」。
  • accountCurrency 仍随快照落盘:磁盘上没有精确报价时(如只声明 currency 的目录)照常写入 —— 账本币种要能随快照恢复,这个事实与有无报价无关。用例:restores the active ledger currency when only the disk cache is hydratedkeeps the preserved disk snapshot internally consistent (quotes + currency + age)
  • 故障标记会被清掉:目录恢复正常后精确报价不再被说成近似。用例:recovers a precise snapshot as-is once the catalog carries prices again

磁盘写入

  • 原子:写临时文件 + 同目录 renamefs.writeFile 是「截断 + 逐块写」,并发写会让读者拿到半截 JSON,hydrate 只能 catch 成缓存失效 → 冷启动又没有报价。
  • 串行enqueueDiskWrite 链,让 preserveDiskQuotes 分支的「读盘 → 决定 → 写盘」不被另一次写入插队。
  • 绝不落降级报价preserveDiskQuotes 且磁盘尚无快照时,只落 accountCurrency、报价留空 —— approximate 过不了 validateQuote,写进去等于让下次 hydrate 整份判无效。
  • 测试须 flush:串行化把写盘推到微任务之后,用例结束时可能还没执行,那时 app.getPath 的 mock 已 restore、路径退化成相对路径会污染工作区。__flushDiskWritesForTesting()afterEach 调用,.gitignore 再兜一道。
  • 用例:keeps the disk cache parseable under back-to-back syncsnever persists an approximate retained quote when the disk has no snapshot yet

展示层

  • 降级金额自证来源:retained / 故障态工作副本的 kind 仍是 actual-cost(它确实是成本量级,不是订阅价值折算),因此不走「价值」文案;Desktop 加 ~ 前缀 + tooltip 的 referencePriceLine,Mobile 加 ~(判据 approximate && kind === 'actual-cost'usdMoneyactual-cost 恒给 approximate=false,故只命中降级副本)。
  • 无金额说明不断言原因:展示层分不清「价格字段缺失」与「显式免费」,文案用中性的 noBilledCost;缺价故障态的可观测性由 main 侧 carry no price fields at all 告警承担(判据同源)。

超出本 PR 范围(如实登记)

磁盘缓存本身没有 TTL —— 冷启动 hydrate 一份很旧的精确快照仍会用于计费。这是本 PR 之前就有的既有行为;给它加 TTL 会影响正常冷启动路径,需要单独评估,没有塞进这个 PR。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ab4fb31da

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/usage/modelPricing.ts
Comment thread apps/desktop/src/main/turnCostBroadcaster.ts Outdated
Comment thread apps/desktop/src/main/model-access/index.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated no new comments.

Suppressed comments (1)

apps/desktop/src/main/model-access/index.ts:174

  • 这里用 pricedCount === 0 来判定「整个目录一个价都没有」会把“显式全 0 的免费目录”(各价格字段都下发但为 0)也误报成故障;同时当冷启动且 quoteCount===0 时日志会写成“falls back to 0 retained quote(s)”,与实际不符。建议改成按“是否下发过任何 token 单价字段”来判断缺价故障态,并在无 retained quote 时输出更准确的文案。
  } else if (pricedCount === 0 && models.length > 0) {
    // 上面那条覆盖率告警的条件是 quoteCount < pricedCount,「整个目录一个价都没有」
    // 恰好是 0 < 0 → 不成立 → 全程静默。而这正是最该报的情形:计费链会整条归零
    // (2026-07-30 现场:67 个模型全部不带 inputCostPerToken,一整天没记一分钱,
    // 日志里一个字都没有)。分开一条日志,把「有几条旧报价被保留」也带上,现场可判。

dashhuang added a commit that referenced this pull request Jul 31, 2026
处理 #1211 第三轮 review 的 3 条 P2(codex)。三条是同一个不变量的三个面:
**retained 兜底与它周边的判据、币种、类型契约必须同源**——上一轮只改了兜底自身,
周边三处仍沿用旧口径。

## 判据同源:告警不再误报免费目录

上一轮引入 declaresGatewayTokenPrice 区分「字段缺失」与「显式 0」,但
applyGatewayModels 的告警仍用 pricedCount === 0。于是显式全 0 的免费目录、
只下发部分字段的目录都会被报成「carry no prices at all」——把正常发布当计费故障,
日志持续产生噪音。告警改用同一判据,只报「价格字段整体缺失」。

## 币种同源:retained 金额不再被账本守卫丢弃

无价响应常常连可选的 currency 字段一起省略,此时 resolveGatewayAccountCurrency 会
按**构建区域**重新推导账本币种。账号结算币种本就不保证等于构建区域(CN 构建 +
USD 结算是正常组合),于是账本币种被改成区域币种、retained 金额仍是旧账号币种 →
被 dailySpend / dailyModelUsage / session 账本的守卫按异币种整批丢弃,兜底白做:
仍然只记 token、不记费用。

- retained 轮沿用上一份账本币种(gatewayLedgerCurrency(pricing)),与 retained
  报价同源;
- 新增边界 (a-3):新目录**显式声明**的币种与旧报价不一致时不启用兜底 —— 账号换了
  结算币种,旧价不可信,沿用等于按错币种记账。判据复用新导出的
  declaredSingleGatewayCurrency,与混币判据同一份实现。

## 类型契约同源:preload 声明直接复用 payload 正本

main 侧 MessageTurnCostPayload 的金额字段已整组可选,但 vite-env.d.ts 里
renderer 可见的 bridge 声明仍写必填 —— 消费方能在 typecheck 通过的情况下解引用
undefined。改为直接 import 同一份类型,不再两侧各写一份。

收敛后 typecheck 立刻抓出一处真实的下游不一致:useSessionEstimatedValue 的
EstimatedValueTurnCostPayload.turnCostIsEstimate 也声明必填(运行时因
`!== true` 早退本就安全,但类型上掩盖了契约)。一并放宽。

验证:pnpm test:unit 全绿(GATE_EXIT=0,零 FAIL);desktop typecheck 通过。
新增 2 条用例:无价响应省略 currency 时账本币种与 retained 报价保持一致、
目录切换币种时不沿用旧报价。

Signed-off-by: Dash <dashhuang@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>
Copilot AI review requested due to automatic review settings July 31, 2026 11:17

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6874dd9468

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated
Comment thread apps/desktop/src/renderer/lib/turnUsageTooltip.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 33 changed files in this pull request and generated no new comments.

dashhuang added a commit that referenced this pull request Jul 31, 2026
处理 #1211 第四轮 review 的 2 条 P2(codex)。两条同属「展示层与真实语义不一致」:
数据早就带着降级标记,UI 却没用;而 UI 又在自己分不清的地方断言了原因。

## 按旧报价折算的金额此前与精确账单同款显示

retained quote 标了 approximate + estimateReasons:['reference-price'],但
computePriceQuoteTurnMoney 只在 source === 'subscription-reference' 时给
kind:'value-estimate',而 retained 的 source 是 'gateway' → kind 仍是 actual-cost
→ recordTurnCostOnMessage 算出的 turnCostIsEstimate 为 false → 两端都按精确金额渲染。
于是 PR 描述里承诺的「明确标注为按最后已知价折算」在用户那儿根本不存在。

kind 保持 actual-cost 是对的(它确实是成本量级,不是订阅价值折算),所以不复用
「价值」那条文案,而是给这类金额单独的展示契约:

- Desktop:金额加 ~ 前缀(turnCostApproxValue),tooltip 追加 referencePriceLine
  说明「按最后已知报价折算(网关暂未下发价格)」;
- Mobile:同样加 ~(turnCostApprox)。判据用 approximate && kind === 'actual-cost'
  —— RemoteMoney 不带 estimateReasons,而 usdMoney 对 actual-cost 恒给
  approximate=false,所以这个判据目前只命中 retained,旧消息不会被误标。

## 无金额的说明行改为不断言原因

原文案断言「取不到模型报价」,但显式全 0 的免费目录同样没有金额 —— 上一轮刚把这种
目录认定为有效发布,这里却对它给出错误解释。展示层拿到的只有 token 明细,分不清
「价格字段缺失(该计费但算不出来)」与「免费模型(本来就不计费)」。

改成中性表述 noBilledCost「本轮未产生计费金额,仅显示用量」,两种情形下都成立;
缺价那个故障态的可观测性由 main 侧的「carry no price fields at all」告警承担,
不靠用户 tooltip 猜。priceUnavailable 四语言一并移除。

验证:pnpm test:unit 全绿(GATE_EXIT=0,零 FAIL);desktop / mobile typecheck、
pnpm check:i18n-glossary 通过。新增用例:reference-price 金额加前缀并出说明行、
精确报价不加、订阅估算仍走 valueLine 不误加说明、说明行不断言原因、
mobile 三种金额形态的文案分流。

Signed-off-by: Dash <dashhuang@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>
Copilot AI review requested due to automatic review settings July 31, 2026 11:41

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 23bcbb47a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 33 changed files in this pull request and generated no new comments.

@MagicLizi

Copy link
Copy Markdown
Contributor

@dashhuang 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/usage/modelPricing.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

dashhuang added a commit that referenced this pull request Jul 31, 2026
处理 #1211 第五轮 review 的 P2(codex):冷启动竞态会让新增的兜底彻底失效,并永久
丢掉可恢复的磁盘快照。

复现路径:冷启动时 /models 可能早于 bootstrap 里 fire-and-forget 的
prewarmModelPricing() 返回一份无价目录。此刻 cacheScope 还没指向本账号 →
retainKnownGatewayQuotes 必然返回 null(拿不到旧报价)→ 兜底不启用;紧接着
replaceGatewayModelPricing 把 {} 标成已 hydrate 并写盘,于是
  1. 磁盘上最后一份精确快照被 {} 覆盖 —— 永久丢失;
  2. hydratedScopes 已登记 → 迟到的 prewarm 被 getModelPricing / hydrateFromDisk
     的短路挡住,再也读不到盘。
恰好在本次线上无价故障这种「持续无价」场景下,重启不但没能启用兜底,反而把唯一的
恢复来源销毁了。

一条不变量收口:**无价故障轮既不覆盖、也不阻断磁盘上那份精确报价。**

- writeDiskCache 新增 preserveDiskQuotes:该轮报价不足以取代磁盘那份时(无价故障轮的
  空报价、retained 轮的 approximate quote —— 后者过不了 validateQuote),读回磁盘既有
  报价并保留**连同它的 fetchedAt**(报价没变,年龄基准不能前移)。accountCurrency 照常
  更新:账本币种要能随快照恢复,这个事实与有没有报价无关。
- 故障轮不再 hydratedScopes.add,getModelPricing 的短路条件相应改成
  「内存已有报价、或已确认过磁盘」才直接返回,否则去读一次盘 —— 迟到的 prewarm 因此
  能把精确报价读回来。
- 故障态判据统一为 declaresGatewayTokenPrice(与 retainKnownGatewayQuotes (a-2) 同源):
  显式全 0 的免费目录**下发了**价格,是有效快照(重启后就该 hydrate 成"没有报价"),
  不能混进故障态;models 为空(登出 / clear)同理照常落盘。
  这一条是写测试时发现的:先前用 `!fetched.xd` 会把免费目录一起算成故障,两条既有
  用例(免费目录写盘、只声明 currency 的目录恢复账本币种)当场失败。

hydratedScopes.add 从 writeDiskCache 内部移到调用方,「是否已确认磁盘」的判定不再
散落两处。

验证:pnpm test:unit 全绿(GATE_EXIT=0,零 FAIL);desktop typecheck 通过。
新增用例 lets a late hydrate recover the disk snapshot after an unpriced cold-start
sync 直接复现该竞态:无价冷启动轮后磁盘仍是精确快照,且 getModelPricing 能读回它。

另:本轮 CI 的 verify 失败项是 ghostOauthFlow.test.ts 的「钉死端口」用例,与本 PR
无关 —— 该用例真实 listen 端口且自带 5 次重试对抗抢占,本地(含全量门禁)41/41 通过,
本 PR 未触碰任何 ghost/oauth 文件。本次 push 会触发全新 CI 运行,不额外 rerun。

Signed-off-by: Dash <dashhuang@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>
@dashhuang

Copy link
Copy Markdown
Member Author

已定位并修复 verify CI 失败:最新主干新增的 ccAgent.draft.worktreeMissingRepoccAgent.draft.worktreeRepoHint 仅存在 zh-CN,导致 en/ja/ko 的 check:i18n 失败。

处理:将对应英文、日文、韩文翻译补齐,提交 453c10e2 fix(i18n): complete worktree draft translations,并随变基后的分支一并 --force-with-lease 推送。pnpm check:i18n 已通过(6236 keys 一致)。

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 36 out of 38 changed files in this pull request and generated no new comments.

Suppressed comments (1)

apps/mobile/src/session/MessageRenderer.tsx:1587

  • 这里的金额展示字符串只基于 turnMoney.kind 决定是否走“价值/估算”文案,但 turnCostIsEstimate(以及 userTurnCostIsEstimate)现在可以在 turnMoney.kind === 'actual-cost' 时为 true(例如一轮里混有 subscription value 段,addCompatibleRegionalMoney 会把总额 kind 仍算作 actual-cost)。结果是 UI 文案会显示成“$1.25”而不是估算值样式,和 desktop 的 displayedCostIsEstimate 口径不一致;同时可访问性 label 又会按 turnCostIsEstimate 走估算文案,前后不一致。建议让 formatMessageTurnCost 接受 isEstimate 标记并在展示文案上优先使用它(或在这里根据 item.message.turnCostIsEstimate 做同等分流)。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 453c10e213

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated
Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated
Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated
@dashhuang

Copy link
Copy Markdown
Member Author

已处理本轮两个 P2 并推送 c2b453fb fix(desktop): serialize retained pricing decisions

  • 无价轮在锁外看到空快照后,不再把 effectivePricing={} 带入锁内覆盖另一实例刚写入的精确报价;现在整个「读 current → 决定保留/空报价 → 写入」都在同一把 O_EXCL 锁内重新决定。
  • verdict 锁竞争失败时不再在锁外调用删除/截断共享缓存;本轮仅跳过写入并保留现有完整快照,等待下一轮同步。
  • 同时保留 owner token + 续租 + token 校验释放,避免慢 I/O 锁被误回收。

验证:modelPricing 52/52;Desktop typecheck 通过。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c2b453fb92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/i18n/locales/en/common.json Outdated
Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 36 out of 38 changed files in this pull request and generated no new comments.

Suppressed comments (2)

apps/desktop/src/renderer/components/chat/MessageActionBar.tsx:399

  • 这里直接把 turnUsageDetails.totalTokens 传给 formatCompactTokens,而 mobile 侧与其它 desktop 入口都会先 Math.floor 后再格式化,避免出现小数 token 并保证两端一致。建议在这里同样先 Math.floor
              tokens: formatCompactTokens(turnUsageDetails.totalTokens),

apps/desktop/src/renderer/components/chat/MessageActionBar.tsx:394

  • 这里对 totalTokens 仅做 > 0 判断,但本仓其它 token 展示在进入 formatCompactTokens 前都会先 Math.floor(例如 apps/desktop/src/renderer/lib/turnUsageTooltip.ts:29-31、apps/desktop/src/renderer/components/status/TodaySpendChip.tsx:925-928),以避免出现小数 token/两端口径不一致。建议把 gate 也改为基于 Math.floor(totalTokens) 判断。

This issue also appears on line 399 of the same file.

    turnUsageDetails.totalTokens > 0 && (

@dashhuang

Copy link
Copy Markdown
Member Author

补充修复并推送 d5edb55d fix(desktop): version model pricing verdict cache

  • 未来时间戳快照清理仍显式绕过普通 verdict 新鲜度闸,保证“空报价清理”不会被未来 verdict 阻断。
  • 存量 model-pricing.json 版本由 v8 升到 v9,使旧 packaged 客户端拒绝带新 verdict 语义的缓存,避免旧读侧忽略 unpricedFailure 后按无 TTL 精确报价恢复。
  • 正常权威报价清理 verdict 时,保留同进程 1ms 顺序窗口;明显晚于 payload 的 verdict 仍阻止旧权威快照覆盖。

验证:modelPricing 52/52、Desktop typecheck、check:i18n、check:i18n-glossary、check:dco 均通过。

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 36 out of 38 changed files in this pull request and generated no new comments.

Suppressed comments (1)

apps/desktop/src/main/model-access/index.ts:180

  • 这一条 warn 的尾句 “keep the last known discount” 与当前代码行为不一致:当目录下发了非法的 costDiscount 时,报价构建会直接忽略该折扣(而不是保留上一份折扣);当价格字段非法导致报价缺失时,本轮会整体拒绝/回落而不是“保留折扣”。建议把提示改成不承诺具体后果的表述,避免误导排障。
  const invalidPriceCount = models.filter(hasInvalidGatewayPriceDeclaration).length;
  if (invalidPriceCount > 0) {
    log.warn(
      `xd gateway models carry invalid price declarations (${invalidPriceCount}/${models.length} models); affected entries lose pricing, drop a tier, or keep the last known discount`,
    );

@MagicLizi

Copy link
Copy Markdown
Contributor

@dashhuang 👋 这个 PR 还有 8 条 review conversation 没 resolve(apps/desktop/src/main/usage/modelPricing.ts / apps/desktop/src/renderer/i18n/locales/en/common.json),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@MagicLizi

Copy link
Copy Markdown
Contributor

@dashhuang 👋 这个 PR 目前与 main 有合并冲突,auto-review 因此暂时跳过、没法继续审查 / 合并。

请在本地 merge 最新的 origin/main 解决冲突后推送;冲突解除后,下一轮 auto-review 会自动重新处理这个 PR。

@dashhuang

Copy link
Copy Markdown
Member Author

已处理本轮新反馈并推送 0f8367b7 fix(desktop): clarify retained pricing estimates

  • noBilledCost 改为“费用暂不可用/Cost unavailable”,不再把未知费用描述成免费。
  • retained gateway quote 携带 estimateReasons: [reference-price];ModelSelector 不再把所有 approximate 都解释成 fixed FX,沿用旧网关报价显示“按最后已知报价估算”。
  • 同步扩展 ModelPriceQuote 类型与金额投影,保留 reference-price 原因。
  • 未来快照清理显式绕过 verdict 时间闸,避免未来 verdict 阻止清空未来报价。

验证:modelPricing 52/52;Desktop typecheck 通过。

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 39 out of 41 changed files in this pull request and generated 1 comment.

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f8367b7e9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@dashhuang 👋 这个 PR 还有 3 条 review conversation 没 resolve(apps/desktop/src/main/usage/modelPricing.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@MagicLizi

Copy link
Copy Markdown
Contributor

@dashhuang 👋 这个 PR 目前与 main 有合并冲突,auto-review 因此暂时跳过、没法继续审查 / 合并。

请在本地 merge 最新的 origin/main 解决冲突后推送;冲突解除后,下一轮 auto-review 会自动重新处理这个 PR。

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 39 out of 41 changed files in this pull request and generated no new comments.

Suppressed comments (1)

apps/desktop/src/main/usage/tests/modelPricing.test.ts:862

  • 这里的用例想模拟“另一个进程持有 verdict lock”,但实际创建的是 ${cacheFile}.lock.${lockToken};实现侧锁文件路径是固定的 ${diskCachePath()}.lock,因此该哨兵文件不会阻塞写入,测试并未覆盖锁等待/重试逻辑。建议改为创建固定的 .lock 文件,并把 token 写入其中。
    const lockToken = `${String(realAt).padStart(13, '0')}-other-process-live`;
    const lockFile = `${cacheFile}.lock.${lockToken}`;
    await writeFile(lockFile, lockToken, 'utf8');
    await utimes(lockFile, new Date(realAt), new Date(realAt));

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4a0799aebc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/usage/modelPricing.ts Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@dashhuang 👋 这个 PR 还有 2 条 review conversation 没 resolve(apps/desktop/src/main/usage/modelPricing.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

Signed-off-by: Dash <dashhuang@gmail.com>
@MagicLizi

Copy link
Copy Markdown
Contributor

@dashhuang 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/usage/modelPricing.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 32 changed files in this pull request and generated no new comments.

Suppressed comments (1)

apps/mobile/src/session/messageNormalize.ts:721

  • projectTurnMoney() 会把 turnCostIsEstimate 设为 true(例如 userTurnCost 混入订阅估值时,desktop 的 addRegionalMoney() 仍可能产出 kind: 'actual-cost'),但这里返回的 turnMoney 仍沿用原始 kind。由于 mobile 的 formatMessageTurnCost() 只看 money.kind 来决定是否显示“估算/价值”文案,这会导致:可访问性标签认为是 estimate,但界面文案不显示 estimate,语义不一致。建议当 isEstimate 为 true 时,将 turnMoney.kind 统一投影为 'value-estimate'(并同步 approximate: true),让显示与 turnCostIsEstimate 一致。
  if (normalized && normalized.amount > 0) {
    const isEstimate = isEstimateFlag || normalized.kind === 'value-estimate';
    return {
      turnMoney: normalized,
      ...(normalized.currency === 'USD' ? { turnCostUsd: normalized.amount } : {}),

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92fd518141

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/mobile/src/session/messageNormalize.ts Outdated
Signed-off-by: Dash <dashhuang@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 33 out of 34 changed files in this pull request and generated no new comments.

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review passed — well-structured token fallback with comprehensive test coverage across both platforms. No P0/P1 issues found.

@MagicLizi

Copy link
Copy Markdown
Contributor

Token 回退显示做得很扎实——共享层的 formatCompactTokens 让两端行为对齐了,五条消费路径都有对应测试覆盖。合并后 copilot/codex-connector 的迟到意见如有到达会另行跟进。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants