1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
namespace Agent.Core.Tools;
public enum ToolUseGuardDecision { Complete, Retry, Fail }
public sealed record ToolUseGuardResult(ToolUseGuardDecision Decision, string Observation, int IdenticalFailureCount);
public sealed class ToolUseGuard(int sameFailureLimit = 5)
{
private readonly Dictionary<string, int> _failures = new(StringComparer.Ordinal);
public int SameFailureLimit { get; } = sameFailureLimit > 0 ? sameFailureLimit : throw new ArgumentOutOfRangeException(nameof(sameFailureLimit));
public ToolUseGuardResult Evaluate(bool requiresExternalEffect, bool hadToolCall, bool hasExternalEffectEvidence, string? failureFingerprint = null)
{
if (!requiresExternalEffect) return new(ToolUseGuardDecision.Complete, string.Empty, 0);
if (hasExternalEffectEvidence) return new(ToolUseGuardDecision.Complete, string.Empty, 0);
string fingerprint = string.IsNullOrWhiteSpace(failureFingerprint) ? "missing-external-effect" : failureFingerprint;
int count = _failures.TryGetValue(fingerprint, out int prior) ? prior + 1 : 1;
_failures[fingerprint] = count;
if (count >= SameFailureLimit) return new(ToolUseGuardDecision.Fail, "The required operation was not verified after repeated identical failures.", count);
return new(ToolUseGuardDecision.Retry, "Required Tool evidence is missing; perform the current operation using the required Internal Tool.", count);
}
}
|