/** * Subagent Delegation Extension for Spectral * * Registers a `subagent` tool that allows the coding agent to delegate tasks * to specialized sub-agents running in-process via `agentLoop()`. * * Each subagent invocation runs with its own fresh AgentContext (isolated * context window), keeping the main conversation lean and focused. * * Three execution modes: * - Single: { agent: "name", task: "..." } * - Parallel: { tasks: [{ agent, task }, ...] } (max 8, 4 concurrent) * - Chain: { chain: [{ agent, task: "... {previous} ..." }, ...] } * * Agents come from two sources only: * - Built-in system agents (SYSTEM_AGENTS, read-only) * - Cloud agents from the backend cache (managed in Aexol Studio /agents) * * Subagents use an in-process `agentLoop()` for: * - Clean context isolation (fresh messages array) * - Combined system prompt (shared/base prompt + subagent-specific instructions) * - Tool filtering (only the tools specified in agent config) * - Model selection (agent-configured model preferred, session model as * fallback) * - Signal propagation (abort passthrough) * - Access to observational memory via the `recall` and * `write_project_observation` tools, which run against a parent-session * point-in-time snapshot (branch + session id). `receive_agent_observations` * also runs inside subagents but polls with a DISTINCT derived * observation session id (never the bare parent id); `share_project_observation`, * `compact_context`, and `subagent` remain excluded */ import type { AgentEvent, AgentTool } from "../sdk/agent-core/index.js"; import { type ExtensionAPI, type ExtensionContext } from "../sdk/coding-agent/index.js"; import { type AgentConfig } from "./agents.js"; import type { ServerEvent } from "../server/wire.ts"; import { type TpsUsageFields } from "../server/agent-bridge/tps-metrics.ts"; import type { ReadonlySessionManager } from "../sdk/coding-agent/core/session-manager.js"; /** * Build the system prompt for a subagent session. * * The host session's base prompt may already contain an injected primary-agent * block (`# Primary Agent: ...` followed by an optional `\n\n---\n\n` delimiter). * A subagent must not inherit the host's primary agent, so the existing block is * stripped and replaced by the subagent's own primary-agent block (appended * below the base). Any content before or after the primary block (provider * preamble, shared base prompt) is preserved. */ export declare function buildSubagentSystemPrompt(baseSystemPrompt: string | undefined, agent: Pick): string; /** * Give subagents a point-in-time branch view without exposing the live parent * SessionManager. Each getBranch call returns fresh clones of the snapshot. */ export declare function createSubagentSessionManagerSnapshot(sessionManager: ExtensionContext["sessionManager"]): Pick; export declare function resolveSubagentTools(cwd: string, ext: ExtensionAPI, ctx: ExtensionContext, agentName?: string): AgentTool[]; /** * Runs a child agent with an independent per-subagent timeout. * * Combines the parent's abort signal with a fresh timeout AbortController so * that no single subagent can exhaust the parent prompt's full timeout budget. * The budget covers the WHOLE child run including any resume retries (see * `runSingleAgent`), so wall time stays bounded by SUBAGENT_TIMEOUT_MS. * On timeout, returns a clear error result instead of throwing so the parent * agent can continue (e.g. stop a chain, or surface the error as the tool * result for parallel/single modes). */ /** * LIVE TPS snapshot emitted by the subagent runner after each LLM round that * produced tokens (subagent_progress contract). Carried through * `onInternalEvent` alongside real `AgentEvent`s; the subagent extension maps * it to the `subagent_tps` wire event for the bridge, which folds it into the * throttled `subagent_progress` frames keyed by the parent tool call id. */ export interface SubagentTpsSnapshotEvent { type: "subagent_tps_snapshot"; /** Token-weighted TPS fields so far (omitted fields = no sound data yet). */ tps: TpsUsageFields; } /** Internal events the subagent runner forwards through `onInternalEvent`. */ export type SubagentInternalEvent = AgentEvent | SubagentTpsSnapshotEvent; /** Test hook: replace the run-level retry sleep (e.g. with an instant/collecting stub). */ export declare function setSubagentRetrySleepForTesting(fn?: (ms: number, signal?: AbortSignal) => Promise): void; /** * Resolve the max number of child-run attempts for the run-level retry loop. * An explicit tool param (clamped to 0-10) overrides everything — including a * globally disabled retry switch. Without the param, the session default * (7 retries) applies unless retry is explicitly disabled, in which case a * single attempt is made. */ export declare function resolveSubagentMaxAttempts(explicit: number | undefined, settings: { enabled?: boolean; maxRetries?: number; } | undefined): number; export default function subagentExtension(ext: ExtensionAPI, opts?: { disabledAgents?: string[]; emitSubagentEvent?: (event: ServerEvent) => void; teamId?: string; /** * Resolve the session's active primary-agent name on each tool call * (mirrors the bridge's per-turn primary-injection logic). The * subagent uses it to scope name resolution to the primary's * subtree so same-named subagents under different primaries resolve * to the caller's own subtree. Returns null when no primary applies. */ resolveActivePrimaryName?: () => string | null | undefined; }): void; //# sourceMappingURL=index.d.ts.map