diff options
Diffstat (limited to 'src/Agent.Core/Runtime/PlannerService.cs')
| -rw-r--r-- | src/Agent.Core/Runtime/PlannerService.cs | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/src/Agent.Core/Runtime/PlannerService.cs b/src/Agent.Core/Runtime/PlannerService.cs index 3591259..756cc41 100644 --- a/src/Agent.Core/Runtime/PlannerService.cs +++ b/src/Agent.Core/Runtime/PlannerService.cs @@ -31,12 +31,13 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se var messages = new List<OllamaMessage> { - new("system", FixedPrompt.Load()), - new("system", _settings.UserSystemPrompt), + // Planning has a dedicated read-only contract. Execution prompts contain instructions + // to inspect files and call tools, so mixing them here creates contradictory system + // instructions and causes models to execute narratively instead of returning a graph. + new("system", BuildPlanningInstruction()), new("system", $"Respond in locale: {_settings.Locale}."), new("system", ComposeSkillCatalog(_settings.Skills)), new("system", _settings.SandboxCapabilitySummary), - new("system", BuildPlanningInstruction()), new("user", request, images) }; @@ -58,11 +59,9 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se var messages = new List<OllamaMessage> { - new("system", FixedPrompt.Load()), - new("system", _settings.UserSystemPrompt), + new("system", BuildReplanInstruction(existing, replanReason)), new("system", $"Respond in locale: {_settings.Locale}."), new("system", _settings.SandboxCapabilitySummary), - new("system", BuildReplanInstruction(existing, replanReason)), new("user", request) }; @@ -74,6 +73,7 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se private TaskGraph BuildTaskGraph(PlanResult plan, string originalRequest) { + ValidatePlanStructure(plan); var graph = new TaskGraph(_settings.MaxTasks); var idMap = new List<Guid>(); @@ -105,6 +105,7 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se private TaskGraph RebuildTaskGraph(TaskGraph existing, PlanResult plan, string originalRequest) { + ValidatePlanStructure(plan); PlannerTask[] completed = existing.Tasks.Where(static t => t.State == PlannerTaskState.Completed).ToArray(); var completedByDescription = completed.GroupBy(static t => t.Description, StringComparer.Ordinal) .ToDictionary(static group => group.Key, static group => group.First(), StringComparer.Ordinal); @@ -182,6 +183,29 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se return tools; } + private static void ValidatePlanStructure(PlanResult plan) + { + for (int index = 0; index < plan.Tasks.Count; index++) + { + PlannedTask task = plan.Tasks[index]; + if (!task.RequiredTools.Contains("file_edit", StringComparer.Ordinal) || + !task.RequiredTools.Contains("process_run", StringComparer.Ordinal)) continue; + + var pending = new Stack<int>(task.Dependencies); + var visited = new HashSet<int>(); + while (pending.TryPop(out int dependency)) + { + if (dependency < 0 || dependency >= index || !visited.Add(dependency)) continue; + PlannedTask ancestor = plan.Tasks[dependency]; + if (ancestor.RequiredTools.Contains("file_edit", StringComparer.Ordinal)) + throw new PlannerValidationException( + "A coding implementation-and-verification Task cannot depend on a separate file_edit Task. " + + "Combine the edits, optional corrections, and process verification in one Task requiring file_edit and process_run."); + foreach (int parent in ancestor.Dependencies) pending.Push(parent); + } + } + } + private static PlanResult? ParsePlan(string content) { try @@ -266,7 +290,7 @@ public sealed class PlannerService(IOllamaClient ollama, AgentRuntimeSettings se { attemptMessages = messages.Concat([ new OllamaMessage("system", - "The previous response was not a valid TaskGraph JSON object. Do not call or execute any Tool while planning. " + + $"The previous response was not a valid TaskGraph: {ex.Message} Do not call or execute any Tool while planning. " + "Return only one JSON object that matches the supplied schema, beginning with {\"tasks\":[ and containing no Markdown or commentary.") ]).ToArray(); } |
