Skip to content

Planner

The planner module decomposes a high-level goal into an ordered, dependency-aware list of Task objects. Two planners ship out of the box:

  • ClassicalPlanner — rule-based, pattern-matching decomposition. Deterministic, no LLM call required. Fast and predictable.
  • LLMPlanner — LLM-driven decomposition. Handles novel goals that don't match any registered pattern. Flexible, but requires a provider.

Both implement the Planner interface so they're interchangeable.


Quick start — ClassicalPlanner

ts
import { ClassicalPlanner, PlanningAlgorithm } from 'confused-ai/planner';

const planner = new ClassicalPlanner({
  algorithm:             PlanningAlgorithm.HIERARCHICAL, // default
  allowParallelExecution: true,
  maxIterations:         10,
  timeoutMs:             30_000,
});

const plan = await planner.plan(
  'Write a blog post about TypeScript 5.5',
  { metadata: { wordCount: 1000, audience: 'developers' } },
);

console.log(plan.id);            // 'plan-xyz'
console.log(plan.tasks.length);  // e.g. 4 tasks

for (const task of plan.tasks) {
  console.log(`[${task.priority}] ${task.name}: ${task.description}`);
  console.log('  deps:', task.dependencies);
}

Quick start — LLMPlanner

ts
import { LLMPlanner } from 'confused-ai/planner';

// The planner takes any object with a generateText method
const llmAdapter = {
  async generateText(prompt: string, opts?: { temperature?: number; maxTokens?: number }) {
    const r = await llm.generateText([{ role: 'user', content: prompt }], {});
    return r.text;
  },
};

const planner = new LLMPlanner(
  {
    temperature:            0.3,
    maxTokens:              2000,
    allowParallelExecution: true,
  },
  llmAdapter,
);

const plan = await planner.plan(
  'Set up a CI/CD pipeline for a monorepo with three services',
  {
    availableTools: ['git', 'docker', 'github-actions'],
    constraints:    { timeboxMs: 4 * 60 * 60 * 1000 },
  },
);

Plan shape

ts
interface Plan {
  readonly id:    string;
  goal:           string;
  tasks:          Task[];
  createdAt:      Date;
  metadata: {
    plannerType:               'classical' | 'llm';
    estimatedTotalDurationMs:  number;
    confidence:                number;   // 0.0–1.0
    context?:                  Record<string, unknown>;
  };
}

Task shape

ts
interface Task {
  readonly id:            string;        // e.g. 'task-1'
  readonly name:          string;        // short label
  readonly description:   string;        // what needs to be done
  readonly dependencies:  string[];      // IDs of tasks that must complete first
  readonly priority:      TaskPriority;  // CRITICAL | HIGH | MEDIUM | LOW
  readonly metadata: {
    toolIds?:        string[];   // tools this task needs
    outputKey?:      string;     // key to store result under
    maxRetries?:     number;
    timeoutMs?:      number;
    custom?:         Record<string, unknown>;
  };
  estimatedDurationMs?: number;
}

TaskPriority enum

ValueNumericUse when
CRITICAL0Blocking — everything depends on this
HIGH1Important, should run early
MEDIUM2Standard task
LOW3Nice-to-have, can be deferred

PlanningAlgorithm enum

Used by ClassicalPlanner:

ValueDescription
HIERARCHICALTop-down goal decomposition (default)
BACKWARD_CHAININGWork backward from the goal
FORWARD_CHAININGWork forward from initial state
MEANS_ENDSMeans-ends analysis

Validating a plan

PlanValidator checks that dependencies are acyclic, all referenced task IDs exist, and no tasks are orphaned:

ts
import { PlanValidator } from 'confused-ai/planner';

const validator = new PlanValidator();
const result = await validator.validate(plan);

if (!result.valid) {
  console.error('Plan errors:', result.errors);
}

Iterative refinement

Both planners support feedback-based replanning via replan():

ts
const refinedPlan = await planner.replan(plan, {
  feedback:    'The CI step needs to handle flaky tests — add a retry step.',
  performance: 'ci-step took 45 minutes',
  adaptations: ['add-retry-ci'],
});

ClassicalPlanner config reference

OptionTypeDefaultDescription
algorithmPlanningAlgorithmHIERARCHICALDecomposition algorithm
allowParallelExecutionbooleantrueWhether to allow parallel task execution
maxIterationsnumber10Iteration cap
timeoutMsnumber30_000Planning timeout in ms
heuristicstring'default'Heuristic function name

LLMPlanner config reference

OptionTypeDefaultDescription
temperaturenumber0.7LLM temperature for planning
maxTokensnumber2_000Max tokens per LLM call
allowParallelExecutionbooleantrueWhether to generate parallel tasks
maxIterationsnumber10Max replanning iterations
timeoutMsnumber60_000Planning timeout in ms
systemPromptstringBuilt-inOverride the planning system prompt

PlanContext

Pass optional context to help the planner make better decisions:

ts
interface PlanContext {
  availableTools?:  string[];                // tool names available to execute tasks
  constraints?:     { timeboxMs?: number };  // time budget
  previousPlans?:   Plan[];                  // history of prior plans for this goal
  metadata?:        Record<string, unknown>; // arbitrary context
}

Released under the MIT License.