Files
multica/packages/core/runtimes/index.ts
Bohan Jiang 6e3e6f714c feat(runtimes): let users set custom prices for unmaintained models (#2386)
* feat(runtimes): let users set custom prices for unmaintained models

The Runtime > Usage pricing diagnostic previously told users to "edit
packages/views/runtimes/utils.ts" when a model wasn't priced. That's
fine for us, useless for everyone else. We can't track every model
release, so let users supply their own per-million-token rates for
anything we don't ship a maintained rate for (e.g. gpt-5.5-mini today).

- Add a persisted Zustand store (custom-pricing-store) keyed by model
  name; rates live in localStorage so they survive reloads.
- resolvePricing consults the maintained MODEL_PRICING catalog first,
  then falls back to the store. Catalog still wins on overlap so a
  stale local override can't shadow a known rate.
- EmptyChartState gains a "Set custom prices" button when unmapped
  models exist; the dialog lists every unmapped model plus everything
  already overridden so users can edit / clear prior entries.

Co-authored-by: multica-agent <github@multica.ai>

* fix(runtimes): show pricing-gap notice for partial unmapping; invalidate cost memos on price save

Two bugs surfaced in review:

1. The "Set custom prices" CTA only showed inside EmptyChartState, which
   only fires when Daily / Hourly total cost is exactly 0. Mixed windows
   (some priced + some unpriced models) rendered the chart normally and
   left no entry point — the unpriced tokens silently contributed \$0
   to totals.

   Add a permanent UnmappedPricingNotice above the KPI grid that appears
   whenever collectUnmappedModels(filtered) is non-empty, regardless of
   chart state. EmptyChartState keeps the diagnostic text but the CTA
   button moves to the notice so the two surfaces don't duplicate.

2. The aggregate useMemo blocks (WhenChart's dailyCostStack / hourlyCost,
   CostByBlock's byAgent / byModel, ActivityHeatmap's cells) keyed only
   on their query data. After a price save the parent re-rendered, but
   the memos returned cached pre-save totals because their deps were
   identical. The KPI cards updated; the charts did not.

   Subscribe to the pricing store in each aggregating component and
   list `pricings` as a memo dependency. The store returns a stable
   reference until setCustomPricing fires, so memos only invalidate
   on real changes.

New unit tests cover both: a mixed priced/unpriced aggregate produces
mixed costs (and surfaces the unpriced names), and aggregateCostByModel
called twice on the same input array reflects a freshly-saved override.

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: multica-agent <github@multica.ai>
2026-05-11 14:36:14 +08:00

11 lines
306 B
TypeScript

export * from "./queries";
export * from "./mutations";
export * from "./hooks";
export * from "./models";
export * from "./local-skills";
export * from "./types";
export * from "./derive-health";
export * from "./use-runtime-health";
export * from "./cli-version";
export * from "./custom-pricing-store";