From 1d03382f268dd8869ae9855a0275ec582fcc8871 Mon Sep 17 00:00:00 2001 From: Michael Preuss Date: Thu, 12 Feb 2026 20:49:17 -0800 Subject: [PATCH] Refine evals objective selection and recommendation URL defaults --- .../evals/methodology/methodology-content.tsx | 8 +- .../recommendations/[roleId]/compare/page.tsx | 2 + .../evals/recommendations/[roleId]/page.tsx | 2 + .../src/app/evals/recommendations/page.tsx | 94 +++++++++++++++++++ .../src/app/evals/workers-v2/page.tsx | 2 +- .../workers/[roleId]/candidates-content.tsx | 2 +- .../[roleId]/compare/comparison-chart.tsx | 2 +- .../evals/workers/[roleId]/compare/page.tsx | 4 +- .../src/app/evals/workers/[roleId]/page.tsx | 4 +- .../src/app/evals/workers/workers-content.tsx | 43 ++++++--- 10 files changed, 138 insertions(+), 25 deletions(-) create mode 100644 apps/web-roo-code/src/app/evals/recommendations/[roleId]/compare/page.tsx create mode 100644 apps/web-roo-code/src/app/evals/recommendations/[roleId]/page.tsx create mode 100644 apps/web-roo-code/src/app/evals/recommendations/page.tsx diff --git a/apps/web-roo-code/src/app/evals/methodology/methodology-content.tsx b/apps/web-roo-code/src/app/evals/methodology/methodology-content.tsx index 852356c6c8..6bca818da1 100644 --- a/apps/web-roo-code/src/app/evals/methodology/methodology-content.tsx +++ b/apps/web-roo-code/src/app/evals/methodology/methodology-content.tsx @@ -147,7 +147,9 @@ export function MethodologyContent() { Evals / - + Recommendations / @@ -183,7 +185,7 @@ export function MethodologyContent() { variants={fadeUpVariants} className="mt-10 flex flex-wrap items-center gap-5"> View recommendations @@ -500,7 +502,7 @@ export function MethodologyContent() { Links

- +
diff --git a/apps/web-roo-code/src/app/evals/recommendations/[roleId]/compare/page.tsx b/apps/web-roo-code/src/app/evals/recommendations/[roleId]/compare/page.tsx new file mode 100644 index 0000000000..24ceb8946c --- /dev/null +++ b/apps/web-roo-code/src/app/evals/recommendations/[roleId]/compare/page.tsx @@ -0,0 +1,2 @@ +export { generateMetadata } from "../../../workers/[roleId]/compare/page" +export { default } from "../../../workers/[roleId]/compare/page" diff --git a/apps/web-roo-code/src/app/evals/recommendations/[roleId]/page.tsx b/apps/web-roo-code/src/app/evals/recommendations/[roleId]/page.tsx new file mode 100644 index 0000000000..e40887c5bf --- /dev/null +++ b/apps/web-roo-code/src/app/evals/recommendations/[roleId]/page.tsx @@ -0,0 +1,2 @@ +export { generateMetadata } from "../../workers/[roleId]/page" +export { default } from "../../workers/[roleId]/page" diff --git a/apps/web-roo-code/src/app/evals/recommendations/page.tsx b/apps/web-roo-code/src/app/evals/recommendations/page.tsx new file mode 100644 index 0000000000..6bf7b6c5e8 --- /dev/null +++ b/apps/web-roo-code/src/app/evals/recommendations/page.tsx @@ -0,0 +1,94 @@ +import type { Metadata } from "next" +import { Fraunces, IBM_Plex_Sans } from "next/font/google" + +import { SEO } from "@/lib/seo" +import { ogImageUrl } from "@/lib/og" +import { getEngineerRoles, getAllRecommendations } from "@/lib/mock-recommendations" + +import { WorkersContent } from "../workers/workers-content" + +// ── SEO Metadata ──────────────────────────────────────────────────────────── + +const TITLE = "Build with Roo Code Cloud | Roo Code Evals" +const DESCRIPTION = + "Outcome-first, eval-backed recommendations for shipping production code. Start from your objective and pick a tradeoff." +const OG_DESCRIPTION = "Outcome-first recommendations for shipping production code" +const PATH = "/evals/recommendations" + +const display = Fraunces({ subsets: ["latin"], variable: "--font-display" }) +const body = IBM_Plex_Sans({ subsets: ["latin"], weight: ["400", "500", "600"], variable: "--font-body" }) + +export const metadata: Metadata = { + title: TITLE, + description: DESCRIPTION, + alternates: { + canonical: `${SEO.url}${PATH}`, + }, + openGraph: { + title: TITLE, + description: DESCRIPTION, + url: `${SEO.url}${PATH}`, + siteName: SEO.name, + images: [ + { + url: ogImageUrl(TITLE, OG_DESCRIPTION), + width: 1200, + height: 630, + alt: TITLE, + }, + ], + locale: SEO.locale, + type: "website", + }, + twitter: { + card: SEO.twitterCard, + title: TITLE, + description: DESCRIPTION, + images: [ogImageUrl(TITLE, OG_DESCRIPTION)], + }, + keywords: [ + ...SEO.keywords, + "AI coding", + "coding agents", + "roo code cloud", + "model recommendations", + "coding evals", + "model comparison", + "shipping code", + "prototype", + ], +} + +// ── Page Component ────────────────────────────────────────────────────────── + +export default function RecommendationsPage() { + const roles = getEngineerRoles() + const recommendations = getAllRecommendations() + + // Aggregate totals + const totalEvalRuns = recommendations.reduce((sum, recommendation) => sum + recommendation.totalEvalRuns, 0) + const totalExercises = recommendations.reduce((sum, recommendation) => sum + recommendation.totalExercises, 0) + const uniqueModels = new Set( + recommendations.flatMap((recommendation) => recommendation.allCandidates.map((candidate) => candidate.modelId)), + ) + const totalModels = uniqueModels.size + + const lastUpdated = recommendations + .map((r) => r.lastUpdated) + .sort() + .pop() + + return ( +
+ +
+ ) +} diff --git a/apps/web-roo-code/src/app/evals/workers-v2/page.tsx b/apps/web-roo-code/src/app/evals/workers-v2/page.tsx index e8559e09ca..4f067eb276 100644 --- a/apps/web-roo-code/src/app/evals/workers-v2/page.tsx +++ b/apps/web-roo-code/src/app/evals/workers-v2/page.tsx @@ -8,5 +8,5 @@ type PageProps = { export default async function WorkersV2Page({ searchParams }: PageProps) { const sp = (await searchParams) ?? {} - permanentRedirect(`/evals/workers${buildQueryString(sp)}`) + permanentRedirect(`/evals/recommendations${buildQueryString(sp)}`) } diff --git a/apps/web-roo-code/src/app/evals/workers/[roleId]/candidates-content.tsx b/apps/web-roo-code/src/app/evals/workers/[roleId]/candidates-content.tsx index 0b1105650f..cda3c52c6e 100644 --- a/apps/web-roo-code/src/app/evals/workers/[roleId]/candidates-content.tsx +++ b/apps/web-roo-code/src/app/evals/workers/[roleId]/candidates-content.tsx @@ -660,7 +660,7 @@ export function CandidatesContent({ totalExercises, lastUpdated, cloudUrls, - workersRootPath = "/evals/workers", + workersRootPath = "/evals/recommendations", }: CandidatesContentProps) { const searchParams = useSearchParams() const theme = ROLE_THEMES[roleId] ?? DEFAULT_THEME diff --git a/apps/web-roo-code/src/app/evals/workers/[roleId]/compare/comparison-chart.tsx b/apps/web-roo-code/src/app/evals/workers/[roleId]/compare/comparison-chart.tsx index 8c005cdbd5..186ef34c77 100644 --- a/apps/web-roo-code/src/app/evals/workers/[roleId]/compare/comparison-chart.tsx +++ b/apps/web-roo-code/src/app/evals/workers/[roleId]/compare/comparison-chart.tsx @@ -441,7 +441,7 @@ export function ComparisonChart({ recommendation, role, roleId, - workersRootPath = "/evals/workers", + workersRootPath = "/evals/recommendations", }: ComparisonChartProps) { const searchParams = useSearchParams() const { allCandidates } = recommendation diff --git a/apps/web-roo-code/src/app/evals/workers/[roleId]/compare/page.tsx b/apps/web-roo-code/src/app/evals/workers/[roleId]/compare/page.tsx index 9d03aa9cca..ac16a21b56 100644 --- a/apps/web-roo-code/src/app/evals/workers/[roleId]/compare/page.tsx +++ b/apps/web-roo-code/src/app/evals/workers/[roleId]/compare/page.tsx @@ -25,7 +25,7 @@ export async function generateMetadata({ params }: PageProps): Promise const title = `Compare Models — ${role.name} | Roo Code Evals` const description = `Interactive comparison of AI models for the ${role.name} setup. Compare composite score, success rate, cost efficiency, and speed.` const ogDescription = `Compare Models — ${role.name}` - const path = `/evals/workers/${roleId}/compare` + const path = `/evals/recommendations/${roleId}/compare` return { title, @@ -82,7 +82,7 @@ export default async function CompareModelsPage({ params }: PageProps) { recommendation={recommendation} role={recommendation.role} roleId={roleId} - workersRootPath="/evals/workers" + workersRootPath="/evals/recommendations" /> ) } diff --git a/apps/web-roo-code/src/app/evals/workers/[roleId]/page.tsx b/apps/web-roo-code/src/app/evals/workers/[roleId]/page.tsx index 54ca16d0d2..c408f5098c 100644 --- a/apps/web-roo-code/src/app/evals/workers/[roleId]/page.tsx +++ b/apps/web-roo-code/src/app/evals/workers/[roleId]/page.tsx @@ -26,7 +26,7 @@ export async function generateMetadata({ params }: PageProps): Promise const title = `${role.name} — Recommended Models | Roo Code Evals` const description = `Eval-backed recommendations for ${role.name}. Compare models by success rate, cost, and speed across 5 languages.` const ogDescription = `${role.name} — Recommended Models` - const path = `/evals/workers/${roleId}` + const path = `/evals/recommendations/${roleId}` return { title, @@ -100,7 +100,7 @@ export default async function RoleCandidatesPage({ params }: PageProps) { totalExercises={totalExercises} lastUpdated={lastUpdated} cloudUrls={cloudUrls} - workersRootPath="/evals/workers" + workersRootPath="/evals/recommendations" /> ) } diff --git a/apps/web-roo-code/src/app/evals/workers/workers-content.tsx b/apps/web-roo-code/src/app/evals/workers/workers-content.tsx index 9189190120..21d8646257 100644 --- a/apps/web-roo-code/src/app/evals/workers/workers-content.tsx +++ b/apps/web-roo-code/src/app/evals/workers/workers-content.tsx @@ -202,7 +202,7 @@ export function WorkersContent({ totalExercises: _totalExercises, totalModels: _totalModels, lastUpdated, - workersRootPath = "/evals/workers", + workersRootPath = "/evals/recommendations", }: WorkersContentProps) { const enableOutcomeLayer = ENABLE_OUTCOME_LAYER const router = useRouter() @@ -214,6 +214,10 @@ export function WorkersContent({ if (!outcome) return null return isEvalOutcomeId(outcome) ? outcome : null }, [searchParams]) + const effectiveOutcomeId = useMemo(() => { + if (selectedOutcomeId) return selectedOutcomeId + return EVAL_OUTCOMES[0]?.id ?? null + }, [selectedOutcomeId]) const selectedMode = useMemo((): EvalOptimizationMode => { const mode = searchParams.get("mode") @@ -255,18 +259,27 @@ export function WorkersContent({ const roleById = useMemo(() => new Map(roles.map((r) => [r.id, r])), [roles]) const selectedOutcome = useMemo(() => { - if (!selectedOutcomeId) return null - return EVAL_OUTCOMES.find((o) => o.id === selectedOutcomeId) ?? null - }, [selectedOutcomeId]) + if (!effectiveOutcomeId) return null + return EVAL_OUTCOMES.find((o) => o.id === effectiveOutcomeId) ?? null + }, [effectiveOutcomeId]) const setupQuery = useMemo(() => { - if (!selectedOutcomeId) return "" + if (!effectiveOutcomeId) return "" const params = new URLSearchParams() - params.set("outcome", selectedOutcomeId) + params.set("outcome", effectiveOutcomeId) params.set("mode", selectedMode) const query = params.toString() return query ? `?${query}` : "" - }, [selectedOutcomeId, selectedMode]) + }, [effectiveOutcomeId, selectedMode]) + + const profileViewQuery = useMemo(() => { + if (!effectiveOutcomeId) return "" + const params = new URLSearchParams() + params.set("outcome", effectiveOutcomeId) + params.set("mode", selectedMode) + params.set("view", "profile") + return `?${params.toString()}` + }, [effectiveOutcomeId, selectedMode]) const isProfileView = useMemo(() => { return searchParams.get("view") === "profile" @@ -277,22 +290,22 @@ export function WorkersContent({ "A default setup built from our eval signals. It’s a baseline, not a guarantee." const profileHowItWorks = selectedOutcome?.builderProfile?.howItWorks ?? selectedOutcome?.whyItWorks ?? [] const objectiveDefaultModel = useMemo(() => { - if (!selectedOutcomeId) return null - return pickObjectiveDefaultModelV1(selectedOutcomeId, selectedMode) - }, [selectedOutcomeId, selectedMode]) + if (!effectiveOutcomeId) return null + return pickObjectiveDefaultModelV1(effectiveOutcomeId, selectedMode) + }, [effectiveOutcomeId, selectedMode]) const objectiveDefaultModelLabel = useMemo(() => { if (!objectiveDefaultModel?.modelId) return "—" return formatModelIdForUi(objectiveDefaultModel.modelId) }, [objectiveDefaultModel]) const examplePrompt = selectedOutcome?.builderProfile?.examplePrompt ?? "" const cloudSetupHref = useMemo(() => { - if (!selectedOutcomeId) return "/cloud-agents/setup" + if (!effectiveOutcomeId) return "/cloud-agents/setup" const params = new URLSearchParams() - params.set("outcome", selectedOutcomeId) + params.set("outcome", effectiveOutcomeId) params.set("mode", selectedMode) if (examplePrompt) params.set("prompt", examplePrompt) return `/cloud-agents/setup?${params.toString()}` - }, [examplePrompt, selectedMode, selectedOutcomeId]) + }, [examplePrompt, selectedMode, effectiveOutcomeId]) const profileCapabilities = useMemo(() => { if (!selectedOutcome) return [] @@ -741,7 +754,7 @@ export function WorkersContent({ {EVAL_OUTCOMES.map((outcome) => { const Icon = outcome.icon - const isSelected = outcome.id === selectedOutcomeId + const isSelected = outcome.id === effectiveOutcomeId return ( Learn more / customize