Skip to content

feat(catalog): mode-aware pricing and litellm-model-catalog-api integration#1

Merged
mateo-berri merged 3 commits into
BerriAI:mainfrom
Sameerlite:feat/catalog-api-pricing-berriai
Jun 3, 2026
Merged

feat(catalog): mode-aware pricing and litellm-model-catalog-api integration#1
mateo-berri merged 3 commits into
BerriAI:mainfrom
Sameerlite:feat/catalog-api-pricing-berriai

Conversation

@Sameerlite

@Sameerlite Sameerlite commented Jun 2, 2026

Copy link
Copy Markdown

Summary

  • Integrate with litellm-model-catalog-api (optional via VITE_USE_LOCAL_CATALOG_API + Vite proxy)
  • Show exact catalog pricing for chat, embedding, image gen, audio transcription, and TTS models
  • Use the same 2×2 pricing grid for all modes; hide chat-only Features for image/audio models
  • Add mode-specific LiteLLM SDK and proxy quick-start snippets

Depends on BerriAI/litellm-model-catalog-api#1 for pricing_slots in API responses.
Fixes LIT-2904

Image Gen
Before
image

After
image

Embedding
Before
image
After
image

Transcription
Before
image
After
image

Audio Speech
Before
image
After
image


Note

Medium Risk
Large UI/pricing refactor affects how every model’s costs are shown and sorted; optional API path depends on external catalog API and env/proxy setup, but default GitHub fetch remains.

Overview
Adds optional litellm-model-catalog-api loading (VITE_USE_LOCAL_CATALOG_API, paginated fetchAllCatalogModels, Vite /model_catalog proxy) alongside the existing GitHub JSON path, with shared finishLoad for both sources.

Extracts catalogApi.ts and modelPresentation.ts so pricing uses pricing_slots when present and falls back to raw catalog fields. Display drops the old <$0.01 per-1M floor in favor of exact USD with unit suffixes (/M, /img, /s, /char, etc.). Image and audio modes get dedicated table/detail pricing, image tier extras, and mode-specific Python SDK + proxy curl snippets (via {@html} with escaped model names).

sample_spec is surfaced as a pinned schema reference row (filters/sort tweaks, field-reference detail panel, no “report incorrect data”). GitHub loads still peel sample_spec out of the JSON object before building model rows.

UI polish: cost column labels, cache column tooltips, Features hidden for image/audio rows, sticky header/table CSS fixes, image_edit mode label.

Reviewed by Cursor Bugbot for commit 3c4644b. Bugbot is set up for automated code reviews on this repo. Configure here.

Sameerlite and others added 3 commits June 2, 2026 20:58
…ration

Load from the catalog API with Vite proxy support, show exact pricing for chat,
image, audio transcription, and TTS models, and render mode-specific quick start snippets.

Co-authored-by: Cursor <cursoragent@cursor.com>
Highlight SDK/proxy code via :global CSS for {@html} snippets. Add audio
transcription and TTS proxy curl examples alongside existing mode-specific SDK samples.

Co-authored-by: Cursor <cursoragent@cursor.com>
@mateo-berri

Copy link
Copy Markdown
Collaborator

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 5 potential issues.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit 3c4644b. Configure here.

Comment thread src/modelPresentation.ts
-d ${curlStr(`{
"model": "${modelStr}",
"messages": [{"role": "user", "content": "Hello!"}]
}`)}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double HTML escaping in curl snippet display

Medium Severity

In getLiteLLmProxyCurlSnippetHtml, model names in JSON-body curl snippets are double-escaped. This occurs because modelStr is pre-escaped, then passed to curlStr which escapes it again, leading to incorrect display for image_generation, embedding, audio_speech, and chat completion examples.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3c4644b. Configure here.

Comment thread src/modelPresentation.ts
return raw;
}
return 0;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Output sort skips valid zero-cost slot values

Medium Severity

The imageModeOutputSortValue function includes an if (v > 0) check that's not present in imageModeInputSortValue. This causes models with a $0.00 output pricing slot to incorrectly use fallback pricing fields for sorting, creating a discrepancy with the displayed $0.00 price.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3c4644b. Configure here.

Comment thread src/App.svelte
{:else if mode === "audio_transcription"}
Audio pricing <span class="detail-unit">per second where applicable</span>
{:else if isAudioPricingMode(mode)}
Audio pricing <span class="detail-unit">per second · per character where applicable</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreachable audio pricing heading branch

Low Severity

The {:else if isAudioPricingMode(mode)} branch in the pricing heading is unreachable. isAudioPricingMode only returns true for "audio_speech" and "audio_transcription", but both are already matched by the two preceding {:else if} branches. The generic "per second · per character" label can never be displayed.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3c4644b. Configure here.

Comment thread src/modelPresentation.ts

function formatUsdPerMillion(perToken: number): string {
return formatTokenCostPerMillion(perToken).replace(/\/M$/, "/M tok");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused helper functions are dead code

Low Severity

formatUsdFlat and formatUsdPerMillion are newly introduced private functions that are never called anywhere in the codebase. Grep confirms the only matches are their definitions. These appear to be leftover helpers that were written but never wired in, adding dead code.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3c4644b. Configure here.

Comment thread src/App.svelte
{:else if mode === "audio_transcription"}
Audio pricing <span class="detail-unit">per second where applicable</span>
{:else if isAudioPricingMode(mode)}
Audio pricing <span class="detail-unit">per second · per character where applicable</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreachable audio pricing mode branch is dead code

Low Severity

The {:else if isAudioPricingMode(mode)} branch is unreachable because mode === "audio_speech" and mode === "audio_transcription" are already matched by the two preceding conditions, and isAudioPricingMode only checks for exactly those two values. This dead branch adds confusion about whether there are other audio modes that could reach it.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3c4644b. Configure here.

@mateo-berri mateo-berri merged commit 3c4644b into BerriAI:main Jun 3, 2026
1 check 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.

2 participants