import React from "react"; import { FileSearch, FileDiff, CheckCircle, AlertTriangle, CircleDashed } from "lucide-react"; import { ToolViewProps } from "./types"; import { extractFilePath, extractStrReplaceContent, formatTimestamp, getToolTitle } from "./utils"; import { GenericToolView } from "./GenericToolView"; import { cn } from "@/lib/utils"; export function StrReplaceToolView({ name = "str-replace", assistantContent, toolContent, assistantTimestamp, toolTimestamp, isSuccess = true, isStreaming = false }: ToolViewProps) { const filePath = extractFilePath(assistantContent); const { oldStr, newStr } = extractStrReplaceContent(assistantContent); const toolTitle = getToolTitle(name); if (!oldStr || !newStr) { return ( ); } // Perform a character-level diff to identify changes const generateDiff = (oldText: string, newText: string) => { const i = 0; const j = 0; // Find common prefix length let prefixLength = 0; while (prefixLength < oldText.length && prefixLength < newText.length && oldText[prefixLength] === newText[prefixLength]) { prefixLength++; } // Find common suffix length let oldSuffixStart = oldText.length; let newSuffixStart = newText.length; while (oldSuffixStart > prefixLength && newSuffixStart > prefixLength && oldText[oldSuffixStart - 1] === newText[newSuffixStart - 1]) { oldSuffixStart--; newSuffixStart--; } // Generate unified diff parts const parts = []; // Add common prefix if (prefixLength > 0) { parts.push({ text: oldText.substring(0, prefixLength), type: 'unchanged' }); } // Add the changed middle parts if (oldSuffixStart > prefixLength) { parts.push({ text: oldText.substring(prefixLength, oldSuffixStart), type: 'removed' }); } if (newSuffixStart > prefixLength) { parts.push({ text: newText.substring(prefixLength, newSuffixStart), type: 'added' }); } // Add common suffix if (oldSuffixStart < oldText.length) { parts.push({ text: oldText.substring(oldSuffixStart), type: 'unchanged' }); } return parts; }; const diffParts = generateDiff(oldStr, newStr); return (
String Replacement
{filePath || 'Unknown file'}
{isStreaming ? (

Processing string replacement...

{filePath && (

{filePath}

)}
) : (
{diffParts.map((part, i) => ( {part.text} ))}
)}
{/* Footer */}
{!isStreaming && (
{isSuccess ? ( ) : ( )} {isSuccess ? 'Replacement applied successfully' : 'Replacement failed'}
)} {isStreaming && (
Processing string replacement...
)}
{toolTimestamp && !isStreaming ? formatTimestamp(toolTimestamp) : assistantTimestamp ? formatTimestamp(assistantTimestamp) : ''}
); }