From 3c8309272f5bc66835a680b7e5ce9d5a2409f13a Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 3 Oct 2026 18:09:50 -0700 Subject: [PATCH] fix(lens): resolve the analysis provider logo from the model catalog --- .../lens/investigations/live/LiveStrip.tsx | 4 +++- .../src/components/lens/model/live.test.ts | 13 ++++++++++--- .../src/components/lens/model/live.ts | 14 +++++++++----- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/ui/litellm-dashboard/src/components/lens/investigations/live/LiveStrip.tsx b/ui/litellm-dashboard/src/components/lens/investigations/live/LiveStrip.tsx index 5ef6d694864..c63edb41bbd 100644 --- a/ui/litellm-dashboard/src/components/lens/investigations/live/LiveStrip.tsx +++ b/ui/litellm-dashboard/src/components/lens/investigations/live/LiveStrip.tsx @@ -3,6 +3,7 @@ import { ArrowRight, PanelRight, X } from "lucide-react"; import type { ReactNode } from "react"; +import { useModelCostMap } from "@/app/(dashboard)/hooks/models/useModelCostMap"; import { ProviderLogo } from "@/components/molecules/models/ProviderLogo"; import { agoLabel } from "@/components/view_logs/TraceView/lensField"; import { Button } from "@/components/ui/button"; @@ -18,8 +19,9 @@ const MARK = { issue: "●", clear: "✓", unknown: "–" } as const; const LOGO = { sm: "size-3.5", md: "size-[18px]" } as const; export function ModelName({ model, size = "sm" }: { model: string; size?: keyof typeof LOGO }) { + const { data: catalog } = useModelCostMap(); if (!model) return null; - const provider = providerOf(model); + const provider = providerOf(model, catalog ?? {}); return ( {provider && } diff --git a/ui/litellm-dashboard/src/components/lens/model/live.test.ts b/ui/litellm-dashboard/src/components/lens/model/live.test.ts index e9814c5d7a9..c9e701c92c4 100644 --- a/ui/litellm-dashboard/src/components/lens/model/live.test.ts +++ b/ui/litellm-dashboard/src/components/lens/model/live.test.ts @@ -60,6 +60,13 @@ describe("provider from model", () => { expect(providerOf("/weird")).toBe(""); }); + it("resolves a bare model name through the model catalog", () => { + const catalog = { "gpt-5.6": { litellm_provider: "openai" }, "cerebras/gpt-oss-120b": { litellm_provider: "cerebras" } }; + expect(providerOf("gpt-5.6", catalog)).toBe("openai"); + expect(providerOf("my-alias", catalog)).toBe(""); + expect(analysisModel(["", "gpt-5.6"], catalog)).toBe("gpt-5.6"); + }); + it("prefers a model that names its provider over a bare alias", () => { expect(analysisModel(["analysis", "", "cerebras/gpt-oss-120b"])).toBe("cerebras/gpt-oss-120b"); expect(analysisModel(["", "analysis"])).toBe("analysis"); @@ -342,9 +349,9 @@ describe("honest live list", () => { it("says how many traces are in flight and how many are done", () => { const job = (reviewed: number, selected: number) => ({ reviewed, coverage: { selected } }) as unknown as Job; - expect(nowLine(job(18, 30), 4)).toBe("Reviewing 4 at a time · 18 of 30 done"); - expect(nowLine(job(30, 30), 0)).toBe("30 of 30 done"); - expect(nowLine(job(3, 0), 1)).toBe("Reviewing 1 at a time · 3 done"); + expect(nowLine(job(18, 30), 4)).toBe("18 of 30 · 4 in flight"); + expect(nowLine(job(30, 30), 0)).toBe("30 of 30"); + expect(nowLine(job(3, 0), 1)).toBe("3 done · 1 in flight"); }); it("keeps a trace as the same row from in flight to finished", () => { diff --git a/ui/litellm-dashboard/src/components/lens/model/live.ts b/ui/litellm-dashboard/src/components/lens/model/live.ts index 67f659623d2..fcd18105d7f 100644 --- a/ui/litellm-dashboard/src/components/lens/model/live.ts +++ b/ui/litellm-dashboard/src/components/lens/model/live.ts @@ -31,7 +31,11 @@ export function reviewKey(review: Pick): string { return `${review.execution_id}@${review.at}`; } -export function providerOf(model: string): string { +export type ProviderCatalog = Readonly>; + +export function providerOf(model: string, catalog: ProviderCatalog = {}): string { + const known = catalog[model]?.litellm_provider; + if (known) return known.toLowerCase(); const slash = model.indexOf("/"); return slash > 0 ? model.slice(0, slash).toLowerCase() : ""; } @@ -104,8 +108,8 @@ export function unseen(reviews: readonly Review[], seen: ReadonlySet): R return reviews.filter((review) => !seen.has(reviewKey(review))); } -export function analysisModel(candidates: readonly string[]): string { - return candidates.find((model) => providerOf(model)) ?? candidates.find(Boolean) ?? ""; +export function analysisModel(candidates: readonly string[], catalog: ProviderCatalog = {}): string { + return candidates.find((model) => providerOf(model, catalog)) ?? candidates.find(Boolean) ?? ""; } const SHORT_LABEL = 48; @@ -232,8 +236,8 @@ export function liveRows(reading: readonly InFlight[], reviews: readonly Review[ export function nowLine(job: Pick, reading: number): string { const { selected } = job.coverage; - const done = selected ? `${Math.min(job.reviewed, selected)} of ${selected} done` : `${job.reviewed} done`; - return reading ? `Reviewing ${reading} at a time · ${done}` : done; + const done = selected ? `${Math.min(job.reviewed, selected)} of ${selected}` : `${job.reviewed} done`; + return reading ? `${done} · ${reading} in flight` : done; } export function durationLabel(ms: number): string {