diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-08-12 05:44:54 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-08-12 05:44:54 +0900 |
| commit | b56614c814b904c224315a11f9686f0d47abd3d3 (patch) | |
| tree | e6ae4feb852ea4492bf947eabba1e11ab157686a /src/Agent.Core/Runtime/PlannerService.cs | |
| parent | 98b6a2aeedd591058c1d81e401d24f3ded162926 (diff) | |
feat: revise sandbox usability around semantic policy and LPAC process trees
Rewrite the specification and design vocabulary around User Sandbox Configuration, Environment Resolution, Executable Approval, Effective Sandbox Policy, and Windows Enforcement. Move the Internal Tool catalog to the design without treating its count as a requirement, and update README, implementation planning, traceability, audit history, prompts, and the Python skill.
Introduce schema_version 1 profiles, workspaces, mounts, executable aliases, network modes, and resource presets. Add local override merging, resolution and approval stores with atomic user-only persistence, fail-closed fingerprints, localized diagnostics, and executable/sandbox management CLI commands.
Change Windows execution to LPAC entry approval with inherited descendant confinement. Separate read and execute ACLs, preserve protected OS DACLs, apply Job process/memory/timeout limits to the tree, enforce WFP network modes, prevent credential environment inheritance, disable out-of-tree MSBuild reuse, and harden transactional ACL/recovery cleanup.
Isolate planning prompts from execution instructions, reject split coding plans that cannot satisfy task-scoped evidence, preserve configured thinking, and prevent optional task_update failures from corrupting completion checks.
Add and update configuration, resolution, approval, LPAC, descendant, readonly/development, Registry/COM, WFP, recovery, .NET/Python/PowerShell process-tree, and Operational E2E coverage. Publish reproducible bundles while preserving deployment-local configuration, prompts, skills, logs, state, approvals, and resolutions.
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(); } |
