?? ?? tool_result preview ??? ???? golden workbook ??? ??

?? ??
- ??, ??, ?? ?? tool_result preview? ??? ??? ???? replacement state? ?? ??? ? ??? ??? ?? ??? ??
- XLSX ?? ?? ??? ?? ?? ?? workbook golden ??? ??? summary/dashboard/detail ??? ????? ??

?? ????
- AgentMessageInvariantHelper? synthetic tool_result preview ?? ??? ??? QueryPreviewContent? ?? ?? ?? ??? tool_use_id, tool_name, ??? content/output/error ?? preview? ????? ??
- BuildToolResultPreviewMap? ?? preview? ?? ???? ?? ?? synthetic preview? ?? ??? ??
- AgentMessageInvariantHelperTests? ??? preview? ?? long tool_result? synthetic preview? ???? ??? explicit preview ?? ?? ??? ?? ??
- AgentQueryContextBuilderTests? synthetic preview? query view ?? ? ?? ???? ???? ????? ??
- ExcelSkillGoldenWorkbookTests? ??? summary/dashboard/detail, formula, data validation, conditional formatting? ??? ?? ?? workbook? Needs work: none ? Repair guide: none? ????? ??
- README.md? docs/DEVELOPMENT.md? 2026-04-15 09:36 (KST) ?? ?? ??? ?? ??? ??

?? ??
- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_preview_golden_finish\\ -p:IntermediateOutputPath=obj\\verify_preview_golden_finish\\ : ?? 0 / ?? 0
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "AgentMessageInvariantHelperTests|AgentQueryContextBuilderTests|AgentQueuedCommandProjectorTests|ExcelSkillGoldenWorkbookTests|ExcelSkillDashboardSummaryTests|PptxSkillGoldenDeckTests" -p:OutputPath=bin\\verify_preview_golden_finish_tests\\ -p:IntermediateOutputPath=obj\\verify_preview_golden_finish_tests\\ : ?? 10
This commit is contained in:
2026-04-15 09:11:56 +09:00
parent ff29a83039
commit 8530ec956a
6 changed files with 299 additions and 1 deletions

View File

@@ -8,13 +8,17 @@ namespace AxCopilot.Services.Agent;
/// </summary>
internal static class AgentMessageInvariantHelper
{
private const int SyntheticPreviewTextLimit = 280;
public static Dictionary<string, string> BuildToolResultPreviewMap(IEnumerable<ChatMessage>? messages)
{
var previews = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (messages == null)
return previews;
foreach (var message in messages)
var bufferedMessages = messages as IList<ChatMessage> ?? messages.ToList();
foreach (var message in bufferedMessages)
{
if (string.IsNullOrWhiteSpace(message.QueryPreviewContent))
continue;
@@ -24,6 +28,16 @@ internal static class AgentMessageInvariantHelper
previews[toolResultId] = message.QueryPreviewContent!;
}
foreach (var message in bufferedMessages)
{
if (!TryGetToolResultId(message, out var toolResultId) || previews.ContainsKey(toolResultId))
continue;
if (!TryBuildSyntheticToolResultPreview(message, out var preview))
continue;
previews[toolResultId] = preview;
}
return previews;
}
@@ -164,4 +178,93 @@ internal static class AgentMessageInvariantHelper
doc?.Dispose();
}
}
internal static bool TryBuildSyntheticToolResultPreview(ChatMessage message, out string preview)
{
preview = "";
if (!TryGetToolResultId(message, out var toolResultId))
return false;
var content = message.Content ?? "";
if (string.IsNullOrWhiteSpace(content))
return false;
try
{
using var doc = JsonDocument.Parse(content);
var root = doc.RootElement;
var toolName = root.TryGetProperty("tool_name", out var toolNameEl)
? toolNameEl.GetString()
: null;
var previewText = ExtractPreviewText(root);
if (string.IsNullOrWhiteSpace(previewText))
previewText = "tool result available";
var payload = new Dictionary<string, object?>
{
["type"] = "tool_result",
["tool_use_id"] = toolResultId,
["tool_name"] = toolName,
["content"] = previewText
};
preview = JsonSerializer.Serialize(payload);
return true;
}
catch
{
return false;
}
}
private static string ExtractPreviewText(JsonElement root)
{
if (root.TryGetProperty("content", out var contentEl))
{
var preview = NormalizePreviewText(contentEl.ValueKind switch
{
JsonValueKind.String => contentEl.GetString() ?? "",
JsonValueKind.Object or JsonValueKind.Array => contentEl.GetRawText(),
JsonValueKind.Number or JsonValueKind.True or JsonValueKind.False => contentEl.ToString(),
_ => ""
});
if (!string.IsNullOrWhiteSpace(preview))
return preview;
}
if (root.TryGetProperty("output", out var outputEl))
{
var preview = NormalizePreviewText(outputEl.ValueKind switch
{
JsonValueKind.String => outputEl.GetString() ?? "",
JsonValueKind.Object or JsonValueKind.Array => outputEl.GetRawText(),
JsonValueKind.Number or JsonValueKind.True or JsonValueKind.False => outputEl.ToString(),
_ => ""
});
if (!string.IsNullOrWhiteSpace(preview))
return preview;
}
if (root.TryGetProperty("error", out var errorEl) && errorEl.ValueKind == JsonValueKind.String)
return NormalizePreviewText(errorEl.GetString() ?? "");
return "";
}
private static string NormalizePreviewText(string text)
{
if (string.IsNullOrWhiteSpace(text))
return "";
var collapsed = string.Join(" ", text
.Replace('\r', ' ')
.Replace('\n', ' ')
.Replace('\t', ' ')
.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
if (collapsed.Length <= SyntheticPreviewTextLimit)
return collapsed;
return collapsed[..(SyntheticPreviewTextLimit - 3)].TrimEnd() + "...";
}
}