summaryrefslogtreecommitdiff
path: root/src/Agent.Core/Runtime
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-08-11 22:23:27 +0900
committertanaka takashi <isazaka@gmail.com>2026-08-11 22:23:27 +0900
commitab69aaa72903b0ac5a35c4823ee97a629b3984fb (patch)
tree204e3ca65df933da44299ac6a35741105ec38358 /src/Agent.Core/Runtime
parent842e55654db060c84448f3a0deddb24f77fad5a7 (diff)
Enforce planner task effect scope
Diffstat (limited to 'src/Agent.Core/Runtime')
-rw-r--r--src/Agent.Core/Runtime/AgentRuntime.cs19
1 files changed, 17 insertions, 2 deletions
diff --git a/src/Agent.Core/Runtime/AgentRuntime.cs b/src/Agent.Core/Runtime/AgentRuntime.cs
index 333d557..9c051e9 100644
--- a/src/Agent.Core/Runtime/AgentRuntime.cs
+++ b/src/Agent.Core/Runtime/AgentRuntime.cs
@@ -266,7 +266,14 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
foreach (OllamaToolCall call in calls)
{
ToolExecutionResult toolResult;
- try
+ bool outOfScopeEffect = IsOutOfScopeEffectCall(call, plannerTask.RequiredEffectTools);
+ 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))}.",
+ false, $"task_scope:{plannerTask.Id}:{call.Function.Name}");
+ }
+ else try
{
toolResult = await _tools.DispatchAsync(taskId, call.Function.Name, call.Function.Arguments, cancellationToken).ConfigureAwait(false);
}
@@ -283,7 +290,7 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
// 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) unresolvedToolFailures[call.Function.Name] = toolResult.FailureFingerprint ?? toolResult.Output;
+ 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));
@@ -330,6 +337,14 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
return finalContent;
}
+ private static bool IsOutOfScopeEffectCall(OllamaToolCall call, IReadOnlySet<string> requiredEffectTools)
+ {
+ 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);
+ }
+
/// <summary>
/// Builds a TaskGraph summary for the prompt context (Design ยง9.2 item 6).
/// Shows the current task position within the overall graph.