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)} +
++ {objective.description} Explore why this setup is recommended, compare options, and + tune it to your constraints before you start in Roo Code Cloud. +
+ ++ Configuration +
+ ++ Optimized for +
+Primary model
++ {primaryCandidate ? ( + <> + + {primaryCandidate.displayName} + {" "} + + ({shortProvider(primaryCandidate.provider)}) + + > + ) : ( + + Pick an objective to see recommendations. + + )} +
+ {primaryCandidate ? ( ++ Score +
++ {primaryCandidate.compositeScore} +
++ Success +
++ {primaryCandidate.successRate}% +
++ Daily +
++ {formatDollars(primaryCandidate.estimatedDailyCost)} +
++ This is a starting point. Adjust the lineup and model picks to match your + repo and delivery constraints. +
++ For {objective.name}, this lineup balances momentum and safety. Swap models per agent if + you have different constraints. +
+ ++ For +
++ {rec.role.name} +
++ {rec.role.salaryRange} +
++ Success +
++ {selected ? `${selected.successRate}%` : "—"} +
++ Daily +
++ {selected + ? formatDollars(selected.estimatedDailyCost) + : "—"} +
++ Time +
++ {selected + ? formatSeconds(selected.avgTimePerTask) + : "—"} +
++ Why this works +
++ How it runs +
++ Example prompt +
+
+ {examplePrompt}
+
+ + Data preview +
++ Composite score vs estimated daily cost for the primary agent, with dot size mapped + to success rate. +
+ +
@@ -890,7 +887,7 @@ export function WorkersContent({
return (
Learn more / customize