/** * Warm subagent worker pool (experimental, opt-in via `--warm-subagents` / * settings.warmSubagents; default off). * * The cold path (SubagentPool) re-execs the whole CLI for every dispatch, paying * a full module-load + resource-graph boot each time. A warm worker instead keeps * a long-lived child running in RPC mode and hands it one task at a time over the * existing JSON-line protocol: `new_session` resets its conversation between * tasks, `prompt` runs the task, and `agent_end` on the event stream signals * completion, after which the answer + usage are pulled inline (no result.json * disk round-trip, no OutputVerifier). The first task per worker still pays the * boot; every reuse after that skips it. * * Scope/limits (deliberately conservative — see the dispatch integration): * - Workers are pinned per agent type: RPC has no per-prompt system-prompt/tools * swap, so each (agentType, model, provider) is its own worker config. * - Only non-resume, non-fork dispatches are eligible; resume/fork need a * persisted/forked session the warm path does not own. * - Any worker/infra failure falls back to the cold pool, so enabling this can * only change latency, never whether a task can run. */ import type { Api, Model } from "@kolisachint/hoocode-ai"; import { type AgentRegistry } from "./agent-registry.js"; import type { Settings } from "./settings-manager.js"; /** Usage totals pulled from a worker after a task, shaped like SubagentResultFile.usage. */ export interface WarmUsage { input: number; output: number; cacheRead: number; cacheWrite: number; cost: number; } /** Outcome of running one task on a warm worker. */ export interface WarmRunResult { ok: boolean; status: "complete" | "failed"; /** The subagent's final assistant text (its answer to the caller). */ summary: string; usage?: WarmUsage; error?: string; } /** Per-dispatch inputs that select and configure a worker. */ export interface WarmDispatchOptions { agentType: string; cwd: string; /** Model id or category (fast/standard/capable); resolved to a concrete id. */ model?: string; provider?: string; } /** Reports the tool a warm worker is currently running ("" = idle between tools). */ export type WarmProgressCallback = (activity: string) => void; /** A run failed at the infrastructure level (worker crash, timeout, protocol error). */ export declare class WarmWorkerError extends Error { } /** * One long-lived RPC child pinned to a single agent-type configuration. Reused * across tasks via reset(); a crash makes it not-alive so the pool discards it. */ export declare class WarmSubagentWorker { readonly key: string; private readonly env; private readonly client; private alive; constructor(key: string, options: WarmDispatchOptions, env: NodeJS.ProcessEnv, registry: AgentRegistry, skillPaths: readonly string[], settings: Settings | undefined, availableModels: readonly Model[], /** Spawn command override (tests inject a fake RPC child); defaults to the real spawn command. */ spawnCommand?: { executable: string; prefixArgs: string[]; }); /** Boot the child. Throws (as WarmWorkerError) if it fails to come up. */ start(): Promise; isAlive(): boolean; /** * Run one task to completion and return its answer + usage. Throws * WarmWorkerError on an infra failure (crash/timeout/protocol) so the caller * can fall back to the cold pool; a task that ran but reported failure returns * `{ ok: false }` instead (no fall back — the work was actually done). */ run(prompt: string, onActivity?: WarmProgressCallback, timeoutMs?: number): Promise; /** Forward the child's coarse tool-lifecycle events to an activity callback. */ private tapProgress; /** Reset the worker's conversation so it can take the next task cleanly. */ reset(): Promise; dispose(): Promise; private readUsage; } /** * Pool of warm workers keyed by agent-type configuration. Hands out an idle * worker (or boots a new one up to a per-key cap), and on release resets the * worker and returns it to the idle set with an idle-TTL reclaim timer. */ export declare class WarmSubagentPool { private readonly cwd; private readonly settings; private skillPaths; /** * Available models used to derive default model-category mappings when a tier * is not explicitly set in `settings.modelCategories` (snapshot at creation). */ private readonly availableModels; private readonly maxPerKey; private readonly idleTtlMs; /** Spawn command override (tests inject a fake RPC child); defaults to the real spawn command. */ private readonly spawnCommand?; private idle; private reclaimTimers; private liveCount; private disposed; private registry?; constructor(cwd: string, settings: Settings | undefined, skillPaths?: string[], /** * Available models used to derive default model-category mappings when a tier * is not explicitly set in `settings.modelCategories` (snapshot at creation). */ availableModels?: readonly Model[], maxPerKey?: number, idleTtlMs?: number, /** Spawn command override (tests inject a fake RPC child); defaults to the real spawn command. */ spawnCommand?: { executable: string; prefixArgs: string[]; } | undefined); updateSkillPaths(paths: string[]): void; private getRegistry; /** A registry agent is poolable when it is not a fork agent (fork needs a forked session). */ isPoolable(agentType: string): boolean; /** Stable key for one worker configuration. */ private keyFor; /** Environment for a warm child: depth stamp + MCP skip, mirroring SubagentPool.childSpawnEnv. */ private childEnv; /** * Run a task on a warm worker end to end: acquire (reuse or boot), run, then * release back to the pool. Throws WarmWorkerError on infra failure so the * caller can fall back to the cold pool. */ dispatch(prompt: string, options: WarmDispatchOptions, onActivity?: WarmProgressCallback): Promise; private acquire; private release; private discard; private armReclaim; private clearReclaim; private incLive; private decLive; /** Number of currently idle (parked) workers — exposed for tests/diagnostics. */ idleCount(): number; dispose(): Promise; } //# sourceMappingURL=warm-subagent-pool.d.ts.map