Skip to content

feat(desktop): add pricing override management UI - #4164

Open
liuxiaocs7 wants to merge 2 commits into
apache:mainfrom
liuxiaocs7:feat/usage-pricing-override-ui
Open

feat(desktop): add pricing override management UI#4164
liuxiaocs7 wants to merge 2 commits into
apache:mainfrom
liuxiaocs7:feat/usage-pricing-override-ui

Conversation

@liuxiaocs7

Copy link
Copy Markdown
Member

Summary

The Usage → Pricing tab was display-only. The Runtime Host pricing authority (pricing.query / pricing.mutate, PricingStore) and the Desktop IPC handlers (usage:pricing:{list,put,reset}) were already implemented and tested, but the preload never bridged the mutation channels and UsagePricingPanel had no add/edit/reset affordance — so a user could not register a custom per-model price, and a model missing built-in pricing reads as "cost unavailable".

This wires up the existing backend to a UI:

  • Preload bridge — expose settings.pricing.put(config) / settings.pricing.reset(modelKey), scoped to the selected Runtime Host, unwrapping the Result so the form can surface a failure inline.
  • Data shape — carry modelKey and optional cache rates on UsageStats.pricing so a row can be edited/reset by its canonical key; project them in the main process.
  • UI — rework UsagePricingPanel: an "Add pricing" toolbar action (always visible, so it is discoverable from the empty state), per-row edit/reset, a Dialog form (provider, model, input/output rates, and a collapsible optional cache-rate section), and a destructive-confirm AlertDialog for reset. Rates are validated inline and again on the Host via normalizePricingConfig. After a mutation the panel reloads so the row and tab count update.

zh + en copy added; provider/model are locked while editing since they form the identity key.

Fixes #4163

Verification

Ran locally:

  • tsc --noEmit for all four desktop projects (preload, main, renderer, storybook) — pass.
  • @maka/core build — pass.
  • node --test on runtime-host-usage-ipc-main.test.js (5), desktop-session-projection.test.js + runtime-host-client-pricing.test.js (22) — pass. The pricing-projection test asserts the new modelKey + cache-rate fields and fails without the projection change.
  • biome check (lint + format) on all changed TS files — clean.

Not run: I did not launch the Electron app, so there is no screenshot/recording of the new UI yet. The renderer/preload wiring is covered by typecheck + lint against the shared bridge contract rather than an automated UI test. Happy to attach a screenshot on request.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Claude Code (Claude Opus 4.8) — investigated the existing pricing stack, implemented the preload bridge + panel UI + copy, and updated the projection test. Reviewed and submitted by the human contributor of record. Affected commit carries a Generated-by: Claude Code trailer.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

The Usage → Pricing tab was display-only. The Runtime Host pricing
authority (pricing.query/mutate, PricingStore) and the desktop IPC
handlers (usage:pricing:{list,put,reset}) were already built, but the
preload never bridged the mutation channels and UsagePricingPanel had
no add/edit/reset affordance, so custom per-model prices could not be
configured from the app.

- Expose settings.pricing.{put,reset} on the preload bridge, scoped to
  the selected Runtime Host, unwrapping the Result so the form can
  surface failures inline.
- Carry modelKey and optional cache rates on UsageStats.pricing so a row
  can be edited or reset by its canonical key; project them in the main
  process.
- Rework UsagePricingPanel: an "Add pricing" toolbar action, per-row
  edit/reset, a Dialog form (provider, model, input/output rates and an
  optional cache-rate section), and a destructive-confirm reset. Rates
  are validated inline and again on the Host via normalizePricingConfig.

Fixes apache#4163

Generated-by: Claude Code
@github-actions github-actions Bot added the effort/M Under 500 readable lines label Aug 29, 2026
The pricing override panel adds Astryx surfaces (Dialog, AlertDialog,
Layout, Collapsible, NumberInput, HStack, VStack); regenerate the
tracked inventory via `npm run astryx:surface-inventory:write` so the
CI consistency check passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/M Under 500 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Usage → Pricing tab is read-only: no UI to add/edit/reset custom pricing overrides

1 participant