@vercel/agent-eval-playground 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +1 -0
- package/.next/build-manifest.json +2 -2
- package/.next/cache/.previewinfo +1 -1
- package/.next/cache/.rscinfo +1 -1
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/config.json +3 -3
- package/.next/fallback-build-manifest.json +2 -2
- package/.next/prerender-manifest.json +3 -3
- package/.next/routes-manifest.json +8 -0
- package/.next/server/app/_global-error.html +2 -2
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/compare/page.js.nft.json +1 -1
- package/.next/server/app/compare/page_client-reference-manifest.js +1 -1
- package/.next/server/app/evals/[name]/page.js.nft.json +1 -1
- package/.next/server/app/evals/[name]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/evals/page.js.nft.json +1 -1
- package/.next/server/app/evals/page_client-reference-manifest.js +1 -1
- package/.next/server/app/experiments/[name]/[timestamp]/page.js.nft.json +1 -1
- package/.next/server/app/experiments/[name]/[timestamp]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/experiments/[name]/page/app-paths-manifest.json +3 -0
- package/.next/server/app/experiments/[name]/page/build-manifest.json +17 -0
- package/.next/server/app/experiments/[name]/page/next-font-manifest.json +12 -0
- package/.next/server/app/experiments/[name]/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/experiments/[name]/page/server-reference-manifest.json +4 -0
- package/.next/server/app/experiments/[name]/page.js +17 -0
- package/.next/server/app/experiments/[name]/page.js.map +5 -0
- package/.next/server/app/experiments/[name]/page.js.nft.json +1 -0
- package/.next/server/app/experiments/[name]/page_client-reference-manifest.js +2 -0
- package/.next/server/app/experiments/page.js.nft.json +1 -1
- package/.next/server/app/experiments/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/transcript/[experiment]/[timestamp]/[evalName]/[run]/page.js.nft.json +1 -1
- package/.next/server/app/transcript/[experiment]/[timestamp]/[evalName]/[run]/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +1 -0
- package/.next/server/chunks/ssr/730ea_playground__next-internal_server_app_experiments_[name]_page_actions_9b119c24.js +3 -0
- package/.next/server/chunks/ssr/730ea_playground__next-internal_server_app_experiments_[name]_page_actions_9b119c24.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__3702960d._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__3702960d._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__4228b9c3._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__4228b9c3._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__a216b589._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__a216b589._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__ac2a456c._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__ac2a456c._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__aca11d57._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__aca11d57._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__b8fc4094._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__b8fc4094._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__c73d60f7._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__c73d60f7._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__f286e9a8._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__f286e9a8._.js.map +1 -1
- package/.next/server/chunks/ssr/_fa6de7c6._.js +4 -0
- package/.next/server/chunks/ssr/_fa6de7c6._.js.map +1 -0
- package/.next/server/chunks/ssr/packages_playground_components_TranscriptViewer_tsx_ba8ff423._.js +1 -1
- package/.next/server/chunks/ssr/packages_playground_components_TranscriptViewer_tsx_ba8ff423._.js.map +1 -1
- package/.next/server/next-font-manifest.js +1 -1
- package/.next/server/next-font-manifest.json +5 -0
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +2 -2
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/225815167619f532.css +4 -0
- package/.next/static/chunks/{419a92b5c17e94a8.js → 405f69d0b8bdad66.js} +1 -1
- package/.next/trace +1 -1
- package/.next/trace-build +1 -1
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/app/experiments/[name]/page.tsx +124 -0
- package/components/ExperimentList.tsx +34 -14
- package/components/O11ySummary.tsx +14 -9
- package/package.json +1 -1
- package/.next/static/chunks/b7a73603aa202938.css +0 -4
- /package/.next/static/{e-_lBXo-NK4NsMjf8KVfw → 7WvStP5_xMiGBpz094_IB}/_buildManifest.js +0 -0
- /package/.next/static/{e-_lBXo-NK4NsMjf8KVfw → 7WvStP5_xMiGBpz094_IB}/_clientMiddlewareManifest.json +0 -0
- /package/.next/static/{e-_lBXo-NK4NsMjf8KVfw → 7WvStP5_xMiGBpz094_IB}/_ssgManifest.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/playground/lib/data.ts","../../../../../../packages/playground/components/ui/card.tsx","../../../../../../packages/playground/app/experiments/%5Bname%5D/page.tsx"],"sourcesContent":["/**\n * Server-side data access for the playground.\n * Reads JSON files from the results/ and evals/ directories.\n * Directory paths are provided via RESULTS_DIR and EVALS_DIR env vars.\n */\n\nimport { readdirSync, readFileSync, existsSync } from \"fs\";\nimport { join, resolve } from \"path\";\n\nfunction getResultsDir(): string {\n return resolve(process.env.RESULTS_DIR || \"./results\");\n}\n\nfunction getEvalsDir(): string {\n return resolve(process.env.EVALS_DIR || \"./evals\");\n}\n\n/** Check if a directory name looks like an ISO timestamp (used as run ID) */\nfunction isTimestamp(name: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}T/.test(name);\n}\n\n/** List experiments from the results directory. Pass limit to cap expensive per-item reads. */\nexport function listExperiments(limit?: number) {\n const resultsDir = getResultsDir();\n\n if (!existsSync(resultsDir)) {\n return { items: [], total: 0 };\n }\n\n // Discover experiments by walking the directory tree until we find\n // timestamp directories. The path from resultsDir to the parent of the\n // first timestamp is the experiment name (e.g. \"my-config/openai/gpt-5.2-codex\").\n const entries: string[] = [];\n\n function walk(dir: string, prefix: string) {\n const children = readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n\n // If any child looks like a timestamp, this directory is an experiment\n if (children.some(isTimestamp)) {\n entries.push(prefix);\n return;\n }\n\n // Otherwise keep recursing\n for (const child of children) {\n walk(join(dir, child), prefix ? `${prefix}/${child}` : child);\n }\n }\n\n walk(resultsDir, \"\");\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const expDir = join(resultsDir, name);\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && isTimestamp(e.name))\n .map((e) => e.name)\n .sort()\n .reverse();\n\n let latestPassRate: number | undefined;\n let latestTotalRuns = 0;\n let latestPassedRuns = 0;\n\n if (timestamps.length > 0) {\n const latestDir = join(expDir, timestamps[0]);\n const evalDirs = readdirSync(latestDir, { withFileTypes: true }).filter(\n (e) => e.isDirectory()\n );\n\n for (const evalDir of evalDirs) {\n const summaryPath = join(latestDir, evalDir.name, \"summary.json\");\n if (existsSync(summaryPath)) {\n try {\n const summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n latestTotalRuns += summary.totalRuns ?? 0;\n latestPassedRuns += summary.passedRuns ?? 0;\n } catch {\n // Skip invalid summary files\n }\n }\n }\n\n if (latestTotalRuns > 0) {\n latestPassRate = (latestPassedRuns / latestTotalRuns) * 100;\n }\n }\n\n return {\n name,\n timestamps,\n latestTimestamp: timestamps[0] ?? null,\n latestPassRate,\n latestTotalRuns,\n latestPassedRuns,\n };\n });\n\n return { items, total };\n}\n\n/** Get timestamps for a specific experiment */\nexport function getExperiment(name: string) {\n const expDir = join(getResultsDir(), name);\n\n if (!existsSync(expDir)) {\n return null;\n }\n\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort()\n .reverse();\n\n return { name, timestamps, latestTimestamp: timestamps[0] ?? null };\n}\n\n/** Get full experiment detail for a specific timestamp */\nexport function getExperimentDetail(name: string, timestamp: string) {\n const runDir = join(getResultsDir(), name, timestamp);\n\n if (!existsSync(runDir)) {\n return null;\n }\n\n // Recursively discover all eval result directories (directories with summary.json)\n const evalDirs: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name.startsWith(\"run-\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const summaryPath = join(entryPath, \"summary.json\");\n\n // Check if this is an eval result directory (has summary.json)\n if (existsSync(summaryPath)) {\n evalDirs.push(relativePath);\n } else {\n // Not an eval result, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(runDir);\n evalDirs.sort();\n\n const evals = evalDirs.map((evalName) => {\n const evalDir = join(runDir, evalName);\n const summaryPath = join(evalDir, \"summary.json\");\n\n let summary = {\n totalRuns: 0,\n passedRuns: 0,\n passRate: \"0%\",\n meanDuration: 0,\n };\n if (existsSync(summaryPath)) {\n try {\n summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n } catch {\n // Use defaults\n }\n }\n\n // List run directories\n const runDirs = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && e.name.startsWith(\"run-\"))\n .map((e) => e.name)\n .sort();\n\n // Read each run's result.json\n const runs = runDirs.map((runDirName) => {\n const resultPath = join(evalDir, runDirName, \"result.json\");\n let result = null;\n if (existsSync(resultPath)) {\n try {\n result = JSON.parse(readFileSync(resultPath, \"utf-8\"));\n } catch {\n // Skip\n }\n }\n return { name: runDirName, result };\n });\n\n return {\n name: evalName,\n totalRuns: summary.totalRuns,\n passedRuns: summary.passedRuns,\n passRate:\n typeof summary.passRate === \"string\"\n ? parseFloat(summary.passRate)\n : summary.passRate,\n meanDuration: summary.meanDuration,\n runs,\n };\n });\n\n return { name, timestamp, evals };\n}\n\n/** Get result for a specific run */\nexport function getRunResult(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const resultPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"result.json\"\n );\n\n if (!existsSync(resultPath)) {\n return null;\n }\n\n try {\n return { result: JSON.parse(readFileSync(resultPath, \"utf-8\")) };\n } catch {\n return null;\n }\n}\n\n/** Get parsed transcript for a specific run */\nexport function getTranscript(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const transcriptPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"transcript.json\"\n );\n\n if (!existsSync(transcriptPath)) {\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(transcriptPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\n/** List evals from the evals directory. Pass limit to cap per-item reads. */\nexport function listEvals(limit?: number) {\n const evalsDir = getEvalsDir();\n\n if (!existsSync(evalsDir)) {\n return { items: [], total: 0 };\n }\n\n // Recursively discover all evals (directories with PROMPT.md)\n const entries: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const promptPath = join(entryPath, \"PROMPT.md\");\n\n // Check if this is an eval directory (has PROMPT.md)\n if (existsSync(promptPath)) {\n entries.push(relativePath);\n } else {\n // Not an eval, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(evalsDir);\n entries.sort();\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const evalDir = join(evalsDir, name);\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n const files = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isFile())\n .map((e) => e.name);\n\n return { name, prompt, files };\n });\n\n return { items, total };\n}\n\n/** Get detail for a specific eval */\nexport function getEvalDetail(name: string) {\n const evalDir = join(getEvalsDir(), name);\n\n if (!existsSync(evalDir)) {\n return null;\n }\n\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n // Recursively list files\n const files: string[] = [];\n function walk(dir: string, prefix: string) {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(join(dir, entry.name), relativePath);\n } else {\n files.push(relativePath);\n }\n }\n }\n walk(evalDir, \"\");\n\n // Read file contents for key files\n const fileContents: Record<string, string> = {};\n const keyFiles = [\"PROMPT.md\", \"EVAL.ts\", \"EVAL.tsx\", \"package.json\"];\n for (const file of keyFiles) {\n const filePath = join(evalDir, file);\n if (existsSync(filePath)) {\n try {\n fileContents[file] = readFileSync(filePath, \"utf-8\");\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n return { name, prompt, files, fileContents };\n}\n","import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & { size?: \"default\" | \"sm\" }) {\n return (\n <div\n data-slot=\"card\"\n data-size={size}\n className={cn(\"ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-muted-foreground text-xs/relaxed\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-4 group-data-[size=sm]/card:px-3\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"rounded-b-lg px-4 group-data-[size=sm]/card:px-3 [.border-t]:pt-4 group-data-[size=sm]/card:[.border-t]:pt-3 flex items-center\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n","import Link from \"next/link\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { getExperiment, getExperimentDetail } from \"@/lib/data\";\nimport { notFound } from \"next/navigation\";\n\nexport const dynamic = \"force-dynamic\";\n\nexport default async function ExperimentRunsPage({\n params,\n}: {\n params: Promise<{ name: string }>;\n}) {\n const { name } = await params;\n const decodedName = decodeURIComponent(name);\n const experiment = getExperiment(decodedName);\n\n if (!experiment) {\n notFound();\n }\n\n // Get details for each timestamp to show pass rates\n const runsWithDetails = experiment.timestamps.map((timestamp) => {\n const detail = getExperimentDetail(decodedName, timestamp);\n if (!detail) {\n return { timestamp, passRate: null, totalRuns: 0, passedRuns: 0 };\n }\n\n const totalRuns = detail.evals.reduce((sum, e) => sum + e.totalRuns, 0);\n const passedRuns = detail.evals.reduce((sum, e) => sum + e.passedRuns, 0);\n const passRate = totalRuns > 0 ? (passedRuns / totalRuns) * 100 : 0;\n\n return {\n timestamp,\n passRate,\n totalRuns,\n passedRuns,\n evalCount: detail.evals.length,\n };\n });\n\n return (\n <div className=\"space-y-6\">\n <div>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground mb-2\">\n <Link href=\"/experiments\" className=\"hover:text-foreground\">\n Experiments\n </Link>\n <span>/</span>\n <span>{decodedName}</span>\n </div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{decodedName}</h1>\n <p className=\"text-muted-foreground mt-1\">\n All runs for this experiment ({experiment.timestamps.length} total)\n </p>\n </div>\n\n <Card>\n <CardContent className=\"pt-0\">\n <div>\n {/* Header */}\n <div className=\"grid grid-cols-[auto_1fr_auto_auto] gap-4 px-3 py-2 text-xs text-muted-foreground font-medium border-b border-border\">\n <span className=\"w-8\">#</span>\n <span>Timestamp</span>\n <span className=\"w-24\">Pass Rate</span>\n <span className=\"w-32\">Evals</span>\n </div>\n {/* Rows */}\n {runsWithDetails.map((run, index) => (\n <Link\n key={run.timestamp}\n href={`/experiments/${encodeURIComponent(decodedName)}/${encodeURIComponent(run.timestamp)}`}\n className=\"grid grid-cols-[auto_1fr_auto_auto] gap-4 items-center px-3 py-2.5 cursor-pointer transition-colors hover:bg-muted rounded-md\"\n >\n <span className=\"w-8 text-muted-foreground\">\n {runsWithDetails.length - index}\n </span>\n <span className=\"font-mono text-sm\">\n {formatTimestamp(run.timestamp)}\n </span>\n <span className=\"w-24\">\n {run.passRate !== null ? (\n <span className=\"flex items-center gap-2\">\n <Badge\n variant={\n run.passRate === 100\n ? \"default\"\n : run.passRate >= 50\n ? \"secondary\"\n : \"destructive\"\n }\n >\n {run.passRate.toFixed(0)}%\n </Badge>\n <span className=\"text-xs text-muted-foreground\">\n {run.passedRuns}/{run.totalRuns}\n </span>\n </span>\n ) : (\n <span className=\"text-muted-foreground\">--</span>\n )}\n </span>\n <span className=\"w-32 text-sm text-muted-foreground\">\n {run.evalCount ?? 0} eval{run.evalCount !== 1 ? \"s\" : \"\"}\n </span>\n </Link>\n ))}\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n\nfunction formatTimestamp(ts: string): string {\n try {\n const isoString = ts.replace(/T(\\d{2})-(\\d{2})-(\\d{2})/, \"T$1:$2:$3\");\n const date = new Date(isoString);\n if (isNaN(date.getTime())) return ts;\n return date.toLocaleString();\n } catch {\n return ts;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
module.exports=[69046,a=>{a.n(a.i(80979))},43619,a=>{a.n(a.i(79962))},13718,a=>{a.n(a.i(85523))},18198,a=>{a.n(a.i(45518))},62212,a=>{a.n(a.i(66114))},22734,(a,b,c)=>{b.exports=a.x("fs",()=>require("fs"))},5419,a=>{"use strict";var b=a.i(22734),c=a.i(14747);function d(){return(0,c.resolve)(process.env.RESULTS_DIR||"./results")}function e(){return(0,c.resolve)(process.env.EVALS_DIR||"./evals")}function f(a){return/^\d{4}-\d{2}-\d{2}T/.test(a)}function g(a){let e=d();if(!(0,b.existsSync)(e))return{items:[],total:0};let g=[];!function a(d,e){let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name);if(h.some(f))return void g.push(e);for(let b of h)a((0,c.join)(d,b),e?`${e}/${b}`:b)}(e,"");let h=g.length;return{items:(a?g.slice(0,a):g).map(a=>{let d,g=(0,c.join)(e,a),h=(0,b.readdirSync)(g,{withFileTypes:!0}).filter(a=>a.isDirectory()&&f(a.name)).map(a=>a.name).sort().reverse(),i=0,j=0;if(h.length>0){let a=(0,c.join)(g,h[0]);for(let d of(0,b.readdirSync)(a,{withFileTypes:!0}).filter(a=>a.isDirectory())){let e=(0,c.join)(a,d.name,"summary.json");if((0,b.existsSync)(e))try{let a=JSON.parse((0,b.readFileSync)(e,"utf-8"));i+=a.totalRuns??0,j+=a.passedRuns??0}catch{}}i>0&&(d=j/i*100)}return{name:a,timestamps:h,latestTimestamp:h[0]??null,latestPassRate:d,latestTotalRuns:i,latestPassedRuns:j}}),total:h}}function h(a,e){let f=(0,c.join)(d(),a,e);if(!(0,b.existsSync)(f))return null;let g=[];return!function a(d,e=""){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!f.isDirectory()||f.name.startsWith(".")||f.name.startsWith("run-"))continue;let h=e?`${e}/${f.name}`:f.name,i=(0,c.join)(d,f.name),j=(0,c.join)(i,"summary.json");(0,b.existsSync)(j)?g.push(h):a(i,h)}}(f),g.sort(),{name:a,timestamp:e,evals:g.map(a=>{let d=(0,c.join)(f,a),e=(0,c.join)(d,"summary.json"),g={totalRuns:0,passedRuns:0,passRate:"0%",meanDuration:0};if((0,b.existsSync)(e))try{g=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()&&a.name.startsWith("run-")).map(a=>a.name).sort().map(a=>{let e=(0,c.join)(d,a,"result.json"),f=null;if((0,b.existsSync)(e))try{f=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}return{name:a,result:f}});return{name:a,totalRuns:g.totalRuns,passedRuns:g.passedRuns,passRate:"string"==typeof g.passRate?parseFloat(g.passRate):g.passRate,meanDuration:g.meanDuration,runs:h}})}}function i(a,e,f,g){let h=(0,c.join)(d(),a,e,f,g,"transcript.json");if(!(0,b.existsSync)(h))return null;try{return JSON.parse((0,b.readFileSync)(h,"utf-8"))}catch{return null}}function j(a){let d=e();if(!(0,b.existsSync)(d))return{items:[],total:0};let f=[];!function a(d,e=""){for(let g of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!g.isDirectory()||g.name.startsWith("."))continue;let h=e?`${e}/${g.name}`:g.name,i=(0,c.join)(d,g.name),j=(0,c.join)(i,"PROMPT.md");(0,b.existsSync)(j)?f.push(h):a(i,h)}}(d),f.sort();let g=f.length;return{items:(a?f.slice(0,a):f).map(a=>{let e=(0,c.join)(d,a),f=(0,c.join)(e,"PROMPT.md"),g="";return(0,b.existsSync)(f)&&(g=(0,b.readFileSync)(f,"utf-8")),{name:a,prompt:g,files:(0,b.readdirSync)(e,{withFileTypes:!0}).filter(a=>a.isFile()).map(a=>a.name)}}),total:g}}function k(a){let d=(0,c.join)(e(),a);if(!(0,b.existsSync)(d))return null;let f=(0,c.join)(d,"PROMPT.md"),g="";(0,b.existsSync)(f)&&(g=(0,b.readFileSync)(f,"utf-8"));let h=[];!function a(d,e){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if("node_modules"===f.name||".git"===f.name)continue;let b=e?`${e}/${f.name}`:f.name;f.isDirectory()?a((0,c.join)(d,f.name),b):h.push(b)}}(d,"");let i={};for(let a of["PROMPT.md","EVAL.ts","EVAL.tsx","package.json"]){let e=(0,c.join)(d,a);if((0,b.existsSync)(e))try{i[a]=(0,b.readFileSync)(e,"utf-8")}catch{}}return{name:a,prompt:g,files:h,fileContents:i}}a.s(["getEvalDetail",()=>k,"getExperimentDetail",()=>h,"getTranscript",()=>i,"listEvals",()=>j,"listExperiments",()=>g])},22977,a=>{"use strict";var b=a.i(7997),c=a.i(95387);function d({className:a,size:d="default",...e}){return(0,b.jsx)("div",{"data-slot":"card","data-size":d,className:(0,c.cn)("ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col",a),...e})}function e({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-header",className:(0,c.cn)("gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",a),...d})}function f({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-title",className:(0,c.cn)("text-sm font-medium",a),...d})}function g({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-content",className:(0,c.cn)("px-4 group-data-[size=sm]/card:px-3",a),...d})}a.s(["Card",()=>d,"CardContent",()=>g,"CardHeader",()=>e,"CardTitle",()=>f])},98720,a=>{"use strict";a.s(["Progress",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call Progress() from the server but Progress is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ui/progress.tsx <module evaluation>","Progress")},46442,a=>{"use strict";a.s(["Progress",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call Progress() from the server but Progress is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ui/progress.tsx","Progress")},71804,a=>{"use strict";a.i(98720);var b=a.i(46442);a.n(b)},37345,a=>{"use strict";a.s(["Separator",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call Separator() from the server but Separator is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ui/separator.tsx <module evaluation>","Separator")},43277,a=>{"use strict";a.s(["Separator",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call Separator() from the server but Separator is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ui/separator.tsx","Separator")},83977,a=>{"use strict";a.i(37345);var b=a.i(43277);a.n(b)},87618,a=>{"use strict";var b=a.i(7997);a.i(70396);var c=a.i(73727),d=a.i(95936),e=a.i(22977),f=a.i(20954),g=a.i(71804),h=a.i(83977);function i({runName:a,result:c,experiment:g,timestamp:h,evalName:i}){return c?(0,b.jsx)(d.default,{href:`/transcript/${encodeURIComponent(g)}/${encodeURIComponent(h)}/${encodeURIComponent(i)}/${encodeURIComponent(a)}`,className:"block cursor-pointer",children:(0,b.jsx)(e.Card,{className:"transition-colors hover:bg-muted",children:(0,b.jsxs)(e.CardContent,{className:"py-3 px-4 flex items-center justify-between",children:[(0,b.jsxs)("div",{className:"flex items-center gap-3",children:[(0,b.jsx)("span",{className:"text-sm font-medium",children:a}),(0,b.jsx)(f.Badge,{variant:"passed"===c.status?"default":"destructive",children:c.status}),c.error&&(0,b.jsx)("span",{className:"text-xs text-destructive truncate max-w-64",children:c.error})]}),(0,b.jsxs)("div",{className:"flex items-center gap-4 text-xs text-muted-foreground",children:[c.o11y&&(0,b.jsxs)("span",{children:[c.o11y.totalToolCalls," tool calls"]}),(0,b.jsxs)("span",{children:[c.duration.toFixed(1),"s"]})]})]})})}):(0,b.jsx)(e.Card,{className:"opacity-50",children:(0,b.jsx)(e.CardContent,{className:"py-3 px-4",children:(0,b.jsxs)("span",{className:"text-sm text-muted-foreground",children:[a,": No result"]})})})}function j({data:a}){let c=a.evals.length,j=a.evals.filter(a=>a.passedRuns===a.totalRuns).length,l=a.evals.reduce((a,b)=>a+b.passRate,0)/(c||1);return(0,b.jsxs)("div",{className:"space-y-6",children:[(0,b.jsxs)("div",{children:[(0,b.jsxs)("div",{className:"flex items-center gap-2 text-sm text-muted-foreground mb-1",children:[(0,b.jsx)(d.default,{href:"/experiments",className:"cursor-pointer hover:underline underline-offset-4",children:"Experiments"}),(0,b.jsx)("span",{children:"/"}),(0,b.jsx)("span",{children:a.name}),(0,b.jsx)("span",{children:"/"}),(0,b.jsx)("span",{children:k(a.timestamp)})]}),(0,b.jsx)("h1",{className:"text-2xl font-bold tracking-tight",children:a.name})]}),(0,b.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[(0,b.jsx)(e.Card,{children:(0,b.jsxs)(e.CardContent,{className:"py-4 px-4",children:[(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:"Overall Pass Rate"}),(0,b.jsxs)("div",{className:"text-2xl font-bold mt-1",children:[l.toFixed(0),"%"]}),(0,b.jsx)(g.Progress,{value:l,className:"mt-2 h-1.5"})]})}),(0,b.jsx)(e.Card,{children:(0,b.jsxs)(e.CardContent,{className:"py-4 px-4",children:[(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:"Evals"}),(0,b.jsxs)("div",{className:"text-2xl font-bold mt-1",children:[j,"/",c]}),(0,b.jsx)("div",{className:"text-xs text-muted-foreground mt-1",children:"passed"})]})}),(0,b.jsx)(e.Card,{children:(0,b.jsxs)(e.CardContent,{className:"py-4 px-4",children:[(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:"Avg Duration"}),(0,b.jsxs)("div",{className:"text-2xl font-bold mt-1",children:[(a.evals.reduce((a,b)=>a+b.meanDuration,0)/(c||1)).toFixed(1),"s"]})]})}),(0,b.jsx)(e.Card,{children:(0,b.jsxs)(e.CardContent,{className:"py-4 px-4",children:[(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:"Timestamp"}),(0,b.jsx)("div",{className:"text-sm font-medium mt-1",children:k(a.timestamp)})]})})]}),(0,b.jsx)(h.Separator,{}),(0,b.jsx)("div",{className:"space-y-6",children:a.evals.map(c=>(0,b.jsxs)(e.Card,{children:[(0,b.jsxs)(e.CardHeader,{children:[(0,b.jsxs)("div",{className:"flex items-center justify-between",children:[(0,b.jsxs)("div",{className:"flex items-center gap-3",children:[(0,b.jsx)(e.CardTitle,{className:"text-lg",children:c.name}),(0,b.jsxs)(f.Badge,{variant:c.passedRuns===c.totalRuns?"default":"destructive",children:[c.passedRuns,"/",c.totalRuns," passed"]})]}),(0,b.jsxs)("div",{className:"text-sm text-muted-foreground",children:["avg ",c.meanDuration.toFixed(1),"s"]})]}),(0,b.jsx)(g.Progress,{value:c.passRate,className:"h-1.5 mt-2"})]}),(0,b.jsx)(e.CardContent,{children:(0,b.jsx)("div",{className:"space-y-2",children:c.runs.map(d=>(0,b.jsx)(i,{runName:d.name,result:d.result,experiment:a.name,timestamp:a.timestamp,evalName:c.name},d.name))})})]},c.name))})]})}function k(a){try{let b=a.replace(/T(\d{2})-(\d{2})-(\d{2})/,"T$1:$2:$3"),c=new Date(b);if(isNaN(c.getTime()))return a;return c.toLocaleString()}catch{return a}}var l=a.i(5419);async function m({params:a}){let{name:d,timestamp:e}=await a,f=decodeURIComponent(d),g=decodeURIComponent(e),h=(0,l.getExperimentDetail)(f,g);return h||(0,c.notFound)(),(0,b.jsx)(j,{data:h})}a.s(["default",()=>m,"dynamic",0,"force-dynamic"],87618)}];
|
|
1
|
+
module.exports=[69046,a=>{a.n(a.i(80979))},43619,a=>{a.n(a.i(79962))},13718,a=>{a.n(a.i(85523))},18198,a=>{a.n(a.i(45518))},62212,a=>{a.n(a.i(66114))},22734,(a,b,c)=>{b.exports=a.x("fs",()=>require("fs"))},5419,a=>{"use strict";var b=a.i(22734),c=a.i(14747);function d(){return(0,c.resolve)(process.env.RESULTS_DIR||"./results")}function e(){return(0,c.resolve)(process.env.EVALS_DIR||"./evals")}function f(a){return/^\d{4}-\d{2}-\d{2}T/.test(a)}function g(a){let e=d();if(!(0,b.existsSync)(e))return{items:[],total:0};let g=[];!function a(d,e){let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name);if(h.some(f))return void g.push(e);for(let b of h)a((0,c.join)(d,b),e?`${e}/${b}`:b)}(e,"");let h=g.length;return{items:(a?g.slice(0,a):g).map(a=>{let d,g=(0,c.join)(e,a),h=(0,b.readdirSync)(g,{withFileTypes:!0}).filter(a=>a.isDirectory()&&f(a.name)).map(a=>a.name).sort().reverse(),i=0,j=0;if(h.length>0){let a=(0,c.join)(g,h[0]);for(let d of(0,b.readdirSync)(a,{withFileTypes:!0}).filter(a=>a.isDirectory())){let e=(0,c.join)(a,d.name,"summary.json");if((0,b.existsSync)(e))try{let a=JSON.parse((0,b.readFileSync)(e,"utf-8"));i+=a.totalRuns??0,j+=a.passedRuns??0}catch{}}i>0&&(d=j/i*100)}return{name:a,timestamps:h,latestTimestamp:h[0]??null,latestPassRate:d,latestTotalRuns:i,latestPassedRuns:j}}),total:h}}function h(a){let e=(0,c.join)(d(),a);if(!(0,b.existsSync)(e))return null;let f=(0,b.readdirSync)(e,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name).sort().reverse();return{name:a,timestamps:f,latestTimestamp:f[0]??null}}function i(a,e){let f=(0,c.join)(d(),a,e);if(!(0,b.existsSync)(f))return null;let g=[];return!function a(d,e=""){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!f.isDirectory()||f.name.startsWith(".")||f.name.startsWith("run-"))continue;let h=e?`${e}/${f.name}`:f.name,i=(0,c.join)(d,f.name),j=(0,c.join)(i,"summary.json");(0,b.existsSync)(j)?g.push(h):a(i,h)}}(f),g.sort(),{name:a,timestamp:e,evals:g.map(a=>{let d=(0,c.join)(f,a),e=(0,c.join)(d,"summary.json"),g={totalRuns:0,passedRuns:0,passRate:"0%",meanDuration:0};if((0,b.existsSync)(e))try{g=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()&&a.name.startsWith("run-")).map(a=>a.name).sort().map(a=>{let e=(0,c.join)(d,a,"result.json"),f=null;if((0,b.existsSync)(e))try{f=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}return{name:a,result:f}});return{name:a,totalRuns:g.totalRuns,passedRuns:g.passedRuns,passRate:"string"==typeof g.passRate?parseFloat(g.passRate):g.passRate,meanDuration:g.meanDuration,runs:h}})}}function j(a,e,f,g){let h=(0,c.join)(d(),a,e,f,g,"transcript.json");if(!(0,b.existsSync)(h))return null;try{return JSON.parse((0,b.readFileSync)(h,"utf-8"))}catch{return null}}function k(a){let d=e();if(!(0,b.existsSync)(d))return{items:[],total:0};let f=[];!function a(d,e=""){for(let g of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!g.isDirectory()||g.name.startsWith("."))continue;let h=e?`${e}/${g.name}`:g.name,i=(0,c.join)(d,g.name),j=(0,c.join)(i,"PROMPT.md");(0,b.existsSync)(j)?f.push(h):a(i,h)}}(d),f.sort();let g=f.length;return{items:(a?f.slice(0,a):f).map(a=>{let e=(0,c.join)(d,a),f=(0,c.join)(e,"PROMPT.md"),g="";return(0,b.existsSync)(f)&&(g=(0,b.readFileSync)(f,"utf-8")),{name:a,prompt:g,files:(0,b.readdirSync)(e,{withFileTypes:!0}).filter(a=>a.isFile()).map(a=>a.name)}}),total:g}}function l(a){let d=(0,c.join)(e(),a);if(!(0,b.existsSync)(d))return null;let f=(0,c.join)(d,"PROMPT.md"),g="";(0,b.existsSync)(f)&&(g=(0,b.readFileSync)(f,"utf-8"));let h=[];!function a(d,e){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if("node_modules"===f.name||".git"===f.name)continue;let b=e?`${e}/${f.name}`:f.name;f.isDirectory()?a((0,c.join)(d,f.name),b):h.push(b)}}(d,"");let i={};for(let a of["PROMPT.md","EVAL.ts","EVAL.tsx","package.json"]){let e=(0,c.join)(d,a);if((0,b.existsSync)(e))try{i[a]=(0,b.readFileSync)(e,"utf-8")}catch{}}return{name:a,prompt:g,files:h,fileContents:i}}a.s(["getEvalDetail",()=>l,"getExperiment",()=>h,"getExperimentDetail",()=>i,"getTranscript",()=>j,"listEvals",()=>k,"listExperiments",()=>g])},22977,a=>{"use strict";var b=a.i(7997),c=a.i(95387);function d({className:a,size:d="default",...e}){return(0,b.jsx)("div",{"data-slot":"card","data-size":d,className:(0,c.cn)("ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col",a),...e})}function e({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-header",className:(0,c.cn)("gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",a),...d})}function f({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-title",className:(0,c.cn)("text-sm font-medium",a),...d})}function g({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-content",className:(0,c.cn)("px-4 group-data-[size=sm]/card:px-3",a),...d})}a.s(["Card",()=>d,"CardContent",()=>g,"CardHeader",()=>e,"CardTitle",()=>f])},98720,a=>{"use strict";a.s(["Progress",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call Progress() from the server but Progress is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ui/progress.tsx <module evaluation>","Progress")},46442,a=>{"use strict";a.s(["Progress",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call Progress() from the server but Progress is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ui/progress.tsx","Progress")},71804,a=>{"use strict";a.i(98720);var b=a.i(46442);a.n(b)},37345,a=>{"use strict";a.s(["Separator",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call Separator() from the server but Separator is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ui/separator.tsx <module evaluation>","Separator")},43277,a=>{"use strict";a.s(["Separator",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call Separator() from the server but Separator is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ui/separator.tsx","Separator")},83977,a=>{"use strict";a.i(37345);var b=a.i(43277);a.n(b)},87618,a=>{"use strict";var b=a.i(7997);a.i(70396);var c=a.i(73727),d=a.i(95936),e=a.i(22977),f=a.i(20954),g=a.i(71804),h=a.i(83977);function i({runName:a,result:c,experiment:g,timestamp:h,evalName:i}){return c?(0,b.jsx)(d.default,{href:`/transcript/${encodeURIComponent(g)}/${encodeURIComponent(h)}/${encodeURIComponent(i)}/${encodeURIComponent(a)}`,className:"block cursor-pointer",children:(0,b.jsx)(e.Card,{className:"transition-colors hover:bg-muted",children:(0,b.jsxs)(e.CardContent,{className:"py-3 px-4 flex items-center justify-between",children:[(0,b.jsxs)("div",{className:"flex items-center gap-3",children:[(0,b.jsx)("span",{className:"text-sm font-medium",children:a}),(0,b.jsx)(f.Badge,{variant:"passed"===c.status?"default":"destructive",children:c.status}),c.error&&(0,b.jsx)("span",{className:"text-xs text-destructive truncate max-w-64",children:c.error})]}),(0,b.jsxs)("div",{className:"flex items-center gap-4 text-xs text-muted-foreground",children:[c.o11y&&(0,b.jsxs)("span",{children:[c.o11y.totalToolCalls," tool calls"]}),(0,b.jsxs)("span",{children:[c.duration.toFixed(1),"s"]})]})]})})}):(0,b.jsx)(e.Card,{className:"opacity-50",children:(0,b.jsx)(e.CardContent,{className:"py-3 px-4",children:(0,b.jsxs)("span",{className:"text-sm text-muted-foreground",children:[a,": No result"]})})})}function j({data:a}){let c=a.evals.length,j=a.evals.filter(a=>a.passedRuns===a.totalRuns).length,l=a.evals.reduce((a,b)=>a+b.passRate,0)/(c||1);return(0,b.jsxs)("div",{className:"space-y-6",children:[(0,b.jsxs)("div",{children:[(0,b.jsxs)("div",{className:"flex items-center gap-2 text-sm text-muted-foreground mb-1",children:[(0,b.jsx)(d.default,{href:"/experiments",className:"cursor-pointer hover:underline underline-offset-4",children:"Experiments"}),(0,b.jsx)("span",{children:"/"}),(0,b.jsx)("span",{children:a.name}),(0,b.jsx)("span",{children:"/"}),(0,b.jsx)("span",{children:k(a.timestamp)})]}),(0,b.jsx)("h1",{className:"text-2xl font-bold tracking-tight",children:a.name})]}),(0,b.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[(0,b.jsx)(e.Card,{children:(0,b.jsxs)(e.CardContent,{className:"py-4 px-4",children:[(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:"Overall Pass Rate"}),(0,b.jsxs)("div",{className:"text-2xl font-bold mt-1",children:[l.toFixed(0),"%"]}),(0,b.jsx)(g.Progress,{value:l,className:"mt-2 h-1.5"})]})}),(0,b.jsx)(e.Card,{children:(0,b.jsxs)(e.CardContent,{className:"py-4 px-4",children:[(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:"Evals"}),(0,b.jsxs)("div",{className:"text-2xl font-bold mt-1",children:[j,"/",c]}),(0,b.jsx)("div",{className:"text-xs text-muted-foreground mt-1",children:"passed"})]})}),(0,b.jsx)(e.Card,{children:(0,b.jsxs)(e.CardContent,{className:"py-4 px-4",children:[(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:"Avg Duration"}),(0,b.jsxs)("div",{className:"text-2xl font-bold mt-1",children:[(a.evals.reduce((a,b)=>a+b.meanDuration,0)/(c||1)).toFixed(1),"s"]})]})}),(0,b.jsx)(e.Card,{children:(0,b.jsxs)(e.CardContent,{className:"py-4 px-4",children:[(0,b.jsx)("div",{className:"text-xs text-muted-foreground",children:"Timestamp"}),(0,b.jsx)("div",{className:"text-sm font-medium mt-1",children:k(a.timestamp)})]})})]}),(0,b.jsx)(h.Separator,{}),(0,b.jsx)("div",{className:"space-y-6",children:a.evals.map(c=>(0,b.jsxs)(e.Card,{children:[(0,b.jsxs)(e.CardHeader,{children:[(0,b.jsxs)("div",{className:"flex items-center justify-between",children:[(0,b.jsxs)("div",{className:"flex items-center gap-3",children:[(0,b.jsx)(e.CardTitle,{className:"text-lg",children:c.name}),(0,b.jsxs)(f.Badge,{variant:c.passedRuns===c.totalRuns?"default":"destructive",children:[c.passedRuns,"/",c.totalRuns," passed"]})]}),(0,b.jsxs)("div",{className:"text-sm text-muted-foreground",children:["avg ",c.meanDuration.toFixed(1),"s"]})]}),(0,b.jsx)(g.Progress,{value:c.passRate,className:"h-1.5 mt-2"})]}),(0,b.jsx)(e.CardContent,{children:(0,b.jsx)("div",{className:"space-y-2",children:c.runs.map(d=>(0,b.jsx)(i,{runName:d.name,result:d.result,experiment:a.name,timestamp:a.timestamp,evalName:c.name},d.name))})})]},c.name))})]})}function k(a){try{let b=a.replace(/T(\d{2})-(\d{2})-(\d{2})/,"T$1:$2:$3"),c=new Date(b);if(isNaN(c.getTime()))return a;return c.toLocaleString()}catch{return a}}var l=a.i(5419);async function m({params:a}){let{name:d,timestamp:e}=await a,f=decodeURIComponent(d),g=decodeURIComponent(e),h=(0,l.getExperimentDetail)(f,g);return h||(0,c.notFound)(),(0,b.jsx)(j,{data:h})}a.s(["default",()=>m,"dynamic",0,"force-dynamic"],87618)}];
|
|
2
2
|
|
|
3
3
|
//# sourceMappingURL=%5Broot-of-the-server%5D__b8fc4094._.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/playground/lib/data.ts","../../../../../../packages/playground/components/ui/card.tsx","../../../../../../packages/playground/components/ui/progress.tsx/__nextjs-internal-proxy.mjs","../../../../../../packages/playground/components/ui/separator.tsx/__nextjs-internal-proxy.mjs","../../../../../../packages/playground/app/experiments/%5Bname%5D/%5Btimestamp%5D/page.tsx","../../../../../../packages/playground/components/ExperimentDetail.tsx","../../../../../../packages/playground/components/RunResultCard.tsx"],"sourcesContent":["/**\n * Server-side data access for the playground.\n * Reads JSON files from the results/ and evals/ directories.\n * Directory paths are provided via RESULTS_DIR and EVALS_DIR env vars.\n */\n\nimport { readdirSync, readFileSync, existsSync } from \"fs\";\nimport { join, resolve } from \"path\";\n\nfunction getResultsDir(): string {\n return resolve(process.env.RESULTS_DIR || \"./results\");\n}\n\nfunction getEvalsDir(): string {\n return resolve(process.env.EVALS_DIR || \"./evals\");\n}\n\n/** Check if a directory name looks like an ISO timestamp (used as run ID) */\nfunction isTimestamp(name: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}T/.test(name);\n}\n\n/** List experiments from the results directory. Pass limit to cap expensive per-item reads. */\nexport function listExperiments(limit?: number) {\n const resultsDir = getResultsDir();\n\n if (!existsSync(resultsDir)) {\n return { items: [], total: 0 };\n }\n\n // Discover experiments by walking the directory tree until we find\n // timestamp directories. The path from resultsDir to the parent of the\n // first timestamp is the experiment name (e.g. \"my-config/openai/gpt-5.2-codex\").\n const entries: string[] = [];\n\n function walk(dir: string, prefix: string) {\n const children = readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n\n // If any child looks like a timestamp, this directory is an experiment\n if (children.some(isTimestamp)) {\n entries.push(prefix);\n return;\n }\n\n // Otherwise keep recursing\n for (const child of children) {\n walk(join(dir, child), prefix ? `${prefix}/${child}` : child);\n }\n }\n\n walk(resultsDir, \"\");\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const expDir = join(resultsDir, name);\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && isTimestamp(e.name))\n .map((e) => e.name)\n .sort()\n .reverse();\n\n let latestPassRate: number | undefined;\n let latestTotalRuns = 0;\n let latestPassedRuns = 0;\n\n if (timestamps.length > 0) {\n const latestDir = join(expDir, timestamps[0]);\n const evalDirs = readdirSync(latestDir, { withFileTypes: true }).filter(\n (e) => e.isDirectory()\n );\n\n for (const evalDir of evalDirs) {\n const summaryPath = join(latestDir, evalDir.name, \"summary.json\");\n if (existsSync(summaryPath)) {\n try {\n const summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n latestTotalRuns += summary.totalRuns ?? 0;\n latestPassedRuns += summary.passedRuns ?? 0;\n } catch {\n // Skip invalid summary files\n }\n }\n }\n\n if (latestTotalRuns > 0) {\n latestPassRate = (latestPassedRuns / latestTotalRuns) * 100;\n }\n }\n\n return {\n name,\n timestamps,\n latestTimestamp: timestamps[0] ?? null,\n latestPassRate,\n latestTotalRuns,\n latestPassedRuns,\n };\n });\n\n return { items, total };\n}\n\n/** Get timestamps for a specific experiment */\nexport function getExperiment(name: string) {\n const expDir = join(getResultsDir(), name);\n\n if (!existsSync(expDir)) {\n return null;\n }\n\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort()\n .reverse();\n\n return { name, timestamps, latestTimestamp: timestamps[0] ?? null };\n}\n\n/** Get full experiment detail for a specific timestamp */\nexport function getExperimentDetail(name: string, timestamp: string) {\n const runDir = join(getResultsDir(), name, timestamp);\n\n if (!existsSync(runDir)) {\n return null;\n }\n\n // Recursively discover all eval result directories (directories with summary.json)\n const evalDirs: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name.startsWith(\"run-\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const summaryPath = join(entryPath, \"summary.json\");\n\n // Check if this is an eval result directory (has summary.json)\n if (existsSync(summaryPath)) {\n evalDirs.push(relativePath);\n } else {\n // Not an eval result, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(runDir);\n evalDirs.sort();\n\n const evals = evalDirs.map((evalName) => {\n const evalDir = join(runDir, evalName);\n const summaryPath = join(evalDir, \"summary.json\");\n\n let summary = {\n totalRuns: 0,\n passedRuns: 0,\n passRate: \"0%\",\n meanDuration: 0,\n };\n if (existsSync(summaryPath)) {\n try {\n summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n } catch {\n // Use defaults\n }\n }\n\n // List run directories\n const runDirs = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && e.name.startsWith(\"run-\"))\n .map((e) => e.name)\n .sort();\n\n // Read each run's result.json\n const runs = runDirs.map((runDirName) => {\n const resultPath = join(evalDir, runDirName, \"result.json\");\n let result = null;\n if (existsSync(resultPath)) {\n try {\n result = JSON.parse(readFileSync(resultPath, \"utf-8\"));\n } catch {\n // Skip\n }\n }\n return { name: runDirName, result };\n });\n\n return {\n name: evalName,\n totalRuns: summary.totalRuns,\n passedRuns: summary.passedRuns,\n passRate:\n typeof summary.passRate === \"string\"\n ? parseFloat(summary.passRate)\n : summary.passRate,\n meanDuration: summary.meanDuration,\n runs,\n };\n });\n\n return { name, timestamp, evals };\n}\n\n/** Get result for a specific run */\nexport function getRunResult(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const resultPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"result.json\"\n );\n\n if (!existsSync(resultPath)) {\n return null;\n }\n\n try {\n return { result: JSON.parse(readFileSync(resultPath, \"utf-8\")) };\n } catch {\n return null;\n }\n}\n\n/** Get parsed transcript for a specific run */\nexport function getTranscript(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const transcriptPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"transcript.json\"\n );\n\n if (!existsSync(transcriptPath)) {\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(transcriptPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\n/** List evals from the evals directory. Pass limit to cap per-item reads. */\nexport function listEvals(limit?: number) {\n const evalsDir = getEvalsDir();\n\n if (!existsSync(evalsDir)) {\n return { items: [], total: 0 };\n }\n\n // Recursively discover all evals (directories with PROMPT.md)\n const entries: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const promptPath = join(entryPath, \"PROMPT.md\");\n\n // Check if this is an eval directory (has PROMPT.md)\n if (existsSync(promptPath)) {\n entries.push(relativePath);\n } else {\n // Not an eval, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(evalsDir);\n entries.sort();\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const evalDir = join(evalsDir, name);\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n const files = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isFile())\n .map((e) => e.name);\n\n return { name, prompt, files };\n });\n\n return { items, total };\n}\n\n/** Get detail for a specific eval */\nexport function getEvalDetail(name: string) {\n const evalDir = join(getEvalsDir(), name);\n\n if (!existsSync(evalDir)) {\n return null;\n }\n\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n // Recursively list files\n const files: string[] = [];\n function walk(dir: string, prefix: string) {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(join(dir, entry.name), relativePath);\n } else {\n files.push(relativePath);\n }\n }\n }\n walk(evalDir, \"\");\n\n // Read file contents for key files\n const fileContents: Record<string, string> = {};\n const keyFiles = [\"PROMPT.md\", \"EVAL.ts\", \"EVAL.tsx\", \"package.json\"];\n for (const file of keyFiles) {\n const filePath = join(evalDir, file);\n if (existsSync(filePath)) {\n try {\n fileContents[file] = readFileSync(filePath, \"utf-8\");\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n return { name, prompt, files, fileContents };\n}\n","import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & { size?: \"default\" | \"sm\" }) {\n return (\n <div\n data-slot=\"card\"\n data-size={size}\n className={cn(\"ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-muted-foreground text-xs/relaxed\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-4 group-data-[size=sm]/card:px-3\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"rounded-b-lg px-4 group-data-[size=sm]/card:px-3 [.border-t]:pt-4 group-data-[size=sm]/card:[.border-t]:pt-3 flex items-center\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n","// This file is generated by next-core EcmascriptClientReferenceModule.\nimport { registerClientReference } from \"react-server-dom-turbopack/server\";\nexport const Progress = registerClientReference(\n function() { throw new Error(\"Attempted to call Progress() from the server but Progress is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.\"); },\n \"[project]/packages/playground/components/ui/progress.tsx\",\n \"Progress\",\n);\n","// This file is generated by next-core EcmascriptClientReferenceModule.\nimport { registerClientReference } from \"react-server-dom-turbopack/server\";\nexport const Separator = registerClientReference(\n function() { throw new Error(\"Attempted to call Separator() from the server but Separator is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.\"); },\n \"[project]/packages/playground/components/ui/separator.tsx\",\n \"Separator\",\n);\n","import { notFound } from \"next/navigation\";\nimport { ExperimentDetail } from \"@/components/ExperimentDetail\";\nimport { getExperimentDetail } from \"@/lib/data\";\n\nexport const dynamic = \"force-dynamic\";\n\nexport default async function ExperimentPage({\n params,\n}: {\n params: Promise<{ name: string; timestamp: string }>;\n}) {\n const { name, timestamp } = await params;\n const decodedName = decodeURIComponent(name);\n const decodedTimestamp = decodeURIComponent(timestamp);\n\n const data = getExperimentDetail(decodedName, decodedTimestamp);\n\n if (!data) {\n notFound();\n }\n\n return <ExperimentDetail data={data} />;\n}\n","import Link from \"next/link\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Progress } from \"@/components/ui/progress\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { RunResultCard } from \"@/components/RunResultCard\";\n\ninterface EvalDetail {\n name: string;\n totalRuns: number;\n passedRuns: number;\n passRate: number;\n meanDuration: number;\n runs: { name: string; result: RunResult | null }[];\n}\n\ninterface RunResult {\n status: \"passed\" | \"failed\";\n error?: string;\n duration: number;\n o11y?: {\n totalToolCalls: number;\n thinkingBlocks: number;\n errors: string[];\n };\n}\n\ninterface ExperimentDetailData {\n name: string;\n timestamp: string;\n evals: EvalDetail[];\n}\n\ninterface ExperimentDetailProps {\n data: ExperimentDetailData;\n}\n\nexport function ExperimentDetail({ data }: ExperimentDetailProps) {\n const totalEvals = data.evals.length;\n const passedEvals = data.evals.filter(\n (e) => e.passedRuns === e.totalRuns\n ).length;\n const overallPassRate =\n data.evals.reduce((sum, e) => sum + e.passRate, 0) / (totalEvals || 1);\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground mb-1\">\n <Link href=\"/experiments\" className=\"cursor-pointer hover:underline underline-offset-4\">\n Experiments\n </Link>\n <span>/</span>\n <span>{data.name}</span>\n <span>/</span>\n <span>{formatTimestamp(data.timestamp)}</span>\n </div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{data.name}</h1>\n </div>\n\n {/* Summary cards */}\n <div className=\"grid grid-cols-1 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"py-4 px-4\">\n <div className=\"text-xs text-muted-foreground\">\n Overall Pass Rate\n </div>\n <div className=\"text-2xl font-bold mt-1\">\n {overallPassRate.toFixed(0)}%\n </div>\n <Progress value={overallPassRate} className=\"mt-2 h-1.5\" />\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"py-4 px-4\">\n <div className=\"text-xs text-muted-foreground\">Evals</div>\n <div className=\"text-2xl font-bold mt-1\">\n {passedEvals}/{totalEvals}\n </div>\n <div className=\"text-xs text-muted-foreground mt-1\">passed</div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"py-4 px-4\">\n <div className=\"text-xs text-muted-foreground\">Avg Duration</div>\n <div className=\"text-2xl font-bold mt-1\">\n {(\n data.evals.reduce((s, e) => s + e.meanDuration, 0) /\n (totalEvals || 1)\n ).toFixed(1)}\n s\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"py-4 px-4\">\n <div className=\"text-xs text-muted-foreground\">Timestamp</div>\n <div className=\"text-sm font-medium mt-1\">\n {formatTimestamp(data.timestamp)}\n </div>\n </CardContent>\n </Card>\n </div>\n\n <Separator />\n\n {/* Per-eval breakdown */}\n <div className=\"space-y-6\">\n {data.evals.map((evalDetail) => (\n <Card key={evalDetail.name}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <CardTitle className=\"text-lg\">{evalDetail.name}</CardTitle>\n <Badge\n variant={\n evalDetail.passedRuns === evalDetail.totalRuns\n ? \"default\"\n : \"destructive\"\n }\n >\n {evalDetail.passedRuns}/{evalDetail.totalRuns} passed\n </Badge>\n </div>\n <div className=\"text-sm text-muted-foreground\">\n avg {evalDetail.meanDuration.toFixed(1)}s\n </div>\n </div>\n <Progress value={evalDetail.passRate} className=\"h-1.5 mt-2\" />\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2\">\n {evalDetail.runs.map((run) => (\n <RunResultCard\n key={run.name}\n runName={run.name}\n result={run.result}\n experiment={data.name}\n timestamp={data.timestamp}\n evalName={evalDetail.name}\n />\n ))}\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n </div>\n );\n}\n\nfunction formatTimestamp(ts: string): string {\n try {\n const isoString = ts.replace(/T(\\d{2})-(\\d{2})-(\\d{2})/, \"T$1:$2:$3\");\n const date = new Date(isoString);\n if (isNaN(date.getTime())) return ts;\n return date.toLocaleString();\n } catch {\n return ts;\n }\n}\n","import Link from \"next/link\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Card, CardContent } from \"@/components/ui/card\";\n\n\ninterface RunResult {\n status: \"passed\" | \"failed\";\n error?: string;\n duration: number;\n o11y?: {\n totalToolCalls: number;\n thinkingBlocks: number;\n errors: string[];\n };\n}\n\ninterface RunResultCardProps {\n runName: string;\n result: RunResult | null;\n experiment: string;\n timestamp: string;\n evalName: string;\n}\n\nexport function RunResultCard({\n runName,\n result,\n experiment,\n timestamp,\n evalName,\n}: RunResultCardProps) {\n if (!result) {\n return (\n <Card className=\"opacity-50\">\n <CardContent className=\"py-3 px-4\">\n <span className=\"text-sm text-muted-foreground\">{runName}: No result</span>\n </CardContent>\n </Card>\n );\n }\n\n return (\n <Link\n href={`/transcript/${encodeURIComponent(experiment)}/${encodeURIComponent(timestamp)}/${encodeURIComponent(evalName)}/${encodeURIComponent(runName)}`}\n className=\"block cursor-pointer\"\n >\n <Card className=\"transition-colors hover:bg-muted\">\n <CardContent className=\"py-3 px-4 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <span className=\"text-sm font-medium\">{runName}</span>\n <Badge\n variant={result.status === \"passed\" ? \"default\" : \"destructive\"}\n >\n {result.status}\n </Badge>\n {result.error && (\n <span className=\"text-xs text-destructive truncate max-w-64\">\n {result.error}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n {result.o11y && (\n <span>{result.o11y.totalToolCalls} tool calls</span>\n )}\n <span>{result.duration.toFixed(1)}s</span>\n </div>\n </CardContent>\n </Card>\n </Link>\n );\n}\n"],"names":[],"mappings":"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","ignoreList":[2,3]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/playground/lib/data.ts","../../../../../../packages/playground/components/ui/card.tsx","../../../../../../packages/playground/components/ui/progress.tsx/__nextjs-internal-proxy.mjs","../../../../../../packages/playground/components/ui/separator.tsx/__nextjs-internal-proxy.mjs","../../../../../../packages/playground/app/experiments/%5Bname%5D/%5Btimestamp%5D/page.tsx","../../../../../../packages/playground/components/ExperimentDetail.tsx","../../../../../../packages/playground/components/RunResultCard.tsx"],"sourcesContent":["/**\n * Server-side data access for the playground.\n * Reads JSON files from the results/ and evals/ directories.\n * Directory paths are provided via RESULTS_DIR and EVALS_DIR env vars.\n */\n\nimport { readdirSync, readFileSync, existsSync } from \"fs\";\nimport { join, resolve } from \"path\";\n\nfunction getResultsDir(): string {\n return resolve(process.env.RESULTS_DIR || \"./results\");\n}\n\nfunction getEvalsDir(): string {\n return resolve(process.env.EVALS_DIR || \"./evals\");\n}\n\n/** Check if a directory name looks like an ISO timestamp (used as run ID) */\nfunction isTimestamp(name: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}T/.test(name);\n}\n\n/** List experiments from the results directory. Pass limit to cap expensive per-item reads. */\nexport function listExperiments(limit?: number) {\n const resultsDir = getResultsDir();\n\n if (!existsSync(resultsDir)) {\n return { items: [], total: 0 };\n }\n\n // Discover experiments by walking the directory tree until we find\n // timestamp directories. The path from resultsDir to the parent of the\n // first timestamp is the experiment name (e.g. \"my-config/openai/gpt-5.2-codex\").\n const entries: string[] = [];\n\n function walk(dir: string, prefix: string) {\n const children = readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n\n // If any child looks like a timestamp, this directory is an experiment\n if (children.some(isTimestamp)) {\n entries.push(prefix);\n return;\n }\n\n // Otherwise keep recursing\n for (const child of children) {\n walk(join(dir, child), prefix ? `${prefix}/${child}` : child);\n }\n }\n\n walk(resultsDir, \"\");\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const expDir = join(resultsDir, name);\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && isTimestamp(e.name))\n .map((e) => e.name)\n .sort()\n .reverse();\n\n let latestPassRate: number | undefined;\n let latestTotalRuns = 0;\n let latestPassedRuns = 0;\n\n if (timestamps.length > 0) {\n const latestDir = join(expDir, timestamps[0]);\n const evalDirs = readdirSync(latestDir, { withFileTypes: true }).filter(\n (e) => e.isDirectory()\n );\n\n for (const evalDir of evalDirs) {\n const summaryPath = join(latestDir, evalDir.name, \"summary.json\");\n if (existsSync(summaryPath)) {\n try {\n const summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n latestTotalRuns += summary.totalRuns ?? 0;\n latestPassedRuns += summary.passedRuns ?? 0;\n } catch {\n // Skip invalid summary files\n }\n }\n }\n\n if (latestTotalRuns > 0) {\n latestPassRate = (latestPassedRuns / latestTotalRuns) * 100;\n }\n }\n\n return {\n name,\n timestamps,\n latestTimestamp: timestamps[0] ?? null,\n latestPassRate,\n latestTotalRuns,\n latestPassedRuns,\n };\n });\n\n return { items, total };\n}\n\n/** Get timestamps for a specific experiment */\nexport function getExperiment(name: string) {\n const expDir = join(getResultsDir(), name);\n\n if (!existsSync(expDir)) {\n return null;\n }\n\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort()\n .reverse();\n\n return { name, timestamps, latestTimestamp: timestamps[0] ?? null };\n}\n\n/** Get full experiment detail for a specific timestamp */\nexport function getExperimentDetail(name: string, timestamp: string) {\n const runDir = join(getResultsDir(), name, timestamp);\n\n if (!existsSync(runDir)) {\n return null;\n }\n\n // Recursively discover all eval result directories (directories with summary.json)\n const evalDirs: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name.startsWith(\"run-\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const summaryPath = join(entryPath, \"summary.json\");\n\n // Check if this is an eval result directory (has summary.json)\n if (existsSync(summaryPath)) {\n evalDirs.push(relativePath);\n } else {\n // Not an eval result, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(runDir);\n evalDirs.sort();\n\n const evals = evalDirs.map((evalName) => {\n const evalDir = join(runDir, evalName);\n const summaryPath = join(evalDir, \"summary.json\");\n\n let summary = {\n totalRuns: 0,\n passedRuns: 0,\n passRate: \"0%\",\n meanDuration: 0,\n };\n if (existsSync(summaryPath)) {\n try {\n summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n } catch {\n // Use defaults\n }\n }\n\n // List run directories\n const runDirs = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && e.name.startsWith(\"run-\"))\n .map((e) => e.name)\n .sort();\n\n // Read each run's result.json\n const runs = runDirs.map((runDirName) => {\n const resultPath = join(evalDir, runDirName, \"result.json\");\n let result = null;\n if (existsSync(resultPath)) {\n try {\n result = JSON.parse(readFileSync(resultPath, \"utf-8\"));\n } catch {\n // Skip\n }\n }\n return { name: runDirName, result };\n });\n\n return {\n name: evalName,\n totalRuns: summary.totalRuns,\n passedRuns: summary.passedRuns,\n passRate:\n typeof summary.passRate === \"string\"\n ? parseFloat(summary.passRate)\n : summary.passRate,\n meanDuration: summary.meanDuration,\n runs,\n };\n });\n\n return { name, timestamp, evals };\n}\n\n/** Get result for a specific run */\nexport function getRunResult(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const resultPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"result.json\"\n );\n\n if (!existsSync(resultPath)) {\n return null;\n }\n\n try {\n return { result: JSON.parse(readFileSync(resultPath, \"utf-8\")) };\n } catch {\n return null;\n }\n}\n\n/** Get parsed transcript for a specific run */\nexport function getTranscript(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const transcriptPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"transcript.json\"\n );\n\n if (!existsSync(transcriptPath)) {\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(transcriptPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\n/** List evals from the evals directory. Pass limit to cap per-item reads. */\nexport function listEvals(limit?: number) {\n const evalsDir = getEvalsDir();\n\n if (!existsSync(evalsDir)) {\n return { items: [], total: 0 };\n }\n\n // Recursively discover all evals (directories with PROMPT.md)\n const entries: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const promptPath = join(entryPath, \"PROMPT.md\");\n\n // Check if this is an eval directory (has PROMPT.md)\n if (existsSync(promptPath)) {\n entries.push(relativePath);\n } else {\n // Not an eval, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(evalsDir);\n entries.sort();\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const evalDir = join(evalsDir, name);\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n const files = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isFile())\n .map((e) => e.name);\n\n return { name, prompt, files };\n });\n\n return { items, total };\n}\n\n/** Get detail for a specific eval */\nexport function getEvalDetail(name: string) {\n const evalDir = join(getEvalsDir(), name);\n\n if (!existsSync(evalDir)) {\n return null;\n }\n\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n // Recursively list files\n const files: string[] = [];\n function walk(dir: string, prefix: string) {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(join(dir, entry.name), relativePath);\n } else {\n files.push(relativePath);\n }\n }\n }\n walk(evalDir, \"\");\n\n // Read file contents for key files\n const fileContents: Record<string, string> = {};\n const keyFiles = [\"PROMPT.md\", \"EVAL.ts\", \"EVAL.tsx\", \"package.json\"];\n for (const file of keyFiles) {\n const filePath = join(evalDir, file);\n if (existsSync(filePath)) {\n try {\n fileContents[file] = readFileSync(filePath, \"utf-8\");\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n return { name, prompt, files, fileContents };\n}\n","import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & { size?: \"default\" | \"sm\" }) {\n return (\n <div\n data-slot=\"card\"\n data-size={size}\n className={cn(\"ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-muted-foreground text-xs/relaxed\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-4 group-data-[size=sm]/card:px-3\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"rounded-b-lg px-4 group-data-[size=sm]/card:px-3 [.border-t]:pt-4 group-data-[size=sm]/card:[.border-t]:pt-3 flex items-center\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n","// This file is generated by next-core EcmascriptClientReferenceModule.\nimport { registerClientReference } from \"react-server-dom-turbopack/server\";\nexport const Progress = registerClientReference(\n function() { throw new Error(\"Attempted to call Progress() from the server but Progress is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.\"); },\n \"[project]/packages/playground/components/ui/progress.tsx\",\n \"Progress\",\n);\n","// This file is generated by next-core EcmascriptClientReferenceModule.\nimport { registerClientReference } from \"react-server-dom-turbopack/server\";\nexport const Separator = registerClientReference(\n function() { throw new Error(\"Attempted to call Separator() from the server but Separator is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.\"); },\n \"[project]/packages/playground/components/ui/separator.tsx\",\n \"Separator\",\n);\n","import { notFound } from \"next/navigation\";\nimport { ExperimentDetail } from \"@/components/ExperimentDetail\";\nimport { getExperimentDetail } from \"@/lib/data\";\n\nexport const dynamic = \"force-dynamic\";\n\nexport default async function ExperimentPage({\n params,\n}: {\n params: Promise<{ name: string; timestamp: string }>;\n}) {\n const { name, timestamp } = await params;\n const decodedName = decodeURIComponent(name);\n const decodedTimestamp = decodeURIComponent(timestamp);\n\n const data = getExperimentDetail(decodedName, decodedTimestamp);\n\n if (!data) {\n notFound();\n }\n\n return <ExperimentDetail data={data} />;\n}\n","import Link from \"next/link\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Progress } from \"@/components/ui/progress\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { RunResultCard } from \"@/components/RunResultCard\";\n\ninterface EvalDetail {\n name: string;\n totalRuns: number;\n passedRuns: number;\n passRate: number;\n meanDuration: number;\n runs: { name: string; result: RunResult | null }[];\n}\n\ninterface RunResult {\n status: \"passed\" | \"failed\";\n error?: string;\n duration: number;\n o11y?: {\n totalToolCalls: number;\n thinkingBlocks: number;\n errors: string[];\n };\n}\n\ninterface ExperimentDetailData {\n name: string;\n timestamp: string;\n evals: EvalDetail[];\n}\n\ninterface ExperimentDetailProps {\n data: ExperimentDetailData;\n}\n\nexport function ExperimentDetail({ data }: ExperimentDetailProps) {\n const totalEvals = data.evals.length;\n const passedEvals = data.evals.filter(\n (e) => e.passedRuns === e.totalRuns\n ).length;\n const overallPassRate =\n data.evals.reduce((sum, e) => sum + e.passRate, 0) / (totalEvals || 1);\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground mb-1\">\n <Link href=\"/experiments\" className=\"cursor-pointer hover:underline underline-offset-4\">\n Experiments\n </Link>\n <span>/</span>\n <span>{data.name}</span>\n <span>/</span>\n <span>{formatTimestamp(data.timestamp)}</span>\n </div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{data.name}</h1>\n </div>\n\n {/* Summary cards */}\n <div className=\"grid grid-cols-1 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"py-4 px-4\">\n <div className=\"text-xs text-muted-foreground\">\n Overall Pass Rate\n </div>\n <div className=\"text-2xl font-bold mt-1\">\n {overallPassRate.toFixed(0)}%\n </div>\n <Progress value={overallPassRate} className=\"mt-2 h-1.5\" />\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"py-4 px-4\">\n <div className=\"text-xs text-muted-foreground\">Evals</div>\n <div className=\"text-2xl font-bold mt-1\">\n {passedEvals}/{totalEvals}\n </div>\n <div className=\"text-xs text-muted-foreground mt-1\">passed</div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"py-4 px-4\">\n <div className=\"text-xs text-muted-foreground\">Avg Duration</div>\n <div className=\"text-2xl font-bold mt-1\">\n {(\n data.evals.reduce((s, e) => s + e.meanDuration, 0) /\n (totalEvals || 1)\n ).toFixed(1)}\n s\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"py-4 px-4\">\n <div className=\"text-xs text-muted-foreground\">Timestamp</div>\n <div className=\"text-sm font-medium mt-1\">\n {formatTimestamp(data.timestamp)}\n </div>\n </CardContent>\n </Card>\n </div>\n\n <Separator />\n\n {/* Per-eval breakdown */}\n <div className=\"space-y-6\">\n {data.evals.map((evalDetail) => (\n <Card key={evalDetail.name}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <CardTitle className=\"text-lg\">{evalDetail.name}</CardTitle>\n <Badge\n variant={\n evalDetail.passedRuns === evalDetail.totalRuns\n ? \"default\"\n : \"destructive\"\n }\n >\n {evalDetail.passedRuns}/{evalDetail.totalRuns} passed\n </Badge>\n </div>\n <div className=\"text-sm text-muted-foreground\">\n avg {evalDetail.meanDuration.toFixed(1)}s\n </div>\n </div>\n <Progress value={evalDetail.passRate} className=\"h-1.5 mt-2\" />\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2\">\n {evalDetail.runs.map((run) => (\n <RunResultCard\n key={run.name}\n runName={run.name}\n result={run.result}\n experiment={data.name}\n timestamp={data.timestamp}\n evalName={evalDetail.name}\n />\n ))}\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n </div>\n );\n}\n\nfunction formatTimestamp(ts: string): string {\n try {\n const isoString = ts.replace(/T(\\d{2})-(\\d{2})-(\\d{2})/, \"T$1:$2:$3\");\n const date = new Date(isoString);\n if (isNaN(date.getTime())) return ts;\n return date.toLocaleString();\n } catch {\n return ts;\n }\n}\n","import Link from \"next/link\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Card, CardContent } from \"@/components/ui/card\";\n\n\ninterface RunResult {\n status: \"passed\" | \"failed\";\n error?: string;\n duration: number;\n o11y?: {\n totalToolCalls: number;\n thinkingBlocks: number;\n errors: string[];\n };\n}\n\ninterface RunResultCardProps {\n runName: string;\n result: RunResult | null;\n experiment: string;\n timestamp: string;\n evalName: string;\n}\n\nexport function RunResultCard({\n runName,\n result,\n experiment,\n timestamp,\n evalName,\n}: RunResultCardProps) {\n if (!result) {\n return (\n <Card className=\"opacity-50\">\n <CardContent className=\"py-3 px-4\">\n <span className=\"text-sm text-muted-foreground\">{runName}: No result</span>\n </CardContent>\n </Card>\n );\n }\n\n return (\n <Link\n href={`/transcript/${encodeURIComponent(experiment)}/${encodeURIComponent(timestamp)}/${encodeURIComponent(evalName)}/${encodeURIComponent(runName)}`}\n className=\"block cursor-pointer\"\n >\n <Card className=\"transition-colors hover:bg-muted\">\n <CardContent className=\"py-3 px-4 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <span className=\"text-sm font-medium\">{runName}</span>\n <Badge\n variant={result.status === \"passed\" ? \"default\" : \"destructive\"}\n >\n {result.status}\n </Badge>\n {result.error && (\n <span className=\"text-xs text-destructive truncate max-w-64\">\n {result.error}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n {result.o11y && (\n <span>{result.o11y.totalToolCalls} tool calls</span>\n )}\n <span>{result.duration.toFixed(1)}s</span>\n </div>\n </CardContent>\n </Card>\n </Link>\n );\n}\n"],"names":[],"mappings":"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","ignoreList":[2,3]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
module.exports=[69046,a=>{a.n(a.i(80979))},43619,a=>{a.n(a.i(79962))},13718,a=>{a.n(a.i(85523))},18198,a=>{a.n(a.i(45518))},62212,a=>{a.n(a.i(66114))},22734,(a,b,c)=>{b.exports=a.x("fs",()=>require("fs"))},5419,a=>{"use strict";var b=a.i(22734),c=a.i(14747);function d(){return(0,c.resolve)(process.env.RESULTS_DIR||"./results")}function e(){return(0,c.resolve)(process.env.EVALS_DIR||"./evals")}function f(a){return/^\d{4}-\d{2}-\d{2}T/.test(a)}function g(a){let e=d();if(!(0,b.existsSync)(e))return{items:[],total:0};let g=[];!function a(d,e){let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name);if(h.some(f))return void g.push(e);for(let b of h)a((0,c.join)(d,b),e?`${e}/${b}`:b)}(e,"");let h=g.length;return{items:(a?g.slice(0,a):g).map(a=>{let d,g=(0,c.join)(e,a),h=(0,b.readdirSync)(g,{withFileTypes:!0}).filter(a=>a.isDirectory()&&f(a.name)).map(a=>a.name).sort().reverse(),i=0,j=0;if(h.length>0){let a=(0,c.join)(g,h[0]);for(let d of(0,b.readdirSync)(a,{withFileTypes:!0}).filter(a=>a.isDirectory())){let e=(0,c.join)(a,d.name,"summary.json");if((0,b.existsSync)(e))try{let a=JSON.parse((0,b.readFileSync)(e,"utf-8"));i+=a.totalRuns??0,j+=a.passedRuns??0}catch{}}i>0&&(d=j/i*100)}return{name:a,timestamps:h,latestTimestamp:h[0]??null,latestPassRate:d,latestTotalRuns:i,latestPassedRuns:j}}),total:h}}function h(a,e){let f=(0,c.join)(d(),a,e);if(!(0,b.existsSync)(f))return null;let g=[];return!function a(d,e=""){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!f.isDirectory()||f.name.startsWith(".")||f.name.startsWith("run-"))continue;let h=e?`${e}/${f.name}`:f.name,i=(0,c.join)(d,f.name),j=(0,c.join)(i,"summary.json");(0,b.existsSync)(j)?g.push(h):a(i,h)}}(f),g.sort(),{name:a,timestamp:e,evals:g.map(a=>{let d=(0,c.join)(f,a),e=(0,c.join)(d,"summary.json"),g={totalRuns:0,passedRuns:0,passRate:"0%",meanDuration:0};if((0,b.existsSync)(e))try{g=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()&&a.name.startsWith("run-")).map(a=>a.name).sort().map(a=>{let e=(0,c.join)(d,a,"result.json"),f=null;if((0,b.existsSync)(e))try{f=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}return{name:a,result:f}});return{name:a,totalRuns:g.totalRuns,passedRuns:g.passedRuns,passRate:"string"==typeof g.passRate?parseFloat(g.passRate):g.passRate,meanDuration:g.meanDuration,runs:h}})}}function
|
|
1
|
+
module.exports=[69046,a=>{a.n(a.i(80979))},43619,a=>{a.n(a.i(79962))},13718,a=>{a.n(a.i(85523))},18198,a=>{a.n(a.i(45518))},62212,a=>{a.n(a.i(66114))},22734,(a,b,c)=>{b.exports=a.x("fs",()=>require("fs"))},5419,a=>{"use strict";var b=a.i(22734),c=a.i(14747);function d(){return(0,c.resolve)(process.env.RESULTS_DIR||"./results")}function e(){return(0,c.resolve)(process.env.EVALS_DIR||"./evals")}function f(a){return/^\d{4}-\d{2}-\d{2}T/.test(a)}function g(a){let e=d();if(!(0,b.existsSync)(e))return{items:[],total:0};let g=[];!function a(d,e){let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name);if(h.some(f))return void g.push(e);for(let b of h)a((0,c.join)(d,b),e?`${e}/${b}`:b)}(e,"");let h=g.length;return{items:(a?g.slice(0,a):g).map(a=>{let d,g=(0,c.join)(e,a),h=(0,b.readdirSync)(g,{withFileTypes:!0}).filter(a=>a.isDirectory()&&f(a.name)).map(a=>a.name).sort().reverse(),i=0,j=0;if(h.length>0){let a=(0,c.join)(g,h[0]);for(let d of(0,b.readdirSync)(a,{withFileTypes:!0}).filter(a=>a.isDirectory())){let e=(0,c.join)(a,d.name,"summary.json");if((0,b.existsSync)(e))try{let a=JSON.parse((0,b.readFileSync)(e,"utf-8"));i+=a.totalRuns??0,j+=a.passedRuns??0}catch{}}i>0&&(d=j/i*100)}return{name:a,timestamps:h,latestTimestamp:h[0]??null,latestPassRate:d,latestTotalRuns:i,latestPassedRuns:j}}),total:h}}function h(a){let e=(0,c.join)(d(),a);if(!(0,b.existsSync)(e))return null;let f=(0,b.readdirSync)(e,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name).sort().reverse();return{name:a,timestamps:f,latestTimestamp:f[0]??null}}function i(a,e){let f=(0,c.join)(d(),a,e);if(!(0,b.existsSync)(f))return null;let g=[];return!function a(d,e=""){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!f.isDirectory()||f.name.startsWith(".")||f.name.startsWith("run-"))continue;let h=e?`${e}/${f.name}`:f.name,i=(0,c.join)(d,f.name),j=(0,c.join)(i,"summary.json");(0,b.existsSync)(j)?g.push(h):a(i,h)}}(f),g.sort(),{name:a,timestamp:e,evals:g.map(a=>{let d=(0,c.join)(f,a),e=(0,c.join)(d,"summary.json"),g={totalRuns:0,passedRuns:0,passRate:"0%",meanDuration:0};if((0,b.existsSync)(e))try{g=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()&&a.name.startsWith("run-")).map(a=>a.name).sort().map(a=>{let e=(0,c.join)(d,a,"result.json"),f=null;if((0,b.existsSync)(e))try{f=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}return{name:a,result:f}});return{name:a,totalRuns:g.totalRuns,passedRuns:g.passedRuns,passRate:"string"==typeof g.passRate?parseFloat(g.passRate):g.passRate,meanDuration:g.meanDuration,runs:h}})}}function j(a,e,f,g){let h=(0,c.join)(d(),a,e,f,g,"transcript.json");if(!(0,b.existsSync)(h))return null;try{return JSON.parse((0,b.readFileSync)(h,"utf-8"))}catch{return null}}function k(a){let d=e();if(!(0,b.existsSync)(d))return{items:[],total:0};let f=[];!function a(d,e=""){for(let g of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!g.isDirectory()||g.name.startsWith("."))continue;let h=e?`${e}/${g.name}`:g.name,i=(0,c.join)(d,g.name),j=(0,c.join)(i,"PROMPT.md");(0,b.existsSync)(j)?f.push(h):a(i,h)}}(d),f.sort();let g=f.length;return{items:(a?f.slice(0,a):f).map(a=>{let e=(0,c.join)(d,a),f=(0,c.join)(e,"PROMPT.md"),g="";return(0,b.existsSync)(f)&&(g=(0,b.readFileSync)(f,"utf-8")),{name:a,prompt:g,files:(0,b.readdirSync)(e,{withFileTypes:!0}).filter(a=>a.isFile()).map(a=>a.name)}}),total:g}}function l(a){let d=(0,c.join)(e(),a);if(!(0,b.existsSync)(d))return null;let f=(0,c.join)(d,"PROMPT.md"),g="";(0,b.existsSync)(f)&&(g=(0,b.readFileSync)(f,"utf-8"));let h=[];!function a(d,e){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if("node_modules"===f.name||".git"===f.name)continue;let b=e?`${e}/${f.name}`:f.name;f.isDirectory()?a((0,c.join)(d,f.name),b):h.push(b)}}(d,"");let i={};for(let a of["PROMPT.md","EVAL.ts","EVAL.tsx","package.json"]){let e=(0,c.join)(d,a);if((0,b.existsSync)(e))try{i[a]=(0,b.readFileSync)(e,"utf-8")}catch{}}return{name:a,prompt:g,files:h,fileContents:i}}a.s(["getEvalDetail",()=>l,"getExperiment",()=>h,"getExperimentDetail",()=>i,"getTranscript",()=>j,"listEvals",()=>k,"listExperiments",()=>g])},22116,a=>{"use strict";a.s(["TranscriptViewer",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call TranscriptViewer() from the server but TranscriptViewer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/TranscriptViewer.tsx <module evaluation>","TranscriptViewer")},20516,a=>{"use strict";a.s(["TranscriptViewer",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call TranscriptViewer() from the server but TranscriptViewer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/TranscriptViewer.tsx","TranscriptViewer")},51835,a=>{"use strict";a.i(22116);var b=a.i(20516);a.n(b)},25535,a=>{"use strict";var b=a.i(7997);a.i(70396);var c=a.i(73727),d=a.i(95936),e=a.i(51835);function f({experiment:a,timestamp:c,evalName:f,run:g,transcript:h}){return(0,b.jsxs)("div",{className:"space-y-4",children:[(0,b.jsxs)("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[(0,b.jsx)(d.default,{href:"/experiments",className:"cursor-pointer hover:underline underline-offset-4",children:"Experiments"}),(0,b.jsx)("span",{children:"/"}),(0,b.jsx)(d.default,{href:`/experiments/${encodeURIComponent(a)}/${encodeURIComponent(c)}`,className:"cursor-pointer hover:underline underline-offset-4",children:a}),(0,b.jsx)("span",{children:"/"}),(0,b.jsx)("span",{children:f}),(0,b.jsx)("span",{children:"/"}),(0,b.jsx)("span",{children:g})]}),(0,b.jsx)("h1",{className:"text-2xl font-bold tracking-tight",children:"Transcript"}),(0,b.jsx)(e.TranscriptViewer,{transcript:h})]})}var g=a.i(5419);async function h({params:a}){let{experiment:d,timestamp:e,evalName:h,run:i}=await a,j=decodeURIComponent(d),k=decodeURIComponent(e),l=decodeURIComponent(h),m=decodeURIComponent(i),n=(0,g.getTranscript)(j,k,l,m);return n||(0,c.notFound)(),(0,b.jsx)(f,{experiment:j,timestamp:k,evalName:l,run:m,transcript:n})}a.s(["default",()=>h,"dynamic",0,"force-dynamic"],25535)}];
|
|
2
2
|
|
|
3
3
|
//# sourceMappingURL=%5Broot-of-the-server%5D__c73d60f7._.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/playground/lib/data.ts","../../../../../../packages/playground/components/TranscriptViewer.tsx/__nextjs-internal-proxy.mjs","../../../../../../packages/playground/app/transcript/%5Bexperiment%5D/%5Btimestamp%5D/%5BevalName%5D/%5Brun%5D/page.tsx","../../../../../../packages/playground/components/TranscriptPage.tsx"],"sourcesContent":["/**\n * Server-side data access for the playground.\n * Reads JSON files from the results/ and evals/ directories.\n * Directory paths are provided via RESULTS_DIR and EVALS_DIR env vars.\n */\n\nimport { readdirSync, readFileSync, existsSync } from \"fs\";\nimport { join, resolve } from \"path\";\n\nfunction getResultsDir(): string {\n return resolve(process.env.RESULTS_DIR || \"./results\");\n}\n\nfunction getEvalsDir(): string {\n return resolve(process.env.EVALS_DIR || \"./evals\");\n}\n\n/** Check if a directory name looks like an ISO timestamp (used as run ID) */\nfunction isTimestamp(name: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}T/.test(name);\n}\n\n/** List experiments from the results directory. Pass limit to cap expensive per-item reads. */\nexport function listExperiments(limit?: number) {\n const resultsDir = getResultsDir();\n\n if (!existsSync(resultsDir)) {\n return { items: [], total: 0 };\n }\n\n // Discover experiments by walking the directory tree until we find\n // timestamp directories. The path from resultsDir to the parent of the\n // first timestamp is the experiment name (e.g. \"my-config/openai/gpt-5.2-codex\").\n const entries: string[] = [];\n\n function walk(dir: string, prefix: string) {\n const children = readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n\n // If any child looks like a timestamp, this directory is an experiment\n if (children.some(isTimestamp)) {\n entries.push(prefix);\n return;\n }\n\n // Otherwise keep recursing\n for (const child of children) {\n walk(join(dir, child), prefix ? `${prefix}/${child}` : child);\n }\n }\n\n walk(resultsDir, \"\");\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const expDir = join(resultsDir, name);\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && isTimestamp(e.name))\n .map((e) => e.name)\n .sort()\n .reverse();\n\n let latestPassRate: number | undefined;\n let latestTotalRuns = 0;\n let latestPassedRuns = 0;\n\n if (timestamps.length > 0) {\n const latestDir = join(expDir, timestamps[0]);\n const evalDirs = readdirSync(latestDir, { withFileTypes: true }).filter(\n (e) => e.isDirectory()\n );\n\n for (const evalDir of evalDirs) {\n const summaryPath = join(latestDir, evalDir.name, \"summary.json\");\n if (existsSync(summaryPath)) {\n try {\n const summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n latestTotalRuns += summary.totalRuns ?? 0;\n latestPassedRuns += summary.passedRuns ?? 0;\n } catch {\n // Skip invalid summary files\n }\n }\n }\n\n if (latestTotalRuns > 0) {\n latestPassRate = (latestPassedRuns / latestTotalRuns) * 100;\n }\n }\n\n return {\n name,\n timestamps,\n latestTimestamp: timestamps[0] ?? null,\n latestPassRate,\n latestTotalRuns,\n latestPassedRuns,\n };\n });\n\n return { items, total };\n}\n\n/** Get timestamps for a specific experiment */\nexport function getExperiment(name: string) {\n const expDir = join(getResultsDir(), name);\n\n if (!existsSync(expDir)) {\n return null;\n }\n\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort()\n .reverse();\n\n return { name, timestamps, latestTimestamp: timestamps[0] ?? null };\n}\n\n/** Get full experiment detail for a specific timestamp */\nexport function getExperimentDetail(name: string, timestamp: string) {\n const runDir = join(getResultsDir(), name, timestamp);\n\n if (!existsSync(runDir)) {\n return null;\n }\n\n // Recursively discover all eval result directories (directories with summary.json)\n const evalDirs: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name.startsWith(\"run-\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const summaryPath = join(entryPath, \"summary.json\");\n\n // Check if this is an eval result directory (has summary.json)\n if (existsSync(summaryPath)) {\n evalDirs.push(relativePath);\n } else {\n // Not an eval result, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(runDir);\n evalDirs.sort();\n\n const evals = evalDirs.map((evalName) => {\n const evalDir = join(runDir, evalName);\n const summaryPath = join(evalDir, \"summary.json\");\n\n let summary = {\n totalRuns: 0,\n passedRuns: 0,\n passRate: \"0%\",\n meanDuration: 0,\n };\n if (existsSync(summaryPath)) {\n try {\n summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n } catch {\n // Use defaults\n }\n }\n\n // List run directories\n const runDirs = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && e.name.startsWith(\"run-\"))\n .map((e) => e.name)\n .sort();\n\n // Read each run's result.json\n const runs = runDirs.map((runDirName) => {\n const resultPath = join(evalDir, runDirName, \"result.json\");\n let result = null;\n if (existsSync(resultPath)) {\n try {\n result = JSON.parse(readFileSync(resultPath, \"utf-8\"));\n } catch {\n // Skip\n }\n }\n return { name: runDirName, result };\n });\n\n return {\n name: evalName,\n totalRuns: summary.totalRuns,\n passedRuns: summary.passedRuns,\n passRate:\n typeof summary.passRate === \"string\"\n ? parseFloat(summary.passRate)\n : summary.passRate,\n meanDuration: summary.meanDuration,\n runs,\n };\n });\n\n return { name, timestamp, evals };\n}\n\n/** Get result for a specific run */\nexport function getRunResult(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const resultPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"result.json\"\n );\n\n if (!existsSync(resultPath)) {\n return null;\n }\n\n try {\n return { result: JSON.parse(readFileSync(resultPath, \"utf-8\")) };\n } catch {\n return null;\n }\n}\n\n/** Get parsed transcript for a specific run */\nexport function getTranscript(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const transcriptPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"transcript.json\"\n );\n\n if (!existsSync(transcriptPath)) {\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(transcriptPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\n/** List evals from the evals directory. Pass limit to cap per-item reads. */\nexport function listEvals(limit?: number) {\n const evalsDir = getEvalsDir();\n\n if (!existsSync(evalsDir)) {\n return { items: [], total: 0 };\n }\n\n // Recursively discover all evals (directories with PROMPT.md)\n const entries: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const promptPath = join(entryPath, \"PROMPT.md\");\n\n // Check if this is an eval directory (has PROMPT.md)\n if (existsSync(promptPath)) {\n entries.push(relativePath);\n } else {\n // Not an eval, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(evalsDir);\n entries.sort();\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const evalDir = join(evalsDir, name);\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n const files = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isFile())\n .map((e) => e.name);\n\n return { name, prompt, files };\n });\n\n return { items, total };\n}\n\n/** Get detail for a specific eval */\nexport function getEvalDetail(name: string) {\n const evalDir = join(getEvalsDir(), name);\n\n if (!existsSync(evalDir)) {\n return null;\n }\n\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n // Recursively list files\n const files: string[] = [];\n function walk(dir: string, prefix: string) {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(join(dir, entry.name), relativePath);\n } else {\n files.push(relativePath);\n }\n }\n }\n walk(evalDir, \"\");\n\n // Read file contents for key files\n const fileContents: Record<string, string> = {};\n const keyFiles = [\"PROMPT.md\", \"EVAL.ts\", \"EVAL.tsx\", \"package.json\"];\n for (const file of keyFiles) {\n const filePath = join(evalDir, file);\n if (existsSync(filePath)) {\n try {\n fileContents[file] = readFileSync(filePath, \"utf-8\");\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n return { name, prompt, files, fileContents };\n}\n","// This file is generated by next-core EcmascriptClientReferenceModule.\nimport { registerClientReference } from \"react-server-dom-turbopack/server\";\nexport const TranscriptViewer = registerClientReference(\n function() { throw new Error(\"Attempted to call TranscriptViewer() from the server but TranscriptViewer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.\"); },\n \"[project]/packages/playground/components/TranscriptViewer.tsx\",\n \"TranscriptViewer\",\n);\n","import { notFound } from \"next/navigation\";\nimport { TranscriptPage } from \"@/components/TranscriptPage\";\nimport { getTranscript } from \"@/lib/data\";\n\nexport const dynamic = \"force-dynamic\";\n\nexport default async function TranscriptRoute({\n params,\n}: {\n params: Promise<{\n experiment: string;\n timestamp: string;\n evalName: string;\n run: string;\n }>;\n}) {\n const { experiment, timestamp, evalName, run } = await params;\n const decodedExperiment = decodeURIComponent(experiment);\n const decodedTimestamp = decodeURIComponent(timestamp);\n const decodedEvalName = decodeURIComponent(evalName);\n const decodedRun = decodeURIComponent(run);\n\n const transcript = getTranscript(\n decodedExperiment,\n decodedTimestamp,\n decodedEvalName,\n decodedRun\n );\n\n if (!transcript) {\n notFound();\n }\n\n return (\n <TranscriptPage\n experiment={decodedExperiment}\n timestamp={decodedTimestamp}\n evalName={decodedEvalName}\n run={decodedRun}\n transcript={transcript}\n />\n );\n}\n","import Link from \"next/link\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { TranscriptViewer } from \"@/components/TranscriptViewer\";\nimport type { Transcript } from \"@/lib/types\";\n\ninterface TranscriptPageProps {\n experiment: string;\n timestamp: string;\n evalName: string;\n run: string;\n transcript: Transcript;\n}\n\nexport function TranscriptPage({\n experiment,\n timestamp,\n evalName,\n run,\n transcript,\n}: TranscriptPageProps) {\n return (\n <div className=\"space-y-4\">\n {/* Breadcrumb */}\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Link href=\"/experiments\" className=\"cursor-pointer hover:underline underline-offset-4\">\n Experiments\n </Link>\n <span>/</span>\n <Link\n href={`/experiments/${encodeURIComponent(experiment)}/${encodeURIComponent(timestamp)}`}\n className=\"cursor-pointer hover:underline underline-offset-4\"\n >\n {experiment}\n </Link>\n <span>/</span>\n <span>{evalName}</span>\n <span>/</span>\n <span>{run}</span>\n </div>\n\n <h1 className=\"text-2xl font-bold tracking-tight\">Transcript</h1>\n\n <TranscriptViewer transcript={transcript} />\n </div>\n );\n}\n"],"names":[],"mappings":"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","ignoreList":[1]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/playground/lib/data.ts","../../../../../../packages/playground/components/TranscriptViewer.tsx/__nextjs-internal-proxy.mjs","../../../../../../packages/playground/app/transcript/%5Bexperiment%5D/%5Btimestamp%5D/%5BevalName%5D/%5Brun%5D/page.tsx","../../../../../../packages/playground/components/TranscriptPage.tsx"],"sourcesContent":["/**\n * Server-side data access for the playground.\n * Reads JSON files from the results/ and evals/ directories.\n * Directory paths are provided via RESULTS_DIR and EVALS_DIR env vars.\n */\n\nimport { readdirSync, readFileSync, existsSync } from \"fs\";\nimport { join, resolve } from \"path\";\n\nfunction getResultsDir(): string {\n return resolve(process.env.RESULTS_DIR || \"./results\");\n}\n\nfunction getEvalsDir(): string {\n return resolve(process.env.EVALS_DIR || \"./evals\");\n}\n\n/** Check if a directory name looks like an ISO timestamp (used as run ID) */\nfunction isTimestamp(name: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}T/.test(name);\n}\n\n/** List experiments from the results directory. Pass limit to cap expensive per-item reads. */\nexport function listExperiments(limit?: number) {\n const resultsDir = getResultsDir();\n\n if (!existsSync(resultsDir)) {\n return { items: [], total: 0 };\n }\n\n // Discover experiments by walking the directory tree until we find\n // timestamp directories. The path from resultsDir to the parent of the\n // first timestamp is the experiment name (e.g. \"my-config/openai/gpt-5.2-codex\").\n const entries: string[] = [];\n\n function walk(dir: string, prefix: string) {\n const children = readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n\n // If any child looks like a timestamp, this directory is an experiment\n if (children.some(isTimestamp)) {\n entries.push(prefix);\n return;\n }\n\n // Otherwise keep recursing\n for (const child of children) {\n walk(join(dir, child), prefix ? `${prefix}/${child}` : child);\n }\n }\n\n walk(resultsDir, \"\");\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const expDir = join(resultsDir, name);\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && isTimestamp(e.name))\n .map((e) => e.name)\n .sort()\n .reverse();\n\n let latestPassRate: number | undefined;\n let latestTotalRuns = 0;\n let latestPassedRuns = 0;\n\n if (timestamps.length > 0) {\n const latestDir = join(expDir, timestamps[0]);\n const evalDirs = readdirSync(latestDir, { withFileTypes: true }).filter(\n (e) => e.isDirectory()\n );\n\n for (const evalDir of evalDirs) {\n const summaryPath = join(latestDir, evalDir.name, \"summary.json\");\n if (existsSync(summaryPath)) {\n try {\n const summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n latestTotalRuns += summary.totalRuns ?? 0;\n latestPassedRuns += summary.passedRuns ?? 0;\n } catch {\n // Skip invalid summary files\n }\n }\n }\n\n if (latestTotalRuns > 0) {\n latestPassRate = (latestPassedRuns / latestTotalRuns) * 100;\n }\n }\n\n return {\n name,\n timestamps,\n latestTimestamp: timestamps[0] ?? null,\n latestPassRate,\n latestTotalRuns,\n latestPassedRuns,\n };\n });\n\n return { items, total };\n}\n\n/** Get timestamps for a specific experiment */\nexport function getExperiment(name: string) {\n const expDir = join(getResultsDir(), name);\n\n if (!existsSync(expDir)) {\n return null;\n }\n\n const timestamps = readdirSync(expDir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort()\n .reverse();\n\n return { name, timestamps, latestTimestamp: timestamps[0] ?? null };\n}\n\n/** Get full experiment detail for a specific timestamp */\nexport function getExperimentDetail(name: string, timestamp: string) {\n const runDir = join(getResultsDir(), name, timestamp);\n\n if (!existsSync(runDir)) {\n return null;\n }\n\n // Recursively discover all eval result directories (directories with summary.json)\n const evalDirs: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name.startsWith(\"run-\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const summaryPath = join(entryPath, \"summary.json\");\n\n // Check if this is an eval result directory (has summary.json)\n if (existsSync(summaryPath)) {\n evalDirs.push(relativePath);\n } else {\n // Not an eval result, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(runDir);\n evalDirs.sort();\n\n const evals = evalDirs.map((evalName) => {\n const evalDir = join(runDir, evalName);\n const summaryPath = join(evalDir, \"summary.json\");\n\n let summary = {\n totalRuns: 0,\n passedRuns: 0,\n passRate: \"0%\",\n meanDuration: 0,\n };\n if (existsSync(summaryPath)) {\n try {\n summary = JSON.parse(readFileSync(summaryPath, \"utf-8\"));\n } catch {\n // Use defaults\n }\n }\n\n // List run directories\n const runDirs = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && e.name.startsWith(\"run-\"))\n .map((e) => e.name)\n .sort();\n\n // Read each run's result.json\n const runs = runDirs.map((runDirName) => {\n const resultPath = join(evalDir, runDirName, \"result.json\");\n let result = null;\n if (existsSync(resultPath)) {\n try {\n result = JSON.parse(readFileSync(resultPath, \"utf-8\"));\n } catch {\n // Skip\n }\n }\n return { name: runDirName, result };\n });\n\n return {\n name: evalName,\n totalRuns: summary.totalRuns,\n passedRuns: summary.passedRuns,\n passRate:\n typeof summary.passRate === \"string\"\n ? parseFloat(summary.passRate)\n : summary.passRate,\n meanDuration: summary.meanDuration,\n runs,\n };\n });\n\n return { name, timestamp, evals };\n}\n\n/** Get result for a specific run */\nexport function getRunResult(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const resultPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"result.json\"\n );\n\n if (!existsSync(resultPath)) {\n return null;\n }\n\n try {\n return { result: JSON.parse(readFileSync(resultPath, \"utf-8\")) };\n } catch {\n return null;\n }\n}\n\n/** Get parsed transcript for a specific run */\nexport function getTranscript(\n experiment: string,\n timestamp: string,\n evalName: string,\n run: string\n) {\n const transcriptPath = join(\n getResultsDir(),\n experiment,\n timestamp,\n evalName,\n run,\n \"transcript.json\"\n );\n\n if (!existsSync(transcriptPath)) {\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(transcriptPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\n/** List evals from the evals directory. Pass limit to cap per-item reads. */\nexport function listEvals(limit?: number) {\n const evalsDir = getEvalsDir();\n\n if (!existsSync(evalsDir)) {\n return { items: [], total: 0 };\n }\n\n // Recursively discover all evals (directories with PROMPT.md)\n const entries: string[] = [];\n function walk(dir: string, basePath: string = \"\") {\n const dirEntries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\")) {\n continue;\n }\n\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n const entryPath = join(dir, entry.name);\n const promptPath = join(entryPath, \"PROMPT.md\");\n\n // Check if this is an eval directory (has PROMPT.md)\n if (existsSync(promptPath)) {\n entries.push(relativePath);\n } else {\n // Not an eval, recurse into it\n walk(entryPath, relativePath);\n }\n }\n }\n\n walk(evalsDir);\n entries.sort();\n\n const total = entries.length;\n const toProcess = limit ? entries.slice(0, limit) : entries;\n\n const items = toProcess.map((name) => {\n const evalDir = join(evalsDir, name);\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n const files = readdirSync(evalDir, { withFileTypes: true })\n .filter((e) => e.isFile())\n .map((e) => e.name);\n\n return { name, prompt, files };\n });\n\n return { items, total };\n}\n\n/** Get detail for a specific eval */\nexport function getEvalDetail(name: string) {\n const evalDir = join(getEvalsDir(), name);\n\n if (!existsSync(evalDir)) {\n return null;\n }\n\n const promptPath = join(evalDir, \"PROMPT.md\");\n let prompt = \"\";\n if (existsSync(promptPath)) {\n prompt = readFileSync(promptPath, \"utf-8\");\n }\n\n // Recursively list files\n const files: string[] = [];\n function walk(dir: string, prefix: string) {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(join(dir, entry.name), relativePath);\n } else {\n files.push(relativePath);\n }\n }\n }\n walk(evalDir, \"\");\n\n // Read file contents for key files\n const fileContents: Record<string, string> = {};\n const keyFiles = [\"PROMPT.md\", \"EVAL.ts\", \"EVAL.tsx\", \"package.json\"];\n for (const file of keyFiles) {\n const filePath = join(evalDir, file);\n if (existsSync(filePath)) {\n try {\n fileContents[file] = readFileSync(filePath, \"utf-8\");\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n return { name, prompt, files, fileContents };\n}\n","// This file is generated by next-core EcmascriptClientReferenceModule.\nimport { registerClientReference } from \"react-server-dom-turbopack/server\";\nexport const TranscriptViewer = registerClientReference(\n function() { throw new Error(\"Attempted to call TranscriptViewer() from the server but TranscriptViewer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.\"); },\n \"[project]/packages/playground/components/TranscriptViewer.tsx\",\n \"TranscriptViewer\",\n);\n","import { notFound } from \"next/navigation\";\nimport { TranscriptPage } from \"@/components/TranscriptPage\";\nimport { getTranscript } from \"@/lib/data\";\n\nexport const dynamic = \"force-dynamic\";\n\nexport default async function TranscriptRoute({\n params,\n}: {\n params: Promise<{\n experiment: string;\n timestamp: string;\n evalName: string;\n run: string;\n }>;\n}) {\n const { experiment, timestamp, evalName, run } = await params;\n const decodedExperiment = decodeURIComponent(experiment);\n const decodedTimestamp = decodeURIComponent(timestamp);\n const decodedEvalName = decodeURIComponent(evalName);\n const decodedRun = decodeURIComponent(run);\n\n const transcript = getTranscript(\n decodedExperiment,\n decodedTimestamp,\n decodedEvalName,\n decodedRun\n );\n\n if (!transcript) {\n notFound();\n }\n\n return (\n <TranscriptPage\n experiment={decodedExperiment}\n timestamp={decodedTimestamp}\n evalName={decodedEvalName}\n run={decodedRun}\n transcript={transcript}\n />\n );\n}\n","import Link from \"next/link\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { TranscriptViewer } from \"@/components/TranscriptViewer\";\nimport type { Transcript } from \"@/lib/types\";\n\ninterface TranscriptPageProps {\n experiment: string;\n timestamp: string;\n evalName: string;\n run: string;\n transcript: Transcript;\n}\n\nexport function TranscriptPage({\n experiment,\n timestamp,\n evalName,\n run,\n transcript,\n}: TranscriptPageProps) {\n return (\n <div className=\"space-y-4\">\n {/* Breadcrumb */}\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Link href=\"/experiments\" className=\"cursor-pointer hover:underline underline-offset-4\">\n Experiments\n </Link>\n <span>/</span>\n <Link\n href={`/experiments/${encodeURIComponent(experiment)}/${encodeURIComponent(timestamp)}`}\n className=\"cursor-pointer hover:underline underline-offset-4\"\n >\n {experiment}\n </Link>\n <span>/</span>\n <span>{evalName}</span>\n <span>/</span>\n <span>{run}</span>\n </div>\n\n <h1 className=\"text-2xl font-bold tracking-tight\">Transcript</h1>\n\n <TranscriptViewer transcript={transcript} />\n </div>\n );\n}\n"],"names":[],"mappings":"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","ignoreList":[1]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
module.exports=[69046,a=>{a.n(a.i(80979))},43619,a=>{a.n(a.i(79962))},13718,a=>{a.n(a.i(85523))},18198,a=>{a.n(a.i(45518))},62212,a=>{a.n(a.i(66114))},22734,(a,b,c)=>{b.exports=a.x("fs",()=>require("fs"))},5419,a=>{"use strict";var b=a.i(22734),c=a.i(14747);function d(){return(0,c.resolve)(process.env.RESULTS_DIR||"./results")}function e(){return(0,c.resolve)(process.env.EVALS_DIR||"./evals")}function f(a){return/^\d{4}-\d{2}-\d{2}T/.test(a)}function g(a){let e=d();if(!(0,b.existsSync)(e))return{items:[],total:0};let g=[];!function a(d,e){let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name);if(h.some(f))return void g.push(e);for(let b of h)a((0,c.join)(d,b),e?`${e}/${b}`:b)}(e,"");let h=g.length;return{items:(a?g.slice(0,a):g).map(a=>{let d,g=(0,c.join)(e,a),h=(0,b.readdirSync)(g,{withFileTypes:!0}).filter(a=>a.isDirectory()&&f(a.name)).map(a=>a.name).sort().reverse(),i=0,j=0;if(h.length>0){let a=(0,c.join)(g,h[0]);for(let d of(0,b.readdirSync)(a,{withFileTypes:!0}).filter(a=>a.isDirectory())){let e=(0,c.join)(a,d.name,"summary.json");if((0,b.existsSync)(e))try{let a=JSON.parse((0,b.readFileSync)(e,"utf-8"));i+=a.totalRuns??0,j+=a.passedRuns??0}catch{}}i>0&&(d=j/i*100)}return{name:a,timestamps:h,latestTimestamp:h[0]??null,latestPassRate:d,latestTotalRuns:i,latestPassedRuns:j}}),total:h}}function h(a,e){let f=(0,c.join)(d(),a,e);if(!(0,b.existsSync)(f))return null;let g=[];return!function a(d,e=""){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!f.isDirectory()||f.name.startsWith(".")||f.name.startsWith("run-"))continue;let h=e?`${e}/${f.name}`:f.name,i=(0,c.join)(d,f.name),j=(0,c.join)(i,"summary.json");(0,b.existsSync)(j)?g.push(h):a(i,h)}}(f),g.sort(),{name:a,timestamp:e,evals:g.map(a=>{let d=(0,c.join)(f,a),e=(0,c.join)(d,"summary.json"),g={totalRuns:0,passedRuns:0,passRate:"0%",meanDuration:0};if((0,b.existsSync)(e))try{g=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()&&a.name.startsWith("run-")).map(a=>a.name).sort().map(a=>{let e=(0,c.join)(d,a,"result.json"),f=null;if((0,b.existsSync)(e))try{f=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}return{name:a,result:f}});return{name:a,totalRuns:g.totalRuns,passedRuns:g.passedRuns,passRate:"string"==typeof g.passRate?parseFloat(g.passRate):g.passRate,meanDuration:g.meanDuration,runs:h}})}}function
|
|
1
|
+
module.exports=[69046,a=>{a.n(a.i(80979))},43619,a=>{a.n(a.i(79962))},13718,a=>{a.n(a.i(85523))},18198,a=>{a.n(a.i(45518))},62212,a=>{a.n(a.i(66114))},22734,(a,b,c)=>{b.exports=a.x("fs",()=>require("fs"))},5419,a=>{"use strict";var b=a.i(22734),c=a.i(14747);function d(){return(0,c.resolve)(process.env.RESULTS_DIR||"./results")}function e(){return(0,c.resolve)(process.env.EVALS_DIR||"./evals")}function f(a){return/^\d{4}-\d{2}-\d{2}T/.test(a)}function g(a){let e=d();if(!(0,b.existsSync)(e))return{items:[],total:0};let g=[];!function a(d,e){let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name);if(h.some(f))return void g.push(e);for(let b of h)a((0,c.join)(d,b),e?`${e}/${b}`:b)}(e,"");let h=g.length;return{items:(a?g.slice(0,a):g).map(a=>{let d,g=(0,c.join)(e,a),h=(0,b.readdirSync)(g,{withFileTypes:!0}).filter(a=>a.isDirectory()&&f(a.name)).map(a=>a.name).sort().reverse(),i=0,j=0;if(h.length>0){let a=(0,c.join)(g,h[0]);for(let d of(0,b.readdirSync)(a,{withFileTypes:!0}).filter(a=>a.isDirectory())){let e=(0,c.join)(a,d.name,"summary.json");if((0,b.existsSync)(e))try{let a=JSON.parse((0,b.readFileSync)(e,"utf-8"));i+=a.totalRuns??0,j+=a.passedRuns??0}catch{}}i>0&&(d=j/i*100)}return{name:a,timestamps:h,latestTimestamp:h[0]??null,latestPassRate:d,latestTotalRuns:i,latestPassedRuns:j}}),total:h}}function h(a){let e=(0,c.join)(d(),a);if(!(0,b.existsSync)(e))return null;let f=(0,b.readdirSync)(e,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>a.name).sort().reverse();return{name:a,timestamps:f,latestTimestamp:f[0]??null}}function i(a,e){let f=(0,c.join)(d(),a,e);if(!(0,b.existsSync)(f))return null;let g=[];return!function a(d,e=""){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!f.isDirectory()||f.name.startsWith(".")||f.name.startsWith("run-"))continue;let h=e?`${e}/${f.name}`:f.name,i=(0,c.join)(d,f.name),j=(0,c.join)(i,"summary.json");(0,b.existsSync)(j)?g.push(h):a(i,h)}}(f),g.sort(),{name:a,timestamp:e,evals:g.map(a=>{let d=(0,c.join)(f,a),e=(0,c.join)(d,"summary.json"),g={totalRuns:0,passedRuns:0,passRate:"0%",meanDuration:0};if((0,b.existsSync)(e))try{g=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}let h=(0,b.readdirSync)(d,{withFileTypes:!0}).filter(a=>a.isDirectory()&&a.name.startsWith("run-")).map(a=>a.name).sort().map(a=>{let e=(0,c.join)(d,a,"result.json"),f=null;if((0,b.existsSync)(e))try{f=JSON.parse((0,b.readFileSync)(e,"utf-8"))}catch{}return{name:a,result:f}});return{name:a,totalRuns:g.totalRuns,passedRuns:g.passedRuns,passRate:"string"==typeof g.passRate?parseFloat(g.passRate):g.passRate,meanDuration:g.meanDuration,runs:h}})}}function j(a,e,f,g){let h=(0,c.join)(d(),a,e,f,g,"transcript.json");if(!(0,b.existsSync)(h))return null;try{return JSON.parse((0,b.readFileSync)(h,"utf-8"))}catch{return null}}function k(a){let d=e();if(!(0,b.existsSync)(d))return{items:[],total:0};let f=[];!function a(d,e=""){for(let g of(0,b.readdirSync)(d,{withFileTypes:!0})){if(!g.isDirectory()||g.name.startsWith("."))continue;let h=e?`${e}/${g.name}`:g.name,i=(0,c.join)(d,g.name),j=(0,c.join)(i,"PROMPT.md");(0,b.existsSync)(j)?f.push(h):a(i,h)}}(d),f.sort();let g=f.length;return{items:(a?f.slice(0,a):f).map(a=>{let e=(0,c.join)(d,a),f=(0,c.join)(e,"PROMPT.md"),g="";return(0,b.existsSync)(f)&&(g=(0,b.readFileSync)(f,"utf-8")),{name:a,prompt:g,files:(0,b.readdirSync)(e,{withFileTypes:!0}).filter(a=>a.isFile()).map(a=>a.name)}}),total:g}}function l(a){let d=(0,c.join)(e(),a);if(!(0,b.existsSync)(d))return null;let f=(0,c.join)(d,"PROMPT.md"),g="";(0,b.existsSync)(f)&&(g=(0,b.readFileSync)(f,"utf-8"));let h=[];!function a(d,e){for(let f of(0,b.readdirSync)(d,{withFileTypes:!0})){if("node_modules"===f.name||".git"===f.name)continue;let b=e?`${e}/${f.name}`:f.name;f.isDirectory()?a((0,c.join)(d,f.name),b):h.push(b)}}(d,"");let i={};for(let a of["PROMPT.md","EVAL.ts","EVAL.tsx","package.json"]){let e=(0,c.join)(d,a);if((0,b.existsSync)(e))try{i[a]=(0,b.readFileSync)(e,"utf-8")}catch{}}return{name:a,prompt:g,files:h,fileContents:i}}a.s(["getEvalDetail",()=>l,"getExperiment",()=>h,"getExperimentDetail",()=>i,"getTranscript",()=>j,"listEvals",()=>k,"listExperiments",()=>g])},22977,a=>{"use strict";var b=a.i(7997),c=a.i(95387);function d({className:a,size:d="default",...e}){return(0,b.jsx)("div",{"data-slot":"card","data-size":d,className:(0,c.cn)("ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col",a),...e})}function e({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-header",className:(0,c.cn)("gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",a),...d})}function f({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-title",className:(0,c.cn)("text-sm font-medium",a),...d})}function g({className:a,...d}){return(0,b.jsx)("div",{"data-slot":"card-content",className:(0,c.cn)("px-4 group-data-[size=sm]/card:px-3",a),...d})}a.s(["Card",()=>d,"CardContent",()=>g,"CardHeader",()=>e,"CardTitle",()=>f])},31636,a=>{"use strict";a.s(["ShowMore",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call ShowMore() from the server but ShowMore is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ShowMore.tsx <module evaluation>","ShowMore")},15821,a=>{"use strict";a.s(["ShowMore",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call ShowMore() from the server but ShowMore is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/packages/playground/components/ShowMore.tsx","ShowMore")},93835,a=>{"use strict";a.i(31636);var b=a.i(15821);a.n(b)},35068,a=>{"use strict";var b=a.i(7997),c=a.i(95936),d=a.i(22977),e=a.i(20954),f=a.i(93835);function g({evals:a,total:g,showAll:h}){return(0,b.jsxs)("div",{className:"space-y-6",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-2xl font-bold tracking-tight",children:"Evals"}),(0,b.jsx)("p",{className:"text-muted-foreground mt-1",children:"Browse all eval fixtures in your project."})]}),0===a.length?(0,b.jsx)(d.Card,{children:(0,b.jsxs)(d.CardContent,{className:"py-12 text-center",children:[(0,b.jsx)("p",{className:"text-muted-foreground text-lg",children:"No evals found"}),(0,b.jsxs)("p",{className:"text-muted-foreground text-sm mt-2",children:["Create evals in your"," ",(0,b.jsx)("code",{className:"text-foreground bg-muted px-1.5 py-0.5 rounded text-xs",children:"evals/"})," ","directory."]})]})}):(0,b.jsx)(f.ShowMore,{total:g,showAllHref:h?void 0:"/evals?all",className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:a.map(a=>(0,b.jsx)(c.default,{href:`/evals/${encodeURIComponent(a.name)}`,className:"block cursor-pointer",children:(0,b.jsxs)(d.Card,{className:"transition-colors hover:bg-muted",children:[(0,b.jsx)(d.CardHeader,{children:(0,b.jsx)(d.CardTitle,{className:"text-base",children:a.name})}),(0,b.jsxs)(d.CardContent,{children:[a.prompt&&(0,b.jsxs)("p",{className:"text-sm text-muted-foreground line-clamp-3 mb-3",children:[a.prompt.slice(0,200),a.prompt.length>200?"...":""]}),(0,b.jsxs)("div",{className:"flex flex-wrap gap-1",children:[a.files.slice(0,5).map(a=>(0,b.jsx)(e.Badge,{variant:"secondary",className:"text-xs font-mono",children:a},a)),a.files.length>5&&(0,b.jsxs)(e.Badge,{variant:"outline",className:"text-xs",children:["+",a.files.length-5," more"]})]})]})]})},a.name))})]})}var h=a.i(5419);async function i({searchParams:a}){let{all:c}=await a,d=void 0!==c,{items:e,total:f}=(0,h.listEvals)(d?void 0:21);return(0,b.jsx)(g,{evals:e,total:f,showAll:d})}a.s(["default",()=>i,"dynamic",0,"force-dynamic"],35068)}];
|
|
2
2
|
|
|
3
3
|
//# sourceMappingURL=%5Broot-of-the-server%5D__f286e9a8._.js.map
|