/** * Goal Decomposer — LLM-powered goal → task DAG → parallel execution * * Provides the `runTeam()` one-liner: describe a goal in plain English, * specify which agents to use, and let an LLM plan the task graph. * Execution respects all Network-AI guardrails (budgets, permissions, audit). * * Zero external dependencies — LLM calls go through the adapter system. * * @module GoalDecomposer * @version 1.0.0 */ import { EventEmitter } from 'events'; import type { AgentPayload, AgentContext, AgentResult } from '../types/agent-adapter'; import type { ScopeMetadata } from './context-throttler'; import type { PartitionSchema } from './partition-planner'; import type { CoverageGate } from './coverage-gate'; import type { RouteClassifier } from './route-classifier'; /** A single node in the task DAG */ export interface TaskNode { /** Unique task identifier */ id: string; /** Human-readable description of the task */ description: string; /** Agent ID (or pool/template) to execute this task */ agent: string; /** Action to invoke on the agent */ action: string; /** Parameters for the action */ params: Record; /** IDs of tasks that must complete before this one starts */ dependencies: string[]; /** Priority (higher = more urgent) */ priority: number; /** Execution status */ status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped'; /** Result after execution */ result?: AgentResult; /** Optional fallback agent to run if this task's primary agent fails. */ fallbackAgent?: string; /** The fallback agent that served this task, if the primary failed. */ fellBackTo?: string; /** Error message if failed */ error?: string; /** Timestamps */ startedAt?: number; completedAt?: number; } /** Directed acyclic graph of tasks */ export interface TaskDAG { /** The original goal */ goal: string; /** All task nodes */ nodes: TaskNode[]; /** Adjacency list: taskId → downstream task IDs */ edges: Map; /** When the DAG was created */ createdAt: number; } /** Configuration for an agent available to the team */ export interface TeamAgent { /** Agent ID (must match an adapter-registered agent or be resolvable by the executor) */ id: string; /** What this agent can do (fed to LLM for planning) */ role: string; /** Which adapter handles this agent */ adapter?: string; /** Default action to invoke */ defaultAction?: string; /** Default parameters */ defaultParams?: Record; /** * Scope metadata tags for ContextThrottler — the agent will only receive * blackboard keys that match at least one of these tags. * Use `['*']` to opt out of filtering (see ContextThrottler). */ scopeMetadata?: ScopeMetadata; } /** Function that invokes an LLM to produce a decomposition plan */ export type PlannerFunction = (goal: string, agents: TeamAgent[], context?: Record) => Promise; /** Output from the planner (LLM-generated) */ export interface PlannedTask { id: string; description: string; agent: string; action: string; params: Record; dependencies: string[]; priority?: number; } /** Function that executes a single task via the adapter system */ export type ExecutorFunction = (agentId: string, payload: AgentPayload, context: AgentContext) => Promise; /** Options for `runTeam` */ export interface RunTeamOptions { /** Maximum number of tasks to run in parallel (default: 5) */ concurrency?: number; /** Timeout per task in ms (default: 30000) */ taskTimeout?: number; /** Timeout for the entire run in ms (default: 300000) */ totalTimeout?: number; /** Whether to continue executing tasks after one fails (default: false) */ continueOnFailure?: boolean; /** * Same-agent retries per task before falling back to the task's `fallbackAgent` * (default: 0). Budgeted per task, so one task's retries never starve another's. */ retriesPerTask?: number; /** Session ID for context propagation */ sessionId?: string; /** Arbitrary metadata passed to agent contexts */ metadata?: Record; /** Maximum LLM retries for planning (default: 1) */ plannerRetries?: number; /** Callback for approval before execution starts */ approvalCallback?: (dag: TaskDAG) => Promise; /** * Maximum sub-goal recursion depth (default: 1 — no recursion). * * When a task node has `params._subgoal: string` AND a `subGoalDecomposer` * is provided, the runner will recursively decompose and execute the sub-goal * as a nested `TeamRunner.run()` call, up to this depth limit. */ maxDepth?: number; /** * Current recursion depth. Set automatically by the runner — do not set manually. * @internal */ depth?: number; /** * Agent pool available for recursive sub-goal decomposition. * Must be provided when `maxDepth > 1`. */ agents?: TeamAgent[]; /** * GoalDecomposer instance used to plan recursive sub-goals. * Must be provided when `maxDepth > 1`. */ subGoalDecomposer?: GoalDecomposer; /** * When provided, the RouteClassifier is run before DAG planning. * If the goal is classified as FACTUAL_LOOKUP the DAG is bypassed entirely * and the result is returned immediately. * If classified as SYSTEM_FAILURE an error is thrown. */ routeClassifier?: RouteClassifier; /** * Agent ID to use for the short-circuit FACTUAL_LOOKUP path. * Required when `routeClassifier` is provided and you want short-circuit execution. */ lookupAgentId?: string; /** * Partition schema to inject as boundary constraints into each agent's params. * Generate via `PartitionPlanner.plan()` before calling `runTeam()`. */ partitionSchema?: PartitionSchema; /** * When provided, the CoverageGate is evaluated after the DAG completes. * If the score is below threshold the gaps are fed back into the GoalDecomposer * and another round of execution is triggered (up to `gate.maxRefinements`). * Requires a blackboard snapshot supplier via `blackboardSnapshot`. */ coverageGate?: CoverageGate; /** * Function that returns the current blackboard snapshot for CoverageGate evaluation. * Called after each DAG execution round. */ blackboardSnapshot?: () => Record; } /** Final result from a team run */ export interface TeamResult { /** Whether the overall goal was achieved */ success: boolean; /** The task graph that was executed */ dag: TaskDAG; /** Aggregated results from all completed tasks */ results: Map; /** Summary of what happened */ summary: string; /** Total execution time in ms */ durationMs: number; /** Count of tasks by status */ stats: { total: number; completed: number; failed: number; skipped: number; }; } /** Events emitted during a team run */ export interface TeamRunnerEvents { 'dag:created': (dag: TaskDAG) => void; 'task:start': (node: TaskNode) => void; 'task:complete': (node: TaskNode, result: AgentResult) => void; 'task:fail': (node: TaskNode, error: string) => void; 'task:skip': (node: TaskNode, reason: string) => void; 'run:complete': (result: TeamResult) => void; } /** * Validate that a set of planned tasks forms a valid DAG (no cycles, valid refs). * @throws Error if the graph contains cycles or invalid dependency references */ export declare function validateDAG(tasks: PlannedTask[]): void; /** * Compute topological layers — tasks in the same layer can execute in parallel. * Returns arrays of task IDs grouped by execution layer. */ export declare function topologicalLayers(tasks: PlannedTask[]): string[][]; /** * Create a planner function that uses an LLM (via executor) to decompose goals. * * The planner sends a structured prompt to the specified agent and parses * the JSON response into PlannedTask[]. Falls back gracefully on parse errors. * * @param executor - Function to call the LLM agent * @param plannerAgent - Agent ID for the LLM that does planning * @param plannerAdapter - Adapter name (optional, defaults to agent's adapter) */ export declare function createLLMPlanner(executor: ExecutorFunction, plannerAgent: string): PlannerFunction; /** * Parse JSON from an LLM response string, handling markdown fences and preamble. */ export declare function parsePlanJSON(text: string): PlannedTask[]; /** * LLM-powered goal decomposition engine. * * Takes a natural language goal, creates a task DAG via an LLM planner, * validates the graph, and returns a ready-to-execute TaskDAG. */ export declare class GoalDecomposer { private planner; constructor(planner: PlannerFunction); /** * Decompose a goal into a validated TaskDAG. * @param goal - Natural language description of the goal * @param agents - Available team agents * @param context - Optional context to feed to the planner * @param retries - Number of retries on planning failure (default: 1) */ decompose(goal: string, agents: TeamAgent[], context?: Record, retries?: number): Promise; } /** * Executes a TaskDAG by running tasks in parallel layers, respecting * dependencies, concurrency limits, and timeouts. * * @example * ```typescript * const runner = new TeamRunner(executor); * const result = await runner.run(dag, { concurrency: 3 }); * console.log(result.summary); * ``` */ export declare class TeamRunner extends EventEmitter { private executor; constructor(executor: ExecutorFunction); /** * Execute a TaskDAG with parallel scheduling. */ run(dag: TaskDAG, options?: RunTeamOptions): Promise; /** * Run a single task with a per-task retry budget, then its own fallback agent. * * Retries are isolated to this task (per request, not per session). Timeouts * and thrown errors count as failed attempts so a retry or fallback can follow. * * @internal */ private runTaskResilient; } /** * Decompose a goal into tasks and execute them with a team of agents. * * This is the main entry point — one line to go from goal to results: * * ```typescript * const result = await runTeam( * "Build a REST API for user management", * [ * { id: "architect", role: "System design and API specification" }, * { id: "coder", role: "Write TypeScript code" }, * { id: "reviewer", role: "Code review and quality checks" }, * ], * { planner, executor } * ); * ``` * * @param goal - Natural language description of what to achieve * @param agents - Team of agents available for task execution * @param config - Planner (LLM decomposition) and executor (agent invocation) functions * @param options - Optional concurrency, timeout, and failure handling settings * @returns Full result with DAG, individual results, and stats */ export declare function runTeam(goal: string, agents: TeamAgent[], config: { planner: PlannerFunction; executor: ExecutorFunction; }, options?: RunTeamOptions): Promise; //# sourceMappingURL=goal-decomposer.d.ts.map