/** * Adaptive spawn cadence for the Plan stage. * * The Plan stage launches four scout subagents and three reviewer subagents. * Firing them all in one burst can trigger provider 429 rate limits; firing * them strictly serially is wasteful for users with healthy quotas. This * module records a per-project tier that the Plan-stage prompt consults: * * A — Parallel burst: launch all N at once. (default start) * B — Staggered: launch one, sleep 5s, launch the next. * C — Batch-2: launch 2, sleep 10s, launch next 2. * D — Fully serial: launch one, wait for artifact, launch the next. * * Demotion triggers (rate-limit-style errors only — NOT auth, network, or * tool bugs, since slower spawning will not fix those): * - "429" or "rate limit" / "rate-limited" / "overload" in any subagent result * - 5xx server errors (500/502/503/504) * - "stopReason: error" surfaced by pi-interactive-subagents v3.7.2+ * * Promotion triggers: 3 consecutive clean Plan-stage approvals (B→A, C→B). * Tier D is the floor and requires manual `/senai-cadence-reset` to escape. * * State lives at `.IDE_Plans/pi-senai/spawn-cadence.json`. Writes go through * atomic-write so a crashed session never leaves a half-written file. */ export type CadenceTier = "A" | "B" | "C" | "D"; export interface CadenceHistoryEntry { ts: string; from: CadenceTier; to: CadenceTier; reason: string; } export interface CadenceState { _comment?: string; version: number; tier: CadenceTier; consecutiveCleanRuns: number; last429At: string | null; lastPromotableAt: string | null; history: CadenceHistoryEntry[]; } /** Clean runs required to promote one tier (B→A, C→B). */ export declare const PROMOTE_AFTER_CLEAN = 3; /** Clean runs required to escape tier D (D→C). D is otherwise the floor. */ export declare const D_FLOOR_CLEAN = 7; /** Max history entries (FIFO). */ export declare const HISTORY_CAP = 50; /** Matches rate-limit-style errors in any text. Conservative — only flags * unambiguous provider-overload signals. */ export declare const RATE_LIMIT_RE: RegExp; /** Return a fresh default state. Useful for tests and first-run creation. */ export declare function defaultCadenceState(): CadenceState; /** Load cadence state from disk. Returns the default state when the file is * missing or corrupt; never throws. */ export declare function loadCadenceState(cwd: string): CadenceState; /** Persist cadence state atomically. */ export declare function saveCadenceState(cwd: string, state: CadenceState): void; /** Record a clean Plan-stage completion. Promotes one tier after * PROMOTE_AFTER_CLEAN consecutive clean runs; B→A and C→B qualify. * Tier A has no promotion target. Tier D requires D_FLOOR_CLEAN clean * runs AND a manual `/senai-cadence-reset`; this function only stamps * `lastPromotableAt` and does NOT auto-promote D→C. * Returns the updated state (also persisted). */ export declare function recordCleanRun(cwd: string, now?: Date): CadenceState; /** Record a rate-limit-style error. Demotes one tier; A→B, B→C, C→D. * Tier D is the floor — no further demotion. Resets the clean-run counter. * Returns the updated state (also persisted). */ export declare function record429(cwd: string, now?: Date): CadenceState; /** Reset cadence to tier A and clear all counters. Returns the new state. */ export declare function resetCadence(cwd: string, now?: Date): CadenceState; /** Returns true if `text` matches the rate-limit-style error regex. */ export declare function isRateLimitError(text: string): boolean; /** Build the markdown block injected into the Plan-stage prompt. Tells the * parent LLM which dispatch rule to apply for this run, and how to recover * from a mid-run rate-limit error. */ export declare function buildCadenceBlock(state: CadenceState): string;