import { ItemBadge } from "@/src/components/ItemBadge"; import { Skeleton } from "@/src/components/ui/skeleton"; import { useExtractVariables } from "@/src/features/evals/hooks/useExtractVariables"; import { type VariableMapping } from "@/src/features/evals/utils/evaluator-form-utils"; import { cn } from "@/src/utils/tailwind"; import { type RouterOutput } from "@/src/utils/types"; import { type EvalTemplate } from "@langfuse/shared"; import Link from "next/link"; import { Fragment, useMemo } from "react"; const VARIABLE_COLORS = [ "text-primary-accent", "text-dark-yellow", "text-dark-blue", "text-dark-green", "text-dark-red", ]; export const getVariableColor = (index: number) => { return VARIABLE_COLORS[index % VARIABLE_COLORS.length]; }; // Component for colored variable display const ColoredVariable = ({ value, index, }: { value: unknown; index: number; }) => { // Rotate through colors const color = getVariableColor(index); // Format the value based on its type const renderValue = () => { if (value === null || value === undefined) { return ""; } if (typeof value === "string") { // Check if the string is a JSON stringified string (starts and ends with quotes) if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) { try { // Attempt to parse it as JSON const parsed = JSON.parse(value); if (typeof parsed === "string") { // If it was a string, return the unquoted version return parsed; } } catch { // If parsing fails, it's not a JSON string literal, so return as-is } } // Display strings directly return value === "" ? "" : value; } if (typeof value === "object") { // Pretty print objects and arrays return JSON.stringify(value, null, 2); } // For other primitives (numbers, booleans) return String(value); }; const displayValue = renderValue(); const isLarge = typeof displayValue === "string" && displayValue.length > 1000; return ( {isLarge ? displayValue.substring(0, 1000) + "..." : displayValue} ); }; // Custom wrapper for prompt that renders fragments with colored variables const ColoredPromptView = ({ fragments, className, }: { fragments: Array<{ type: "text" | "variable"; content?: string; name?: string; value?: unknown; colorIndex?: number; }>; className?: string; }) => { return (
          {fragments.map((fragment, idx) => (
            
              {fragment.type === "text" ? (
                fragment.content
              ) : (
                
              )}
            
          ))}
        
); }; export const EvaluationPromptPreview = ({ evalTemplate, trace, variableMapping, isLoading, showControls = true, className, controlButtons, }: { evalTemplate: EvalTemplate; trace: RouterOutput["traces"]["byIdWithObservationsAndScores"]; variableMapping: VariableMapping[]; isLoading: boolean; showControls?: boolean; className?: string; controlButtons?: React.ReactNode; }) => { const memoizedVariables = useMemo( () => variableMapping.map(({ templateVariable }) => templateVariable), [variableMapping], ); const { extractedVariables, isExtracting } = useExtractVariables({ variables: memoizedVariables, variableMapping, trace: trace, isLoading, }); if (isExtracting) { return ; } // Helper function for prompt rendering const getPromptFragments = () => { if (!evalTemplate.prompt) { return [{ type: "text" as const, content: "" }]; } const fragments = []; let lastIndex = 0; const regex = /{{([^{}]+)}}/g; let match; let colorIndex = 0; const promptText = evalTemplate.prompt; while ((match = regex.exec(promptText)) !== null) { // Add text before variable if (match.index > lastIndex) { fragments.push({ type: "text" as const, content: promptText.substring(lastIndex, match.index), }); } // Add variable const variableName = match[1]; const variableValue = extractedVariables.find((v) => v.variable === variableName)?.value || ""; fragments.push({ type: "variable" as const, name: variableName, value: variableValue, colorIndex: colorIndex++, }); lastIndex = match.index + match[0].length; } // Add remaining text if (lastIndex < promptText.length) { fragments.push({ type: "text" as const, content: promptText.substring(lastIndex), }); } return fragments; }; const content = (
{isLoading ? (

Loading variables...

) : ( )}
); if (!showControls) { return content; } return (
Evaluation Prompt Preview
{controlButtons}
{content}
); };