Skip to content

Display usage spend in CNY (¥) instead of USD ($) - #136

Merged
yikkuro merged 1 commit into
mainfrom
sunt-microsoft-issue-127-usd-to-cny-conversion
Jul 29, 2026
Merged

Display usage spend in CNY (¥) instead of USD ($)#136
yikkuro merged 1 commit into
mainfrom
sunt-microsoft-issue-127-usd-to-cny-conversion

Conversation

@yikkuro

@yikkuro yikkuro commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

The Total Spend / per-model spend figures shown in Settings → Usage were displayed with a $ prefix, implying USD. This PR converts those values to CNY and relabels the symbol to ¥.

Where the number comes from (and why the math is already correct)

MicroClaw does not compute cost itself. It calls the OpenClaw gateway RPC sessions.usage and relays totals.totalCost, byModel[].totals.totalCost, daily[].cost, and sessions[].usage.totalCost verbatim (each with || 0) in desktop/src/main.ts.

The value OpenClaw returns is USD: OpenClaw's src/utils/usage-format.ts estimateUsageCost() computes (input*price.input + output*price.output + cacheRead*… + cacheWrite*…) / 1_000_000, where prices come from the USD-denominated remote model catalog (catalog.openclaw.ai/models/v1/catalog.json). Its JSDoc says "Estimates USD usage cost" and there is a formatUsd() helper. There is no currency/FX logic anywhere in OpenClaw or MicroClaw.

Conclusion for the "verify calculation accuracy" part of #127: the arithmetic lives in OpenClaw and is correct; MicroClaw only relays it, so there is no MicroClaw-side math bug. The $ label was factually accurate, which is exactly why we can't just swap the glyph — doing so would mislabel a genuine USD value as CNY. A real USD→CNY conversion is required.

What this PR changes

  1. Live exchange-rate lookup (desktop/src/exchange-rate.ts, new). Fetches the current USD→CNY rate from https://api.frankfurter.app/latest?from=USD&to=CNY (ECB data, no API key). In-memory cache with a 12h TTL. Robust fallback to a hardcoded ~7.2 constant (USD_TO_CNY_FALLBACK_RATE, clearly commented) when the fetch fails, so the UI never breaks offline. Injectable fetcher for tests, mirroring update-checker.ts.
  2. Expose the rate to the renderer. New usage:get-exchange-rate IPC (+ preload usage.getExchangeRate()), and the rate is also included in the existing usage:get-stats payload (exchangeRate / currency).
  3. Convert at the display boundary. SettingsView.vue (the only place spend is rendered) multiplies the relayed USD values by the rate via a single toCny() helper — no double conversion; raw USD is untouched everywhere else.
  4. Relabel $¥. Via a new settings.currencySymbol i18n key in both en-US.ts and zh-CN.ts, preserving the existing precision (.toFixed(4) for spend, .toFixed(2) for budget).

Validation

  • desktop vitest: 653 passed (incl. 6 new exchange-rate.test.ts cases: cache hit / TTL refetch / live / fallback / stale-reuse).
  • desktop/renderer vitest: 194 passed; vue-tsc typecheck clean; eslint 0 errors.
  • Sanity: 0.00342 USD × 7.2¥0.0246.

Closes #127

The total-spend / per-model spend shown in Settings comes verbatim from the
OpenClaw gateway `sessions.usage` RPC, which reports cost in USD (OpenClaw's
`estimateUsageCost()` is priced from a USD model catalog). MicroClaw only
relays the number, so there is no MicroClaw-side math to fix — the arithmetic
is OpenClaw's responsibility and is correct.

This adds a live USD->CNY conversion at the display boundary:
- New `exchange-rate.ts` fetches the USD->CNY rate from Frankfurter (ECB data,
  no API key), caches it in memory (12h TTL), and falls back to a hardcoded
  ~7.2 rate when offline so the UI never breaks.
- Expose the rate via a new `usage:get-exchange-rate` IPC and include it in the
  `usage:get-stats` payload.
- SettingsView converts the relayed USD values to CNY and renders `¥` via a new
  `settings.currencySymbol` i18n key, preserving existing decimal precision.

Fixes #127

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1fe75171-fea2-45ef-9401-bf8a4ea0f2ba
@yikkuro
yikkuro merged commit bbbb8be into main Jul 29, 2026
1 of 2 checks passed
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.

Verify total spend amount calculation accuracy and use CNY instead of USD

1 participant