/** * Agent Teams — sub-agent orchestration for agent-native. * * The main agent chat acts as an orchestrator. It spawns sub-agents * for individual tasks, which run in their own threads. Sub-agents * appear as rich preview cards (chips) inline in the main chat. * * This module provides the server-side infrastructure: * - Creating sub-agent threads and running them in background * - Tracking task status and results * - Emitting SSE events for live preview cards * - Bidirectional messaging between main agent and sub-agents * * Task state is persisted in application_state (SQL) so it survives * serverless cold starts and works across multiple processes. */ import type { AgentEngine } from "../agent/engine/types.js"; import type { ActionEntry, AgentLoopFinalResponseGuard } from "../agent/production-agent.js"; import { type ActiveRun } from "../agent/run-manager.js"; import type { AgentChatEvent } from "../agent/types.js"; import type { RunEvent } from "../agent/types.js"; import type { BackgroundAgentRun, BackgroundAgentRunStatus, BackgroundAgentTranscriptEvent } from "../code-agents/background-run.js"; import type { BackgroundAgentController } from "../code-agents/index.js"; import { type AgentTeamRunPayload } from "./agent-teams-run-queue.js"; /** * Run `fn` with `depth` recorded as the ambient delegation depth so any * `spawnTask` call made transitively from `fn` knows the depth of the agent * doing the spawning. */ declare function runWithDelegationDepth(depth: number, fn: () => T | Promise): T | Promise; /** Depth of the agent currently executing (0 = top-level chat). */ declare function currentAmbientDelegationDepth(): number; /** * Public read of the ambient sub-agent delegation depth for the currently * executing agent. 0 = the top-level (user-facing) chat; 1+ = a spawned * sub-agent. Used by the chat plugin to thread the depth into * `buildRuntimeContextPrompt` so a sub-agent at the cap is told it can't * delegate further. Mirrors `currentAmbientDelegationDepth`; exported under a * descriptive name so callers outside this module don't depend on the private * helper or the test-only export object. */ export declare function getCurrentDelegationDepth(): number; export interface SubagentDepthDecision { /** Whether the spawn is allowed under the depth cap. */ allowed: boolean; /** Depth of the agent doing the spawning (parent). */ parentDepth: number; /** Depth the spawned sub-agent would have (parentDepth + 1). */ childDepth: number; /** The effective cap (resolved from env, clamped). */ maxDepth: number; /** Human-readable refusal message when `allowed` is false. */ error?: string; } /** * Decide whether an agent at `parentDepth` may spawn another sub-agent. The * child would sit at `parentDepth + 1`; a child deeper than `maxDepth` is * refused. Pure + exported so the enforcement is unit-testable and reusable. */ export declare function evaluateSubagentDepth(parentDepth: number, env?: Record): SubagentDepthDecision; /** Framework route the self-fire dispatch targets to run a queued sub-agent in * a fresh function invocation. Mounted inside the agent-chat plugin (where the * sub-agent action/prompt/engine closures live). */ export declare const AGENT_TEAM_PROCESS_RUN_PATH = "/_agent-native/agent-teams/_process-run"; export interface AgentTask { taskId: string; threadId: string; parentThreadId?: string; name?: string; description: string; status: "running" | "completed" | "errored"; preview: string; summary: string; currentStep: string; createdAt: number; updatedAt?: number; startedAt?: number; completedAt?: number; runId?: string; error?: string; /** * Delegation depth of THIS sub-agent: 1 for a sub-agent spawned by the * top-level chat, 2 for a sub-agent spawned by a depth-1 sub-agent, etc. * Drives the runaway-delegation guardrail (see `evaluateSubagentDepth`). */ delegationDepth?: number; } export type AgentTeamBackgroundRun = Omit & { kind: "agent-team"; source: "hosted-agent-team"; sourceRecord: { type: "agent-team-task"; id: string; threadId: string; }; status: BackgroundAgentRunStatus; cwd?: string; goalId: "agent-team"; transcriptPath?: string; artifactRoot?: string; }; export type AgentTeamBackgroundTranscriptEvent = Omit & { kind: "user" | "system" | "note" | "artifact" | "status"; source: "hosted-agent-team"; sourceRecord: { type: "agent-team-run-event"; id: string; seq: number; }; }; export interface SendToAgentTeamBackgroundRunResult { ok: boolean; error?: string; messageId?: string; queuedCount?: number; } export interface ControlAgentTeamBackgroundRunResult { ok: boolean; error?: string; } export declare function createAgentTeamBackgroundAgentController(): BackgroundAgentController; export declare const agentTeamBackgroundAgentController: BackgroundAgentController; export interface ParentCompletionInjection { id: string; taskId: string; taskName?: string; status: "completed" | "errored"; hitContinuationLimit: boolean; summaryExcerpt: string; fullSummaryAvailable: boolean; timestamp: number; } /** * Drain the parent-completion injection queue for a thread. Returns all * pending injections and deletes them atomically. Exported so the agent-chat * plugin can drain these into the orchestrator's next user-turn. */ export declare function drainParentCompletionInjections(parentThreadId: string): Promise; /** * Format all drained parent-completion injections as a single user-turn * message to inject into the orchestrator thread. */ export declare function formatParentCompletionInjections(injections: ParentCompletionInjection[]): string; export interface QueuedTaskMessage { id: string; from: "orchestrator"; message: string; timestamp: number; } declare function formatQueuedTaskMessages(messages: QueuedTaskMessage[]): string; declare function drainQueuedTaskMessages(taskId: string): Promise; declare function createMessageAwareActions(taskId: string, actions: Record): Record; declare function createTaskMessageFinalGuard(taskId: string): AgentLoopFinalResponseGuard; /** * Reconcile all of an owner's in-flight sub-agent runs. Wired into the RunsTray * data path (`/_agent-native/runs`) so the tray self-heals: dropped dispatches * are re-fired and dead runs are marked failed promptly, even when the * orchestrator chat never polls `status`/`read-result`. */ export declare function reconcileAgentTeamRunsForOwner(owner: string, event?: any): Promise; type TerminalProgressStatus = "succeeded" | "failed" | "cancelled"; declare function resolveTaskCompletion(run: Pick, accumulatedText: string, options?: { hitContinuationLimit?: boolean; }): { taskStatus: "completed" | "errored"; summary: string; progressStatus: TerminalProgressStatus; progressStep: string; error?: string; }; export declare function toAgentTaskBackgroundRun(task: AgentTask): AgentTeamBackgroundRun; export declare function toAgentTaskBackgroundTranscriptEvent(runId: string, event: RunEvent, options?: { seq?: number; sourceRunId?: string; }): AgentTeamBackgroundTranscriptEvent | null; export interface SpawnTaskOptions { /** Description of what the sub-agent should do */ description: string; /** Additional instructions scoped to this sub-agent */ instructions?: string; /** Model to use (e.g. "claude-haiku-4-5"). Uses default if omitted */ model?: string; /** The owner email for thread creation */ ownerEmail: string; /** The system prompt base for the sub-agent */ systemPrompt: string; /** Available actions for the sub-agent */ actions: Record; /** Agent engine to use. Falls back to creating an Anthropic engine with apiKey. */ engine?: AgentEngine; /** API key for Anthropic (used only if engine is not provided) */ apiKey?: string; /** Callback to emit events to the parent chat stream */ parentSend: (event: AgentChatEvent) => void; /** Parent thread ID — used to auto-respond when the sub-agent finishes */ parentThreadId?: string; /** Display name for the sub-agent tab (carried into the dispatch payload). */ name?: string; /** * Delegation depth of the agent doing the spawning (the parent). Top-level * chat is 0. When omitted, the depth is read from the ambient run context * (set by `processAgentTeamRun` when a sub-agent is itself running), so a * sub-agent that reaches `spawnTask` inherits its own depth automatically. * The spawned sub-agent's depth is `parentDelegationDepth + 1`. */ parentDelegationDepth?: number; } /** * Error thrown when a spawn is refused because it would exceed the delegation * depth cap. Carries the structured decision so callers (and the tool layer) * can surface a precise message to the parent agent. */ export declare class SubagentDelegationDepthError extends Error { readonly decision: SubagentDepthDecision; constructor(decision: SubagentDepthDecision); } /** * Spawn a sub-agent task. Creates a thread, starts a background agent run, * and emits agent_task events to the parent chat stream. */ export declare function spawnTask(opts: SpawnTaskOptions): Promise; /** Run config the processor route resolves from plugin-scope closures. */ export interface AgentTeamRunConfig { baseSystemPrompt: string; actions: Record; engine: AgentEngine; model: string; /** * Tool names to expose on the FIRST engine request for this sub-agent * chunk. See `SchedulerDeps.getInitialToolNames` (`jobs/scheduler.ts`) — * same semantics: when provided, every other action in `actions` is * deferred behind an attached `tool-search` entry instead of being * serialized on every chunk; `runAgentLoop`'s mid-run tool expansion still * lets the model discover and call them after a search. Omit to keep the * full `actions` set visible up front (current behavior). */ initialToolNames?: string[]; } export interface ProcessAgentTeamRunOptions { taskId: string; /** "start" = first chunk; "continue" = resume from thread_data after a * soft-timeout boundary. Defaults from the queue row's continuation count. */ mode?: "start" | "continue"; /** Inbound request event, used to resolve the self-dispatch base URL for * continuation self-fires. */ event?: any; /** Count of consecutive non-progressing chunks carried forward from the * previous invocation. Used by the progress-aware continuation budget. */ noProgressCount?: number; /** Builds the sub-agent run config from the queue payload + resolved owner. * The plugin supplies this because the action registry / base prompt / * engine are per-deployment plugin-scope closures, not serializable. */ resolveConfig: (ctx: { payload: AgentTeamRunPayload; ownerEmail: string; orgId: string | null; }) => Promise; } /** * Execute one chunk of a queued sub-agent run in a fresh function invocation. * Called by the `/_agent-native/agent-teams/_process-run` route. Atomically * claims the run (idempotent on duplicate self-fires), reconstructs the * messages (start vs continue), runs the agent loop to completion, persists * thread_data, and either self-fires a continuation (soft-timeout boundary, * under the cap) or finalizes the task. */ export declare function processAgentTeamRun(opts: ProcessAgentTeamRunOptions): Promise<{ ok: boolean; skipped?: string; }>; /** Get task by ID */ export declare function getTask(taskId: string): Promise; /** Get task by thread ID */ export declare function getTaskByThread(threadId: string): Promise; /** List all tasks (most recent first) */ export declare function listTasks(): Promise; export declare function listAgentTeamBackgroundRuns(): Promise; export declare function getAgentTeamBackgroundRun(runId: string): Promise; export declare function listAgentTeamBackgroundTranscriptEvents(runId: string): Promise; export declare function subscribeToAgentTeamBackgroundRun(runId: string, fromSeq?: number): ReadableStream | null; /** Send a message/update to a running sub-agent via application state */ export declare function sendToTask(taskId: string, message: string): Promise<{ ok: boolean; error?: string; messageId?: string; queuedCount?: number; }>; export declare function sendToAgentTeamBackgroundRun(runId: string, message: string): Promise; export declare function stopAgentTeamBackgroundRun(runId: string, reason?: string): Promise; /** Mark a task as errored */ export declare function markTaskErrored(taskId: string, error: string): Promise; export declare const _agentTeamsQueueForTests: { createMessageAwareActions: typeof createMessageAwareActions; createTaskMessageFinalGuard: typeof createTaskMessageFinalGuard; drainQueuedTaskMessages: typeof drainQueuedTaskMessages; formatQueuedTaskMessages: typeof formatQueuedTaskMessages; resolveTaskCompletion: typeof resolveTaskCompletion; evaluateSubagentDepth: typeof evaluateSubagentDepth; runWithDelegationDepth: typeof runWithDelegationDepth; currentAmbientDelegationDepth: typeof currentAmbientDelegationDepth; }; export {}; //# sourceMappingURL=agent-teams.d.ts.map