import type { ModelRegistry } from "../config/model-registry.js"; import type { Settings } from "../config/settings.js"; import type { AsyncJobManagerApi } from "../async/index.js"; import type { PreparedExtension } from "../extensibility/extensions/types.js"; import type { PersistedSubagentReviverFactory } from "../registry/agent-lifecycle.js"; import { type AgentRef } from "../registry/agent-registry.js"; import type { AgentSession } from "../session/agent-session.js"; import type { AgentSessionHandle } from "../session/agent-session-handle.js"; import type { ArtifactManagerApi } from "../session/artifacts.js"; import type { CostGateApi } from "../session/cost-gate.js"; import type { AuthStorage } from "../session/auth-storage.js"; import { type PersistedSessionInit } from "../session/session-manager.js"; import type { EventBus } from "../utils/event-bus.js"; import { type RestoredSeanceSession } from "./seance.js"; import type { AgentDefinition } from "./types.js"; /** * Ambient context the reviver needs at revive time. The top-level session is * kept LIVE (cwd / artifact manager read on demand) so a later `/new` or cwd * move is followed rather than snapshotted; auth/models/settings are * process-stable and captured by reference. */ export interface PersistedSubagentReviveContext { session: AgentSession; authStorage: AuthStorage; modelRegistry: ModelRegistry; settings: Settings; /** LSP policy of the top-level session; revived subagents inherit it rather than defaulting on. */ enableLsp: boolean; /** * Shared event bus feeding RPC/collab subagent subscriptions. Passed through * to the wake-turn monitor so an IRC send to a cold-revived subagent emits * the same lifecycle/progress frames a live run does. */ eventBus?: EventBus; /** Root-scoped observability bus the revived run's frames also publish to. */ subagentEventBus?: EventBus; } /** * Everything one cold revive of a persisted subagent needs, built on main per revive and * cloneable (live objects cross as their bridged proxies), so the session can be created * on main or inside a pooled worker alike. */ export interface PersistedReviveSpec { readonly id: string; readonly displayName: string; readonly parentId: string | undefined; readonly sessionFile: string; /** Depth derived from the persisted parent chain (drives capability gating). */ readonly taskDepth: number; /** The consulted source of a persisted seance session. */ readonly restoredSeance: RestoredSeanceSession | undefined; /** The live top-level session revived agents join (cwd, extension roots, parent grants). */ readonly root: AgentSessionHandle; /** Registry id of {@link root}. */ readonly rootAgentId: string; readonly costGate: CostGateApi; readonly asyncJobManager: AsyncJobManagerApi | undefined; /** The root's artifact manager at revive time; a revived non-seance agent adopts it. */ readonly artifactManager: ArtifactManagerApi | undefined; readonly preparedExtensions: readonly PreparedExtension[] | undefined; readonly authStorage: AuthStorage; readonly modelRegistry: ModelRegistry; readonly settings: Settings; readonly enableLsp: boolean; readonly eventBus: EventBus | undefined; readonly subagentEventBus: EventBus | undefined; } /** * Durable agent definition name (`scout`, `reviewer`, …) of a persisted subagent. * Cold-revived refs register with `displayName: id` (`registry/persisted-agents.ts`), * so a generated task id would silently drop agent-scoped rules and budgets. * `init.agent` carries the real name; only files predating that field fall back to * `displayName`. A parked transcript may also predate the `main`/`sub` definition-name * reservation (`discovery/helpers.ts`): a persisted `init.agent` of either sentinel * value from such a legacy custom agent must not masquerade as that sentinel, so it * falls back to `displayName` too, keeping it scoped as an ordinary subagent under its * generated id instead of `main` or the shared `sub` bucket. */ export declare function persistedAgentName(displayName: string, init: PersistedSessionInit): string; /** * The agent definition a cold-revived subagent's monitored turns report (IRC wakes, * `omp --restore`): persisted files predate an agent-source field, so frames carry * the runtime-neutral `user` source; the name is the registry ref's. */ export declare function persistedAgentDefinition(displayName: string, init: PersistedSessionInit): AgentDefinition; /** * Build the factory the {@link AgentLifecycleManager} uses to cold-revive a * `parked` subagent ref restored from disk (Agent Hub scan, collab mirror, or a * resumed process). Such a ref carries a sessionFile but no in-memory adoption — * the executor's live reviver closure died with the process/turn that spawned * it — so `ensureLive` (IRC sends, hub focus) would otherwise refuse it. * * This rebuilds the subagent the same way `--resume` rebuilds a session: reopen * the JSONL and replay it through {@link createAgentSession}. The catch is that * resume restores only conversation/model from the file — the runtime contract * (tools / system prompt / output schema / kind) is built from options, so a * bare reopen would resurrect a wrong (top-level) session. We source that * contract from the persisted `session_init` entry instead, and mirror the * executor's subagent wiring (MCP proxy tools, depth-derived gating, * yield-required, active-tool clamp, registry status sync). */ export declare function createPersistedSubagentReviverFactory(ctx: PersistedSubagentReviveContext): PersistedSubagentReviverFactory; /** * Rebuild the persisted subagent of `spec` on the calling thread (main, or the pooled * worker that will home it) and claim `expectedRef` for it. */ export declare function revivePersistedSubagent(spec: PersistedReviveSpec, expectedRef: AgentRef): Promise;