fix(dashboard/api-manager): use getProviderDisplayName for owned_by labels (#2021)

Custom OpenAI-/Anthropic-compatible providers ship with synthetic IDs
like "openai-compatible-chat-<uuid>". ApiManagerPageClient was grouping
models by raw `model.owned_by`, so the user saw the full synthetic id
in the model picker.

Wrap `model.owned_by` with the existing centralized
`getProviderDisplayName` helper (already used by Endpoint, Health, and
Combos pages). The helper detects the dynamic-compatible pattern and
renders it as "Compatible (openai)" / "Compatible (anthropic)" — a
small but meaningful improvement that takes the dashboard one step
closer to issue #260's "no raw IDs in the UI" goal.

Showing the user-entered node name ("Poe") instead of the generic
"Compatible (openai)" label remains a follow-up (requires fetching
/api/provider-nodes here and matching by id/prefix); tracked separately.

Reported by @pulyankote with a complete surface-by-surface table.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
diegosouzapw
2026-05-14 12:58:26 -03:00
parent f63f29830f
commit 7210a73e1f
2 changed files with 8 additions and 3 deletions

View File

@@ -8,6 +8,7 @@
- **fix(translator/claude-to-openai):** stop including `cache_creation_input_tokens` in `prompt_tokens`. Anthropic pads short prompts up to a 1024-token minimum on cache creation, so a 2-token `"hi"` could be reported as ~2008 `prompt_tokens` and inflate downstream billing (Sub2API/NewAPI/OneAPI) ~250x. `prompt_tokens` now matches the dashboard "Total In" (`input + cache_read`); `cache_creation_tokens` is exposed separately in `prompt_tokens_details.cache_creation_tokens` for auditing. (#2215)
- **fix(ui/claude-extra-usage):** clarify the toggle-success notification text to spell out the toggle→effect relationship ("Claude extra-usage blocking enabled/disabled" instead of the ambiguous "blocked/allowed"). (#2157)
- **fix(providers/qoder):** disambiguate the "Local CLI runtime is not installed" error when a user pastes a Personal Access Token but the connection is in OAuth/CLI-flavored mode. The test route now surfaces a single actionable message ("switch this connection to API Key auth") instead of cascading CLI + 401 errors. (#2247)
- **fix(dashboard/api-manager):** route custom OpenAI-/Anthropic-compatible provider IDs through `getProviderDisplayName` so the model grouping label shows `Compatible (openai)` instead of leaking the raw synthetic `openai-compatible-chat-<uuid>` value. (#2021)
### Changed

View File

@@ -4,6 +4,7 @@ import { useState, useEffect, useMemo, useCallback, memo } from "react";
import { Card, Button, Input, Modal, CardSkeleton } from "@/shared/components";
import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard";
import { useTranslations } from "next-intl";
import { getProviderDisplayName } from "@/lib/display/names";
// Constants for validation
const MAX_KEY_NAME_LENGTH = 200;
@@ -434,16 +435,19 @@ export default function ApiManagerPageClient() {
// Debounced search for performance
const debouncedSearchModel = useDebouncedValue(searchModel, 150);
// Group models by provider
// Group models by provider (issue #2021 — use centralized display helper so
// custom OpenAI-/Anthropic-compatible providers don't leak raw synthetic
// ids like "openai-compatible-chat-<uuid>" into the grouping label)
const modelsByProvider = useMemo((): ProviderGroup[] => {
const grouped: Record<string, Model[]> = {};
for (const model of allModels) {
const provider = model.owned_by || t("unknownProvider");
const provider =
getProviderDisplayName(model.owned_by) || model.owned_by || t("unknownProvider");
if (!grouped[provider]) grouped[provider] = [];
grouped[provider].push(model);
}
return Object.entries(grouped).sort((a, b) => a[0].localeCompare(b[0]));
}, [allModels]);
}, [allModels, t]);
// Filter models based on debounced search
const filteredModelsByProvider = useMemo((): ProviderGroup[] => {