/** * Adaptive Execution Planner. * * Scores and selects execution strategies based on risk, latency, and * capability inputs. Emits typed reason codes for every decision and * maintains an explicit override path that is logged in full. * * Commands: /plan mode auto|single|cohort|background|remote * /plan explain * /plan override */ import { type PlanProposal, type PlanProposalIssue, type RawDecomposition } from './plan-proposal.js'; /** * The five supported execution strategies. * * - `auto` , planner selects the best strategy each turn * - `single` , one LLM call, no parallelism or agents * - `cohort` , fan-out to a coordinated agent cohort * - `background`, defer execution to a background task * - `remote` , delegate to a remote provider/agent endpoint */ export type ExecutionStrategy = 'auto' | 'single' | 'cohort' | 'background' | 'remote'; /** All valid strategy names (including 'auto'). Exported for use in command handlers. */ export declare const VALID_STRATEGIES: ExecutionStrategy[]; /** * Typed reason codes emitted with every strategy decision. * * Each code maps to a human-readable explanation available via * `AdaptivePlanner.explainReasonCode()`. */ export type StrategyReasonCode = 'OVERRIDE_IN_EFFECT' | 'HIGH_RISK_SINGLE_PREFERRED' | 'LOW_LATENCY_SINGLE' | 'COHORT_CAPABLE' | 'BACKGROUND_DEFERRED' | 'REMOTE_CAPABLE' | 'AUTO_FALLBACK_SINGLE' | 'USER_OVERRIDE' | 'FLAG_DISABLED' | 'INVALID_STRATEGY'; /** Inputs used by the scorer to rank strategy candidates. */ export interface PlannerInputs { /** 0-1 risk score: 0 = safe, 1 = highly uncertain / destructive */ riskScore: number; /** * Available wall-clock budget in milliseconds. * `Infinity` means no latency constraint. */ latencyBudgetMs: number; /** Whether the task is classified as multi-step/project (cohort eligible). */ isMultiStep: boolean; /** Whether a remote agent endpoint is currently available. */ remoteAvailable: boolean; /** Whether the task can be safely deferred to a background queue. */ backgroundEligible: boolean; /** Free-form task description (used for logging and explain output). */ taskDescription?: string | undefined; } /** A ranked strategy candidate produced by the scorer. */ export interface StrategyCandidate { strategy: ExecutionStrategy; score: number; reasonCode: StrategyReasonCode; } /** * The outcome of the deterministic "does this task warrant decomposition?" * gate. This is a semantic projection of the existing strategy selection, * `decompose` is simply `selected !== 'single'`, so every existing reason * code and the `/plan explain` output stay authoritative. No new scoring * logic lives here. */ export interface DecompositionGate { decompose: boolean; strategy: ExecutionStrategy; reasonCode: StrategyReasonCode; } /** The outcome of a planner selection pass. */ export interface PlannerDecision { /** The strategy that was ultimately selected. */ selected: ExecutionStrategy; /** Primary reason code for the selection. */ reasonCode: StrategyReasonCode; /** Full ranked list of all evaluated candidates. */ candidates: StrategyCandidate[]; /** Whether a user override was in effect when this decision was made. */ overrideActive: boolean; /** Unix timestamp (ms) of this decision. */ timestamp: number; /** Snapshot of inputs used for this decision. */ inputs: PlannerInputs; } export declare class AdaptivePlanner { /** Current user override, or null when the planner runs freely. */ private overrideStrategy; /** Current operating mode (default: auto). */ private mode; /** Audit log of all decisions, capped at MAX_HISTORY entries. */ private history; private static readonly MAX_HISTORY; /** * Select the best execution strategy for the given inputs. * * - If a user override is active, it is returned immediately with reason * `OVERRIDE_IN_EFFECT`. * - If mode is not `auto`, the mode itself is returned (as a pinned choice). * - Otherwise all concrete strategies are scored and the highest wins. * * The decision is appended to the history log. */ select(inputs: PlannerInputs): PlannerDecision; /** * Deterministic gate: does this task warrant decomposition into a * multi-phase workstream, or is a single-item workstream the honest * answer? * * This calls the existing `select()` pipeline, no new scoring logic, and * projects the result: `decompose` is `selected !== 'single'`. Because it * goes through `select()`, the decision is appended to the same audit * history as every other planner call, and `/plan explain` / `/plan * status` remain authoritative for it. */ shouldDecompose(inputs: PlannerInputs): DecompositionGate; /** * Produce a typed `PlanProposal` for the given inputs. * * `AdaptivePlanner` never spawns a planning agent and never performs LLM * decomposition itself, it only gates (via `shouldDecompose`) and * validates/assembles (via `assemblePlanProposal`, in `plan-proposal.ts`). * The raw decomposition, if any, is expected to come from a planning * agent that the ORCHESTRATION ENGINE spawns and hands back here. * * - If the gate says decomposition is not warranted, or no raw * decomposition is available yet, this returns the honest single-item * fallback (`singleItemProposal`), never a partially-assembled guess. * - Otherwise it validates `raw` via `assemblePlanProposal`, which never * throws: malformed decompositions degrade to an honest partial result * plus a list of `issues`. * * Returns the `gate` alongside the proposal so callers (the engine, or the * TUI) can show WHY a proposal was or wasn't decomposed, reusing * `AdaptivePlanner.explainReasonCode`. */ proposeWorkstream(inputs: PlannerInputs, raw?: RawDecomposition): { proposal: PlanProposal; gate: DecompositionGate; issues: PlanProposalIssue[]; }; /** * Set the operating mode for future calls to `select()`. * * Setting to `'auto'` clears any pinned mode (but does NOT clear a user * override, use `clearOverride()` for that). */ setMode(mode: ExecutionStrategy): void; /** Get the current operating mode. */ getMode(): ExecutionStrategy; /** * Apply an explicit user override. Overrides are stronger than mode: even * in `auto` mode the override strategy is always returned until cleared. * * Returns `false` with reason `INVALID_STRATEGY` if the strategy name is * not recognised. */ override(strategy: string): { ok: true; strategy: ExecutionStrategy; } | { ok: false; reasonCode: StrategyReasonCode; }; /** Clear any active user override. */ clearOverride(): void; /** Whether a user override is currently active. */ hasOverride(): boolean; /** Return the active override strategy, or null. */ getOverride(): ExecutionStrategy | null; /** * Return a human-readable explanation of the most recent decision, or of * a specific reason code. */ explain(reasonCode?: StrategyReasonCode): string; /** Return the full static explanation for a reason code. */ static explainReasonCode(code: StrategyReasonCode): string; /** Return the N most recent decisions (default: 20). */ getHistory(limit?: number): PlannerDecision[]; /** Return the most recent decision, or null. */ getLatest(): PlannerDecision | null; /** * Validate and clamp PlannerInputs to safe ranges. * Logs a debug warning if any value is out of range. */ private _validateInputs; private _appendHistory; private _formatDecisionExplanation; } //# sourceMappingURL=adaptive-planner.d.ts.map