import { useState } from "react";
import type { QuestionData } from "../types";
import { highlightTrace } from "../utils/traceHighlight";
import { parsePrompt, type ParsedMessage } from "../utils/promptParser";
export interface DragHandleProps {
draggable: true;
onDragStart: (e: React.DragEvent) => void;
onDragEnd: (e: React.DragEvent) => void;
}
interface TracePanelProps {
datasetName: string;
repoName?: string;
data: QuestionData | undefined;
sampleIdx: number;
isLoading?: boolean;
dragHandleProps?: DragHandleProps;
}
export default function TracePanel({ datasetName, repoName, data, sampleIdx, isLoading, dragHandleProps }: TracePanelProps) {
const [promptExpanded, setPromptExpanded] = useState(false);
if (isLoading) {
return (
);
}
if (!data) {
return (
);
}
const isCorrect = data.eval_correct[sampleIdx];
const analysis = data.analyses[sampleIdx];
const extraction = data.extractions?.[sampleIdx];
const borderColor = isCorrect === undefined
? "border-gray-700"
: isCorrect
? "border-green-600"
: "border-red-600";
const thinkSegments = highlightTrace(analysis?.think_text || "");
const answerText = analysis?.answer_text || "";
const promptMessages = data.prompt_text ? parsePrompt(data.prompt_text) : [];
return (
{/* Header */}
{datasetName}
{isCorrect !== undefined && (
{isCorrect ? "CORRECT" : "WRONG"}
)}
{analysis && (
<>Think: {analysis.think_len.toLocaleString()} | BT: {analysis.backtracks}>
)}
{dragHandleProps && (
)}
{/* Extraction / extracted answer */}
{extraction && (
Extracted:
{extraction}
)}
{/* Trace content */}
{/* Prompt section — collapsible */}
{promptMessages.length > 0 && (
{promptExpanded && (
{promptMessages.map((msg, i) => (
))}
)}
)}
{/* Thinking section */}
Thinking ({analysis?.think_len.toLocaleString() || 0} chars)
{thinkSegments.map((seg, i) => (
{seg.text}
))}
{/* Answer section */}
{answerText && (
Answer ({analysis?.answer_len.toLocaleString() || 0} chars)
{answerText}
)}
);
}
const ROLE_STYLES: Record = {
system: { border: "border-l-purple-500", label: "text-purple-400", bg: "bg-purple-500/5" },
user: { border: "border-l-blue-500", label: "text-blue-400", bg: "bg-blue-500/5" },
assistant: { border: "border-l-green-500", label: "text-green-400", bg: "bg-green-500/5" },
prompt: { border: "border-l-gray-500", label: "text-gray-400", bg: "bg-gray-500/5" },
};
function PromptMessage({ message }: { message: ParsedMessage }) {
const style = ROLE_STYLES[message.role] || ROLE_STYLES.prompt;
return (
{message.role}
{message.content}
);
}