/** * agent-manager.ts — Tracks agents, background execution, resume support. * * Background agents are subject to a configurable concurrency limit (default: 4). * Excess agents are queued and auto-started as running agents complete. * Foreground agents bypass the queue (they block the parent anyway). */ import type { Api, Model } from "@earendil-works/pi-ai"; import type { AgentSession, ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent"; import { type ToolActivity } from "./agent-runner.js"; import type { AgentRecord, IsolationMode, RunnerBackend, SubagentType, ThinkingLevel } from "./types.js"; export type OnAgentComplete = (record: AgentRecord) => void; export type OnAgentStart = (record: AgentRecord) => void; export interface SpawnOptions { description: string; model?: Model; maxTurns?: number; isolated?: boolean; inheritContext?: boolean; thinkingLevel?: ThinkingLevel; runnerBackend?: RunnerBackend; isBackground?: boolean; /** Whether this run may block on ask_parent. Defaults to background runs only. */ allowAskParent?: boolean; /** Isolation mode — "worktree" creates a temp git worktree for the agent. */ isolation?: IsolationMode; /** Parent abort signal — when aborted, the subagent is also stopped. */ signal?: AbortSignal; /** Extra tools available only for this agent run. */ customTools?: ToolDefinition[]; /** Called on tool start/end with activity info (for streaming progress to UI). */ onToolActivity?: (activity: ToolActivity) => void; /** Called on streaming text deltas from the assistant response. */ onTextDelta?: (delta: string, fullText: string) => void; /** Called when the agent session is created (for accessing session stats). */ onSessionCreated?: (session: AgentSession) => void; /** Called at the end of each agentic turn with the cumulative count. */ onTurnEnd?: (turnCount: number) => void; } export declare class AgentManager { private readonly agents; private readonly cleanupInterval; private readonly onComplete?; private readonly onStart?; private maxConcurrent; /** Queue of background agents waiting to start. */ private queue; /** Number of currently running background agents. */ private runningBackground; constructor(onComplete?: OnAgentComplete, maxConcurrent?: number, onStart?: OnAgentStart); /** Update the max concurrent background agents limit. */ setMaxConcurrent(n: number): void; getMaxConcurrent(): number; /** * Spawn an agent and return its ID immediately (for background use). * If the concurrency limit is reached, the agent is queued. */ spawn(pi: ExtensionAPI, ctx: ExtensionContext, type: SubagentType, prompt: string, options: SpawnOptions): string; /** Actually start an agent (called immediately or from queue drain). */ private startAgent; /** Start queued agents up to the concurrency limit. */ private drainQueue; /** * Spawn an agent and wait for completion (foreground use). * Foreground agents bypass the concurrency queue. */ spawnAndWait(pi: ExtensionAPI, ctx: ExtensionContext, type: SubagentType, prompt: string, options: Omit): Promise; /** * Resume an existing agent session with a new prompt. */ resume(id: string, prompt: string, signal?: AbortSignal): Promise; getRecord(id: string): AgentRecord | undefined; listAgents(): AgentRecord[]; abort(id: string): boolean; private disposeBridgeState; /** Dispose a record's session and remove it from the map. */ private removeRecord; private cleanup; /** * Remove all completed/stopped/errored records immediately. * Called on session start/switch so tasks from a prior session don't persist. */ clearCompleted(): void; /** Whether any agents are still running or queued. */ hasRunning(): boolean; /** Abort all running and queued agents immediately. */ abortAll(): number; /** Wait for all running and queued agents to complete (including queued ones). */ waitForAll(): Promise; dispose(): void; }