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 08cbe8d77cd..9091e0ab991 100644 --- a/ui/litellm-dashboard/src/components/lens/model/live.test.ts +++ b/ui/litellm-dashboard/src/components/lens/model/live.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "vitest"; import { + analysisModel, conclusions, liveStats, modelName, @@ -48,6 +49,12 @@ describe("provider from model", () => { expect(providerOf("/weird")).toBe(""); }); + 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"); + expect(analysisModel([])).toBe(""); + }); + it("drops only the provider prefix from the model name", () => { expect(modelName("openrouter/meta/llama")).toBe("meta/llama"); expect(modelName("analysis")).toBe("analysis"); @@ -102,11 +109,11 @@ describe("conclusions", () => { describe("playback pacing", () => { it("slows to a full window for one review and speeds up as the backlog grows", () => { - expect(stepDuration(1)).toBe(3200); - expect(stepDuration(4)).toBe(800); + expect(stepDuration(1)).toBe(4200); + expect(stepDuration(4)).toBe(1050); expect(stepDuration(10)).toBeLessThan(stepDuration(4)); expect(stepDuration(10_000)).toBe(140); - expect(stepDuration(0)).toBe(3200); + expect(stepDuration(0)).toBe(4200); }); it("highlights spans one at a time, then types reasoning, then shows the verdict", () => { diff --git a/ui/litellm-dashboard/src/components/lens/model/live.ts b/ui/litellm-dashboard/src/components/lens/model/live.ts index a3346737d87..7c117244547 100644 --- a/ui/litellm-dashboard/src/components/lens/model/live.ts +++ b/ui/litellm-dashboard/src/components/lens/model/live.ts @@ -23,7 +23,7 @@ export interface LiveStats { elapsedSeconds: number; } -const PACE_WINDOW_MS = 3200; +const PACE_WINDOW_MS = 4200; const MIN_STEP_MS = 140; const COMPACT_STEP_MS = 700; const READ_SHARE = 0.35; @@ -69,8 +69,16 @@ export function stepDuration(backlog: number): number { return Math.max(MIN_STEP_MS, Math.min(PACE_WINDOW_MS, Math.round(PACE_WINDOW_MS / Math.max(1, backlog)))); } +export function isCompact(duration: number): boolean { + return duration < COMPACT_STEP_MS; +} + +export function analysisModel(candidates: readonly string[]): string { + return candidates.find((model) => providerOf(model)) ?? candidates.find(Boolean) ?? ""; +} + export function playbackPhase(elapsed: number, duration: number, spans: number, chars: number): Phase { - if (duration < COMPACT_STEP_MS) return { span: -1, typed: chars, verdict: true }; + if (isCompact(duration)) return { span: -1, typed: chars, verdict: true }; const t = Math.max(0, elapsed) / duration; const reading = t < READ_SHARE; const span = reading && spans > 0 ? Math.min(spans - 1, Math.floor((t / READ_SHARE) * spans)) : -1;