summaryrefslogtreecommitdiff
path: root/src/Agent.Core/Runtime/PlannerService.cs
AgeCommit message (Collapse)Author
2026-08-11Preserve planned tool parameters and bound failurestanaka takashi
2026-08-11Complete runtime diagnostics and verification coveragetanaka takashi
2026-08-11Audit and align v1 runtime designtanaka takashi
2026-08-11Fix: AgentRuntime tool failure handling and PlannerService fallback graph ↵tanaka takashi
persistence AgentRuntime.ExecutePlannerTaskAsync: - Add PlannerValidationException and FileNotFoundException to the tool execution catch clause so that 'Completed tasks are immutable' and 'Approved path does not exist' errors are returned as tool results instead of propagating as unhandled task failures. - Treat task_update as a metadata tool: its failures no longer add to unresolvedToolFailures, so the LLM is not forced into an infinite retry loop when task_update receives invalid arguments. - Skip throwing InvalidOperationException for RetryAllowed=false failures originating from metadata tools (task_update), preventing unnecessary replan cycles caused by graph bookkeeping errors. - Improve the 'No tasks were executed' fallback message: when replan was attempted but no tasks could execute, report that the sandbox policy denied required operations. PlannerService.PlanAsync: - Persist fallback TaskGraph to session.TaskGraphs[taskId] in all three fallback paths (ChatStructuredAsync exception, empty/null plan, BuildTaskGraph exception) so that BeginTask's TryAdd does not create an empty graph that shadows the fallback.
2026-08-11Fix PlanAsync fallback and BeginTask TaskGraph conflicttanaka takashi
Two runtime bugs discovered during MCP integration testing: 1. PlannerService.BuildTaskGraph fallback: If the LLM-generated plan contains invalid tasks (bad estimates, cycles, etc.), graph.AddTask throws PlannerValidationException. Previously this propagated up and caused "No tasks were executed." or "Planning failed" errors. Fix: wrap BuildTaskGraph in try/catch, fall back to single-task graph. Also handle graph.Count == 0 after filtering. 2. TaskGraphToolHandler.BeginTask conflict: PlanAsync stores the planned TaskGraph in session.TaskGraphs[taskId] before RunAsync calls BeginTaskAsync. BeginTask then tried TryAdd which failed because the key already existed, throwing "TaskGraph for '...' already exists in session". Fix: use TryAdd without throwing on conflict — if PlanAsync already created the graph, keep it; otherwise add a new empty one. Test results: Core 61/61, Planner 10/10, Windows 41/41 (elevated). MCP integration: agent_run/agent_status verified via HTTP transport. ACL boundary: C:\Windows\System32 access correctly denied by sandbox. ToolUseGuard: "Required external effect was not completed" fires correctly when LLM does not produce verifiable external effect.
2026-08-11Implement P2/P3: Plan-Run flow separation, PlannerService, and Windows test ↵tanaka takashi
fixes ## P3: Session/Planning Foundation ### PlanAsync / RunAsync flow separation (Design §8.4) - AgentRuntime.ExecuteAsync now follows a two-phase lifecycle: 1. Planning: generate Initial TaskGraph via Ollama structured output 2. Running: execute ready Tasks (dependencies satisfied) in critical-path then creation order - Sandbox Task Resource (BeginTask/EndTask) is applied at RunAsync time, not PlanAsync time (Design constraint) - QueuedTaskWorker transitions to Planning; ExecuteAsync transitions to Running internally ### PlannerService (new: src/Agent.Core/Runtime/PlannerService.cs) - PlanAsync: uses Ollama ChatStructuredAsync with JSON Schema to generate a TaskGraph with per-Task requires_external_effect - ReplanAsync: rebuilds TaskGraph after policy deny, preserving completed tasks (Design §8.4) - Fallback: single-task plan with conservative estimates when structured output fails or returns empty - Pure analysis tasks get RequiresExternalEffect=false with at least 1 Task (Design constraint) ### PlanResult / PlanSchema (new: src/Agent.Core/Runtime/PlanResult.cs) - JSON model for LLM structured output during Planning - JSON Schema with tasks array: description, dependencies (by index), budget_class, PERT estimates, requires_external_effect ### requires_external_effect integration (P2 + P3) - Removed keyword heuristic RequiresExternalEffect() from AgentRuntime - Removed tool-name-counting RequiredToolCalls() from AgentRuntime - ToolUseGuard now receives PlannerTask.RequiresExternalEffect (set by Planner during Planning, not by keyword matching) - requires_external_effect is NOT always true; it is a per-Task attribute determined by the Planner (Design constraint) ### RunAsync / ready Task execution - SelectNextReadyTask: dependencies satisfied, not completed/failed, critical path first then creation order - Each PlannerTask executed via ExecutePlannerTaskAsync (LLM chat-with-tools iteration loop) - TaskGraph.AddUsage records per-Task token usage for CPM tracking ### Replan implementation - Policy deny (InvalidOperationException with "denied by sandbox policy") triggers ReplanAsync, up to max 3 replan attempts - Failed task is marked Failed in TaskGraph before replan - Registry transitions back to Running for replan iteration ## P3-A: AgentSession + TaskGraph ownership ### AgentSession expansion (src/Agent.Core/Sessions/AgentSession.cs) - Added Summary, ExecutionResults, TaskGraphs (ConcurrentDictionary<Guid, TaskGraph>) - TaskGraph is per-MCP-Task (1 agent_run = 1 TaskGraph), NOT shared per-Session (Design constraint) - Added CompactConversation, CompactExecutionResults, SetSummary methods for context summary compaction ### ExecutionResult (new: src/Agent.Core/Sessions/ExecutionResult.cs) - Records tool execution results in session for context summary - Fields: TaskId, ToolName, Success, Output ### SessionStore (src/Agent.Core/Sessions/SessionStore.cs) - Added Sessions property for TaskGraphToolHandler to resolve graphs by TaskId across sessions ### sessionId threading - IInternalToolBackend.BeginTaskAsync signature changed to include sessionId parameter - InternalToolDispatcher, WindowsToolBackend, TaskGraphToolHandler updated to thread sessionId through - task_update schema includes requires_external_effect property - McpHost and Program.cs pass SessionStore to TaskRegistry ## P3: Context Summary (Design §9.3) - Context utilization = latest prompt_eval_count / num_ctx (NOT cumulative InputTokens) (Design constraint) - TryContextSummary: compacts old Conversation/ExecutionResults when utilization exceeds 80% threshold - AgentRuntimeSettings: added NumCtx, ContextSummaryThreshold, ConversationKeepLastN, ExecutionResultsKeepLastN - OllamaResult: added PromptEvalCount field - OllamaClient: passes PromptEvalCount from OllamaChatResponse ## P3: ExecutionResults Session recording - ExecutePlannerTaskAsync records each tool execution result via session.AppendExecutionResult for context summary and audit ## Windows test fixes ### SandboxPolicyException catch (src/Agent.Windows/Tools/WindowsToolBackend.cs) - ExecuteAsync now catches SandboxPolicyException and returns ToolExecutionResult(false, ..., RetryAllowed: false) instead of propagating the exception - Fixes Dir_mkdir_outside_approved_root_is_denied and File_edit_rename_rejects_outside_approved_root tests ### LoopbackExemption cleanup (tests/Agent.Windows.Tests/SecurityPolicyTests.cs) - Recovery_after_crash: added pre-clean and try/finally to ensure LoopbackExemption is always removed, even on assertion failure - Independent_process_crash: added pre-clean to remove residual loopback exemption from prior test failures - Fixes 7 Independent_process_crash scenarios that were failing due to LoopbackExemption residue from Recovery_after_crash ## Test updates (tests/Agent.Core.Tests/PromptAndRuntimeTests.cs) - FakeOllamaClient implementations updated with ChatStructuredAsync and ChatWithToolsAsync overrides to support Plan/Run flow - RecordingOllamaClient: returns single-task plan JSON for ChatStructuredAsync, tracks all call types - ToolCallingOllamaClient: returns plan with requires_external_effect=true for file edit tasks - Test expectations updated for Plan+Run call counts and token accounting (Plan tokens not added to registry usage) ## Documentation updates - Design.md §7.7: requires_external_effect is set by Planner during Planning, not keyword heuristic - Design.md §8.4: Plan/Run phase separation, replan after policy deny - Design.md §9.3: context utilization formula clarified - ImplementationPlan.md §10.3: Plan/Run flow, replan, Context Summary ## Test results (all passing) - Agent.Core.Tests: 61/61 - Agent.Planner.Tests: 10/10 - Agent.Windows.Tests (elevated): 41/41 - Build: 0 errors, 0 warnings