/** * RunController centralises abort + cleanup for a single agent run. It * wraps a single AbortController and exposes a registry of teardown * hooks that fire (LIFO, exactly once) when the run aborts OR ends * normally. Anyone holding the controller can: * * - read `signal` to bail out cooperatively * - call `abort(reason?)` to abort the run * - call `onAbort(fn)` to register a cleanup hook * - call `dispose()` when the run ends normally — this fires the * hooks too, so cleanup runs regardless of outcome * * Hooks must be idempotent and synchronous-or-quick. Errors thrown * inside hooks are caught and surfaced through `errorSink` (or the * console as a last resort) so one bad hook can't block the others. */ export interface RunControllerOptions { /** Optional parent signal — abort propagates from parent → this. */ parentSignal?: AbortSignal | undefined; /** Receives errors thrown by cleanup hooks. Defaults to console.warn. */ errorSink?: (err: unknown, where: string) => void; } export declare class RunController { private readonly ctrl; private readonly hooks; private disposed; private hooksDrained; private readonly errorSink; /** * Shared promise for the in-flight `runHooks()` call. Set by the abort * signal handler or by `dispose()`, whichever fires first. Both callers * await the same promise so abort-triggered async cleanup (session flush, * socket close) completes before `dispose()` resolves. */ private _hooksPromise; constructor(opts?: RunControllerOptions); get signal(): AbortSignal; get aborted(): boolean; abort(reason?: unknown): void; /** * Register a teardown hook. Returns an unsubscribe function so callers * can opt out before the hook fires (e.g. when a tool finishes cleanly * before abort happens). * * If the controller has already drained its hooks (a prior abort() or * dispose() ran), the new hook is fired immediately on a best-effort * basis — otherwise a hook registered after teardown would be silently * dropped and the resource it cleans up would leak. The returned * unsubscribe is a no-op in that case (the hook has already run). Errors * from the immediate run are routed through `errorSink` like any other * cleanup failure. */ onAbort(fn: () => void | Promise): () => void; /** * Fire cleanup hooks and tear down listeners — called when the run * ends *normally* so cleanup happens regardless of outcome. Subsequent * aborts become no-ops. */ dispose(): Promise; /** * Start running hooks (or wait for an already-in-flight run) and return * a promise that settles when all hooks complete. Both the abort signal * handler and `dispose()` call this so they share the same underlying * promise — abort-triggered async cleanup (session flush, socket close) * is guaranteed to finish before `dispose()` resolves. */ private ensureHooksRun; private runHooks; } //# sourceMappingURL=run-controller.d.ts.map