From 7ef76eabffad9e048354f497030e2184208624be Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 3 Oct 2026 17:40:35 -0700 Subject: [PATCH] fix(lens): feed the live run from the reviews endpoint and keep View run open LiveRun now gets its reviews from useJobReviews instead of the list, which no longer carries them. View run stays clickable while a run is queued or running, and before the first trace the opened view says what the worker is doing. --- .../investigations/InvestigationsView.tsx | 1 + .../detail/InvestigationDetail.tsx | 8 ++++++- .../lens/investigations/live/LiveDrawer.tsx | 9 ++++++-- .../lens/investigations/live/LiveRun.tsx | 16 +++++++------- .../investigations/live/LiveRunLoader.tsx | 21 +++++++++++++++++++ .../lens/investigations/live/LiveStrip.tsx | 2 +- .../lens/investigations/live/useJobReviews.ts | 18 ++++++++++++++++ .../lens/investigations/useQueueReason.ts | 2 ++ 8 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/lens/investigations/live/LiveRunLoader.tsx create mode 100644 ui/litellm-dashboard/src/components/lens/investigations/live/useJobReviews.ts diff --git a/ui/litellm-dashboard/src/components/lens/investigations/InvestigationsView.tsx b/ui/litellm-dashboard/src/components/lens/investigations/InvestigationsView.tsx index 187e96df238..f7756471dec 100644 --- a/ui/litellm-dashboard/src/components/lens/investigations/InvestigationsView.tsx +++ b/ui/litellm-dashboard/src/components/lens/investigations/InvestigationsView.tsx @@ -282,6 +282,7 @@ export function InvestigationsView({ results={results} agents={Array.isArray(agents.data) ? agents.data : []} queue={{ + api, lenses, workers: query.data?.workers ?? [], onConnect: () => setWorkerSetup(true), diff --git a/ui/litellm-dashboard/src/components/lens/investigations/detail/InvestigationDetail.tsx b/ui/litellm-dashboard/src/components/lens/investigations/detail/InvestigationDetail.tsx index 431bc9eefd3..a2f06a5af12 100644 --- a/ui/litellm-dashboard/src/components/lens/investigations/detail/InvestigationDetail.tsx +++ b/ui/litellm-dashboard/src/components/lens/investigations/detail/InvestigationDetail.tsx @@ -7,6 +7,7 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; import { RunsTab } from "./RunsTab"; import { InvestigationProgress } from "../InvestigationProgress"; import { LiveRun } from "../live/LiveRun"; +import { LiveRunLoader } from "../live/LiveRunLoader"; import { type QueueContext } from "../useQueueReason"; import { liveJob } from "../../model/live"; import { RunNowDialog } from "./RunNowDialog"; @@ -109,7 +110,12 @@ export function InvestigationDetail({ onCancel={readOnly ? undefined : () => void update((api) => api.cancelRun(lens.id))} /> )} - {live && } + {live && + (queue ? ( + + ) : ( + + ))} {runNow && ( void; name: string; @@ -86,7 +88,10 @@ export function LiveDrawer({ phase={following ? phase : SETTLED} /> ) : ( -

Waiting for the first trace review.

+
+

Waiting for the first trace…

+ {waiting} +
)}
diff --git a/ui/litellm-dashboard/src/components/lens/investigations/live/LiveRun.tsx b/ui/litellm-dashboard/src/components/lens/investigations/live/LiveRun.tsx index 1a4fcf44fe2..d046fbd4069 100644 --- a/ui/litellm-dashboard/src/components/lens/investigations/live/LiveRun.tsx +++ b/ui/litellm-dashboard/src/components/lens/investigations/live/LiveRun.tsx @@ -50,6 +50,12 @@ export function LiveRun({ if (review) pin(review); setDrawerOpen(true); }; + const waiting = reason && ( + <> + + + + ); return ( <> @@ -57,14 +63,7 @@ export function LiveRun({ - - - - ) - } + waiting={waiting} playback={playback} reviewed={reviewed} selected={job.coverage.selected} @@ -97,6 +96,7 @@ export function LiveRun({ groups={conclusions(decided, job.settings.checks)} decided={decided.length} scope={job.reviewed > reviews.length ? `From the latest ${reviews.length} of ${job.reviewed} reviewed traces` : ""} + waiting={waiting} onPick={pin} onFollow={() => setPinned(null)} /> diff --git a/ui/litellm-dashboard/src/components/lens/investigations/live/LiveRunLoader.tsx b/ui/litellm-dashboard/src/components/lens/investigations/live/LiveRunLoader.tsx new file mode 100644 index 00000000000..2e7e854365a --- /dev/null +++ b/ui/litellm-dashboard/src/components/lens/investigations/live/LiveRunLoader.tsx @@ -0,0 +1,21 @@ +"use client"; + +import type { Job } from "../../model/types"; +import type { QueueContext } from "../useQueueReason"; +import { LiveRun } from "./LiveRun"; +import { useJobReviews } from "./useJobReviews"; + +export function LiveRunLoader({ + lensId, + job, + name, + queue, +}: { + lensId: string; + job: Job; + name: string; + queue: QueueContext; +}) { + const reviews = useJobReviews(queue.api, lensId, job); + return ; +} 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 3a7db401f5a..b493e286084 100644 --- a/ui/litellm-dashboard/src/components/lens/investigations/live/LiveStrip.tsx +++ b/ui/litellm-dashboard/src/components/lens/investigations/live/LiveStrip.tsx @@ -112,7 +112,7 @@ export function LiveStrip({ )}
- diff --git a/ui/litellm-dashboard/src/components/lens/investigations/live/useJobReviews.ts b/ui/litellm-dashboard/src/components/lens/investigations/live/useJobReviews.ts new file mode 100644 index 00000000000..e6c47f40119 --- /dev/null +++ b/ui/litellm-dashboard/src/components/lens/investigations/live/useJobReviews.ts @@ -0,0 +1,18 @@ +"use client"; + +import { useQuery } from "@tanstack/react-query"; +import { useState } from "react"; + +import { lensQueries } from "../../api/queries"; +import type { LensApi } from "../../api/service"; +import { appendPage, EMPTY_FEED, type ReviewFeed } from "../../model/live"; +import type { Job, Review } from "../../model/types"; + +export function useJobReviews(api: LensApi, lensId: string, job: Pick): readonly Review[] { + const [feed, setFeed] = useState(EMPTY_FEED); + const live = job.status === "queued" || job.status === "running"; + const { data } = useQuery(lensQueries.reviews(api, { lensId, jobId: job.id, after: feed.cursor, live })); + const next = data ? appendPage(feed, data) : feed; + if (next !== feed) setFeed(next); + return next.reviews; +} diff --git a/ui/litellm-dashboard/src/components/lens/investigations/useQueueReason.ts b/ui/litellm-dashboard/src/components/lens/investigations/useQueueReason.ts index 7337892d671..155f8564e59 100644 --- a/ui/litellm-dashboard/src/components/lens/investigations/useQueueReason.ts +++ b/ui/litellm-dashboard/src/components/lens/investigations/useQueueReason.ts @@ -2,10 +2,12 @@ import { useNow } from "@/hooks/useNow"; +import type { LensApi } from "../api/service"; import { queueReason, type QueueReason } from "../model/status"; import type { Job, Lens, LensList } from "../model/types"; export interface QueueContext { + api: LensApi; lenses: readonly Lens[]; workers: readonly LensList["workers"][number][]; onConnect: () => void;