mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-11 03:38:38 +00:00
refactor(lens): name inline objects in the live run
This commit is contained in:
parent
775a808003
commit
8b9e799a19
4 changed files with 69 additions and 27 deletions
|
|
@ -11,7 +11,8 @@ import type { Job, Review } from "../../model/types";
|
|||
export function useJobReviews(api: LensApi, lensId: string, job: Pick<Job, "id" | "status">): readonly Review[] {
|
||||
const [feed, setFeed] = useState<ReviewFeed>(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 page = { lensId, jobId: job.id, after: feed.cursor, live };
|
||||
const { data } = useQuery(lensQueries.reviews(api, page));
|
||||
const next = data ? appendPage(feed, data) : feed;
|
||||
if (next !== feed) setFeed(next);
|
||||
return next.reviews;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ export function useStage(
|
|||
const [charMs] = useState(() => (prefersReducedMotion() ? 0 : CHAR_MS));
|
||||
const [stage, setStage] = useState(() => startStage(reviews));
|
||||
const [now, setNow] = useState(Date.now);
|
||||
const next = stepStage(stage, { reading, reviews, now, slots, running, charMs });
|
||||
const input = { reading, reviews, now, slots, running, charMs };
|
||||
const next = stepStage(stage, input);
|
||||
if (next !== stage) setStage(next);
|
||||
const busy = running || next.lanes.length > 0;
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import {
|
|||
outcome,
|
||||
providerOf,
|
||||
rateLabel,
|
||||
reviewKey,
|
||||
secondsToFinishReading,
|
||||
tokenLabel,
|
||||
} from "./live";
|
||||
|
|
@ -61,7 +60,10 @@ describe("provider from model", () => {
|
|||
});
|
||||
|
||||
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" } };
|
||||
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");
|
||||
|
|
@ -72,7 +74,6 @@ describe("provider from model", () => {
|
|||
expect(analysisModel(["", "analysis"])).toBe("analysis");
|
||||
expect(analysisModel([])).toBe("");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("review outcome", () => {
|
||||
|
|
@ -155,7 +156,6 @@ describe("conclusions", () => {
|
|||
expect(share(5, 0)).toBe(0);
|
||||
expect(share(9, 4)).toBe(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("which job the live run shows", () => {
|
||||
|
|
@ -189,7 +189,10 @@ describe("strip state", () => {
|
|||
const MODEL = "cerebras/gpt-oss-120b";
|
||||
|
||||
it("says what is happening before the first review instead of a silent spinner", () => {
|
||||
expect(stripState(base, MODEL)).toEqual({ kind: "waiting", message: "Reading 328 traces with cerebras/gpt-oss-120b…" });
|
||||
expect(stripState(base, MODEL)).toEqual({
|
||||
kind: "waiting",
|
||||
message: "Reading 328 traces with cerebras/gpt-oss-120b…",
|
||||
});
|
||||
expect(stripState({ ...base, stage: "Grouping observations" }, "")).toEqual({
|
||||
kind: "waiting",
|
||||
message: "Grouping observations…",
|
||||
|
|
@ -205,7 +208,10 @@ describe("strip state", () => {
|
|||
kind: "failed",
|
||||
message: "Anthropic: credit balance too low",
|
||||
});
|
||||
expect(stripState({ ...base, status: "failed" }, MODEL)).toEqual({ kind: "failed", message: "The investigation failed" });
|
||||
expect(stripState({ ...base, status: "failed" }, MODEL)).toEqual({
|
||||
kind: "failed",
|
||||
message: "The investigation failed",
|
||||
});
|
||||
});
|
||||
|
||||
it("surfaces a model error step while still running with nothing reviewed", () => {
|
||||
|
|
@ -228,16 +234,15 @@ describe("issue count", () => {
|
|||
|
||||
it("uses the job's issue findings once the run completes", () => {
|
||||
const findings = [{ kind: "issue" }, { kind: "pattern" }, { kind: "issue" }] as Job["findings"];
|
||||
expect(issueCount({ status: "completed", findings, reviews: [issueReview], reviewed: 328 })).toEqual({
|
||||
count: 2,
|
||||
scope: "findings",
|
||||
});
|
||||
const completed = { status: "completed" as const, findings, reviews: [issueReview], reviewed: 328 };
|
||||
expect(issueCount(completed)).toEqual({ count: 2, scope: "findings" });
|
||||
});
|
||||
|
||||
it("labels counts honestly when only the last reviews are kept", () => {
|
||||
const reviews = [issueReview, review("y"), issueReview];
|
||||
expect(issueCount({ status: "running", findings: null, reviews, reviewed: 3 })).toEqual({ count: 2, scope: "" });
|
||||
expect(issueCount({ status: "running", findings: null, reviews, reviewed: 120 })).toEqual({
|
||||
const running = { status: "running" as const, findings: null, reviews };
|
||||
expect(issueCount({ ...running, reviewed: 3 })).toEqual({ count: 2, scope: "" });
|
||||
expect(issueCount({ ...running, reviewed: 120 })).toEqual({
|
||||
count: 2,
|
||||
scope: "in last 3 reviewed",
|
||||
});
|
||||
|
|
@ -303,12 +308,36 @@ describe("live stats", () => {
|
|||
created_at: "2026-10-03T16:00:00Z",
|
||||
finished_at: null,
|
||||
steps: [
|
||||
{ at: "2026-10-03T16:00:05Z", kind: "stage", label: "Reading executions", model: "", purpose: "", cost: 0,
|
||||
prompt_tokens: 0, completion_tokens: 0 },
|
||||
{ at: "2026-10-03T16:00:06Z", kind: "model", label: "extract", model: "m", purpose: "extract", cost: 0.01,
|
||||
prompt_tokens: 1200, completion_tokens: 300 },
|
||||
{ at: "2026-10-03T16:00:07Z", kind: "model", label: "extract", model: "m", purpose: "extract", cost: 0.01,
|
||||
prompt_tokens: 800, completion_tokens: 200 },
|
||||
{
|
||||
at: "2026-10-03T16:00:05Z",
|
||||
kind: "stage",
|
||||
label: "Reading executions",
|
||||
model: "",
|
||||
purpose: "",
|
||||
cost: 0,
|
||||
prompt_tokens: 0,
|
||||
completion_tokens: 0,
|
||||
},
|
||||
{
|
||||
at: "2026-10-03T16:00:06Z",
|
||||
kind: "model",
|
||||
label: "extract",
|
||||
model: "m",
|
||||
purpose: "extract",
|
||||
cost: 0.01,
|
||||
prompt_tokens: 1200,
|
||||
completion_tokens: 300,
|
||||
},
|
||||
{
|
||||
at: "2026-10-03T16:00:07Z",
|
||||
kind: "model",
|
||||
label: "extract",
|
||||
model: "m",
|
||||
purpose: "extract",
|
||||
cost: 0.01,
|
||||
prompt_tokens: 800,
|
||||
completion_tokens: 200,
|
||||
},
|
||||
],
|
||||
} as unknown as Job;
|
||||
|
||||
|
|
@ -341,7 +370,11 @@ describe("live stats", () => {
|
|||
|
||||
describe("honest live list", () => {
|
||||
it("lists completed reviews newest first in the order they finished, never re-sorted by time", () => {
|
||||
const reviews = [review("a", { at: "2026-10-03T16:05:00Z" }), review("b", { at: "2026-10-03T16:01:00Z" }), review("c")];
|
||||
const reviews = [
|
||||
review("a", { at: "2026-10-03T16:05:00Z" }),
|
||||
review("b", { at: "2026-10-03T16:01:00Z" }),
|
||||
review("c"),
|
||||
];
|
||||
expect(newestFirst(reviews, 10).map((r) => r.execution_id)).toEqual(["c", "b", "a"]);
|
||||
expect(newestFirst(reviews, 2).map((r) => r.execution_id)).toEqual(["c", "b"]);
|
||||
expect(reviews.map((r) => r.execution_id)).toEqual(["a", "b", "c"]);
|
||||
|
|
@ -355,7 +388,12 @@ describe("honest live list", () => {
|
|||
});
|
||||
|
||||
it("keeps a trace as the same row from in flight to finished", () => {
|
||||
const reading = (id: string) => ({ execution_id: id, trace_id: `t-${id}`, agent: "bot", started_at: "2026-10-03T16:00:00Z" });
|
||||
const reading = (id: string) => ({
|
||||
execution_id: id,
|
||||
trace_id: `t-${id}`,
|
||||
agent: "bot",
|
||||
started_at: "2026-10-03T16:00:00Z",
|
||||
});
|
||||
const before = liveRows([reading("x"), reading("y")], [review("a")], 10);
|
||||
expect(before.map((row) => [row.kind, row.key])).toEqual([
|
||||
["reading", "x"],
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export function conclusions(reviews: readonly Review[], checks: Settings["checks
|
|||
return [...verdictsByCheck(review).values()].reduce((next, verdict) => {
|
||||
const prior = next.get(verdict.check_id);
|
||||
const issue = verdict.kind === "issue";
|
||||
return new Map(next).set(verdict.check_id, {
|
||||
const merged: Conclusion = {
|
||||
key: verdict.check_id,
|
||||
checkId: verdict.check_id,
|
||||
label: checkLabel(verdict.check_id, instructions.get(verdict.check_id)),
|
||||
|
|
@ -142,7 +142,8 @@ export function conclusions(reviews: readonly Review[], checks: Settings["checks
|
|||
count: (prior?.count ?? 0) + Number(issue),
|
||||
noted: (prior?.noted ?? 0) + Number(!issue),
|
||||
issue: (prior?.issue ?? false) || issue,
|
||||
});
|
||||
};
|
||||
return new Map(next).set(verdict.check_id, merged);
|
||||
}, groups);
|
||||
}, new Map<string, Conclusion>());
|
||||
return [...grouped.values()].sort((a, b) => b.count - a.count || b.noted - a.noted);
|
||||
|
|
@ -163,7 +164,6 @@ export function briefReasoning(reasoning: string): string {
|
|||
return sentences.slice(0, BRIEF_SENTENCES).join(" ").trim();
|
||||
}
|
||||
|
||||
|
||||
export function grownGroups(before: readonly Conclusion[], after: readonly Conclusion[]): Set<string> {
|
||||
const prior = new Map(before.map((group) => [group.key, group.count + group.noted]));
|
||||
return new Set(
|
||||
|
|
@ -220,7 +220,7 @@ export interface InFlight {
|
|||
|
||||
export function inFlight(job: Job): readonly InFlight[] {
|
||||
const reading = (job as Job & { reading?: readonly InFlight[] }).reading;
|
||||
return job.status === "running" ? (reading ?? []) : [];
|
||||
return job.status === "running" ? reading ?? [] : [];
|
||||
}
|
||||
|
||||
export type LiveRow = { kind: "reading"; key: string; item: InFlight } | { kind: "done"; key: string; review: Review };
|
||||
|
|
@ -242,7 +242,9 @@ export function nowLine(job: Pick<Job, "coverage" | "reviewed">, reading: number
|
|||
|
||||
export function durationLabel(ms: number): string {
|
||||
if (ms < 1000) return `${Math.max(0, Math.round(ms))}ms`;
|
||||
return ms < 60_000 ? `${(ms / 1000).toFixed(1)}s` : `${Math.floor(ms / 60_000)}m ${Math.round((ms % 60_000) / 1000)}s`;
|
||||
return ms < 60_000
|
||||
? `${(ms / 1000).toFixed(1)}s`
|
||||
: `${Math.floor(ms / 60_000)}m ${Math.round((ms % 60_000) / 1000)}s`;
|
||||
}
|
||||
|
||||
export function doneLine(job: Pick<Job, "reviewed" | "created_at" | "finished_at" | "steps">): string {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue