feat: implement credential selection logic for provider credentials
This commit is contained in:
parent
9f8b2906c4
commit
7d297df9aa
|
|
@ -92,6 +92,7 @@ import {
|
|||
formatTimestamp,
|
||||
parseTimestamp,
|
||||
} from "@/lib/formatters";
|
||||
import { selectPreferredProviderCredential } from "@/lib/provider-credential-selection";
|
||||
|
||||
type SessionSummary = {
|
||||
key: string;
|
||||
|
|
@ -865,11 +866,27 @@ export default function DashboardPage() {
|
|||
const credentialsRes = await listProviderCredentialsApiV1ProviderCredentialsGet();
|
||||
if (credentialsRes.status !== 200) return [];
|
||||
|
||||
const credentials = (credentialsRes.data ?? []).filter(
|
||||
(cred) => cred.active && cred.has_session_key,
|
||||
const credentials = credentialsRes.data ?? [];
|
||||
const providerIds = Array.from(
|
||||
new Set(
|
||||
credentials
|
||||
.filter((cred) => cred.active && cred.has_session_key)
|
||||
.map((cred) => cred.provider),
|
||||
),
|
||||
);
|
||||
const selectedCredentials = providerIds
|
||||
.map((providerId) =>
|
||||
selectPreferredProviderCredential(
|
||||
credentials.filter((cred) => cred.has_session_key),
|
||||
providerId,
|
||||
),
|
||||
)
|
||||
.filter(
|
||||
(cred): cred is (typeof credentials)[number] =>
|
||||
Boolean(cred?.active && cred.has_session_key),
|
||||
);
|
||||
const settled = await Promise.allSettled(
|
||||
credentials.map((cred) =>
|
||||
selectedCredentials.map((cred) =>
|
||||
getProviderUsageLiveApiV1ProviderCredentialsCredentialIdUsageGet(
|
||||
cred.id,
|
||||
).then((res) => ({ cred, res })),
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ import {
|
|||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import {
|
||||
credentialIsUsable,
|
||||
selectPreferredProviderCredential,
|
||||
} from "@/lib/provider-credential-selection";
|
||||
|
||||
type NavbarProviderId = "anthropic" | "openai";
|
||||
|
||||
|
|
@ -134,42 +138,6 @@ function providerStatusColor(status: ProviderNavbarItem["status"]): string {
|
|||
return "bg-[color:var(--text-quiet)]";
|
||||
}
|
||||
|
||||
function credentialIsUsable(cred: ProviderCredentialRead): boolean {
|
||||
return cred.active && (cred.has_api_key || cred.has_session_key || Boolean(cred.base_url));
|
||||
}
|
||||
|
||||
function navbarCredentialScore(cred: ProviderCredentialRead): number {
|
||||
let score = 0;
|
||||
|
||||
if (cred.active) score += 100;
|
||||
if (cred.has_session_key) score += 50;
|
||||
if (cred.account_key === "default") score += 40;
|
||||
if (cred.display_name.toLowerCase().includes("local")) score += 30;
|
||||
if (cred.has_api_key) score += 10;
|
||||
if (cred.base_url) score += 5;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
function selectNavbarCredential(
|
||||
credentials: ProviderCredentialRead[],
|
||||
providerId: NavbarProviderId,
|
||||
): ProviderCredentialRead | null {
|
||||
const providerCredentials = credentials.filter((cred) => cred.provider === providerId);
|
||||
const usableCredentials = providerCredentials.filter(credentialIsUsable);
|
||||
|
||||
return (
|
||||
[...usableCredentials].sort((a, b) => {
|
||||
const scoreDelta = navbarCredentialScore(b) - navbarCredentialScore(a);
|
||||
if (scoreDelta !== 0) return scoreDelta;
|
||||
return a.account_key.localeCompare(b.account_key);
|
||||
})[0] ??
|
||||
providerCredentials.find((cred) => cred.active) ??
|
||||
providerCredentials[0] ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
function MiniRemainingBar({
|
||||
pct,
|
||||
className = "w-10",
|
||||
|
|
@ -202,7 +170,7 @@ function buildProviderNavbarItems({
|
|||
isLoading: boolean;
|
||||
}): ProviderNavbarItem[] {
|
||||
return NAVBAR_PROVIDER_IDS.map((providerId) => {
|
||||
const credential = selectNavbarCredential(credentials, providerId);
|
||||
const credential = selectPreferredProviderCredential(credentials, providerId);
|
||||
const activeCredential = credential && credentialIsUsable(credential) ? credential : null;
|
||||
const usage = activeCredential ? usageByCredentialId[activeCredential.id] : null;
|
||||
const status: ProviderNavbarItem["status"] = activeCredential
|
||||
|
|
@ -293,7 +261,7 @@ export function ProviderNavbarStatus() {
|
|||
|
||||
const usageCredentials = useMemo(() => {
|
||||
return NAVBAR_PROVIDER_IDS.map((providerId) =>
|
||||
selectNavbarCredential(credentials, providerId),
|
||||
selectPreferredProviderCredential(credentials, providerId),
|
||||
).filter((cred): cred is ProviderCredentialRead => Boolean(cred && credentialIsUsable(cred)));
|
||||
}, [credentials]);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
import type { ProviderCredentialRead } from "@/api/generated/model";
|
||||
|
||||
export function credentialIsUsable(cred: ProviderCredentialRead): boolean {
|
||||
return cred.active && (cred.has_api_key || cred.has_session_key || Boolean(cred.base_url));
|
||||
}
|
||||
|
||||
function providerCredentialScore(cred: ProviderCredentialRead): number {
|
||||
let score = 0;
|
||||
|
||||
if (cred.active) score += 100;
|
||||
if (cred.has_session_key) score += 50;
|
||||
if (cred.account_key === "default") score += 40;
|
||||
if (cred.display_name.toLowerCase().includes("local")) score += 30;
|
||||
if (cred.has_api_key) score += 10;
|
||||
if (cred.base_url) score += 5;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
export function selectPreferredProviderCredential(
|
||||
credentials: ProviderCredentialRead[],
|
||||
providerId: string,
|
||||
): ProviderCredentialRead | null {
|
||||
const providerCredentials = credentials.filter((cred) => cred.provider === providerId);
|
||||
const usableCredentials = providerCredentials.filter(credentialIsUsable);
|
||||
|
||||
return (
|
||||
[...usableCredentials].sort((a, b) => {
|
||||
const scoreDelta = providerCredentialScore(b) - providerCredentialScore(a);
|
||||
if (scoreDelta !== 0) return scoreDelta;
|
||||
return a.account_key.localeCompare(b.account_key);
|
||||
})[0] ??
|
||||
providerCredentials.find((cred) => cred.active) ??
|
||||
providerCredentials[0] ??
|
||||
null
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue