Patterns
Task Trees
Build tree-structured multi-agent workflows using compilePlan() to coordinate sequential and parallel execution across agent roles.
Overview
Task Trees let you define a hierarchical plan where each node is assigned to an agent role and specifies whether its children run sequentially or in parallel. compilePlan() compiles this tree into a single Step that the runtime executes.
PlanNode
interface PlanNode {
id: string;
description: string;
assignee: string;
execution: 'sequential' | 'parallel';
children?: PlanNode[];
}| Field | Type | Purpose |
|---|---|---|
id | string | Unique node identifier |
description | string | Task description passed to the assigned agent |
assignee | string | Key into the agents registry |
execution | 'sequential' | 'parallel' | How children are executed |
children | PlanNode[] | Sub-tasks (optional -- leaf nodes are executed directly) |
compilePlan()
function compilePlan<O>(
plan: PlanNode,
agents: Record<string, (prompt: string) => Step<string, unknown>>,
constraints?: PlanConstraints,
executeStep?: ExecuteStepFn,
): Step<string, O>| Parameter | Type | Purpose |
|---|---|---|
plan | PlanNode | The task tree to compile |
agents | Record<string, (prompt: string) => Step> | Factory functions keyed by agent role |
constraints | PlanConstraints | Optional execution constraints |
executeStep | ExecuteStepFn | Optional custom step executor |
PlanConstraints
interface PlanConstraints {
toolAllowlist?: Record<string, string[]>;
maxStepsPerNode?: number;
requireApproval?: string[];
validate?: (taskId: string, input: unknown, ctx: Context) => Promise<boolean>;
}Example
import { compilePlan, react } from '@noetic/core';
const agents = {
researcher: (prompt: string) => react({
model: 'gpt-4o',
system: prompt,
tools: [searchTool],
}),
writer: (prompt: string) => react({
model: 'gpt-4o',
system: prompt,
tools: [writeTool],
}),
reviewer: (prompt: string) => react({
model: 'gpt-4o',
system: prompt,
tools: [],
}),
};
const plan: PlanNode = {
id: 'write-article',
description: 'Write a technical article',
assignee: 'writer',
execution: 'sequential',
children: [
{
id: 'research',
description: 'Research the topic',
assignee: 'researcher',
execution: 'parallel',
children: [
{ id: 'search-papers', description: 'Find academic papers', assignee: 'researcher', execution: 'sequential' },
{ id: 'search-blogs', description: 'Find blog posts', assignee: 'researcher', execution: 'sequential' },
],
},
{ id: 'draft', description: 'Write the first draft', assignee: 'writer', execution: 'sequential' },
{ id: 'review', description: 'Review and improve', assignee: 'reviewer', execution: 'sequential' },
],
};
const step = compilePlan(plan, agents);How It Works
- Leaf nodes call the agent factory with the node's
descriptionand return the resulting step. - Parallel nodes compile children into a
fork({ mode: 'all' })that runs them concurrently. - Sequential nodes compile children into a
runstep that chains execution, passing each output as the next input.
The PlanNodeSchema Zod schema is also exported, so you can have an LLM generate plans and validate them at runtime:
import { PlanNodeSchema } from '@noetic/core';
const plan = PlanNodeSchema.parse(llmOutput);Next Steps
- Adaptive Plans -- dynamic plans that revise themselves on failure
- ReAct -- the agent pattern used inside each tree node