import type { AgentTool } from "@jaeswift/jae-agent-core"; import { Type } from "@sinclair/typebox"; import type { ToolResultMessage } from "@jaeswift/jae-ai"; import { html } from "lit"; import { GitCompare } from "lucide"; import { registerToolRenderer, renderHeader } from "./renderer-registry.js"; import type { ToolRenderer, ToolRenderResult } from "./types.js"; export interface DiffDetails { original: string; modified: string; filename?: string; } interface DiffParams { original: string; modified: string; filename?: string; } const diffSchema = Type.Object({ original: Type.String({ description: "Original file content" }), modified: Type.String({ description: "Modified file content" }), filename: Type.Optional(Type.String({ description: "Filename for display" })), }); function computeLineDiff(original: string, modified: string): Array<{ type: "add" | "remove" | "same"; line: string }> { const oldLines = original.split("\n"); const newLines = modified.split("\n"); const result: Array<{ type: "add" | "remove" | "same"; line: string }> = []; const maxLen = Math.max(oldLines.length, newLines.length); for (let i = 0; i < maxLen; i++) { if (i >= oldLines.length) { result.push({ type: "add", line: newLines[i] }); } else if (i >= newLines.length) { result.push({ type: "remove", line: oldLines[i] }); } else if (oldLines[i] === newLines[i]) { result.push({ type: "same", line: oldLines[i] }); } else { result.push({ type: "remove", line: oldLines[i] }); result.push({ type: "add", line: newLines[i] }); } } return result; } export const diffTool: AgentTool = { name: "show_diff", label: "Show Diff", description: "Show a diff between two versions of code or text", parameters: diffSchema, async execute(toolCallId, params, signal) { return { content: [{ type: "text", text: `Diff shown for: ${params.filename || "file"}` }], details: { original: params.original, modified: params.modified, filename: params.filename }, }; }, }; class DiffRenderer implements ToolRenderer { render(params: DiffParams | undefined, result: ToolResultMessage | undefined): ToolRenderResult { const state = result ? (result.isError ? "error" : "complete") : "inprogress"; if (!result?.details) { return { content: renderHeader(state, GitCompare, `Diff: ${params?.filename || "file"}`), isCustom: false }; } const { original, modified, filename } = result.details; const diffLines = computeLineDiff(original, modified); const adds = diffLines.filter(l => l.type === "add").length; const removes = diffLines.filter(l => l.type === "remove").length; return { content: html`
${renderHeader(state, GitCompare, html`Diff: ${filename || "file"} +${adds}-${removes}`)}
${diffLines.map((l, i) => html`
${i + 1} ${ l.type === "add" ? "+ " : l.type === "remove" ? "- " : " " }${l.line}
`)}
`, isCustom: false, }; } } registerToolRenderer("show_diff", new DiffRenderer()); export function createDiffTool(): AgentTool { return diffTool; }