"use client"; /** * 批量测试用例详情面板。 * 与 prompt mode DebugDrawer overlay 相同:作为右侧 flex 半屏,无遮罩/模糊。 */ import { CheckCircle2, Circle, Loader2, MessageSquareText, Pencil, RotateCcw, Target, TriangleAlert, Wrench, X, } from "lucide-react"; import { useEffect, useRef } from "react"; import { BatchCaseStatusBadge } from "@/components/batch-test/batch-case-status"; import { Button } from "@/components/ui/button"; import { firstEvaluationFailureReason, type BatchEvaluationResult, type BatchRunCase, type BatchToolCallRecord, type BatchTurnResult, } from "@/data/batch-run"; import { cn } from "@/lib/utils"; type BatchCaseDetailDrawerProps = { item: BatchRunCase; assistantName: string; onClose: () => void; onEdit?: () => void; onRerun?: () => void; }; export function BatchCaseDetailDrawer({ item, assistantName, onClose, onEdit, onRerun, }: BatchCaseDetailDrawerProps) { const closeButtonRef = useRef(null); const failureReason = firstEvaluationFailureReason(item); useEffect(() => { closeButtonRef.current?.focus(); }, [item.id]); return ( ); } function statusDescription(item: BatchRunCase): string { if (item.status === "waiting") { return item.attemptCount > 0 ? `第 ${item.attemptCount} 次执行发生错误,正在等待重试。` : "已加入执行队列,正在等待可用并发。"; } if (item.status === "running") { return item.attemptCount > 1 ? `正在进行第 ${item.attemptCount} 次尝试。` : "正在请求助手响应,结果尚未生成。"; } if (item.status === "pass") return "执行与结果判断均已完成。"; if (item.status === "fail") return "执行完成,但实际回复未达到预期。"; if (item.status === "error") return "执行未完成,已用尽配置的重试次数。"; return "本轮运行已结束,该用例未执行。"; } function TurnResultCard({ turn }: { turn: BatchTurnResult }) { return (

第 {turn.index + 1} 轮

用户输入

{turn.userInput}

Agent 回复

{turn.assistantReply}

{turn.toolCalls.length > 0 && (

工具调用记录

{turn.toolCalls.map((toolCall) => ( ))}
)}
{turn.evaluations.length === 0 ? (

本轮仅推动对话,不执行评估。

) : ( turn.evaluations.map((evaluation) => ( )) )}
); } function ToolCallCard({ toolCall }: { toolCall: BatchToolCallRecord }) { return (
{toolCall.functionName} {toolCall.outcome === "success" ? "成功" : "错误"} ·{" "} {toolCall.durationMs} ms
); } function CodeResult({ label, value }: { label: string; value: string }) { return (

{label}

        {value}
      
); } function EvaluationCard({ evaluation, }: { evaluation: BatchEvaluationResult; }) { const passed = evaluation.status === "pass"; return (
{passed ? ( ) : ( )}

{evaluation.label}

{passed ? "通过" : "失败"}
预期
{evaluation.expected}
实际
{evaluation.actual}
{evaluation.reason && ( <>
原因
{evaluation.reason}
)}
); } function DetailSection({ icon, title, value, tone = "default", }: { icon: React.ReactNode; title: string; value: string; tone?: "default" | "destructive"; }) { return (
{icon}

{title}

{value}

); } function ExecutionTimeline({ status }: { status: "waiting" | "running" }) { const isRunning = status === "running"; const steps = [ { label: "载入测试上下文", detail: isRunning ? "已完成" : "等待开始", state: isRunning ? "done" : "pending", }, { label: "请求助手响应", detail: isRunning ? "Pipeline 生成中" : "尚未开始", state: isRunning ? "active" : "pending", }, { label: "执行结果判断", detail: "尚未开始", state: "pending", }, ] as const; return (

执行进度

    {steps.map((step) => (
  1. {step.state === "done" ? ( ) : step.state === "active" ? ( ) : ( )} {step.label} {step.detail}
  2. ))}
); }