fix(lens): restore the onboarding reference visuals

This commit is contained in:
moe-berri 2026-10-03 18:23:25 -07:00
parent 06a50d055a
commit debe7b2343
3 changed files with 214 additions and 73 deletions

View file

@ -65,10 +65,10 @@ export function LensGettingStarted({
};
return (
<div className="mx-auto w-full max-w-6xl space-y-8 py-4">
<div className="mx-auto w-full max-w-7xl space-y-10 py-5 sm:space-y-12 sm:py-7">
{onDemo && <LensPreviewButton onClick={onDemo} />}
<LensIntroduction onStart={start} onDemo={onDemo} />
<div className="grid items-start gap-6 lg:grid-cols-[minmax(0,1fr)_260px]">
<div className="grid items-start gap-6 xl:grid-cols-[minmax(0,1fr)_280px] xl:gap-8">
<section
ref={setupRef}
tabIndex={-1}
@ -76,13 +76,13 @@ export function LensGettingStarted({
className="min-w-0 scroll-mt-4 outline-none"
onFocusCapture={onStart}
>
<div className="mb-5 flex flex-wrap items-center justify-between gap-3">
<div className="mb-6 flex flex-wrap items-center justify-between gap-3">
<div>
<h2 id="lens-setup-title" className="text-xl font-semibold tracking-tight">
<h2 id="lens-setup-title" className="text-2xl font-semibold tracking-tight">
Get Lens running
</h2>
<p className="mt-1 text-sm text-muted-foreground">
We’ll check each connection. Stay here until your first investigation is ready.
<p className="mt-2 text-sm leading-6 text-muted-foreground">
Each step checks your connection, so you’ll see when it’s working.
</p>
</div>
{canLeave && (
@ -117,20 +117,23 @@ export function LensGettingStarted({
</p>
)}
</section>
<aside className="rounded-lg border p-5" aria-labelledby="lens-prerequisites">
<h2 id="lens-prerequisites" className="text-base font-medium">
<aside className="rounded-2xl border bg-card p-6" aria-labelledby="lens-prerequisites">
<h2 id="lens-prerequisites" className="text-base font-semibold">
Before you start
</h2>
<ul className="mt-4 space-y-4 text-sm text-muted-foreground">
<ul className="mt-5 space-y-5 text-sm">
{[
"Access to your LiteLLM gateway configuration",
"ClickHouse for trace storage",
"A server with Docker for the worker",
"An analysis model on your gateway",
{ title: "LiteLLM gateway", detail: "Access to its configuration" },
{ title: "ClickHouse", detail: "Self-hosted or managed trace storage" },
{ title: "A server with Docker", detail: "To run the analysis worker" },
{ title: "An analysis model", detail: "Available through your gateway" },
].map((item) => (
<li key={item} className="flex gap-2">
<Check aria-hidden="true" className="mt-0.5 size-4 shrink-0" />
{item}
<li key={item.title} className="flex gap-3">
<Check aria-hidden="true" className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<div>
<p className="font-medium">{item.title}</p>
<p className="mt-1 leading-5 text-muted-foreground">{item.detail}</p>
</div>
</li>
))}
</ul>

View file

@ -1,70 +1,198 @@
import { Aperture, ArrowRight, ArrowUpRight, GitBranch } from "lucide-react";
import { useId } from "react";
import { ArrowRight, ArrowUpRight, ChevronDown, ChevronRight } from "lucide-react";
import { Button } from "@/components/ui/button";
import { scenarios } from "../demo/scenarios";
const swarmColors = ["fill-violet-400", "fill-sky-400", "fill-amber-400", "fill-rose-400", "fill-indigo-400"];
function flowDot(index: number) {
const column = index % 100;
const row = Math.floor(index / 100);
const wave = 2.5 + 2.6 * Math.sin((column + 5) / 3.8);
if (Math.abs(row - wave) > 0.9) return null;
return {
x: column * 10 + 5,
y: row * 10 + 5,
color: column < 61 ? swarmColors[(column + row) % swarmColors.length] : "fill-indigo-600 dark:fill-indigo-400",
};
}
const flowDots = Array.from({ length: 600 }, (_, index) => flowDot(index)).filter((dot) => dot !== null);
function GatewayFlow() {
const patternId = useId();
return (
<div className="mt-10 sm:mt-12">
<div className="grid grid-cols-3 gap-3 text-xs sm:text-sm">
<div>
<p className="font-semibold">Agent swarms</p>
<p className="mt-1 leading-5 text-muted-foreground">Every run, every recorded step</p>
</div>
<div className="text-center">
<p className="font-semibold">LiteLLM gateway</p>
<p className="mt-1 leading-5 text-muted-foreground">One place, your infrastructure</p>
</div>
<div className="text-right">
<p className="font-semibold">Lens</p>
<p className="mt-1 leading-5 text-muted-foreground">Findings to improve your agents</p>
</div>
</div>
<svg aria-hidden="true" viewBox="0 0 1000 60" className="mt-3 h-auto w-full" focusable="false">
<defs>
<pattern id={patternId} width="10" height="10" patternUnits="userSpaceOnUse">
<circle cx="5" cy="5" r="2.3" className="fill-muted-foreground/10" />
</pattern>
</defs>
<rect width="1000" height="60" fill={`url(#${patternId})`} />
{flowDots.map((dot) => (
<circle key={`${dot.x}-${dot.y}`} cx={dot.x} cy={dot.y} r="2.3" className={dot.color} />
))}
<path d="M 615 1 H 609 V 59 H 615" fill="none" stroke="currentColor" strokeWidth="1.8" />
</svg>
</div>
);
}
const traceSteps = [
{ name: "research_agent", start: 0, duration: 14.2, failed: false },
{ name: "plan", start: 0, duration: 1.7, failed: false },
{ name: "search_docs", start: 1.7, duration: 3.1, failed: false },
{ name: "run_benchmark", start: 4.8, duration: 1.3, failed: true },
{ name: "search_docs", start: 6.1, duration: 3.6, failed: false },
{ name: "answer", start: 9.7, duration: 4.5, failed: false },
];
const sampleAnswer = "The column store is 40% faster than the row store for your workload.";
function TraceExample() {
return (
<section aria-labelledby="lens-sample-trace" className="min-w-0 rounded-2xl border bg-card p-4 sm:p-5">
<div className="flex flex-wrap items-center justify-between gap-2 text-sm">
<h3 id="lens-sample-trace" className="font-semibold">
Tracing
</h3>
<p className="text-xs text-muted-foreground">Sample trace · 14.2s</p>
</div>
<ol className="mt-5 space-y-3.5 text-xs sm:text-[13px]" aria-label="Sample trace timeline">
{traceSteps.map((item, index) => (
<li
key={`${item.name}-${item.start}`}
className="grid grid-cols-[minmax(0,1fr)_minmax(48px,1fr)_2.5rem] items-center gap-2 sm:gap-3"
>
<span className={`flex min-w-0 items-center gap-1 ${index > 0 ? "pl-2" : ""}`}>
{index === 0 ? (
<ChevronDown aria-hidden="true" className="size-3 shrink-0" />
) : (
<ChevronRight aria-hidden="true" className="size-3 shrink-0" />
)}
<span className="truncate" title={item.name}>
{item.name}
</span>
{item.failed && <span className="sr-only">Failed</span>}
</span>
<span aria-hidden="true" className="relative h-2.5 overflow-hidden rounded-sm bg-muted/70">
<span
className={`absolute inset-y-0 rounded-sm ${item.failed ? "bg-rose-400" : "bg-indigo-600 dark:bg-indigo-400"}`}
style={{ left: `${(item.start / 14.2) * 100}%`, width: `${(item.duration / 14.2) * 100}%` }}
/>
</span>
<span className="text-right tabular-nums text-muted-foreground">{item.duration}s</span>
</li>
))}
</ol>
<div className="mt-5 grid gap-3 border-t pt-4 sm:grid-cols-2">
<div className="rounded-xl bg-muted/60 p-3.5">
<p className="text-xs text-muted-foreground">run_benchmark · output</p>
<p className="mt-2 text-[13px] leading-5">Error: benchmark runner unavailable (503)</p>
</div>
<div className="rounded-xl bg-muted/60 p-3.5">
<p className="text-xs text-muted-foreground">answer · output</p>
<p className="mt-2 text-[13px] leading-5">“{sampleAnswer}”</p>
</div>
</div>
</section>
);
}
function FindingExamples() {
return (
<section aria-labelledby="lens-sample-findings" className="min-w-0 rounded-2xl border bg-card p-4 sm:p-5">
<div className="flex flex-wrap items-center justify-between gap-2 text-sm">
<h3 id="lens-sample-findings" className="font-semibold">
Lens findings
</h3>
<p className="text-xs text-muted-foreground">500 sample runs reviewed</p>
</div>
<div className="mt-4 divide-y border-t">
<article className="py-4">
<h4 className="flex items-start gap-2 text-sm font-semibold">
<span aria-hidden="true" className="mt-1.5 size-2 shrink-0 rounded-full bg-rose-500" />
Claims numbers it never measured
</h4>
<div className="ml-4 mt-2 space-y-2 text-[13px] leading-5">
<p className="text-muted-foreground">
When the benchmark tool fails, the agent still reports a speedup in its answer.
</p>
<blockquote className="border-l-2 pl-3 italic">“{sampleAnswer}”</blockquote>
<p>
<span className="text-muted-foreground">Next step: </span>Tell the agent to report the failed benchmark
instead of estimating.
</p>
<p className="text-xs text-muted-foreground">38 linked runs · High priority</p>
</div>
</article>
<article className="pt-4">
<h4 className="flex items-start gap-2 text-sm font-semibold">
<span aria-hidden="true" className="mt-1.5 size-2 shrink-0 rounded-full bg-amber-500" />
Promises to follow up, then stops
</h4>
<div className="ml-4 mt-2 space-y-2 text-[13px] leading-5 text-muted-foreground">
<p>After the order lookup times out, the support agent replies “I will check” and ends the run.</p>
<p className="text-xs">12 linked runs · Medium priority</p>
</div>
</article>
</div>
</section>
);
}
export function LensIntroduction({ onStart, onDemo }: { onStart: () => void; onDemo?: () => void }) {
const example = scenarios[1];
return (
<section aria-labelledby="lens-introduction" className="rounded-lg border bg-card p-5 sm:p-8">
<h2 id="lens-introduction" className="max-w-2xl text-2xl font-semibold tracking-tight sm:text-3xl">
<section
aria-labelledby="lens-introduction"
className="rounded-2xl border bg-card p-5 sm:p-8 xl:rounded-3xl xl:p-10"
>
<h2
id="lens-introduction"
className="max-w-[800px] text-3xl leading-[1.12] font-semibold tracking-[-0.035em] sm:text-4xl xl:text-[42px]"
>
The gateway that helps your agents improve
</h2>
<p className="mt-3 max-w-2xl text-sm leading-6 text-muted-foreground">
Lens reviews your agents’ recorded activity and finds behavior worth fixing. Each finding links to the original
steps, so you can see what happened and what to change next.
<p className="mt-5 max-w-[780px] text-base leading-7 text-muted-foreground">
Lens turns recorded agent runs into findings tied to the exact steps that caused them, so you can see what needs
to change without reading every trace by hand.
</p>
<div className="mt-6 flex flex-wrap items-center gap-3">
<div className="mt-7 flex flex-wrap items-center gap-3">
{onDemo && (
<Button onClick={onDemo}>
<Button size="lg" className="h-11 rounded-lg px-5" onClick={onDemo}>
Explore with sample data <ArrowRight aria-hidden="true" className="size-4" />
</Button>
)}
<Button variant={onDemo ? "outline" : "default"} onClick={onStart}>
<Button size="lg" variant={onDemo ? "outline" : "default"} className="h-11 rounded-lg px-5" onClick={onStart}>
Set up Lens
</Button>
<a
href="https://docs.litellm.ai/docs/proxy/lens"
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1 px-2 text-sm text-muted-foreground underline-offset-4 hover:underline"
className="inline-flex items-center gap-1 px-3 text-sm font-medium text-muted-foreground underline-offset-4 hover:underline"
>
Docs <ArrowUpRight aria-hidden="true" className="size-3.5" />
Docs <ArrowUpRight aria-hidden="true" className="size-4" />
</a>
</div>
<div className="mt-8 grid overflow-hidden rounded-lg border lg:grid-cols-2">
<div className="border-b bg-muted/20 p-5 lg:border-r lg:border-b-0">
<div className="flex flex-wrap items-center justify-between gap-2 text-sm">
<h3 className="flex items-center gap-2 font-medium">
<GitBranch aria-hidden="true" className="size-4" />
Agent trace
</h3>
<span className="text-xs text-muted-foreground">Sample · {example.agent}</span>
</div>
<dl className="mt-5 space-y-4 text-sm">
<div>
<dt className="font-mono text-xs text-muted-foreground">{example.tool}</dt>
<dd className="mt-1.5 leading-6">{example.result}</dd>
</div>
<div className="border-t pt-4">
<dt className="text-xs text-muted-foreground">Final answer</dt>
<dd className="mt-1.5 leading-6">“{example.answer}”</dd>
</div>
</dl>
</div>
<div className="p-5">
<h3 className="flex items-center gap-2 text-sm font-medium">
<Aperture aria-hidden="true" className="size-4" />
Lens finding
</h3>
<h4 className="mt-5 text-base font-medium">Performance claim has no supporting benchmark</h4>
<p className="mt-2 text-sm leading-6 text-muted-foreground">
The answer claims a 40% improvement, but the retrieved documentation contains no comparative benchmark.
</p>
<p className="mt-4 border-t pt-4 text-sm leading-6">
<span className="font-medium">Suggested change: </span>Require a benchmark source for numerical performance
claims, or remove the comparison.
</p>
</div>
<GatewayFlow />
<div className="mt-7 grid items-stretch gap-4 lg:grid-cols-2">
<TraceExample />
<FindingExamples />
</div>
</section>
);

View file

@ -3,6 +3,7 @@ import { Button } from "@/components/ui/button";
import { TracingSetupFields } from "@/components/view_logs/TraceView/TracingSetupCard";
import type { TraceSummary } from "@/components/view_logs/TraceView/traceTypes";
import type { LensSetupState } from "./useLensSetup";
import { cn } from "@/lib/cva.config";
type StepProps = {
accessToken: string;
@ -160,7 +161,7 @@ export function LensSetupSteps({ step, ...props }: StepProps & { step: number })
},
];
return (
<ol className="divide-y overflow-hidden rounded-lg border">
<ol className="divide-y overflow-hidden rounded-2xl border bg-card">
{items.map((item, index) => (
<li key={item.title}>
<h3>
@ -169,21 +170,30 @@ export function LensSetupSteps({ step, ...props }: StepProps & { step: number })
aria-expanded={step === index}
aria-controls={`lens-setup-step-${index}`}
onClick={() => props.onStep(index)}
className="flex w-full items-start gap-3 p-5 text-left hover:bg-muted/30"
className="group flex w-full items-start gap-4 p-5 text-left outline-none hover:bg-muted/30 focus-visible:bg-muted/50 sm:p-6"
>
<span
className={
item.complete
? "flex size-7 shrink-0 items-center justify-center rounded-full bg-success/10 text-success"
: "flex size-7 shrink-0 items-center justify-center rounded-full border text-xs font-medium"
}
className={cn(
"flex size-8 shrink-0 items-center justify-center rounded-full text-sm font-medium",
item.complete ? "bg-success/10 text-success" : "border text-muted-foreground",
!item.complete && step === index && "border-primary bg-primary text-primary-foreground",
)}
aria-label={item.complete ? `Step ${index + 1} complete` : `Step ${index + 1}`}
>
{item.complete ? <Check aria-hidden="true" className="size-4" /> : index + 1}
</span>
<span className="min-w-0 flex-1">
<span className="block text-sm font-medium">{item.title}</span>
<span className="mt-1 block text-sm font-normal text-muted-foreground">{item.description}</span>
<span
className={cn(
"block text-sm font-medium sm:text-base",
step !== index && "text-muted-foreground group-hover:text-foreground",
)}
>
{item.title}
</span>
<span className="mt-1 block text-sm leading-6 font-normal text-muted-foreground">
{item.description}
</span>
</span>
<ChevronDown
aria-hidden="true"
@ -191,7 +201,7 @@ export function LensSetupSteps({ step, ...props }: StepProps & { step: number })
/>
</button>
</h3>
<div id={`lens-setup-step-${index}`} hidden={step !== index} className="px-5 pb-5 sm:pl-15">
<div id={`lens-setup-step-${index}`} hidden={step !== index} className="px-5 pb-6 sm:pr-6 sm:pb-7 sm:pl-18">
{item.content}
</div>
</li>