/** * v2 MVP — LLM Planner ([ref] §3: leader = LLM-planner that splits a DAG + deterministic Coordinator). * Decomposes an objective into N **disjoint-file** sub-tasks via one model completion, then VALIDATES the plan * deterministically (the trust boundary: an LLM proposes, the Coordinator enforces — service[19] leaderless- * leader). Disjoint file-ownership is the invariant that lets workers run in parallel + merge without conflict. * * The model call is injected (`runPlan: prompt → text`) so this is pure + mock-tested; wire.ts binds it to a * real Runner completion. Invalid/overlapping plans throw a clear error → the leader returns plan-failed * (never a half-valid fan-out). */ import type { SubtaskSpec } from "./leader.js"; export interface PlanOptions { /** Max sub-tasks the planner may emit (guards a runaway fan-out). Default 6. */ maxSubtasks?: number; /** Extra repo/context guidance appended to the prompt (e.g. file layout, conventions). */ context?: string; /** Deployment knob ([ref] §11 A6, correctness-first): `false` = never fan out — `routePlan` skips the * router model call entirely and returns the deterministic single route (zero routing cost, zero risk of a * false fan-out). Default (undefined/true) = the router decides. */ fanoutEnabled?: boolean; /** Economic guard threshold ([ref] §7, search[83] ruling): an objective SHORTER than this never reaches * the router — deterministic single (a small task can't be economically decomposable; false-single is the * cheap error side). Default 64 — deliberately below the route corpus's smallest fan-out case. */ minFanoutChars?: number; } /** * Deterministic economic 防灾 guard ([ref] §7 / §11 D2, search [83] ruling (b)): the asymmetry is that a * false fan-out is the -98% disaster while a false single merely runs slower — so every case decidable WITHOUT * the model resolves to single, for free. Pure function (unit-testable); the semantic judgments (sequential/ * coupled/uncertain) stay with the router LLM, and "估不准回 single" is the collapse fallback (B3). */ export declare function economicGuard(objective: string, opts?: PlanOptions): { single: true; reason: string; } | { single: false; }; /** The deterministic SINGLE route: one sub-task owning the whole objective (the same shape the router emits * for its single decision — N=1 runs through the identical leader pipeline). */ export declare function singleRoute(objective: string): SubtaskSpec[]; /** The planning prompt: asks for a strict JSON array of disjoint-file sub-tasks. */ export declare function planPrompt(objective: string, opts?: PlanOptions): string; /** Parse + VALIDATE a planner completion into SubtaskSpec[]. Throws on any violation (disjointness etc.). */ export declare function parsePlan(raw: string, opts?: PlanOptions): SubtaskSpec[]; /** * Deterministically validate an array of sub-tasks (the trust boundary — see file header). Used both for the * LLM planner output AND for caller-supplied `body.subtasks`, which would otherwise skip every invariant: the * `branch` is interpolated into a worker-container shell command (`git checkout -b `), so an * unvalidated branch (`x; curl …|sh`, `` `reboot` ``, `--upload-pack=…`) would inject; and the disjoint-file / * unique-id invariants are what the Coordinator's parallel-merge depends on. Throws on any violation. */ export declare function validateSubtasks(arr: unknown, opts?: PlanOptions): SubtaskSpec[]; /** Run the planner: one model completion → validated disjoint-file sub-tasks. */ export declare function llmPlan(objective: string, runPlan: (prompt: string) => Promise, opts?: PlanOptions): Promise; /** * The DIFFICULTY-ROUTER prompt (search [43], planner-light). Same disjoint-subtask contract as `planPrompt`, * but the model FIRST routes: default to a SINGLE agent (one sub-task owning the whole task) and only fan out * when the objective is CLEARLY + ECONOMICALLY decomposable (disjoint files, independent/non-sequential, each * part buildable without most of the same context). The campaign proved forcing fan-out on a sequential/coupled * task is a -98% disaster, so the bias is firmly toward single. The output is still a plain disjoint-file * sub-task array — a 1-element array IS the single route (the leader runs N=1 through the same pipeline). */ export declare function routePrompt(objective: string, opts?: PlanOptions): string; /** Run the difficulty router: one model completion → a routed plan (1 sub-task = single route, N = fan-out), * validated by `parsePlan` (the same disjointness/shape invariants the Coordinator depends on). */ export declare function routePlan(objective: string, runRoute: (prompt: string) => Promise, opts?: PlanOptions): Promise; /** * Decomposer quality gate ([ref] §5/§11 B1-B3): run the router, and on a rejected/unparseable plan retry * the LLM AT MOST ONCE, then COLLAPSE TO SINGLE (never fail the task on a bad plan — single is almost always * the right fallback, and a false fan-out is the -98% disaster; a plan failure must not be louder than that). * `collapsed` carries the reason (observability: a collapse is a router-quality signal, not silent). */ export declare function routePlanWithFallback(objective: string, runRoute: (prompt: string) => Promise, opts?: PlanOptions): Promise<{ subs: SubtaskSpec[]; collapsed?: string; rawSample?: string; }>; //# sourceMappingURL=planner.d.ts.map