feat(desktop,mobile): 算不出模型报价时消息底部回退显示本轮 token - #1211
Conversation
|
| 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
Reviews (37): Last reviewed commit: "fix(mobile): canonicalize turn estimate ..." | Re-trigger Greptile
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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.
处理 #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>
There was a problem hiding this comment.
💡 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".
处理 #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>
计费兜底的不变量清单(给后续 review 当锚点)
一句话不变量
结构:一个状态 + 一处投影「沿用最后已知报价」有三条路径,此前各自判断、各自标记(漏洞就出在这里):
判据同样都是单一来源:混币 → 启用条件:全部对称路径
时序与持久化
磁盘写入
展示层
超出本 PR 范围(如实登记)磁盘缓存本身没有 TTL —— 冷启动 hydrate 一份很旧的精确快照仍会用于计费。这是本 PR 之前就有的既有行为;给它加 TTL 会影响正常冷启动路径,需要单独评估,没有塞进这个 PR。 |
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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,一整天没记一分钱,
// 日志里一个字都没有)。分开一条日志,把「有几条旧报价被保留」也带上,现场可判。
处理 #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>
There was a problem hiding this comment.
💡 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".
处理 #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>
There was a problem hiding this comment.
💡 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".
|
@dashhuang 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/usage/modelPricing.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。 如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。 |
处理 #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>
|
已定位并修复 verify CI 失败:最新主干新增的 处理:将对应英文、日文、韩文翻译补齐,提交 |
There was a problem hiding this comment.
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 做同等分流)。
There was a problem hiding this comment.
💡 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".
|
已处理本轮两个 P2 并推送
验证:modelPricing 52/52;Desktop typecheck 通过。 |
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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 && (
|
补充修复并推送
验证:modelPricing 52/52、Desktop typecheck、check:i18n、check:i18n-glossary、check:dco 均通过。 |
There was a problem hiding this comment.
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`,
);
|
@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。 |
|
@dashhuang 👋 这个 PR 目前与 请在本地 merge 最新的 |
|
已处理本轮新反馈并推送
验证:modelPricing 52/52;Desktop typecheck 通过。 |
There was a problem hiding this comment.
💡 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".
|
@dashhuang 👋 这个 PR 还有 3 条 review conversation 没 resolve(apps/desktop/src/main/usage/modelPricing.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。 如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。 |
|
@dashhuang 👋 这个 PR 目前与 请在本地 merge 最新的 |
There was a problem hiding this comment.
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));
There was a problem hiding this comment.
💡 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".
|
@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>
|
@dashhuang 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/usage/modelPricing.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。 如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。 |
There was a problem hiding this comment.
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 } : {}),
There was a problem hiding this comment.
💡 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".
Signed-off-by: Dash <dashhuang@gmail.com>
MagicLizi
left a comment
There was a problem hiding this comment.
Code review passed — well-structured token fallback with comprehensive test coverage across both platforms. No P0/P1 issues found.
|
Token 回退显示做得很扎实——共享层的 formatCompactTokens 让两端行为对齐了,五条消费路径都有对应测试覆盖。合并后 copilot/codex-connector 的迟到意见如有到达会另行跟进。 |
这次改了什么
摘要
消息底部原本只在能算出金额时显示费用;上游没有下发模型价格时,该位置会完全消失。现在 Desktop 与 Mobile 都会在没有金额但有本轮用量时回退显示紧凑 token 数,例如
2.1M tokens。本 PR 已按 review 收窄:不再沿用历史报价,不修改价格缓存,也不引入价格缓存锁。 有金额仍显示金额;没有金额才显示 token。
变更类型
feat新功能fix缺陷修复refactor/perf重构或性能优化docs/test/chore文档、测试或工程维护范围
TurnUsageDetails写入消息agent_meta,并复用现有usage:message-turn-cost推送。formatCompactTokens下沉到@cindy/maker-shared,Desktop 与 Mobile 复用。approximate/reference-price金额。/models缺少价格字段的根因修复。2.1M tokens;有金额时维持原金额展示。UI 变化
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 样式,无硬编码单模式颜色。怎么验证的
自动验证
手工验证
未执行。
未执行的验证
风险
风险分类
影响与回滚
agent_metaJSON patch;不改数据库 schema,不写近似金额,不触碰计费账本。usage:message-turn-costpush;Mobile 已同步适配实时与历史路径。turnUsageDetails对旧版本是可忽略的附加 JSON 字段。提交前检查
git commit -s)