using System; using System.Collections.Generic; 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 JsonTool : IAgentTool { private record PathSegment(string Key, int Index, bool IsIndex); public string Name => "json_tool"; public string Description => "JSON processing tool. Actions: 'validate' — check if text is valid JSON and report errors; 'format' — pretty-print or minify JSON; 'query' — extract value by dot-path (e.g. 'data.users[0].name'); 'keys' — list top-level keys; 'convert' — convert between JSON/CSV (flat arrays only)."; public ToolParameterSchema Parameters { get { ToolParameterSchema toolParameterSchema = new ToolParameterSchema(); Dictionary dictionary = new Dictionary(); ToolProperty obj = new ToolProperty { Type = "string", Description = "Action to perform" }; int num = 5; List list = new List(num); CollectionsMarshal.SetCount(list, num); Span span = CollectionsMarshal.AsSpan(list); span[0] = "validate"; span[1] = "format"; span[2] = "query"; span[3] = "keys"; span[4] = "convert"; obj.Enum = list; dictionary["action"] = obj; dictionary["json"] = new ToolProperty { Type = "string", Description = "JSON text to process" }; dictionary["path"] = new ToolProperty { Type = "string", Description = "Dot-path for query action (e.g. 'data.items[0].name')" }; dictionary["minify"] = new ToolProperty { Type = "string", Description = "For format action: 'true' to minify, 'false' to pretty-print (default)" }; ToolProperty obj2 = new ToolProperty { Type = "string", Description = "For convert action: target format" }; num = 1; List list2 = new List(num); CollectionsMarshal.SetCount(list2, num); CollectionsMarshal.AsSpan(list2)[0] = "csv"; obj2.Enum = list2; dictionary["target_format"] = obj2; toolParameterSchema.Properties = dictionary; num = 2; List list3 = new List(num); CollectionsMarshal.SetCount(list3, num); Span span2 = CollectionsMarshal.AsSpan(list3); span2[0] = "action"; span2[1] = "json"; toolParameterSchema.Required = list3; return toolParameterSchema; } } public Task ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken)) { string text = args.GetProperty("action").GetString() ?? ""; string json = args.GetProperty("json").GetString() ?? ""; try { if (1 == 0) { } JsonElement value; JsonElement value2; JsonElement value3; ToolResult result = text switch { "validate" => Validate(json), "format" => Format(json, args.TryGetProperty("minify", out value) && value.GetString() == "true"), "query" => Query(json, args.TryGetProperty("path", out value2) ? (value2.GetString() ?? "") : ""), "keys" => Keys(json), "convert" => Convert(json, args.TryGetProperty("target_format", out value3) ? (value3.GetString() ?? "csv") : "csv"), _ => ToolResult.Fail("Unknown action: " + text), }; if (1 == 0) { } return Task.FromResult(result); } catch (Exception ex) { return Task.FromResult(ToolResult.Fail("JSON 처리 오류: " + ex.Message)); } } private static ToolResult Validate(string json) { try { using JsonDocument jsonDocument = JsonDocument.Parse(json); JsonElement rootElement = jsonDocument.RootElement; JsonValueKind valueKind = rootElement.ValueKind; if (1 == 0) { } string text = valueKind switch { JsonValueKind.Object => $"Object ({rootElement.EnumerateObject().Count()} keys)", JsonValueKind.Array => $"Array ({rootElement.GetArrayLength()} items)", _ => rootElement.ValueKind.ToString(), }; if (1 == 0) { } string text2 = text; return ToolResult.Ok("✓ Valid JSON — " + text2); } catch (JsonException ex) { return ToolResult.Ok("✗ Invalid JSON — " + ex.Message); } } private static ToolResult Format(string json, bool minify) { using JsonDocument jsonDocument = JsonDocument.Parse(json); JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = !minify }; string text = JsonSerializer.Serialize(jsonDocument.RootElement, options); if (text.Length > 8000) { text = text.Substring(0, 8000) + "\n... (truncated)"; } return ToolResult.Ok(text); } private static ToolResult Query(string json, string path) { if (string.IsNullOrEmpty(path)) { return ToolResult.Fail("path parameter is required for query action"); } using JsonDocument jsonDocument = JsonDocument.Parse(json); JsonElement value = jsonDocument.RootElement; foreach (PathSegment item in ParsePath(path)) { if (item.IsIndex) { if (value.ValueKind != JsonValueKind.Array || item.Index >= value.GetArrayLength()) { return ToolResult.Fail($"Array index [{item.Index}] out of range"); } value = value[item.Index]; } else { if (value.ValueKind != JsonValueKind.Object || !value.TryGetProperty(item.Key, out var value2)) { return ToolResult.Fail("Key '" + item.Key + "' not found"); } value = value2; } } JsonValueKind valueKind = value.ValueKind; if (1 == 0) { } string text = valueKind switch { JsonValueKind.String => value.GetString() ?? "", JsonValueKind.Number => value.GetRawText(), JsonValueKind.True => "true", JsonValueKind.False => "false", JsonValueKind.Null => "null", _ => JsonSerializer.Serialize(value, new JsonSerializerOptions { WriteIndented = true }), }; if (1 == 0) { } string text2 = text; if (text2.Length > 5000) { text2 = text2.Substring(0, 5000) + "\n... (truncated)"; } return ToolResult.Ok(text2); } private static ToolResult Keys(string json) { using JsonDocument jsonDocument = JsonDocument.Parse(json); if (jsonDocument.RootElement.ValueKind != JsonValueKind.Object) { return ToolResult.Fail("Root element is not an object"); } IEnumerable values = jsonDocument.RootElement.EnumerateObject().Select(delegate(JsonProperty p) { JsonValueKind valueKind = p.Value.ValueKind; if (1 == 0) { } string text; switch (valueKind) { case JsonValueKind.Object: text = "object"; break; case JsonValueKind.Array: text = $"array[{p.Value.GetArrayLength()}]"; break; case JsonValueKind.String: text = "string"; break; case JsonValueKind.Number: text = "number"; break; case JsonValueKind.True: case JsonValueKind.False: text = "boolean"; break; default: text = "null"; break; } if (1 == 0) { } string text2 = text; return " " + p.Name + ": " + text2; }); return ToolResult.Ok($"Keys ({jsonDocument.RootElement.EnumerateObject().Count()}):\n{string.Join("\n", values)}"); } private static ToolResult Convert(string json, string targetFormat) { if (targetFormat != "csv") { return ToolResult.Fail("Unsupported target format: " + targetFormat); } using JsonDocument jsonDocument = JsonDocument.Parse(json); if (jsonDocument.RootElement.ValueKind != JsonValueKind.Array) { return ToolResult.Fail("JSON must be an array for CSV conversion"); } JsonElement rootElement = jsonDocument.RootElement; if (rootElement.GetArrayLength() == 0) { return ToolResult.Ok("(empty array)"); } List list = new List(); foreach (JsonElement item2 in rootElement.EnumerateArray()) { if (item2.ValueKind != JsonValueKind.Object) { return ToolResult.Fail("All array items must be objects for CSV conversion"); } foreach (JsonProperty item3 in item2.EnumerateObject()) { if (!list.Contains(item3.Name)) { list.Add(item3.Name); } } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(string.Join(",", list.Select((string k) => "\"" + k + "\""))); foreach (JsonElement item in rootElement.EnumerateArray()) { JsonElement value; IEnumerable values = list.Select((string k) => (!item.TryGetProperty(k, out value)) ? "\"\"" : ((value.ValueKind == JsonValueKind.String) ? ("\"" + value.GetString()?.Replace("\"", "\"\"") + "\"") : value.GetRawText())); stringBuilder.AppendLine(string.Join(",", values)); } string text = stringBuilder.ToString(); if (text.Length > 8000) { text = text.Substring(0, 8000) + "\n... (truncated)"; } return ToolResult.Ok(text); } private static List ParsePath(string path) { List list = new List(); string[] array = path.Split('.'); foreach (string text in array) { int num = text.IndexOf('['); if (num >= 0) { string text2 = text.Substring(0, num); if (!string.IsNullOrEmpty(text2)) { list.Add(new PathSegment(text2, 0, IsIndex: false)); } string text3 = text; int num2 = num + 1; string s = text3.Substring(num2, text3.Length - num2).TrimEnd(']'); if (int.TryParse(s, out var result)) { list.Add(new PathSegment("", result, IsIndex: true)); } } else { list.Add(new PathSegment(text, 0, IsIndex: false)); } } return list; } }