Repository navigation
feat(cost): Cost compare — fleet usage priced as any hosted model - #231
fish-not-phish wants to merge 3 commits into
Conversation
Add a /cost page that prices the fleet's token counters at any model from the community litellm price list, with a searchable catalog dropdown (~2.9k models), input/output/cached cost split, per-day cost chart, cache-savings and blended $/1M tiles. - server/prices: GET /api/model-prices; 24 h memory cache, last-good copy persisted to config/model-prices.json as an offline fallback - src/components/CostPage: page + pure cost math (costStats) w/ tests - wire into sidebar, mobile sheet, command palette and routes
|
Reviewed at ff4cd86. It merges cleanly and typecheck, build and the full tests pass (server 1064/1065, frontend 803), and I found no injection or SSRF problem (the URL is a constant and the route sits behind the auth middleware), but it is not ported yet. (1) (Review notes prepared with Claude Code on behalf of the maintainer.) |
…tch, tracked-day average Review items from MiaAI-Lab on MiaAI-Lab#231: - ModelPrices: the disk fallback is no longer promoted into the fresh memory cache; it is served (and stays) stale:true while refreshes fail. - ModelPrices: failed refreshes retry at most once per 60 s and share a single in-flight attempt; fetch timeout 15 s -> 5 s. - ModelPrices: the raw.githubusercontent refresh is now opt-in via MODEL_PRICES_FETCH=1 (default off: the route serves the disk catalog and never phones out); the default fetch uses redirect:'error' and a 10 MB body cap. - CostPage: prices load independently of usage, so a slow/dead price source no longer holds the whole page on a spinner; price failures get their own note with retry. - CostPage: the All-time 'average per day' divides by tracked days (trackedBuckets, same rule as Token totals) instead of a fixed 30. - README/.env.example: MODEL_PRICES_FETCH + MODEL_PRICES_JSON_PATH documented.
|
Thanks for the careful review! All four points are addressed in d95f735:
Tests: five new cases in |
# Conflicts: # server/index.js # src/components/shell/AppSidebar.tsx
Squash of #231 (ff4cd86, d95f735, ef69b33) by its author, with two changes on top: the price fetch counts bytes as they stream and cancels past the 10 MB cap (a body without Content-Length or a compressed one was buffered whole before the cap applied), and a CHANGELOG entry. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Now on main as b361e06, squashed with your authorship (thank you). I re-checked the four points from the review at (Review notes prepared with Claude Code on behalf of the maintainer.) |
What
New Cost compare page (
/cost, sidebar → "Cost compare", mobile Stats sheet, commandpalette): prices the fleet's token counters at any hosted model — "what would our usage have
cost on Claude Opus, Sonnet, GPT-5.2, …?"
litellm price catalog
(~2.9k chat models, prefix-ranked search). The last pick is remembered per browser.
prefill × the provider's cache-read rate when published (else the full input rate) — so the
page also shows what the prefix cache saves in the selected period.
Token totals page, so the two pages reconcile; All time uses lifetime totals.
How
GET /api/model-prices(server/prices/ModelPrices.js): fetches the litellm JSON, keepschat-shaped entries with real per-token input/output costs, serves a slim catalog. Cached in
memory for 24 h; the last good copy persists to
config/model-prices.json(gitignored) andis served if the upstream fetch fails — stale prices beat an error, 502 only with no cache
at all.
src/components/CostPage/costStats.ts— pure functions, noReact, no I/O — so the page component stays presentation-only.
Testing
Per
README.md §Contributions:npm run typecheck— cleannpm run test:frontend— 99 files / 803 tests pass, including the newsrc/components/CostPage/costStats.test.tsand the updated MobileTabBar sheet testnode --test server/__tests__/isolatedEnv.test.js server/prices/__tests__/ModelPrices.test.js— parser, disk-cache fallback and theno-cache 502 path covered;
server/pricesadded to thetest:serverglob inpackage.json; the newMODEL_PRICES_JSON_PATHregistered inisolatedEnv.jsmain(the deltas are theenvironment-dependent sudo/vulnhunt/llmlaunch checks, identical on pristine
main)/costrenders in all four themes; thepage keeps working with the network path down via the disk cache
Notes
fetch(Node 18+) likeserver/collectors/HermesReleases.js.server/index.jschanges are two lines (import + oneapp.get).