← Back to Files
ToolResultTextSanitizer.cs
using System;
using System.Text;
using System.Text.RegularExpressions;
namespace KaiChat.Services;
public static class ToolResultTextSanitizer
{
private static readonly Regex ToolResultHeaderRegex = new(
@"(?im)^[ \t]*(?:Tool execution results?\s*\(round\s+\d+\)|PRIVATE TOOL OUTPUT[^\r\n]*)\s*:?[ \t]*(?:\r?\n|$)",
RegexOptions.Compiled);
public static string RemoveEchoedToolResultBlocks(string? text)
{
if (string.IsNullOrEmpty(text))
return text ?? "";
var output = new StringBuilder(text.Length);
var searchIndex = 0;
while (searchIndex < text.Length)
{
var header = ToolResultHeaderRegex.Match(text, searchIndex);
if (!header.Success)
{
output.Append(text, searchIndex, text.Length - searchIndex);
break;
}
output.Append(text, searchIndex, header.Index - searchIndex);
searchIndex = FindBlockEnd(text, header);
}
return NormalizeVisibleText(output.ToString());
}
private static int FindBlockEnd(string text, Match header)
{
var bodyStart = header.Index + header.Length;
var nextHeader = ToolResultHeaderRegex.Match(text, bodyStart);
if (header.Value.Contains("PRIVATE TOOL OUTPUT", StringComparison.OrdinalIgnoreCase))
{
var privateEnd = IndexOfIgnoreCase(text, "END PRIVATE TOOL OUTPUT", bodyStart);
if (privateEnd >= 0 && (!nextHeader.Success || privateEnd < nextHeader.Index))
return AdvancePastFollowingWhitespace(text, privateEnd + "END PRIVATE TOOL OUTPUT".Length);
}
var instructionStart = IndexOfIgnoreCase(text, "Use this tool result before answering Raymond.", bodyStart);
if (instructionStart >= 0 && (!nextHeader.Success || instructionStart < nextHeader.Index))
return AdvancePastFollowingWhitespace(text, FindInstructionEnd(text, instructionStart));
return nextHeader.Success ? nextHeader.Index : text.Length;
}
private static int FindInstructionEnd(string text, int instructionStart)
{
string[] endPhrases =
[
"Do not keep sampling alternatives just because more files are available. If a tool call was skipped as a repeat, use the earlier result or answer directly instead of trying the same call again.",
"If this was skipped as a repeat, use the earlier result or answer directly instead of trying the same call again.",
"If you cannot fix it, explain the problem clearly to Raymond."
];
var bestEnd = -1;
foreach (var phrase in endPhrases)
{
var index = IndexOfIgnoreCase(text, phrase, instructionStart);
if (index >= 0)
bestEnd = Math.Max(bestEnd, index + phrase.Length);
}
if (bestEnd >= 0)
return bestEnd;
var paragraphEnd = text.IndexOf("\n\n", instructionStart, StringComparison.Ordinal);
return paragraphEnd >= 0 ? paragraphEnd : text.Length;
}
private static int AdvancePastFollowingWhitespace(string text, int index)
{
while (index < text.Length && char.IsWhiteSpace(text[index]))
index++;
return index;
}
private static int IndexOfIgnoreCase(string text, string value, int startIndex)
{
return text.IndexOf(value, startIndex, StringComparison.OrdinalIgnoreCase);
}
private static string NormalizeVisibleText(string text)
{
var normalized = Regex.Replace(text, @"[ \t]+(\r?\n)", "$1");
normalized = Regex.Replace(normalized, @"(\r?\n){3,}", Environment.NewLine + Environment.NewLine);
return normalized.Trim();
}
}