summaryrefslogtreecommitdiff
path: root/src/Agent.Core/Runtime/AgentRuntime.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Agent.Core/Runtime/AgentRuntime.cs')
-rw-r--r--src/Agent.Core/Runtime/AgentRuntime.cs25
1 files changed, 15 insertions, 10 deletions
diff --git a/src/Agent.Core/Runtime/AgentRuntime.cs b/src/Agent.Core/Runtime/AgentRuntime.cs
index 9c051e9..4aaf646 100644
--- a/src/Agent.Core/Runtime/AgentRuntime.cs
+++ b/src/Agent.Core/Runtime/AgentRuntime.cs
@@ -228,6 +228,7 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
var guard = new ToolUseGuard(settings.SameFailureLimit);
bool requiresExternalEffect = plannerTask.RequiresExternalEffect;
bool externalEffectEvidence = false;
+ var successfulRequiredTools = new HashSet<string>(StringComparer.Ordinal);
var unresolvedToolFailures = new Dictionary<string, string>(StringComparer.Ordinal);
string? finalContent = null;
@@ -266,11 +267,11 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
foreach (OllamaToolCall call in calls)
{
ToolExecutionResult toolResult;
- bool outOfScopeEffect = IsOutOfScopeEffectCall(call, plannerTask.RequiredEffectTools);
+ bool outOfScopeEffect = IsOutOfScopeEffectCall(call, requiresExternalEffect, plannerTask.RequiredTools);
if (outOfScopeEffect)
{
toolResult = new(false,
- $"The '{call.Function.Name}' external effect belongs to another Planner Task. Perform only the current Task; required effect Tool(s): {string.Join(", ", plannerTask.RequiredEffectTools.Order(StringComparer.Ordinal))}.",
+ $"The '{call.Function.Name}' external effect belongs to another Planner Task. Perform only the current Task; required Tool(s): {string.Join(", ", plannerTask.RequiredTools.Order(StringComparer.Ordinal))}.",
false, $"task_scope:{plannerTask.Id}:{call.Function.Name}");
}
else try
@@ -286,14 +287,16 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
toolResult = new(false, ex.Message, false, $"{call.Function.Name}:{ex.GetType().Name}:{ex.Message}");
}
- externalEffectEvidence |= toolResult.Success && toolResult.ExternalEffect && plannerTask.RequiredEffectTools.Contains(call.Function.Name);
+ if (toolResult.Success && plannerTask.RequiredTools.Contains(call.Function.Name)) successfulRequiredTools.Add(call.Function.Name);
+ externalEffectEvidence |= toolResult.Success && toolResult.ExternalEffect && plannerTask.RequiredTools.Contains(call.Function.Name);
// task_update is a metadata tool for graph bookkeeping; its failures should not block completion.
bool isMetadataTool = call.Function.Name == "task_update";
if (toolResult.Success) unresolvedToolFailures.Remove(call.Function.Name);
else if (!isMetadataTool && !outOfScopeEffect) unresolvedToolFailures[call.Function.Name] = toolResult.FailureFingerprint ?? toolResult.Output;
// Record ExecutionResult in session for context summary.
- session.AppendExecutionResult(new ExecutionResult(taskId, call.Function.Name, toolResult.Success, toolResult.Output));
+ if (!outOfScopeEffect)
+ session.AppendExecutionResult(new ExecutionResult(taskId, call.Function.Name, toolResult.Success, toolResult.Output));
_observer.ToolResult(callContext, call.Function.Name, toolResult);
if (!toolResult.Success && !toolResult.RetryAllowed && !isMetadataTool)
@@ -303,11 +306,12 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
failureFingerprint = toolResult.FailureFingerprint ?? failureFingerprint;
messages.Add(new OllamaMessage("tool", toolResult.Output, ToolName: call.Function.Name));
}
- ToolUseGuardResult callGuard = guard.Evaluate(requiresExternalEffect, true, externalEffectEvidence, failureFingerprint);
+ bool verified = plannerTask.RequiredTools.All(successfulRequiredTools.Contains) && (!requiresExternalEffect || externalEffectEvidence);
+ ToolUseGuardResult callGuard = guard.Evaluate(plannerTask.RequiredTools.Count > 0 || requiresExternalEffect, true, verified, failureFingerprint);
if (callGuard.Decision == ToolUseGuardDecision.Fail) throw new InvalidOperationException(callGuard.Observation);
if (callGuard.Decision == ToolUseGuardDecision.Retry)
- messages.Add(new OllamaMessage("system", callGuard.Observation + " Required effect Tool(s) for the current Task: " +
- string.Join(", ", plannerTask.RequiredEffectTools.Order(StringComparer.Ordinal)) + "."));
+ messages.Add(new OllamaMessage("system", callGuard.Observation + " Required Tool(s) for the current Task: " +
+ string.Join(", ", plannerTask.RequiredTools.Order(StringComparer.Ordinal)) + "."));
continue;
}
@@ -322,7 +326,8 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
continue;
}
- ToolUseGuardResult completion = guard.Evaluate(requiresExternalEffect, false, externalEffectEvidence);
+ bool completionVerified = plannerTask.RequiredTools.All(successfulRequiredTools.Contains) && (!requiresExternalEffect || externalEffectEvidence);
+ ToolUseGuardResult completion = guard.Evaluate(plannerTask.RequiredTools.Count > 0 || requiresExternalEffect, false, completionVerified);
if (completion.Decision == ToolUseGuardDecision.Retry)
{
messages.Add(new OllamaMessage("system", completion.Observation));
@@ -337,12 +342,12 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
return finalContent;
}
- private static bool IsOutOfScopeEffectCall(OllamaToolCall call, IReadOnlySet<string> requiredEffectTools)
+ private static bool IsOutOfScopeEffectCall(OllamaToolCall call, bool requiresExternalEffect, IReadOnlySet<string> requiredTools)
{
bool createsExternalEffect = call.Function.Name is "file_edit" or "process_run" ||
call.Function.Name == "dir" && call.Function.Arguments.TryGetProperty("operation", out JsonElement operation) &&
operation.GetString() is "mkdir" or "rmdir";
- return createsExternalEffect && !requiredEffectTools.Contains(call.Function.Name);
+ return createsExternalEffect && (!requiresExternalEffect || !requiredTools.Contains(call.Function.Name));
}
/// <summary>