feat(observability2): apply design system to trace components

Phase 3 of visual redesign - refine trace-specific visualization:

- Create custom zincDarkTheme for syntax highlighting
- Update trace-summary with flat zinc metric cards
- Restyle code-context-section with zinc hierarchy
- Apply zinc styling to function-to-optimize-section
- Clean decorative elements from llm-calls-timeline
- Establish clear visual hierarchy in errors-section
- Update trace-search with zinc input styling
- Migrate page.tsx and layout.tsx to zinc colors

Requirements: TRC-01 through TRC-05
This commit is contained in:
Kevin Turcios 2026-01-30 18:09:24 -05:00
parent 021ed80988
commit 5441ffa800
9 changed files with 355 additions and 301 deletions

View file

@ -2,11 +2,11 @@ import { ReactNode } from "react"
export default function Observability2Layout({ children }: { children: ReactNode }) {
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
<nav className="border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800">
<div className="min-h-screen bg-zinc-50 dark:bg-zinc-950">
<nav className="border-b border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex h-14 items-center justify-center">
<h1 className="text-lg font-semibold text-gray-900 dark:text-white">
<h1 className="text-lg font-semibold text-zinc-900 dark:text-zinc-50">
Observability v2
</h1>
</div>

View file

@ -311,13 +311,13 @@ function TraceContent({ traceId, traceData }: { traceId: string; traceData: Trac
function EmptyState() {
return (
<div className="flex flex-col items-center justify-center py-16 text-center">
<div className="w-16 h-16 mb-6 rounded-full bg-gray-100 dark:bg-gray-800 flex items-center justify-center">
<Search className="h-8 w-8 text-gray-400" />
<div className="w-16 h-16 mb-6 rounded-full bg-zinc-100 dark:bg-zinc-800 flex items-center justify-center">
<Search className="h-8 w-8 text-zinc-400" />
</div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
<h3 className="text-xl font-semibold text-zinc-900 dark:text-zinc-50 mb-2">
Enter a Trace ID to Get Started
</h3>
<p className="text-gray-500 dark:text-gray-400 max-w-md">
<p className="text-zinc-500 dark:text-zinc-400 max-w-md">
Paste or type a trace ID in the search box above to view all associated LLM calls,
generated candidates, and any errors that occurred during processing.
</p>
@ -331,14 +331,14 @@ function NotFoundState({ traceId }: { traceId: string }) {
<div className="w-16 h-16 mb-6 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center">
<Search className="h-8 w-8 text-red-500" />
</div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">Trace Not Found</h3>
<p className="text-gray-500 dark:text-gray-400 max-w-md mb-4">
<h3 className="text-xl font-semibold text-zinc-900 dark:text-zinc-50 mb-2">Trace Not Found</h3>
<p className="text-zinc-500 dark:text-zinc-400 max-w-md mb-4">
No data was found for the trace ID:
</p>
<code className="text-sm font-mono text-gray-900 dark:text-white bg-gray-100 dark:bg-gray-700 px-3 py-2 rounded">
<code className="text-sm font-mono text-zinc-900 dark:text-zinc-50 bg-zinc-100 dark:bg-zinc-700 px-3 py-2 rounded">
{traceId}
</code>
<p className="text-gray-500 dark:text-gray-400 max-w-md mt-4 text-sm">
<p className="text-zinc-500 dark:text-zinc-400 max-w-md mt-4 text-sm">
Please check that the trace ID is correct and try again.
</p>
</div>
@ -353,8 +353,8 @@ function SearchSkeleton() {
return (
<div className="w-full max-w-2xl mx-auto">
<div className="flex items-center gap-3">
<div className="flex-1 h-12 bg-gray-200 dark:bg-gray-700 rounded-lg animate-pulse" />
<div className="w-24 h-12 bg-gray-200 dark:bg-gray-700 rounded-lg animate-pulse" />
<div className="flex-1 h-12 bg-zinc-200 dark:bg-zinc-700 rounded-md animate-pulse" />
<div className="w-24 h-12 bg-zinc-200 dark:bg-zinc-700 rounded-md animate-pulse" />
</div>
</div>
)
@ -364,38 +364,38 @@ function TraceContentSkeleton() {
return (
<div className="space-y-6">
{/* Summary skeleton */}
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 border border-gray-200 dark:border-gray-700">
<div className="bg-white dark:bg-zinc-800 rounded-md shadow p-6 border border-zinc-200 dark:border-zinc-700">
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
{createSkeletonArray(4).map((_, i) => (
<div key={i}>
<div className="h-4 w-16 bg-gray-200 dark:bg-gray-700 rounded mb-2 animate-pulse" />
<div className="h-8 w-24 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="h-4 w-16 bg-zinc-200 dark:bg-zinc-700 rounded mb-2 animate-pulse" />
<div className="h-8 w-24 bg-zinc-200 dark:bg-zinc-700 rounded animate-pulse" />
</div>
))}
</div>
</div>
{/* Timeline skeleton */}
<div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-200 dark:border-gray-700">
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
<div className="h-6 w-48 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="bg-white dark:bg-zinc-800 rounded-md shadow border border-zinc-200 dark:border-zinc-700">
<div className="p-6 border-b border-zinc-200 dark:border-zinc-700">
<div className="h-6 w-48 bg-zinc-200 dark:bg-zinc-700 rounded animate-pulse" />
</div>
<div className="divide-y divide-gray-200 dark:divide-gray-700">
<div className="divide-y divide-zinc-200 dark:divide-zinc-700">
{createSkeletonArray(3).map((_, i) => (
<div key={i} className="p-4">
<div className="h-6 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="h-6 bg-zinc-200 dark:bg-zinc-700 rounded animate-pulse" />
</div>
))}
</div>
</div>
{/* Errors skeleton */}
<div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-200 dark:border-gray-700">
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
<div className="h-6 w-32 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="bg-white dark:bg-zinc-800 rounded-md shadow border border-zinc-200 dark:border-zinc-700">
<div className="p-6 border-b border-zinc-200 dark:border-zinc-700">
<div className="h-6 w-32 bg-zinc-200 dark:bg-zinc-700 rounded animate-pulse" />
</div>
<div className="p-6">
<div className="h-16 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
<div className="h-16 bg-zinc-200 dark:bg-zinc-700 rounded animate-pulse" />
</div>
</div>
</div>

View file

@ -1,7 +1,7 @@
"use client"
import { useState, useMemo, useCallback, memo } from "react"
import { ChevronDown, ChevronRight, Code, FileText, Hash, FolderTree } from "lucide-react"
import { ChevronDown, Code, FileText, Hash, FolderTree } from "lucide-react"
import { CodeHighlighter, CODE_STYLE } from "./code-highlighter"
import { CopyButton } from "@/components/observability/copy-button"
import { InfoIcon } from "@/components/observability/info-icon"
@ -109,15 +109,15 @@ export const CodeContextSection = memo(function CodeContextSection({
}
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-200 dark:border-gray-700">
<div className="bg-white dark:bg-zinc-900 rounded-sm border border-zinc-200 dark:border-zinc-800">
{/* Header - always visible */}
<button
onClick={() => setIsExpanded(!isExpanded)}
className="w-full p-6 flex items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors rounded-lg"
className="w-full p-6 flex items-center justify-between hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors rounded-sm"
>
<div className="flex items-center gap-2">
<Code className="h-5 w-5 text-gray-400" />
<h2 className="text-xl font-bold text-gray-900 dark:text-white">Code Context</h2>
<Code className="h-4 w-4 text-zinc-400" />
<h2 className="text-xl font-bold text-zinc-900 dark:text-white">Code Context</h2>
<InfoIcon
content="The code provided to the LLM for optimization. Read-writable code can be modified, read-only dependencies are for reference only."
side="right"
@ -125,7 +125,7 @@ export const CodeContextSection = memo(function CodeContextSection({
</div>
<div className="flex items-center gap-4">
{/* Summary metrics */}
<div className="flex items-center gap-4 text-sm text-gray-500 dark:text-gray-400">
<div className="flex items-center gap-4 text-sm text-zinc-500 dark:text-zinc-400">
<span className="flex items-center gap-1">
<Hash className="h-4 w-4" />
{metrics.totalTokens.toLocaleString()} tokens
@ -135,32 +135,28 @@ export const CodeContextSection = memo(function CodeContextSection({
{metrics.totalFiles} files
</span>
</div>
{isExpanded ? (
<ChevronDown className="h-5 w-5 text-gray-400" />
) : (
<ChevronRight className="h-5 w-5 text-gray-400" />
)}
<ChevronDown className={`h-4 w-4 text-zinc-400 transition-transform duration-200 ${isExpanded ? '' : '-rotate-90'}`} />
</div>
</button>
{/* Expanded content */}
{isExpanded && (
<div className="px-6 pb-6 pt-0 border-t border-gray-200 dark:border-gray-700 space-y-4">
<div className="px-6 pb-6 pt-0 border-t border-zinc-200 dark:border-zinc-800 space-y-4">
{/* Function info */}
{(functionName || filePath) && (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 py-4">
{functionName && (
<div className="flex flex-col">
<span className="text-xs text-gray-500 dark:text-gray-400 mb-1">Function</span>
<code className="text-sm font-mono text-gray-900 dark:text-white bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded w-fit">
<span className="text-xs text-zinc-500 dark:text-zinc-400 mb-1">Function</span>
<code className="text-sm font-mono text-zinc-900 dark:text-white bg-zinc-100 dark:bg-zinc-800 px-2 py-1 rounded-sm w-fit">
{functionName}
</code>
</div>
)}
{filePath && (
<div className="flex flex-col">
<span className="text-xs text-gray-500 dark:text-gray-400 mb-1">File</span>
<code className="text-sm font-mono text-gray-900 dark:text-white bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded w-fit truncate max-w-full" title={filePath}>
<span className="text-xs text-zinc-500 dark:text-zinc-400 mb-1">File</span>
<code className="text-sm font-mono text-zinc-900 dark:text-white bg-zinc-100 dark:bg-zinc-800 px-2 py-1 rounded-sm w-fit truncate max-w-full" title={filePath}>
{filePath}
</code>
</div>
@ -170,10 +166,10 @@ export const CodeContextSection = memo(function CodeContextSection({
{/* Token breakdown - only show when both types exist */}
{rwFiles.length > 0 && roFiles.length > 0 && (
<div className="p-4 bg-gray-50 dark:bg-gray-900/50 rounded-lg">
<div className="p-4 bg-zinc-50 dark:bg-zinc-950 rounded-sm border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-2 mb-3">
<Hash className="h-4 w-4 text-gray-400" />
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
<Hash className="h-4 w-4 text-zinc-400" />
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
Token Distribution (estimated)
</span>
</div>
@ -185,13 +181,13 @@ export const CodeContextSection = memo(function CodeContextSection({
<div className="flex gap-4 text-xs">
<div className="flex items-center gap-1.5">
<div className="w-3 h-3 rounded-sm bg-emerald-500" />
<span className="text-gray-600 dark:text-gray-400">
<span className="text-zinc-600 dark:text-zinc-400">
Read-Writable: {metrics.rwTokens.toLocaleString()} ({rwFiles.length} files)
</span>
</div>
<div className="flex items-center gap-1.5">
<div className="w-3 h-3 rounded-sm bg-slate-500" />
<span className="text-gray-600 dark:text-gray-400">
<span className="text-zinc-600 dark:text-zinc-400">
Read-Only: {metrics.roTokens.toLocaleString()} ({roFiles.length} files)
</span>
</div>
@ -256,15 +252,15 @@ function getAccentColorClasses(accentColor: "emerald" | "slate"): { border: stri
switch (accentColor) {
case "emerald":
return {
border: "border-emerald-200 dark:border-emerald-800",
bg: "bg-emerald-50 dark:bg-emerald-900/20",
border: "border-zinc-200 dark:border-zinc-800",
bg: "bg-zinc-50 dark:bg-zinc-900",
icon: "text-emerald-500",
}
case "slate":
return {
border: "border-slate-200 dark:border-slate-700",
bg: "bg-slate-50 dark:bg-slate-900/20",
icon: "text-slate-500",
border: "border-zinc-200 dark:border-zinc-800",
bg: "bg-zinc-50 dark:bg-zinc-900",
icon: "text-zinc-500",
}
}
}
@ -285,42 +281,38 @@ const CodeGroupSection = memo(function CodeGroupSection({
const { border: borderColor, bg: bgColor, icon: iconColor } = getAccentColorClasses(accentColor)
return (
<div className={`rounded-lg border ${borderColor} overflow-hidden`}>
<div className={`rounded-sm border ${borderColor} overflow-hidden`}>
<div
role="button"
tabIndex={0}
onClick={onToggle}
onKeyDown={e => { if (e.key === "Enter" || e.key === " ") onToggle() }}
className={`w-full p-4 flex items-center justify-between hover:bg-opacity-80 transition-colors cursor-pointer ${bgColor}`}
className={`w-full p-4 flex items-center justify-between hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors cursor-pointer ${bgColor}`}
>
<div className="flex items-center gap-3">
<FileText className={`h-4 w-4 ${iconColor}`} />
<div className="text-left">
<span className="text-sm font-medium text-gray-900 dark:text-white">{title}</span>
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">{subtitle}</span>
<span className="text-sm font-medium text-zinc-900 dark:text-white">{title}</span>
<span className="text-xs text-zinc-500 dark:text-zinc-400 ml-2">{subtitle}</span>
</div>
</div>
<div className="flex items-center gap-3">
<span className="text-xs text-gray-500 dark:text-gray-400">
<span className="text-xs text-zinc-500 dark:text-zinc-400">
{tokenCount.toLocaleString()} tokens · {charCount.toLocaleString()} chars · {files.length} files
</span>
{isExpanded ? (
<ChevronDown className="h-4 w-4 text-gray-400" />
) : (
<ChevronRight className="h-4 w-4 text-gray-400" />
)}
<ChevronDown className={`h-4 w-4 text-zinc-400 transition-transform duration-200 ${isExpanded ? '' : '-rotate-90'}`} />
</div>
</div>
{isExpanded && (
<div className="border-t border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700">
<div className="border-t border-zinc-200 dark:border-zinc-800 divide-y divide-zinc-200 dark:divide-zinc-800">
{files.map((file, index) => {
const fileKey = `${sectionKey}-${index}`
const isFileExpanded = expandedFiles.has(fileKey)
return (
<div key={fileKey}>
{/* File header */}
<div className="px-4 py-2 flex items-center justify-between bg-gray-100 dark:bg-gray-800">
<div className="px-4 py-2 flex items-center justify-between bg-zinc-100 dark:bg-zinc-950">
<div
role="button"
tabIndex={0}
@ -328,21 +320,17 @@ const CodeGroupSection = memo(function CodeGroupSection({
onKeyDown={e => { if (e.key === "Enter" || e.key === " ") onToggleFile(fileKey) }}
className="flex items-center gap-2 cursor-pointer hover:opacity-80 flex-1"
>
<FileText className="h-3.5 w-3.5 text-gray-400" />
<span className="text-sm font-mono font-medium text-gray-900 dark:text-white">
<FileText className="h-3.5 w-3.5 text-zinc-400" />
<span className="text-sm font-mono font-medium text-zinc-900 dark:text-white">
{file.filename}
</span>
<span className="text-xs text-gray-500 dark:text-gray-400" title={file.path}>
<span className="text-xs text-zinc-500 dark:text-zinc-400" title={file.path}>
{file.path !== file.filename && `(${file.path})`}
</span>
{isFileExpanded ? (
<ChevronDown className="h-3.5 w-3.5 text-gray-400" />
) : (
<ChevronRight className="h-3.5 w-3.5 text-gray-400" />
)}
<ChevronDown className={`h-3.5 w-3.5 text-zinc-400 transition-transform duration-200 ${isFileExpanded ? '' : '-rotate-90'}`} />
</div>
<div className="flex items-center gap-2">
<span className="text-xs text-gray-500 dark:text-gray-400">
<span className="text-xs text-zinc-500 dark:text-zinc-400">
{file.code.split("\n").length} lines
</span>
<CopyButton text={file.code} label={file.filename} size="sm" />
@ -383,7 +371,7 @@ const TokenDistributionBar = memo(function TokenDistributionBar({
const roPercent = Math.round((roTokens / totalTokens) * 100)
return (
<div className="flex h-6 rounded-lg overflow-hidden border border-gray-200 dark:border-gray-600 mb-2">
<div className="flex h-6 rounded-sm overflow-hidden border border-zinc-200 dark:border-zinc-800 mb-2">
<div
className="bg-emerald-500 flex items-center justify-center text-white text-xs font-semibold"
style={{ width: `${rwPercent}%` }}

View file

@ -9,17 +9,105 @@ const SyntaxHighlighter = dynamic(
{
ssr: false,
loading: () => (
<div className="animate-pulse bg-gray-800 rounded p-4 min-h-[100px]">
<div className="h-4 bg-gray-700 rounded w-3/4 mb-2" />
<div className="h-4 bg-gray-700 rounded w-1/2 mb-2" />
<div className="h-4 bg-gray-700 rounded w-2/3" />
<div className="animate-pulse bg-zinc-800 rounded p-4 min-h-[100px]">
<div className="h-4 bg-zinc-700 rounded w-3/4 mb-2" />
<div className="h-4 bg-zinc-700 rounded w-1/2 mb-2" />
<div className="h-4 bg-zinc-700 rounded w-2/3" />
</div>
),
}
)
// Import style - this is just JSON data, relatively small
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism"
// Custom zinc-based theme for syntax highlighting
export const zincDarkTheme = {
// Base colors
'code[class*="language-"]': {
color: 'rgb(250, 250, 250)', // zinc-50
background: 'none',
fontFamily: 'var(--font-mono)',
fontSize: '1em',
textAlign: 'left',
whiteSpace: 'pre',
wordSpacing: 'normal',
wordBreak: 'normal',
wordWrap: 'normal',
lineHeight: '1.5',
tabSize: 4,
hyphens: 'none',
},
'pre[class*="language-"]': {
color: 'rgb(250, 250, 250)', // zinc-50
background: 'rgb(24, 24, 27)', // zinc-900
fontFamily: 'var(--font-mono)',
fontSize: '1em',
textAlign: 'left',
whiteSpace: 'pre',
wordSpacing: 'normal',
wordBreak: 'normal',
wordWrap: 'normal',
lineHeight: '1.5',
tabSize: 4,
hyphens: 'none',
padding: '1em',
margin: '0',
overflow: 'auto',
},
// Comments
comment: {
color: 'rgb(113, 113, 122)', // zinc-500
fontStyle: 'italic',
},
prolog: { color: 'rgb(113, 113, 122)' },
doctype: { color: 'rgb(113, 113, 122)' },
cdata: { color: 'rgb(113, 113, 122)' },
// Keywords
keyword: { color: 'rgb(96, 165, 250)' }, // blue-400
'control-flow': { color: 'rgb(96, 165, 250)' },
// Strings
string: { color: 'rgb(134, 239, 172)' }, // green-300
'attr-value': { color: 'rgb(134, 239, 172)' },
// Functions
function: { color: 'rgb(253, 224, 71)' }, // yellow-300
'class-name': { color: 'rgb(253, 224, 71)' },
// Numbers and boolean
number: { color: 'rgb(251, 146, 60)' }, // orange-400
boolean: { color: 'rgb(251, 146, 60)' },
// Operators and punctuation
operator: { color: 'rgb(161, 161, 170)' }, // zinc-400
punctuation: { color: 'rgb(161, 161, 170)' },
// Variables and properties
variable: { color: 'rgb(250, 250, 250)' }, // zinc-50
property: { color: 'rgb(250, 250, 250)' },
// Tags and attributes
tag: { color: 'rgb(96, 165, 250)' }, // blue-400
'attr-name': { color: 'rgb(250, 250, 250)' },
namespace: { opacity: 0.7 },
// Other tokens
selector: { color: 'rgb(253, 224, 71)' },
important: {
color: 'rgb(251, 146, 60)',
fontWeight: 'bold',
},
atrule: { color: 'rgb(96, 165, 250)' },
builtin: { color: 'rgb(253, 224, 71)' },
entity: {
color: 'rgb(250, 250, 250)',
cursor: 'help',
},
url: {
color: 'rgb(96, 165, 250)',
textDecoration: 'underline',
},
// Inserted and deleted for diffs
inserted: {
color: 'rgb(134, 239, 172)',
background: 'rgba(134, 239, 172, 0.1)',
},
deleted: {
color: 'rgb(248, 113, 113)',
background: 'rgba(248, 113, 113, 0.1)',
},
} as const
// Shared style constants to avoid recreating objects on each render
export const CODE_STYLE = {
@ -27,6 +115,7 @@ export const CODE_STYLE = {
padding: "1rem",
fontSize: "0.875rem",
lineHeight: 1.5,
background: 'rgb(24, 24, 27)', // zinc-900 - ensure background consistency
} as const
export const CODE_STYLE_RELAXED = {
@ -34,6 +123,7 @@ export const CODE_STYLE_RELAXED = {
padding: "1rem",
fontSize: "0.875rem",
lineHeight: 1.6,
background: 'rgb(24, 24, 27)', // zinc-900 - ensure background consistency
} as const
export const CODE_STYLE_SMALL = {
@ -41,6 +131,7 @@ export const CODE_STYLE_SMALL = {
padding: "1rem",
fontSize: "0.8125rem",
lineHeight: 1.5,
background: 'rgb(24, 24, 27)', // zinc-900 - ensure background consistency
} as const
interface CodeHighlighterProps {
@ -59,7 +150,7 @@ export const CodeHighlighter = memo(function CodeHighlighter({
return (
<SyntaxHighlighter
language={language}
style={oneDark}
style={zincDarkTheme}
customStyle={customStyle}
showLineNumbers={showLineNumbers}
>

View file

@ -6,7 +6,6 @@ import {
AlertCircle,
AlertTriangle,
ChevronDown,
ChevronRight,
} from "lucide-react"
import { CopyButton } from "@/components/observability/copy-button"
@ -51,18 +50,18 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
}
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-200 dark:border-gray-700">
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
<div className="bg-white dark:bg-zinc-900 rounded-sm border border-zinc-200 dark:border-zinc-700">
<div className="p-6 border-b border-zinc-200 dark:border-zinc-700">
<div className="flex items-center gap-3">
<AlertCircle className="h-5 w-5 text-red-600 dark:text-red-400" />
<h2 className="text-xl font-bold text-red-600 dark:text-red-400">Errors</h2>
<span className="bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 text-sm px-2.5 py-0.5 rounded font-semibold">
<span className="text-red-400 border border-red-600 text-sm px-2.5 py-0.5 rounded-sm font-semibold">
{errors.length}
</span>
</div>
</div>
<div className="divide-y divide-gray-200 dark:divide-gray-700">
<div className="divide-y divide-zinc-200 dark:divide-zinc-700">
{errors.map(error => {
const isExpanded = expandedErrors.has(error.id)
const isTestFailure = error.error_type === "test_failure"
@ -73,11 +72,11 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
let severityColor: string
if (error.severity === "critical") {
severityColor = "text-red-700 dark:text-red-300 bg-red-100 dark:bg-red-900"
severityColor = "text-red-400 border border-red-600 px-1.5 py-0.5"
} else if (error.severity === "error") {
severityColor = "text-orange-700 dark:text-orange-300 bg-orange-100 dark:bg-orange-900"
severityColor = "text-orange-400 border border-orange-600 px-1.5 py-0.5"
} else {
severityColor = "text-yellow-700 dark:text-yellow-300 bg-yellow-100 dark:bg-yellow-900"
severityColor = "text-yellow-400 border border-yellow-600 px-1.5 py-0.5"
}
return (
@ -88,31 +87,28 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
tabIndex={0}
onClick={() => toggleError(error.id)}
onKeyDown={e => { if (e.key === "Enter" || e.key === " ") toggleError(error.id) }}
className="flex items-start gap-3 cursor-pointer hover:opacity-80 flex-1"
className="flex items-start gap-3 cursor-pointer hover:opacity-80 flex-1 transition-opacity duration-150"
>
<SeverityIcon className="h-5 w-5 text-red-600 dark:text-red-400 mt-0.5 flex-shrink-0" />
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1 flex-wrap">
<span className="font-semibold text-gray-900 dark:text-white">
<span className="font-semibold text-zinc-900 dark:text-white">
{error.error_type}
</span>
<span className={`px-2 py-0.5 text-xs font-semibold rounded ${severityColor}`}>
<span className={`text-xs font-semibold rounded-sm ${severityColor}`}>
{error.severity}
</span>
<span className="text-xs text-gray-500 dark:text-gray-400 ml-auto">
<span className="text-xs text-zinc-500 dark:text-zinc-400 ml-auto">
{new Date(error.created_at).toLocaleString()}
</span>
</div>
<p className="text-sm text-gray-700 dark:text-gray-300 line-clamp-2">
<p className="text-sm text-zinc-700 dark:text-zinc-300 line-clamp-2">
{error.error_message}
</p>
</div>
{(hasContext || isTestFailure) &&
(isExpanded ? (
<ChevronDown className="h-5 w-5 text-gray-400" />
) : (
<ChevronRight className="h-5 w-5 text-gray-400" />
))}
{(hasContext || isTestFailure) && (
<ChevronDown className={`h-4 w-4 text-zinc-400 transition-transform duration-200 ${isExpanded ? '' : '-rotate-90'}`} />
)}
</div>
<div className="flex items-center gap-2">
<CopyButton text={error.error_message} label="error message" size="sm" />
@ -121,17 +117,17 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
{isExpanded && isTestFailure && error.context && (
<div className="px-4 pb-4 ml-8">
<div className="p-4 bg-red-50 dark:bg-red-900/20 rounded-lg border border-red-200 dark:border-red-800">
<h4 className="text-sm font-semibold text-red-800 dark:text-red-300 mb-3">
<div className="p-4 bg-zinc-50 dark:bg-zinc-800 rounded-sm border border-zinc-200 dark:border-zinc-700">
<h4 className="text-sm font-semibold text-red-600 dark:text-red-400 mb-3">
Test Failure Details
</h4>
{error.context.test_name && (
<div className="mb-3">
<span className="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase tracking-wide">
<span className="text-xs font-medium text-zinc-600 dark:text-zinc-400 uppercase tracking-wide">
Test Name
</span>
<p className="text-sm text-gray-900 dark:text-white font-mono mt-1">
<p className="text-sm text-zinc-900 dark:text-white font-mono mt-1">
{error.context.test_name}
</p>
</div>
@ -139,10 +135,10 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
{error.context.failure_reason && (
<div className="mb-3">
<span className="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase tracking-wide">
<span className="text-xs font-medium text-zinc-600 dark:text-zinc-400 uppercase tracking-wide">
Failure Reason
</span>
<p className="text-sm text-gray-900 dark:text-white mt-1 whitespace-pre-wrap">
<p className="text-sm text-zinc-900 dark:text-white mt-1 whitespace-pre-wrap">
{error.context.failure_reason}
</p>
</div>
@ -150,10 +146,10 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
{error.context.expected && (
<div className="mb-3">
<span className="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase tracking-wide">
<span className="text-xs font-medium text-zinc-600 dark:text-zinc-400 uppercase tracking-wide">
Expected
</span>
<pre className="text-xs text-gray-900 dark:text-white mt-1 bg-white dark:bg-gray-800 p-2 rounded overflow-x-auto font-mono">
<pre className="text-xs text-zinc-900 dark:text-white mt-1 bg-white dark:bg-zinc-900 p-2 rounded-sm overflow-x-auto font-mono">
{String(error.context.expected)}
</pre>
</div>
@ -161,10 +157,10 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
{error.context.actual && (
<div className="mb-3">
<span className="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase tracking-wide">
<span className="text-xs font-medium text-zinc-600 dark:text-zinc-400 uppercase tracking-wide">
Actual
</span>
<pre className="text-xs text-gray-900 dark:text-white mt-1 bg-white dark:bg-gray-800 p-2 rounded overflow-x-auto font-mono">
<pre className="text-xs text-zinc-900 dark:text-white mt-1 bg-white dark:bg-zinc-900 p-2 rounded-sm overflow-x-auto font-mono">
{String(error.context.actual)}
</pre>
</div>
@ -172,10 +168,10 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
{error.context.test_output && (
<div>
<span className="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase tracking-wide">
<span className="text-xs font-medium text-zinc-600 dark:text-zinc-400 uppercase tracking-wide">
Test Output
</span>
<pre className="text-xs text-gray-900 dark:text-white mt-1 bg-white dark:bg-gray-800 p-2 rounded overflow-x-auto whitespace-pre-wrap font-mono max-h-48">
<pre className="text-xs text-zinc-900 dark:text-white mt-1 bg-white dark:bg-zinc-900 p-2 rounded-sm overflow-x-auto whitespace-pre-wrap font-mono max-h-48">
{String(error.context.test_output)}
</pre>
</div>
@ -186,11 +182,11 @@ export const ErrorsSection = memo(function ErrorsSection({ errors }: ErrorsSecti
{isExpanded && !isTestFailure && hasContext && (
<div className="px-4 pb-4 ml-8">
<div className="p-4 bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700">
<span className="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase tracking-wide">
<div className="p-4 bg-zinc-50 dark:bg-zinc-900 rounded-sm border border-zinc-200 dark:border-zinc-700">
<span className="text-xs font-medium text-zinc-600 dark:text-zinc-400 uppercase tracking-wide">
Context
</span>
<pre className="text-xs text-gray-900 dark:text-white mt-2 overflow-auto whitespace-pre-wrap font-mono max-h-48">
<pre className="text-xs text-zinc-900 dark:text-white mt-2 overflow-auto whitespace-pre-wrap font-mono max-h-48">
{JSON.stringify(error.context, null, 2)}
</pre>
</div>

View file

@ -1,7 +1,7 @@
"use client"
import { memo, useMemo, useState } from "react"
import { Code, FileText, ChevronDown, ChevronRight } from "lucide-react"
import { Code, FileText, ChevronDown } from "lucide-react"
import { CodeHighlighter, CODE_STYLE_RELAXED } from "./code-highlighter"
import { CopyButton } from "@/components/observability/copy-button"
@ -68,9 +68,9 @@ export const FunctionToOptimizeSection = memo(function FunctionToOptimizeSection
}
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-200 dark:border-gray-700 overflow-hidden">
<div className="bg-white dark:bg-zinc-900 rounded-sm border border-zinc-200 dark:border-zinc-800 overflow-hidden">
{/* Header */}
<div className="w-full p-4 bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-blue-900/20 dark:to-indigo-900/20 flex items-center justify-between">
<div className="w-full p-4 bg-zinc-950 flex items-center justify-between">
<div
role="button"
tabIndex={0}
@ -78,26 +78,22 @@ export const FunctionToOptimizeSection = memo(function FunctionToOptimizeSection
onKeyDown={e => { if (e.key === "Enter" || e.key === " ") setIsExpanded(!isExpanded) }}
className="flex items-center gap-3 cursor-pointer hover:opacity-80 flex-1"
>
<div className="p-2 bg-blue-100 dark:bg-blue-900/50 rounded-lg">
<Code className="h-5 w-5 text-blue-600 dark:text-blue-400" />
<div className="p-2 bg-zinc-800 rounded-sm">
<Code className="h-4 w-4 text-zinc-400" />
</div>
<div className="text-left">
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
<h2 className="text-lg font-semibold text-zinc-50">
Function to Optimize
</h2>
<div className="flex items-center gap-2 mt-1">
{functionName && (
<code className="text-sm font-mono text-blue-600 dark:text-blue-400 bg-blue-100 dark:bg-blue-900/50 px-2 py-0.5 rounded">
<code className="text-sm font-mono text-zinc-300 bg-zinc-800 px-2 py-0.5 rounded-sm">
{functionName}
</code>
)}
</div>
</div>
{isExpanded ? (
<ChevronDown className="h-5 w-5 text-gray-400" />
) : (
<ChevronRight className="h-5 w-5 text-gray-400" />
)}
<ChevronDown className={`h-4 w-4 text-zinc-500 transition-transform duration-200 ${isExpanded ? '' : '-rotate-90'}`} />
</div>
<div className="flex items-center gap-2">
<CopyButton text={functionFile.code} label="function code" />
@ -107,17 +103,17 @@ export const FunctionToOptimizeSection = memo(function FunctionToOptimizeSection
{isExpanded && (
<>
{/* File info */}
<div className="px-4 py-2 bg-gray-50 dark:bg-gray-900/50 border-t border-b border-gray-200 dark:border-gray-700 flex items-center gap-2">
<FileText className="h-4 w-4 text-gray-400" />
<span className="text-sm font-mono font-medium text-gray-700 dark:text-gray-300">
<div className="px-4 py-2 bg-zinc-900 border-t border-b border-zinc-800 flex items-center gap-2">
<FileText className="h-4 w-4 text-zinc-500" />
<span className="text-sm font-mono font-medium text-zinc-300">
{functionFile.filename}
</span>
{functionFile.path !== functionFile.filename && (
<span className="text-xs text-gray-500 dark:text-gray-400">
<span className="text-xs font-mono text-zinc-500">
({functionFile.path})
</span>
)}
<span className="text-xs text-gray-500 dark:text-gray-400 ml-auto">
<span className="text-xs text-zinc-500 ml-auto">
{functionFile.code.split("\n").length} lines
</span>
</div>

View file

@ -3,7 +3,6 @@
import { useState, useMemo, useCallback, memo, useEffect } from "react"
import {
ChevronDown,
ChevronRight,
Hash,
FileText,
Code,
@ -106,38 +105,34 @@ const CodeFileDisplay = memo(function CodeFileDisplay({
return (
<div>
{/* File header */}
<div className="px-4 py-2 flex items-center justify-between bg-gray-100 dark:bg-gray-800">
<div className="px-4 py-2 flex items-center justify-between bg-zinc-100 dark:bg-zinc-800">
<div
role="button"
tabIndex={0}
onClick={onToggle}
onKeyDown={e => { if (e.key === "Enter" || e.key === " ") onToggle() }}
className="flex items-center gap-2 cursor-pointer hover:opacity-80 flex-1"
className="flex items-center gap-2 cursor-pointer hover:opacity-80 flex-1 transition-opacity duration-150"
>
<FileText className="h-3.5 w-3.5 text-gray-400" />
<FileText className="h-3.5 w-3.5 text-zinc-400" />
{parsed.filename ? (
<>
<span className="text-sm font-mono font-medium text-gray-900 dark:text-white">
<span className="text-sm font-mono font-medium text-zinc-900 dark:text-white">
{parsed.filename}
</span>
{parsed.path && parsed.path !== parsed.filename && (
<span className="text-xs text-gray-500 dark:text-gray-400" title={parsed.path}>
<span className="text-xs text-zinc-500 dark:text-zinc-400" title={parsed.path}>
({parsed.path})
</span>
)}
</>
) : (
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
{label || "Code"}
</span>
)}
{isExpanded ? (
<ChevronDown className="h-3.5 w-3.5 text-gray-400" />
) : (
<ChevronRight className="h-3.5 w-3.5 text-gray-400" />
)}
<ChevronDown className={`h-3.5 w-3.5 text-zinc-400 transition-transform duration-200 ${isExpanded ? '' : '-rotate-90'}`} />
</div>
<span className="text-xs text-gray-500 dark:text-gray-400">
<span className="text-xs text-zinc-500 dark:text-zinc-400">
{parsed.code.split("\n").length} lines
</span>
</div>
@ -161,7 +156,7 @@ const DiffView = memo(function DiffView({ diff }: { diff: string }) {
const lines = diff.split("\n")
return (
<div className="font-mono text-sm bg-gray-900 overflow-x-auto">
<div className="font-mono text-sm bg-zinc-900 overflow-x-auto">
{lines.map((line, index) => {
const isAddition = line.startsWith("+")
const isDeletion = line.startsWith("-")
@ -181,7 +176,7 @@ const DiffView = memo(function DiffView({ diff }: { diff: string }) {
// Determine line styling
let bgClass = ""
let textClass = "text-gray-300"
let textClass = "text-zinc-300"
let lineContent = line
let indicator: React.ReactNode = null
let borderClass = "border-transparent"
@ -310,7 +305,7 @@ const CandidateCodeDisplay = memo(function CandidateCodeDisplay({
<div>
{/* File header with view toggle */}
<div
className="px-4 py-2 flex items-center justify-between bg-gray-100 dark:bg-gray-800"
className="px-4 py-2 flex items-center justify-between bg-zinc-100 dark:bg-zinc-800"
>
<div
role="button"
@ -319,39 +314,35 @@ const CandidateCodeDisplay = memo(function CandidateCodeDisplay({
onKeyDown={e => { if (e.key === "Enter" || e.key === " ") onToggle() }}
className="flex items-center gap-2 cursor-pointer hover:opacity-80"
>
<FileText className="h-3.5 w-3.5 text-gray-400" />
<FileText className="h-3.5 w-3.5 text-zinc-400" />
{parsedCandidate.filename ? (
<>
<span className="text-sm font-mono font-medium text-gray-900 dark:text-white">
<span className="text-sm font-mono font-medium text-zinc-900 dark:text-white">
{parsedCandidate.filename}
</span>
{parsedCandidate.path && parsedCandidate.path !== parsedCandidate.filename && (
<span className="text-xs text-gray-500 dark:text-gray-400" title={parsedCandidate.path}>
<span className="text-xs text-zinc-500 dark:text-zinc-400" title={parsedCandidate.path}>
({parsedCandidate.path})
</span>
)}
</>
) : (
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
Optimized Code
</span>
)}
{isExpanded ? (
<ChevronDown className="h-3.5 w-3.5 text-gray-400" />
) : (
<ChevronRight className="h-3.5 w-3.5 text-gray-400" />
)}
<ChevronDown className={`h-3.5 w-3.5 text-zinc-400 transition-transform duration-200 ${isExpanded ? '' : '-rotate-90'}`} />
</div>
<div className="flex items-center gap-2">
{/* View toggle */}
{hasDiff && (
<div className="flex items-center bg-gray-200 dark:bg-gray-700 rounded-md p-0.5">
<div className="flex items-center bg-zinc-200 dark:bg-zinc-800 rounded-sm p-0.5">
<button
onClick={() => setViewMode("diff")}
className={`px-2 py-1 text-xs font-medium rounded transition-colors flex items-center gap-1 ${
className={`px-2 py-1 text-xs font-medium rounded transition-colors duration-150 flex items-center gap-1 ${
viewMode === "diff"
? "bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm"
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white"
? "bg-white dark:bg-zinc-700 text-zinc-900 dark:text-white border border-zinc-400 dark:border-zinc-600"
: "text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-white hover:bg-zinc-100 dark:hover:bg-zinc-800"
}`}
>
<GitCompare className="h-3 w-3" />
@ -359,10 +350,10 @@ const CandidateCodeDisplay = memo(function CandidateCodeDisplay({
</button>
<button
onClick={() => setViewMode("code")}
className={`px-2 py-1 text-xs font-medium rounded transition-colors flex items-center gap-1 ${
className={`px-2 py-1 text-xs font-medium rounded transition-colors duration-150 flex items-center gap-1 ${
viewMode === "code"
? "bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm"
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white"
? "bg-white dark:bg-zinc-700 text-zinc-900 dark:text-white border border-zinc-400 dark:border-zinc-600"
: "text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-white hover:bg-zinc-100 dark:hover:bg-zinc-800"
}`}
>
<Code className="h-3 w-3" />
@ -370,7 +361,7 @@ const CandidateCodeDisplay = memo(function CandidateCodeDisplay({
</button>
</div>
)}
<span className="text-xs text-gray-500 dark:text-gray-400">
<span className="text-xs text-zinc-500 dark:text-zinc-400">
{parsedCandidate.code.split("\n").length} lines
</span>
</div>
@ -387,14 +378,14 @@ const CandidateCodeDisplay = memo(function CandidateCodeDisplay({
/>
) : diffLoading ? (
<div className="p-4 animate-pulse">
<div className="h-4 bg-gray-700 rounded w-3/4 mb-2" />
<div className="h-4 bg-gray-700 rounded w-1/2 mb-2" />
<div className="h-4 bg-gray-700 rounded w-2/3" />
<div className="h-4 bg-zinc-700 rounded w-3/4 mb-2" />
<div className="h-4 bg-zinc-700 rounded w-1/2 mb-2" />
<div className="h-4 bg-zinc-700 rounded w-2/3" />
</div>
) : unifiedDiff ? (
<DiffView diff={unifiedDiff} />
) : (
<div className="p-4 text-sm text-gray-500 dark:text-gray-400">
<div className="p-4 text-sm text-zinc-500 dark:text-zinc-400">
No original code available for comparison
</div>
)}
@ -494,7 +485,7 @@ function getModelColorClasses(modelName: string): string {
return "bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200"
}
return "bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200"
return "bg-zinc-100 dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200"
}
/** Reusable debug dialog for LLM call details */
@ -535,7 +526,7 @@ const PromptContent = memo(function PromptContent({ content }: { content: string
if (parts.length === 0) {
return (
<pre className="text-sm whitespace-pre-wrap break-words text-gray-800 dark:text-gray-200 leading-relaxed">
<pre className="text-sm whitespace-pre-wrap break-words text-zinc-800 dark:text-zinc-200 leading-relaxed">
{content}
</pre>
)
@ -545,7 +536,7 @@ const PromptContent = memo(function PromptContent({ content }: { content: string
<div className="space-y-3">
{parts.map((part, i) =>
part.type === "code" ? (
<div key={i} className="rounded-lg overflow-hidden border border-gray-700">
<div key={i} className="rounded-sm overflow-hidden border border-zinc-700">
<CodeHighlighter
language={part.language || "python"}
code={part.content}
@ -553,7 +544,7 @@ const PromptContent = memo(function PromptContent({ content }: { content: string
/>
</div>
) : (
<pre key={i} className="text-sm whitespace-pre-wrap break-words text-gray-800 dark:text-gray-200 leading-relaxed">
<pre key={i} className="text-sm whitespace-pre-wrap break-words text-zinc-800 dark:text-zinc-200 leading-relaxed">
{part.content}
</pre>
)
@ -565,7 +556,7 @@ const PromptContent = memo(function PromptContent({ content }: { content: string
const LLMCallDebugDialog = memo(function LLMCallDebugDialog({
call,
callType,
buttonClassName = "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700",
buttonClassName = "text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-700",
}: LLMCallDebugDialogProps) {
const [open, setOpen] = useState(false)
const [activeTab, setActiveTab] = useState<"user" | "system">("user")
@ -586,7 +577,7 @@ const LLMCallDebugDialog = memo(function LLMCallDebugDialog({
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<button
className={`flex items-center gap-1.5 px-2 py-1 text-xs rounded transition-colors ${buttonClassName}`}
className={`flex items-center gap-1.5 px-2 py-1 text-xs rounded transition-colors duration-150 ${buttonClassName}`}
title="View LLM call details"
>
<Bug className="h-3 w-3" />
@ -594,29 +585,29 @@ const LLMCallDebugDialog = memo(function LLMCallDebugDialog({
</button>
</DialogTrigger>
<DialogContent className="w-[95vw] max-w-[95vw] h-[90vh] max-h-[90vh] flex flex-col overflow-hidden">
<DialogHeader className="flex-shrink-0 pb-3 border-b border-gray-200 dark:border-gray-700">
<DialogHeader className="flex-shrink-0 pb-3 border-b border-zinc-200 dark:border-zinc-700">
<DialogTitle className="flex items-center gap-2">
<Bug className="h-4 w-4" />
<span>LLM Call Details</span>
</DialogTitle>
{/* Metadata row */}
<div className="flex items-center gap-3 mt-2 text-sm flex-wrap">
<span className="font-medium text-gray-900 dark:text-white">{callType}</span>
<span className="text-gray-400">·</span>
<span className="font-medium text-zinc-900 dark:text-white">{callType}</span>
<span className="text-zinc-400">·</span>
{call.model_name && (
<span className={`${getModelColorClasses(call.model_name)} text-xs px-2 py-0.5 rounded`}>
{call.model_name}
</span>
)}
<span className="text-gray-400">·</span>
<span className="text-gray-600 dark:text-gray-400">{((call.latency_ms || 0) / 1000).toFixed(2)}s</span>
<span className="text-gray-400">·</span>
<span className="text-gray-600 dark:text-gray-400">${(call.llm_cost || 0).toFixed(4)}</span>
<span className="text-gray-400">·</span>
<span className="text-gray-600 dark:text-gray-400">{call.total_tokens?.toLocaleString() ?? "?"} tokens</span>
<span className="text-zinc-400">·</span>
<span className="text-zinc-600 dark:text-zinc-400">{((call.latency_ms || 0) / 1000).toFixed(2)}s</span>
<span className="text-zinc-400">·</span>
<span className="text-zinc-600 dark:text-zinc-400">${(call.llm_cost || 0).toFixed(4)}</span>
<span className="text-zinc-400">·</span>
<span className="text-zinc-600 dark:text-zinc-400">{call.total_tokens?.toLocaleString() ?? "?"} tokens</span>
{call.prompt_tokens && call.completion_tokens && (
<>
<span className="text-gray-400">·</span>
<span className="text-zinc-400">·</span>
<span className="text-blue-600 dark:text-blue-400 text-xs">
{call.prompt_tokens.toLocaleString()} in
</span>
@ -627,7 +618,7 @@ const LLMCallDebugDialog = memo(function LLMCallDebugDialog({
)}
{call.status && (
<>
<span className="text-gray-400">·</span>
<span className="text-zinc-400">·</span>
<span className={`text-xs px-1.5 py-0.5 rounded ${
call.status === "success" ? "bg-green-100 dark:bg-green-900/50 text-green-700 dark:text-green-300" :
call.status === "failed" ? "bg-red-100 dark:bg-red-900/50 text-red-700 dark:text-red-300" :
@ -644,39 +635,39 @@ const LLMCallDebugDialog = memo(function LLMCallDebugDialog({
<TabsList className="flex-shrink-0 w-fit mx-auto">
<TabsTrigger value="user">
User Prompt
<span className="ml-1.5 text-xs text-gray-400">
<span className="ml-1.5 text-xs text-zinc-400">
({(call.user_prompt?.length || 0).toLocaleString()} chars)
</span>
</TabsTrigger>
<TabsTrigger value="system">
System Prompt
<span className="ml-1.5 text-xs text-gray-400">
<span className="ml-1.5 text-xs text-zinc-400">
({(call.system_prompt?.length || 0).toLocaleString()} chars)
</span>
</TabsTrigger>
</TabsList>
{/* Only render active tab content to avoid parsing/rendering both prompts */}
<div className="flex-1 overflow-y-auto mt-3 p-4 bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700">
<div className="flex-1 overflow-y-auto mt-3 p-4 bg-white dark:bg-zinc-900 rounded-sm border border-zinc-200 dark:border-zinc-700">
{!contentReady ? (
<div className="animate-pulse space-y-3">
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-3/4" />
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-1/2" />
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-2/3" />
<div className="h-4 bg-zinc-200 dark:bg-zinc-700 rounded w-3/4" />
<div className="h-4 bg-zinc-200 dark:bg-zinc-700 rounded w-1/2" />
<div className="h-4 bg-zinc-200 dark:bg-zinc-700 rounded w-2/3" />
</div>
) : activeTab === "user" ? (
call.user_prompt ? (
<PromptContent content={call.user_prompt} />
) : (
<span className="text-gray-400">No user prompt</span>
<span className="text-zinc-400">No user prompt</span>
)
) : (
call.system_prompt ? (
<pre className="text-sm whitespace-pre-wrap break-words text-gray-800 dark:text-gray-200 leading-relaxed font-mono">
<pre className="text-sm whitespace-pre-wrap break-words text-zinc-800 dark:text-zinc-200 leading-relaxed font-mono">
{call.system_prompt}
</pre>
) : (
<span className="text-gray-400">No system prompt</span>
<span className="text-zinc-400">No system prompt</span>
)
)}
</div>
@ -806,13 +797,13 @@ const CallItem = memo(function CallItem({
}
}
return {
border: "border-gray-200 dark:border-gray-700",
border: "border-zinc-200 dark:border-zinc-700",
bg: "",
headerBg: "bg-gray-50 dark:bg-gray-800",
headerBorder: "border-gray-200 dark:border-gray-700",
text: "text-gray-700 dark:text-gray-300",
icon: "text-gray-500",
debugBtn: "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700",
headerBg: "bg-zinc-50 dark:bg-zinc-800",
headerBorder: "border-zinc-200 dark:border-zinc-700",
text: "text-zinc-700 dark:text-zinc-300",
icon: "text-zinc-500",
debugBtn: "text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-700",
}
}
@ -820,7 +811,7 @@ const CallItem = memo(function CallItem({
const title = getTitle()
return (
<div className={`rounded-lg border overflow-hidden ${theme.border} ${theme.bg}`}>
<div className={`rounded-sm border overflow-hidden ${theme.border} ${theme.bg}`}>
{/* Header */}
<div className={`p-3 border-b ${theme.headerBg} ${theme.headerBorder}`}>
<div className="flex items-center justify-between">
@ -850,15 +841,15 @@ const CallItem = memo(function CallItem({
</div>
{/* Explanation text */}
{candidate && !refinementCandidate && candidate.explanation && (
<p className="mt-2 text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap leading-relaxed">
<p className="mt-2 text-sm text-zinc-700 dark:text-zinc-300 whitespace-pre-wrap leading-relaxed">
{candidate.explanation}
</p>
)}
{refinementCandidate && refinementCandidate.explanation && (
<p className="mt-2 text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap leading-relaxed">
<p className="mt-2 text-sm text-zinc-700 dark:text-zinc-300 whitespace-pre-wrap leading-relaxed">
{refinementCandidate.explanation}
{parentCandidate && (
<span className="ml-2 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 text-xs px-2 py-0.5 rounded">
<span className="ml-2 bg-zinc-100 dark:bg-zinc-700 text-zinc-700 dark:text-zinc-300 text-xs px-2 py-0.5 rounded">
from Candidate #{parentCandidate.index}
</span>
)}
@ -1106,8 +1097,8 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
}, [])
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-200 dark:border-gray-700">
<div className="divide-y divide-gray-200 dark:divide-gray-700">
<div className="bg-white dark:bg-zinc-800 rounded-sm border border-zinc-200 dark:border-zinc-700">
<div className="divide-y divide-zinc-200 dark:divide-zinc-700">
{orderedTypes.map(callType => {
// Skip ranking calls - they're shown in the Ranking Explanation section
if (callType === "ranking") return null
@ -1117,7 +1108,7 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
return (
<div key={callType} className="p-4">
{/* Call Type Header */}
<div className="font-semibold text-gray-900 dark:text-white mb-3">
<div className="font-semibold text-zinc-900 dark:text-white mb-3">
{callType === "optimization" ? "Standard Optimization Candidates" :
callType === "line_profiler" ? "Line Profiler-Guided Optimization Candidates" : callType}
</div>
@ -1149,11 +1140,11 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
{/* Divider between optimization items */}
{callType === "optimization" && typeIndex > 0 && (
<div className="flex items-center gap-3 mb-4">
<div className="flex-1 h-px bg-gray-300 dark:bg-gray-600" />
<span className="text-xs text-gray-400 dark:text-gray-500 font-medium">
<div className="flex-1 h-px bg-zinc-300 dark:bg-zinc-600" />
<span className="text-xs text-zinc-400 dark:text-zinc-500 font-medium">
Candidate {typeIndex + 1}
</span>
<div className="flex-1 h-px bg-gray-300 dark:bg-gray-600" />
<div className="flex-1 h-px bg-zinc-300 dark:bg-zinc-600" />
</div>
)}
<CallItem
@ -1185,7 +1176,7 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
{/* Ranking Explanation */}
{rankingExplanation && (
<div className="mt-6 rounded-lg border border-indigo-200 dark:border-indigo-800 overflow-hidden">
<div className="mt-6 rounded-sm border border-indigo-200 dark:border-indigo-800 overflow-hidden">
<div className="p-4 bg-indigo-50 dark:bg-indigo-900/20 border-b border-indigo-200 dark:border-indigo-800">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
@ -1199,7 +1190,7 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
<Dialog>
<DialogTrigger asChild>
<button
className="flex items-center gap-1.5 px-2 py-1 text-xs text-indigo-600 dark:text-indigo-400 hover:bg-indigo-100 dark:hover:bg-indigo-900/40 rounded transition-colors"
className="flex items-center gap-1.5 px-2 py-1 text-xs text-indigo-600 dark:text-indigo-400 hover:bg-indigo-100 dark:hover:bg-indigo-900/40 rounded transition-colors duration-150"
title="View ranking LLM call details"
>
<Bug className="h-3 w-3" />
@ -1221,7 +1212,7 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
<div className="flex items-center gap-3 text-sm">
<span className="text-green-600 dark:text-green-400"></span>
<span className="font-medium">ranking</span>
<span className="text-gray-500">
<span className="text-zinc-500">
{((rankingCall.latency_ms || 0) / 1000).toFixed(2)}s · ${(rankingCall.llm_cost || 0).toFixed(4)}
</span>
{rankingCall.model_name && (
@ -1232,30 +1223,30 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
</div>
{/* Metrics Grid */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4 p-4 bg-gray-50 dark:bg-gray-900/50 rounded-lg text-sm">
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4 p-4 bg-zinc-50 dark:bg-zinc-900/50 rounded-sm text-sm">
<div className="flex flex-col">
<span className="text-gray-500 dark:text-gray-400 text-xs mb-1">Tokens</span>
<span className="text-zinc-500 dark:text-zinc-400 text-xs mb-1">Tokens</span>
<span className="font-medium">{rankingCall.total_tokens?.toLocaleString() ?? "N/A"}</span>
</div>
<div className="flex flex-col">
<span className="text-gray-500 dark:text-gray-400 text-xs mb-1">Latency</span>
<span className="text-zinc-500 dark:text-zinc-400 text-xs mb-1">Latency</span>
<span className="font-medium">{rankingCall.latency_ms ? `${rankingCall.latency_ms}ms` : "N/A"}</span>
</div>
<div className="flex flex-col">
<span className="text-gray-500 dark:text-gray-400 text-xs mb-1">Time</span>
<span className="text-zinc-500 dark:text-zinc-400 text-xs mb-1">Time</span>
<span className="font-medium">{new Date(rankingCall.created_at).toLocaleTimeString()}</span>
</div>
<div className="flex flex-col">
<span className="text-gray-500 dark:text-gray-400 text-xs mb-1">Cost</span>
<span className="text-zinc-500 dark:text-zinc-400 text-xs mb-1">Cost</span>
<span className="font-medium">${(rankingCall.llm_cost || 0).toFixed(4)}</span>
</div>
</div>
{/* Token Distribution */}
{rankingCall.prompt_tokens && rankingCall.completion_tokens && (
<div className="p-4 bg-gray-50 dark:bg-gray-900/50 rounded-lg">
<div className="p-4 bg-zinc-50 dark:bg-zinc-900/50 rounded-sm">
<div className="flex items-center gap-2 mb-3">
<Hash className="h-4 w-4 text-gray-400" />
<Hash className="h-4 w-4 text-zinc-400" />
<span className="text-sm font-medium">Token Distribution</span>
</div>
<TokenDistributionBar
@ -1271,12 +1262,12 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
<div className="space-y-2">
<div className="flex items-center justify-between">
<span className="text-sm font-medium flex items-center gap-2">
<FileText className="h-4 w-4 text-gray-400" />
<FileText className="h-4 w-4 text-zinc-400" />
User Prompt
</span>
<CopyButton text={rankingCall.user_prompt} label="user prompt" size="sm" />
</div>
<pre className="p-3 text-xs bg-gray-50 dark:bg-gray-900 rounded-lg overflow-auto max-h-48 whitespace-pre-wrap">
<pre className="p-3 text-xs bg-zinc-50 dark:bg-zinc-900 rounded-sm overflow-auto max-h-48 whitespace-pre-wrap">
{rankingCall.user_prompt}
</pre>
</div>
@ -1287,12 +1278,12 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
<div className="space-y-2">
<div className="flex items-center justify-between">
<span className="text-sm font-medium flex items-center gap-2">
<Code className="h-4 w-4 text-gray-400" />
<Code className="h-4 w-4 text-zinc-400" />
Response
</span>
<CopyButton text={rankingCall.raw_response} label="response" size="sm" />
</div>
<pre className="p-3 text-xs bg-gray-50 dark:bg-gray-900 rounded-lg overflow-auto max-h-48 whitespace-pre-wrap">
<pre className="p-3 text-xs bg-zinc-50 dark:bg-zinc-900 rounded-sm overflow-auto max-h-48 whitespace-pre-wrap">
{rankingCall.raw_response}
</pre>
</div>
@ -1305,8 +1296,8 @@ export const LLMCallsTimeline = memo(function LLMCallsTimeline({
)}
</div>
</div>
<div className="p-4 bg-white dark:bg-gray-800">
<p className="text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap leading-relaxed">
<div className="p-4 bg-white dark:bg-zinc-800">
<p className="text-sm text-zinc-700 dark:text-zinc-300 whitespace-pre-wrap leading-relaxed">
{rankingExplanation}
</p>
</div>
@ -1335,7 +1326,7 @@ const TokenDistributionBar = memo(function TokenDistributionBar({
const completionPercent = effectiveTotal > 0 ? Math.round((completionTokens / effectiveTotal) * 100) : 0
return (
<div className="flex h-6 rounded-lg overflow-hidden border border-gray-200 dark:border-gray-600 mb-2">
<div className="flex h-6 rounded-sm overflow-hidden border border-zinc-200 dark:border-zinc-600 mb-2">
<div
className="bg-blue-500 flex items-center justify-center text-white text-xs font-semibold"
style={{ width: `${promptPercent}%` }}
@ -1378,49 +1369,45 @@ const LineProfilerResultsSection = memo(function LineProfilerResultsSection({
const hasData = report.functions.length > 0
return (
<div className="mt-3 rounded-lg border border-amber-200 dark:border-amber-800 overflow-hidden">
<div className="mt-3 rounded-sm border border-amber-200 dark:border-amber-800 overflow-hidden">
<div className="w-full p-3 flex items-center justify-between bg-amber-50 dark:bg-amber-900/20">
<div
role="button"
tabIndex={0}
onClick={onToggle}
onKeyDown={e => { if (e.key === "Enter" || e.key === " ") onToggle() }}
className="flex items-center gap-2 cursor-pointer hover:opacity-80 flex-1"
className="flex items-center gap-2 cursor-pointer hover:opacity-80 flex-1 transition-opacity duration-150"
>
<Activity className="h-4 w-4 text-amber-500" />
<span className="text-sm font-medium text-gray-900 dark:text-white">Original code profiling data</span>
<span className="text-sm font-medium text-zinc-900 dark:text-white">Original code profiling data</span>
{hasData && report.functions[0] && (
<span className="text-xs text-gray-500 dark:text-gray-400">
<span className="text-xs text-zinc-500 dark:text-zinc-400">
{report.functions[0].functionName} · {report.functions[0].totalTime}
</span>
)}
{isExpanded ? (
<ChevronDown className="h-4 w-4 text-gray-400" />
) : (
<ChevronRight className="h-4 w-4 text-gray-400" />
)}
<ChevronDown className={`h-4 w-4 text-zinc-400 transition-transform duration-200 ${isExpanded ? '' : '-rotate-90'}`} />
</div>
</div>
{isExpanded && (
<div className="border-t border-gray-200 dark:border-gray-700">
<div className="border-t border-zinc-200 dark:border-zinc-700">
{hasData && (
<div className="flex gap-1 p-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
<div className="flex gap-1 p-2 bg-zinc-100 dark:bg-zinc-800 border-b border-zinc-200 dark:border-zinc-700">
<button
onClick={e => { e.stopPropagation(); setViewMode("table") }}
className={`px-2 py-1 text-xs rounded ${viewMode === "table" ? "bg-amber-500 text-white" : "bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300"}`}
className={`px-2 py-1 text-xs rounded ${viewMode === "table" ? "bg-zinc-700 text-white border border-zinc-600" : "bg-zinc-200 dark:bg-transparent text-zinc-600 dark:text-zinc-300 hover:bg-zinc-300 dark:hover:bg-zinc-800"}`}
>
Table
</button>
<button
onClick={e => { e.stopPropagation(); setViewMode("code") }}
className={`px-2 py-1 text-xs rounded ${viewMode === "code" ? "bg-amber-500 text-white" : "bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300"}`}
className={`px-2 py-1 text-xs rounded ${viewMode === "code" ? "bg-zinc-700 text-white border border-zinc-600" : "bg-zinc-200 dark:bg-transparent text-zinc-600 dark:text-zinc-300 hover:bg-zinc-300 dark:hover:bg-zinc-800"}`}
>
Code
</button>
<button
onClick={e => { e.stopPropagation(); setViewMode("bars") }}
className={`px-2 py-1 text-xs rounded ${viewMode === "bars" ? "bg-amber-500 text-white" : "bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300"}`}
className={`px-2 py-1 text-xs rounded ${viewMode === "bars" ? "bg-zinc-700 text-white border border-zinc-600" : "bg-zinc-200 dark:bg-transparent text-zinc-600 dark:text-zinc-300 hover:bg-zinc-300 dark:hover:bg-zinc-800"}`}
>
Bars
</button>
@ -1434,7 +1421,7 @@ const LineProfilerResultsSection = memo(function LineProfilerResultsSection({
{viewMode === "bars" && <LineProfilerBarsView report={report} />}
</>
) : (
<pre className="p-4 text-sm overflow-auto whitespace-pre-wrap text-gray-900 dark:text-gray-100 leading-relaxed font-mono max-h-96 bg-gray-50 dark:bg-gray-900">
<pre className="p-4 text-sm overflow-auto whitespace-pre-wrap text-zinc-900 dark:text-zinc-100 leading-relaxed font-mono max-h-96 bg-zinc-50 dark:bg-zinc-900">
{content}
</pre>
)}
@ -1448,12 +1435,12 @@ const LineProfilerResultsSection = memo(function LineProfilerResultsSection({
// View 1: Table view with all columns
const LineProfilerTableView = memo(function LineProfilerTableView({ report }: { report: LineProfilerReport }) {
return (
<div className="bg-gray-50 dark:bg-gray-900 max-h-96 overflow-auto">
<div className="bg-zinc-50 dark:bg-zinc-900 max-h-96 overflow-auto">
{report.functions.map((func, funcIndex) => (
<div key={`${func.functionName}-${funcIndex}`}>
<table className="w-full text-xs font-mono">
<thead className="sticky top-0 bg-gray-100 dark:bg-gray-800">
<tr className="text-gray-500 dark:text-gray-400 border-b border-gray-200 dark:border-gray-700">
<thead className="sticky top-0 bg-zinc-100 dark:bg-zinc-800">
<tr className="text-zinc-500 dark:text-zinc-400 border-b border-zinc-200 dark:border-zinc-700">
<th className="px-2 py-1.5 text-right w-16">Hits</th>
<th className="px-2 py-1.5 text-right w-20">Time</th>
<th className="px-2 py-1.5 text-right w-16">% Time</th>
@ -1465,17 +1452,17 @@ const LineProfilerTableView = memo(function LineProfilerTableView({ report }: {
const heatLevel = getHeatLevel(entry.percentTime)
const heatColor = HEAT_COLORS[heatLevel]
return (
<tr key={i} className={`border-b border-gray-100 dark:border-gray-800 ${heatColor}`}>
<td className="px-2 py-0.5 text-right text-gray-500 dark:text-gray-400">{entry.hits}</td>
<td className="px-2 py-0.5 text-right text-gray-500 dark:text-gray-400">{entry.time}</td>
<tr key={i} className={`border-b border-zinc-100 dark:border-zinc-800 ${heatColor}`}>
<td className="px-2 py-0.5 text-right text-zinc-500 dark:text-zinc-400">{entry.hits}</td>
<td className="px-2 py-0.5 text-right text-zinc-500 dark:text-zinc-400">{entry.time}</td>
<td className="px-2 py-0.5 text-right">
{entry.percentTime > 0 && (
<span className={heatLevel !== "cold" ? "font-semibold text-orange-600 dark:text-orange-400" : "text-gray-500 dark:text-gray-400"}>
<span className={heatLevel !== "cold" ? "font-semibold text-orange-600 dark:text-orange-400" : "text-zinc-500 dark:text-zinc-400"}>
{entry.percentTime.toFixed(1)}%
</span>
)}
</td>
<td className="px-2 py-0.5 text-gray-900 dark:text-gray-100 whitespace-pre">{entry.lineContents}</td>
<td className="px-2 py-0.5 text-zinc-900 dark:text-zinc-100 whitespace-pre">{entry.lineContents}</td>
</tr>
)
})}
@ -1490,16 +1477,16 @@ const LineProfilerTableView = memo(function LineProfilerTableView({ report }: {
// View 2: Code-centric view with timing in gutter
const LineProfilerCodeView = memo(function LineProfilerCodeView({ report }: { report: LineProfilerReport }) {
return (
<div className="bg-gray-900 max-h-96 overflow-auto">
<div className="bg-zinc-900 max-h-96 overflow-auto">
{report.functions.map((func, funcIndex) => (
<div key={`${func.functionName}-${funcIndex}`} className="font-mono text-xs">
{func.entries.map((entry, i) => {
const heatLevel = getHeatLevel(entry.percentTime)
const barWidth = Math.min(entry.percentTime, 100)
return (
<div key={i} className="flex group hover:bg-gray-800">
<div key={i} className="flex group hover:bg-zinc-800">
{/* Gutter with timing info */}
<div className="w-24 flex-shrink-0 flex items-center justify-end pr-2 border-r border-gray-700 bg-gray-950 text-gray-500">
<div className="w-24 flex-shrink-0 flex items-center justify-end pr-2 border-r border-zinc-700 bg-zinc-950 text-zinc-500">
{entry.percentTime > 0 && (
<span className={`${heatLevel !== "cold" ? "text-orange-400 font-semibold" : ""}`}>
{entry.percentTime.toFixed(1)}%
@ -1507,7 +1494,7 @@ const LineProfilerCodeView = memo(function LineProfilerCodeView({ report }: { re
)}
</div>
{/* Heat indicator bar */}
<div className="w-12 flex-shrink-0 relative bg-gray-950">
<div className="w-12 flex-shrink-0 relative bg-zinc-950">
{entry.percentTime > 0 && (
<div
className={`absolute top-0 bottom-0 left-0 ${
@ -1521,7 +1508,7 @@ const LineProfilerCodeView = memo(function LineProfilerCodeView({ report }: { re
)}
</div>
{/* Code */}
<pre className="flex-1 py-0.5 px-2 text-gray-100 whitespace-pre overflow-x-auto">
<pre className="flex-1 py-0.5 px-2 text-zinc-100 whitespace-pre overflow-x-auto">
{entry.lineContents}
</pre>
</div>
@ -1536,7 +1523,7 @@ const LineProfilerCodeView = memo(function LineProfilerCodeView({ report }: { re
// View 3: Horizontal bar chart view
const LineProfilerBarsView = memo(function LineProfilerBarsView({ report }: { report: LineProfilerReport }) {
return (
<div className="bg-gray-50 dark:bg-gray-900 max-h-96 overflow-auto p-2">
<div className="bg-zinc-50 dark:bg-zinc-900 max-h-96 overflow-auto p-2">
{report.functions.map((func, funcIndex) => (
<div key={`${func.functionName}-${funcIndex}`} className="space-y-0.5">
{func.entries.map((entry, i) => {
@ -1548,13 +1535,13 @@ const LineProfilerBarsView = memo(function LineProfilerBarsView({ report }: { re
{/* Percentage */}
<div className="w-12 text-right flex-shrink-0">
{hasTime && (
<span className={heatLevel !== "cold" ? "text-orange-600 dark:text-orange-400 font-semibold" : "text-gray-400"}>
<span className={heatLevel !== "cold" ? "text-orange-600 dark:text-orange-400 font-semibold" : "text-zinc-400"}>
{entry.percentTime.toFixed(1)}%
</span>
)}
</div>
{/* Bar */}
<div className="w-24 h-4 bg-gray-200 dark:bg-gray-800 rounded-sm overflow-hidden flex-shrink-0">
<div className="w-24 h-4 bg-zinc-200 dark:bg-zinc-800 rounded-sm overflow-hidden flex-shrink-0">
{hasTime && (
<div
className={`h-full rounded-sm ${
@ -1562,15 +1549,15 @@ const LineProfilerBarsView = memo(function LineProfilerBarsView({ report }: { re
heatLevel === "hot-3" ? "bg-orange-500" :
heatLevel === "hot-2" ? "bg-yellow-500" :
heatLevel === "hot-1" ? "bg-yellow-400" :
"bg-gray-400"
"bg-zinc-400"
}`}
style={{ width: `${barWidth}%` }}
/>
)}
</div>
{/* Code snippet (truncated) */}
<div className="flex-1 truncate text-gray-700 dark:text-gray-300" title={entry.lineContents}>
{entry.lineContents.trim() || <span className="text-gray-400 italic">empty line</span>}
<div className="flex-1 truncate text-zinc-700 dark:text-zinc-300" title={entry.lineContents}>
{entry.lineContents.trim() || <span className="text-zinc-400 italic">empty line</span>}
</div>
</div>
)
@ -1608,15 +1595,15 @@ const TestContextSection = memo(function TestContextSection({
const helpers = context.helper_function_names || []
return (
<div className="mb-3 rounded-lg border border-cyan-200 dark:border-cyan-800 overflow-hidden text-xs">
<div className="mb-3 rounded-sm border border-cyan-200 dark:border-cyan-800 overflow-hidden text-xs">
{/* Collapsible Header */}
<button
onClick={() => setIsExpanded(!isExpanded)}
className="w-full p-3 flex items-center justify-between bg-cyan-50/50 dark:bg-cyan-900/10 hover:bg-cyan-100/50 dark:hover:bg-cyan-900/20 transition-colors"
className="w-full p-3 flex items-center justify-between bg-cyan-50/50 dark:bg-cyan-900/10 hover:bg-cyan-100/50 dark:hover:bg-cyan-900/20 transition-colors duration-150"
>
<div className="flex items-center gap-2">
<FlaskConical className="h-3.5 w-3.5 text-cyan-500" />
<span className="font-medium text-gray-700 dark:text-gray-300">Test Generation Context</span>
<span className="font-medium text-zinc-700 dark:text-zinc-300">Test Generation Context</span>
{testFramework && (
<span className="px-1.5 py-0.5 bg-cyan-100 dark:bg-cyan-900/50 text-cyan-700 dark:text-cyan-300 rounded text-[10px] font-medium">
{testFramework}
@ -1634,26 +1621,22 @@ const TestContextSection = memo(function TestContextSection({
{context.function_to_optimize.qualified_name}
</code>
)}
{isExpanded ? (
<ChevronDown className="h-4 w-4 text-gray-400" />
) : (
<ChevronRight className="h-4 w-4 text-gray-400" />
)}
<ChevronDown className={`h-4 w-4 text-zinc-400 transition-transform duration-200 ${isExpanded ? '' : '-rotate-90'}`} />
</div>
</button>
{/* Expanded Content */}
{isExpanded && (
<div className="p-3 border-t border-cyan-200 dark:border-cyan-800 bg-white dark:bg-gray-800 space-y-2">
<div className="p-3 border-t border-cyan-200 dark:border-cyan-800 bg-white dark:bg-zinc-800 space-y-2">
{context.function_to_optimize && (
<div>
<span className="text-gray-500 dark:text-gray-400 text-[10px] uppercase tracking-wide">Function</span>
<span className="text-zinc-500 dark:text-zinc-400 text-[10px] uppercase tracking-wide">Function</span>
<div className="flex items-center gap-2 mt-0.5">
<code className="text-cyan-700 dark:text-cyan-300 font-mono break-all">
{context.function_to_optimize.qualified_name}
</code>
{context.function_to_optimize.starting_line && context.function_to_optimize.ending_line && (
<span className="text-gray-400 dark:text-gray-500 shrink-0">
<span className="text-zinc-400 dark:text-zinc-500 shrink-0">
L{context.function_to_optimize.starting_line}-{context.function_to_optimize.ending_line}
</span>
)}
@ -1663,7 +1646,7 @@ const TestContextSection = memo(function TestContextSection({
{context.function_to_optimize?.file_path && (
<div>
<span className="text-gray-500 dark:text-gray-400 text-[10px] uppercase tracking-wide">File</span>
<span className="text-zinc-500 dark:text-zinc-400 text-[10px] uppercase tracking-wide">File</span>
<code className="block text-cyan-700 dark:text-cyan-300 font-mono mt-0.5 break-all">
{context.function_to_optimize.file_path}
</code>
@ -1672,7 +1655,7 @@ const TestContextSection = memo(function TestContextSection({
{context.module_path && (
<div>
<span className="text-gray-500 dark:text-gray-400 text-[10px] uppercase tracking-wide">Module</span>
<span className="text-zinc-500 dark:text-zinc-400 text-[10px] uppercase tracking-wide">Module</span>
<code className="block text-cyan-700 dark:text-cyan-300 font-mono mt-0.5 break-all">
{context.module_path}
</code>
@ -1681,7 +1664,7 @@ const TestContextSection = memo(function TestContextSection({
{context.test_module_path && (
<div>
<span className="text-gray-500 dark:text-gray-400 text-[10px] uppercase tracking-wide">Test Module</span>
<span className="text-zinc-500 dark:text-zinc-400 text-[10px] uppercase tracking-wide">Test Module</span>
<code className="block text-cyan-700 dark:text-cyan-300 font-mono mt-0.5 break-all">
{context.test_module_path}
</code>
@ -1692,9 +1675,9 @@ const TestContextSection = memo(function TestContextSection({
<div>
<button
onClick={(e) => { e.stopPropagation(); setShowHelpers(!showHelpers) }}
className="flex items-center gap-1 text-gray-500 dark:text-gray-400 text-[10px] uppercase tracking-wide hover:text-gray-700 dark:hover:text-gray-200"
className="flex items-center gap-1 text-zinc-500 dark:text-zinc-400 text-[10px] uppercase tracking-wide hover:text-zinc-700 dark:hover:text-zinc-200"
>
{showHelpers ? <ChevronDown className="h-3 w-3" /> : <ChevronRight className="h-3 w-3" />}
<ChevronDown className={`h-3 w-3 transition-transform duration-200 ${showHelpers ? '' : '-rotate-90'}`} />
Helpers ({helpers.length})
</button>
{showHelpers && (

View file

@ -39,7 +39,7 @@ export function TraceSearch({ initialTraceId = "", isLoading = false, hasResults
const inputBorderClass = hasResults
? "border-green-500 dark:border-green-500 focus:ring-green-500"
: "border-gray-300 dark:border-gray-600 focus:ring-blue-500"
: "border-zinc-300 dark:border-zinc-600 focus:ring-blue-500"
return (
<div className="w-full max-w-2xl mx-auto">
@ -51,10 +51,10 @@ export function TraceSearch({ initialTraceId = "", isLoading = false, hasResults
onChange={handleChange}
onKeyDown={handleKeyDown}
placeholder="Enter trace ID..."
className={`w-full px-4 py-3 pl-11 ${hasResults ? "pr-11" : ""} text-base rounded-lg border ${inputBorderClass} bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:border-transparent transition-shadow`}
className={`w-full px-4 py-3 pl-11 ${hasResults ? "pr-11" : ""} text-base rounded-md border ${inputBorderClass} bg-white dark:bg-zinc-950 text-zinc-900 dark:text-zinc-50 placeholder-zinc-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:border-transparent transition-all duration-150`}
aria-label="Trace ID"
/>
<Search className="absolute left-4 top-1/2 -translate-y-1/2 h-5 w-5 text-gray-400" />
<Search className="absolute left-4 top-1/2 -translate-y-1/2 h-4 w-4 text-zinc-400" />
{hasResults && (
<CheckCircle className="absolute right-4 top-1/2 -translate-y-1/2 h-5 w-5 text-green-500" />
)}
@ -62,7 +62,7 @@ export function TraceSearch({ initialTraceId = "", isLoading = false, hasResults
<button
onClick={handleSearch}
disabled={!traceId.trim() || isLoading}
className="px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors flex items-center gap-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
className="px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 disabled:cursor-not-allowed text-white font-medium rounded-md transition-colors duration-150 flex items-center gap-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
>
{isLoading ? (
<>
@ -75,7 +75,7 @@ export function TraceSearch({ initialTraceId = "", isLoading = false, hasResults
</button>
</div>
{!hasResults && (
<p className="mt-2 text-sm text-gray-500 dark:text-gray-400">
<p className="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
Paste or type a trace ID to view all associated LLM calls, candidates, and errors
</p>
)}

View file

@ -49,10 +49,10 @@ export function TraceSummary({
const SourceIcon = source.toLowerCase().includes("github") ? Github : Terminal
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 border border-gray-200 dark:border-gray-700">
<div className="bg-white dark:bg-zinc-950 rounded-sm p-6 border border-zinc-200 dark:border-zinc-800">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-6">
<div>
<div className="flex items-center gap-1.5 text-sm text-gray-600 dark:text-gray-400 font-medium mb-2">
<div className="group">
<div className="flex items-center gap-1.5 text-sm text-zinc-600 dark:text-zinc-400 font-medium mb-2">
<StatusIcon className="h-4 w-4" />
<span>Status</span>
<InfoIcon content="Overall trace status based on all contained calls" side="top" />
@ -60,60 +60,60 @@ export function TraceSummary({
<div className={`text-xl font-bold ${statusColor}`}>{status}</div>
</div>
<div>
<div className="flex items-center gap-1.5 text-sm text-gray-600 dark:text-gray-400 font-medium mb-2">
<div className="group">
<div className="flex items-center gap-1.5 text-sm text-zinc-600 dark:text-zinc-400 font-medium mb-2">
<SourceIcon className="h-4 w-4" />
<span>Source</span>
<InfoIcon content="Where this optimization was triggered from" side="top" />
</div>
<div className="text-xl font-bold text-gray-900 dark:text-white">
<span className="px-2 py-1 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded text-sm">
<div className="text-xl font-bold text-zinc-900 dark:text-zinc-50">
<span className="px-2 py-1 bg-zinc-100 dark:bg-zinc-700 text-zinc-700 dark:text-zinc-300 rounded-sm text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800 transition-colors duration-150">
{source}
</span>
</div>
</div>
<div>
<div className="flex items-center gap-1.5 text-sm text-gray-600 dark:text-gray-400 font-medium mb-2">
<div className="group">
<div className="flex items-center gap-1.5 text-sm text-zinc-600 dark:text-zinc-400 font-medium mb-2">
<Timer className="h-4 w-4" />
<span>Duration</span>
<InfoIcon content="Total time from first call to last call completion" side="top" />
</div>
<div className="text-xl font-bold text-gray-900 dark:text-white">
<div className="text-xl font-bold text-zinc-900 dark:text-zinc-50">
{durationSeconds.toFixed(2)}s
</div>
</div>
<div>
<div className="flex items-center gap-1.5 text-sm text-gray-600 dark:text-gray-400 font-medium mb-2">
<div className="group">
<div className="flex items-center gap-1.5 text-sm text-zinc-600 dark:text-zinc-400 font-medium mb-2">
<DollarSign className="h-4 w-4" />
<span>Cost</span>
<InfoIcon content="Sum of all LLM call costs in this trace" side="top" />
</div>
<div className="text-xl font-bold text-gray-900 dark:text-white">
<div className="text-xl font-bold text-zinc-900 dark:text-zinc-50">
${totalCost.toFixed(4)}
</div>
</div>
<div>
<div className="flex items-center gap-1.5 text-sm text-gray-600 dark:text-gray-400 font-medium mb-2">
<div className="group">
<div className="flex items-center gap-1.5 text-sm text-zinc-600 dark:text-zinc-400 font-medium mb-2">
<Hash className="h-4 w-4" />
<span>Tokens</span>
<InfoIcon content="Total tokens (prompt + completion) across all calls" side="top" />
</div>
<div className="text-xl font-bold text-gray-900 dark:text-white">
<div className="text-xl font-bold text-zinc-900 dark:text-zinc-50">
{totalTokens.toLocaleString()}
</div>
</div>
{candidatesCount !== undefined && (
<div>
<div className="flex items-center gap-1.5 text-sm text-gray-600 dark:text-gray-400 font-medium mb-2">
<div className="group">
<div className="flex items-center gap-1.5 text-sm text-zinc-600 dark:text-zinc-400 font-medium mb-2">
<CodeIcon className="h-4 w-4" />
<span>Candidates</span>
<InfoIcon content="Number of optimization candidates generated" side="top" />
</div>
<div className="text-xl font-bold text-gray-900 dark:text-white">
<div className="text-xl font-bold text-zinc-900 dark:text-zinc-50">
{candidatesCount}
</div>
</div>