tests — planner
tests — planner
This documentation covers the planner module, specifically focusing on the core components responsible for managing task dependencies and delegating tasks to appropriate subagents. These components are central to how the agent breaks down a high-level goal into actionable steps and orchestrates their execution.
The tests in tests/planner/delegation-engine.test.ts and tests/planner/task-graph.test.ts validate the functionality of the DelegationEngine and TaskGraph classes, respectively, which reside in src/agent/planner/.
Module Overview
The planner module provides the foundational structures and logic for an autonomous agent to:
- Represent a plan as a directed acyclic graph (DAG) of tasks with dependencies.
- Orchestrate task execution in the correct order, handling parallel execution where possible.
- Delegate tasks to specialized subagents based on their description or explicit instructions.
- Manage task execution robustness through retries and shared context.
These capabilities enable the agent to tackle complex problems by breaking them down into smaller, manageable units and leveraging specialized tools or sub-agents for specific types of work.
Core Components
TaskGraph
The TaskGraph class (src/agent/planner/task-graph.js) is responsible for managing a collection of PlannedTask objects, their dependencies, and their execution status. It ensures tasks are processed in a valid order and provides mechanisms for tracking progress and handling failures.
Key Concepts
PlannedTask: Represents a single unit of work.id: Unique identifier.description: Human-readable description of the task.dependencies: An array ofids of tasks that must complete before this task can start.status: Current state of the task (e.g.,pending,running,complete,failed,skipped).delegateTo?: Optional hint for theDelegationEngineto assign this task to a specific subagent.TaskResult: The outcome of executing aPlannedTask.success: Boolean indicating if the task completed successfully.output: Any output generated by the task.duration: Time taken for execution.error?: Error message if the task failed.
Functionality
The TaskGraph provides methods for:
- Graph Construction and Manipulation:
constructor(initialTasks?: PlannedTask[]): Initializes the graph, optionally with a set of tasks.addTask(task: PlannedTask): Adds a new task to the graph.getTask(id: string): Retrieves a task by its ID.getAllTasks(): Returns all tasks in the graph.- Dependency Management and Status Updates:
getReady(): Returns an array ofPlannedTaskobjects that arependingand have all their dependenciescomplete. These tasks are ready for execution.markComplete(id: string): Marks a task ascomplete. This can unblock its dependent tasks.markFailed(id: string, error: string): Marks a task asfailed. Crucially, this will recursively mark all its dependent tasks asskippedto prevent further execution of a broken chain.- Graph Analysis:
hasCycle(): Detects if the graph contains any circular dependencies, which would prevent a valid execution order.topologicalSort(): Returns an array of tasks in a valid execution order (where dependencies always come before their dependents). Throws an error if a cycle is detected.- Execution Orchestration:
execute(executor: (task: PlannedTask) => Promise: The primary method for running the tasks. It takes an) executorfunction (which typically wraps theDelegationEngine) and processes tasks in dependency order, potentially executing independent tasks in parallel. It updates task statuses and handles failures.- Progress Reporting:
getProgress(): Returns an object detailing the current state of the graph (total tasks, completed, pending, failed, skipped).
Example Task Graph
A simple task graph with dependencies:
graph TD
t1[Task 1] --> t2[Task 2]
t1 --> t3[Task 3]
t2 --> t4[Task 4]
t3 --> t4
In this graph:
t1is ready immediately.t2andt3become ready oncet1is complete.t4becomes ready once botht2andt3are complete.
DelegationEngine
The DelegationEngine class (src/agent/planner/delegation-engine.js) is responsible for deciding which specialized subagent should handle a given PlannedTask and for managing the robust execution of these tasks, including retries and shared context.
Key Concepts
- Subagent Matching: The process of assigning a
PlannedTaskto a specific subagent (e.g.,debugger,code-reviewer,test-runner). - Retry Mechanism: Handling transient failures by re-attempting task execution a configurable number of times with backoff.
- Shared Context: A mechanism to store and retrieve information that might be relevant across different task executions or subagents.
Functionality
The DelegationEngine provides methods for:
- Subagent Matching Logic:
matchSubagent(task: PlannedTask): Determines the appropriate subagent for a given task. The matching logic follows a hierarchy:
- Explicit
delegateTo: Iftask.delegateTois specified, that subagent is chosen. - Custom Mappings: User-defined mappings (added via
addMapping) can override or extend the default heuristics. - Keyword Heuristics: The task's
descriptionis analyzed for keywords (e.g., "debug" ->debugger, "review" ->code-reviewer). - Default: If no other match is found, the task defaults to the
mainagent.
addMapping({ taskType: string, subagent: string, priority?: number }): Allows adding custom rules for subagent delegation.taskTypeis a keyword or pattern to match in the task description.- Robust Task Execution:
executeWithRetry(task: PlannedTask, executor: () => Promise: Executes the provided) executorfunction for a task. If the execution fails (TaskResult.successisfalse), it retries up tomaxRetriestimes, with a configurableretryDelayMsandbackoffMultiplier. It returns the finalTaskResultand the number of retries attempted.- Result Aggregation:
aggregateResults(results: Array<{ taskId: string, subagent: string, result: TaskResult, retries: number }>): Takes an array of individual task execution outcomes and provides a summary, including overall success/failure, total retries, and a human-readable summary string.- Shared Context Management:
getSharedContext(): Returns aMapthat can be used to store and retrieve arbitrary data, allowing subagents or tasks to share information. The output of a successful task execution is automatically stored in this context using the task's ID as the key.
Integration and Usage
The TaskGraph and DelegationEngine are designed to work in conjunction within the agent's planning and execution loop:
- An initial plan (a list of
PlannedTaskobjects) is fed into aTaskGraph. - The agent repeatedly queries the
TaskGraphforgetReady()tasks. - For each ready task, the
DelegationEngineis used tomatchSubagent()and thenexecuteWithRetry()the task. Theexecutorfunction passed toexecuteWithRetrywould typically involve invoking the identified subagent with the task details. - Based on the
TaskResultfromexecuteWithRetry, theTaskGraphis updated usingmarkComplete()ormarkFailed(). - This loop continues until all tasks are either
complete,failed, orskipped.
This modular design allows for flexible planning, robust execution, and the integration of diverse specialized subagents.
Contributing to the Module
When contributing to the planner module:
TaskGraph:- Ensure any changes to dependency logic or status transitions are thoroughly tested, especially edge cases like cycles, parallel paths, and recursive skipping on failure.
- Performance for large graphs should be considered for methods like
getReady()andtopologicalSort(). DelegationEngine:- When adding new keyword heuristics or custom mappings, ensure they are precise and do not inadvertently match tasks intended for other subagents.
- The retry mechanism's parameters (
maxRetries,retryDelayMs,backoffMultiplier) are crucial for agent stability and responsiveness; consider their impact carefully. - The shared context mechanism is a simple
Map. For more complex state management or persistence, consider extending this functionality. - General:
- Maintain clear separation of concerns between graph management (
TaskGraph) and task execution/delegation (DelegationEngine). - The
PlannedTaskandTaskResulttypes are central; ensure any modifications are backward-compatible or handled with clear migration paths. - Refer to the existing test files (
delegation-engine.test.ts,task-graph.test.ts) for examples of how to test new features or bug fixes.