From 268b183dee756271f629b93a30050bb77f151331 Mon Sep 17 00:00:00 2001 From: Michael Preuss Date: Thu, 12 Feb 2026 21:21:14 -0800 Subject: [PATCH] Add objective deep-dive pages under eval recommendations --- .../[objectiveSlug]/objective-content.tsx | 631 ++++++++++++++++++ .../recommendations/[objectiveSlug]/page.tsx | 102 +++ .../recommendations/[roleId]/compare/page.tsx | 2 - .../evals/recommendations/[roleId]/page.tsx | 2 - .../src/app/evals/recommendations/layout.tsx | 9 + .../src/app/evals/recommendations/page.tsx | 47 +- .../roles/[roleId]/compare/page.tsx | 85 +++ .../recommendations/roles/[roleId]/page.tsx | 101 +++ .../workers/[roleId]/candidates-content.tsx | 31 +- .../[roleId]/compare/comparison-chart.tsx | 31 +- .../evals/workers/[roleId]/compare/page.tsx | 4 +- .../src/app/evals/workers/[roleId]/page.tsx | 4 +- .../src/app/evals/workers/workers-content.tsx | 21 +- apps/web-roo-code/src/lib/eval-outcomes.ts | 12 + 14 files changed, 1026 insertions(+), 56 deletions(-) create mode 100644 apps/web-roo-code/src/app/evals/recommendations/[objectiveSlug]/objective-content.tsx create mode 100644 apps/web-roo-code/src/app/evals/recommendations/[objectiveSlug]/page.tsx delete mode 100644 apps/web-roo-code/src/app/evals/recommendations/[roleId]/compare/page.tsx delete mode 100644 apps/web-roo-code/src/app/evals/recommendations/[roleId]/page.tsx create mode 100644 apps/web-roo-code/src/app/evals/recommendations/layout.tsx create mode 100644 apps/web-roo-code/src/app/evals/recommendations/roles/[roleId]/compare/page.tsx create mode 100644 apps/web-roo-code/src/app/evals/recommendations/roles/[roleId]/page.tsx diff --git a/apps/web-roo-code/src/app/evals/recommendations/[objectiveSlug]/objective-content.tsx b/apps/web-roo-code/src/app/evals/recommendations/[objectiveSlug]/objective-content.tsx new file mode 100644 index 0000000000..2ceea57a0f --- /dev/null +++ b/apps/web-roo-code/src/app/evals/recommendations/[objectiveSlug]/objective-content.tsx @@ -0,0 +1,631 @@ +"use client" + +import { useCallback, useMemo, useState } from "react" +import Link from "next/link" +import { useSearchParams } from "next/navigation" +import { motion } from "framer-motion" +import { ArrowRight, BarChart3, Copy, ExternalLink, SlidersHorizontal, Sparkles, Workflow } from "lucide-react" +import { Cell, ResponsiveContainer, Scatter, ScatterChart, Tooltip, XAxis, YAxis, ZAxis } from "recharts" + +import type { RoleRecommendation, ModelCandidate } from "@/lib/mock-recommendations" +import { getCloudSetupUrl } from "@/lib/mock-recommendations" + +type EvalOptimizationMode = "best" | "fastest" | "cost" + +type ObjectiveDeepDive = { + id: string + slug: string + name: string + description: string + whyItWorks: string[] + recommendedRoleIds: string[] + builderProfile?: { + title: string + description: string + examplePrompt?: string + howItWorks: string[] + } +} + +type ObjectiveRoleRec = { + roleId: string + recommendation: RoleRecommendation +} + +type Props = { + objective: ObjectiveDeepDive + initialMode: EvalOptimizationMode + recs: ObjectiveRoleRec[] +} + +const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { staggerChildren: 0.08, delayChildren: 0.08 }, + }, +} + +const fadeUp = { + hidden: { opacity: 0, y: 14 }, + visible: { opacity: 1, y: 0, transition: { duration: 0.55, ease: [0.21, 0.45, 0.27, 0.9] as const } }, +} + +function isEvalOptimizationMode(value: string): value is EvalOptimizationMode { + return value === "best" || value === "fastest" || value === "cost" +} + +function pickCandidate(rec: RoleRecommendation | undefined, mode: EvalOptimizationMode): ModelCandidate | null { + if (!rec) return null + if (mode === "fastest") return rec.speedHire ?? rec.best[0] ?? null + if (mode === "cost") return rec.budgetHire ?? rec.best[0] ?? null + return rec.best[0] ?? null +} + +function shortProvider(provider: string) { + switch (provider) { + case "openai": + return "OpenAI" + case "anthropic": + return "Anthropic" + case "google": + return "Google" + case "xai": + return "xAI" + case "deepseek": + return "DeepSeek" + case "moonshot": + return "Moonshot" + default: + return provider + } +} + +function formatDollars(value: number) { + if (!Number.isFinite(value)) return "—" + return `$${Math.round(value)}` +} + +function formatSeconds(value: number) { + if (!Number.isFinite(value)) return "—" + return `${value.toFixed(1)}s` +} + +function buildObjectiveQueryString( + searchParams: { get(name: string): string | null }, + objectiveSlug: string, + mode: EvalOptimizationMode, +) { + const params = new URLSearchParams() + params.set("objective", objectiveSlug) + params.set("mode", mode) + + // Preserve any existing query bits we might add later without breaking URLs. + const view = searchParams.get("view") + if (view) params.set("view", view) + + return `?${params.toString()}` +} + +type ObjectiveTooltipPayloadEntry = { payload?: unknown } + +function ObjectiveTooltip({ active, payload }: { active?: boolean; payload?: ObjectiveTooltipPayloadEntry[] }) { + if (!active || !payload?.length) return null + const entryPayload = payload[0]?.payload + const p = entryPayload as + | { + name?: string + provider?: string + score?: number + dailyCost?: number + successRate?: number + } + | undefined + if (!p) return null + + return ( +
+

{p.name}

+

+ {shortProvider(p.provider ?? "")} · {p.score} score ·{" "} + {p.successRate}% success +

+

+ Est daily cost {formatDollars(p.dailyCost ?? NaN)} +

+
+ ) +} + +export function ObjectiveContent({ objective, initialMode, recs }: Props) { + const searchParams = useSearchParams() + + const recByRole = useMemo(() => new Map(recs.map((r) => [r.roleId, r.recommendation])), [recs]) + const lineup = useMemo(() => objective.recommendedRoleIds.filter((id) => recByRole.has(id)), [objective, recByRole]) + + const [mode, setMode] = useState(() => { + const m = searchParams.get("mode") + if (m && isEvalOptimizationMode(m)) return m + return initialMode + }) + + const [overrides, setOverrides] = useState>({}) + + const selectedByRole = useMemo(() => { + const next = new Map() + for (const roleId of lineup) { + const rec = recByRole.get(roleId) + const overrideModelId = overrides[roleId] + if (overrideModelId && rec) { + next.set(roleId, rec.allCandidates.find((c) => c.modelId === overrideModelId) ?? null) + } else { + next.set(roleId, pickCandidate(rec, mode)) + } + } + return next + }, [lineup, mode, overrides, recByRole]) + + const primaryRoleId = lineup[0] ?? null + const primaryCandidate = primaryRoleId ? (selectedByRole.get(primaryRoleId) ?? null) : null + + const modePill = useMemo( + () => [ + { id: "best" as const, label: "Quality" }, + { id: "fastest" as const, label: "Speed" }, + { id: "cost" as const, label: "Cost" }, + ], + [], + ) + + const cloudHref = useMemo(() => { + if (!primaryCandidate) return "https://app.roocode.com" + return getCloudSetupUrl(primaryCandidate) + }, [primaryCandidate]) + + const examplePrompt = objective.builderProfile?.examplePrompt?.trim() ?? "" + const copyPrompt = useCallback(async () => { + if (!examplePrompt) return + await navigator.clipboard.writeText(examplePrompt) + }, [examplePrompt]) + + const onSelectModel = useCallback((roleId: string, modelId: string) => { + setOverrides((prev) => ({ ...prev, [roleId]: modelId })) + }, []) + + const onSetMode = useCallback((next: EvalOptimizationMode) => { + setMode(next) + }, []) + + const roleQuery = useMemo( + () => buildObjectiveQueryString(searchParams, objective.slug, mode), + [mode, objective.slug, searchParams], + ) + + const primaryScatter = useMemo(() => { + if (!primaryRoleId) return [] + const rec = recByRole.get(primaryRoleId) + if (!rec) return [] + return rec.allCandidates.map((c) => ({ + name: c.displayName, + provider: c.provider, + score: c.compositeScore, + successRate: c.successRate, + dailyCost: Math.round(c.estimatedDailyCost), + dotSize: Math.round(40 + (c.successRate / 100) * 260), + isSelected: primaryCandidate?.modelId === c.modelId, + })) + }, [primaryCandidate?.modelId, primaryRoleId, recByRole]) + + return ( +
+ {/* Atmosphere */} +