using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace AxCopilot.Services.Agent; public class DiffTool : IAgentTool { public string Name => "diff_tool"; public string Description => "Compare two texts or files and output a unified diff. Use 'text' mode to compare two text strings directly, or 'file' mode to compare two files by path."; public ToolParameterSchema Parameters { get { ToolParameterSchema toolParameterSchema = new ToolParameterSchema(); Dictionary dictionary = new Dictionary(); ToolProperty obj = new ToolProperty { Type = "string", Description = "Comparison mode" }; int num = 2; List list = new List(num); CollectionsMarshal.SetCount(list, num); Span span = CollectionsMarshal.AsSpan(list); span[0] = "text"; span[1] = "file"; obj.Enum = list; dictionary["mode"] = obj; dictionary["left"] = new ToolProperty { Type = "string", Description = "Left text content or file path" }; dictionary["right"] = new ToolProperty { Type = "string", Description = "Right text content or file path" }; dictionary["left_label"] = new ToolProperty { Type = "string", Description = "Label for left side (optional, default: 'left')" }; dictionary["right_label"] = new ToolProperty { Type = "string", Description = "Label for right side (optional, default: 'right')" }; toolParameterSchema.Properties = dictionary; num = 3; List list2 = new List(num); CollectionsMarshal.SetCount(list2, num); Span span2 = CollectionsMarshal.AsSpan(list2); span2[0] = "mode"; span2[1] = "left"; span2[2] = "right"; toolParameterSchema.Required = list2; return toolParameterSchema; } } public Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken)) { string text = args.GetProperty("mode").GetString() ?? "text"; string text2 = args.GetProperty("left").GetString() ?? ""; string text3 = args.GetProperty("right").GetString() ?? ""; JsonElement value; string leftLabel = (args.TryGetProperty("left_label", out value) ? (value.GetString() ?? "left") : "left"); JsonElement value2; string rightLabel = (args.TryGetProperty("right_label", out value2) ? (value2.GetString() ?? "right") : "right"); try { if (text == "file") { string text4 = (Path.IsPathRooted(text2) ? text2 : Path.Combine(context.WorkFolder, text2)); string text5 = (Path.IsPathRooted(text3) ? text3 : Path.Combine(context.WorkFolder, text3)); if (!File.Exists(text4)) { return Task.FromResult(ToolResult.Fail("Left file not found: " + text4)); } if (!File.Exists(text5)) { return Task.FromResult(ToolResult.Fail("Right file not found: " + text5)); } text2 = File.ReadAllText(text4); text3 = File.ReadAllText(text5); leftLabel = Path.GetFileName(text4); rightLabel = Path.GetFileName(text5); } string[] left = (from l in text2.Split('\n') select l.TrimEnd('\r')).ToArray(); string[] right = (from l in text3.Split('\n') select l.TrimEnd('\r')).ToArray(); string text6 = GenerateUnifiedDiff(left, right, leftLabel, rightLabel); if (string.IsNullOrEmpty(text6)) { return Task.FromResult(ToolResult.Ok("No differences found — files/texts are identical.")); } if (text6.Length > 10000) { text6 = text6.Substring(0, 10000) + "\n... (truncated)"; } return Task.FromResult(ToolResult.Ok(text6)); } catch (Exception ex) { return Task.FromResult(ToolResult.Fail("Diff 오류: " + ex.Message)); } } private static string GenerateUnifiedDiff(string[] left, string[] right, string leftLabel, string rightLabel) { List list = ComputeLcs(left, right); StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2); handler.AppendLiteral("--- "); handler.AppendFormatted(leftLabel); stringBuilder3.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2); handler.AppendLiteral("+++ "); handler.AppendFormatted(rightLabel); stringBuilder4.AppendLine(ref handler); int i = 0; int j = 0; int num = 0; List<(int, int, int, int)> list2 = new List<(int, int, int, int)>(); while (i < left.Length || j < right.Length) { if (num < list.Count && i < left.Length && j < right.Length && left[i] == list[num] && right[j] == list[num]) { i++; j++; num++; continue; } int item = i; int item2 = j; for (; i < left.Length && (num >= list.Count || left[i] != list[num]); i++) { } for (; j < right.Length && (num >= list.Count || right[j] != list[num]); j++) { } list2.Add((item, i, item2, j)); } if (list2.Count == 0) { return ""; } foreach (var item7 in list2) { int item3 = item7.Item1; int item4 = item7.Item2; int item5 = item7.Item3; int item6 = item7.Item4; int num2 = Math.Max(0, item3 - 3); stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(11, 4, stringBuilder2); handler.AppendLiteral("@@ -"); handler.AppendFormatted(item3 + 1); handler.AppendLiteral(","); handler.AppendFormatted(item4 - item3); handler.AppendLiteral(" +"); handler.AppendFormatted(item5 + 1); handler.AppendLiteral(","); handler.AppendFormatted(item6 - item5); handler.AppendLiteral(" @@"); stringBuilder5.AppendLine(ref handler); for (int k = item3; k < item4; k++) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(1, 1, stringBuilder2); handler.AppendLiteral("-"); handler.AppendFormatted(left[k]); stringBuilder6.AppendLine(ref handler); } for (int l = item5; l < item6; l++) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder7 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(1, 1, stringBuilder2); handler.AppendLiteral("+"); handler.AppendFormatted(right[l]); stringBuilder7.AppendLine(ref handler); } } return stringBuilder.ToString(); } private static List ComputeLcs(string[] a, string[] b) { int num = a.Length; int num2 = b.Length; if ((long)num * (long)num2 > 10000000) { return new List(); } int[,] array = new int[num + 1, num2 + 1]; for (int num3 = num - 1; num3 >= 0; num3--) { for (int num4 = num2 - 1; num4 >= 0; num4--) { array[num3, num4] = ((a[num3] == b[num4]) ? (array[num3 + 1, num4 + 1] + 1) : Math.Max(array[num3 + 1, num4], array[num3, num4 + 1])); } } List list = new List(); int num5 = 0; int num6 = 0; while (num5 < num && num6 < num2) { if (a[num5] == b[num6]) { list.Add(a[num5]); num5++; num6++; } else if (array[num5 + 1, num6] >= array[num5, num6 + 1]) { num5++; } else { num6++; } } return list; } }