/** * agent-runner.ts — Enterprise Agent Execution Engine * * Core execution engine that creates sessions, runs agents, collects results. * Enhanced with: * - Swarm integration (heartbeats, inter-agent messaging) * - Resource quotas (token budgets, time limits, tool limits) * - Circuit breaker for model calls * - Structured error classification * - Graceful degradation strategies * - Comprehensive telemetry and metrics */ import type { Api, Model } from "@earendil-works/pi-ai"; import type { ExtensionContext } from "@earendil-works/pi-coding-agent"; import { type AgentSession, type ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { type EffectiveConfig } from "./agent-types.js"; import { type AgentHandoff } from "./handoff.js"; import { type HookRegistry } from "./hooks.js"; import type { SubagentType, ThinkingLevel, ValidationResult } from "./types.js"; export declare class AgentRunnerError extends Error { readonly code: "depth_exceeded" | "model_unavailable" | "quota_exceeded" | "aborted" | "timeout" | "unknown"; readonly context?: Record | undefined; constructor(message: string, code: "depth_exceeded" | "model_unavailable" | "quota_exceeded" | "aborted" | "timeout" | "unknown", context?: Record | undefined); } export declare function normalizeMaxTurns(n: number | undefined): number | undefined; export declare function getDefaultMaxTurns(): number | undefined; export declare function setDefaultMaxTurns(n: number | undefined): void; export declare function getGraceTurns(): number; export declare function setGraceTurns(n: number): void; export declare function getMaxEndHookRevisions(): number; /** Clamp end-hook revision budget to a safe finite 0..10 range (NaN/Inf → 0). */ export declare function clampMaxEndHookRevisions(n: number): number; export declare function setMaxEndHookRevisions(n: number): void; declare class ModelCircuitBreaker { private failures; private lastFailureAt; private state; call(fn: () => Promise): Promise; getState(): { state: string; failures: number; lastFailureAt: number; }; } declare const globalCircuitBreaker: ModelCircuitBreaker; export interface ToolActivity { type: "start" | "end"; toolName: string; } export interface ResourceQuotas { /** Max total tokens (input + output) before hard stop. */ maxTokens?: number; /** Max execution duration in ms. */ maxDurationMs?: number; /** Max number of tool calls. */ maxToolCalls?: number; } export interface SwarmOptions { /** Enable swarm heartbeat reporting. */ enableHeartbeat?: boolean; /** Heartbeat interval in ms (default: 10000). */ heartbeatIntervalMs?: number; /** Enable inter-agent message polling. */ enableMessaging?: boolean; /** Poll interval in ms (default: 5000). */ messagePollIntervalMs?: number; } export interface RunOptions { pi: ExtensionAPI; agentId?: string; model?: Model; maxTurns?: number; signal?: AbortSignal; isolated?: boolean; inheritContext?: boolean; thinkingLevel?: ThinkingLevel; cwd?: string; onToolActivity?: (activity: ToolActivity) => void; onTextDelta?: (delta: string, fullText: string) => void; onSessionCreated?: (session: AgentSession) => void; onTurnEnd?: (turnCount: number) => void; onAssistantUsage?: (usage: { input: number; output: number; cacheWrite: number; }) => void; onCompaction?: (info: { reason: "manual" | "threshold" | "overflow"; tokensBefore: number; }) => void; skipValidators?: boolean; onValidationComplete?: (results: ValidationResult[]) => void; currentLevel?: number; levelLimit?: number; parentConfig?: EffectiveConfig; partitions?: readonly string[]; /** * Short correlation id (8 hex chars) shared by every span the agent * emits. If absent, `startAgentSpan` simply omits the `correlation.id` * attribute. The manager sets this on every spawn so the id is stable * across `resumeAgent` calls and is queryable from the agent record. */ correlationId?: string; hooks?: HookRegistry; spawnedAt?: number; onContextBuilt?: (timestamp: number) => void; /** Resource quotas for this run. */ quotas?: ResourceQuotas; /** Swarm collaboration options. */ swarm?: SwarmOptions; /** Called when a swarm message is received. */ onSwarmMessage?: (from: string, payload: unknown) => void; /** * Override the module-level `maxEndHookRevisions` setting for this run. * `0` = fail closed on `subagent:end` block with no revision turn. */ maxEndHookRevisions?: number; } export interface RunResult { responseText: string; session: AgentSession; aborted: boolean; steered: boolean; validationResults?: ValidationResult[]; validated?: boolean; handoff?: AgentHandoff; /** Execution metrics. */ metrics: RunMetrics; } export interface RunMetrics { durationMs: number; turns: number; toolCalls: number; tokensIn: number; tokensOut: number; tokensCacheWrite: number; contextBuiltAt?: number; latencyToFirstTokenMs?: number; } export declare function buildEffectivePrompt(ctx: ExtensionContext, prompt: string, options: RunOptions): string; export declare function runAgent(ctx: ExtensionContext, type: SubagentType, prompt: string, options: RunOptions): Promise; export declare function resumeAgent(session: AgentSession, prompt: string, options?: { onToolActivity?: (activity: ToolActivity) => void; onAssistantUsage?: (usage: { input: number; output: number; cacheWrite: number; }) => void; onCompaction?: (info: { reason: "manual" | "threshold" | "overflow"; tokensBefore: number; }) => void; signal?: AbortSignal; inheritContext?: boolean; ctx?: ExtensionContext; }): Promise; export declare function steerAgent(session: AgentSession, message: string): Promise; export declare function getAgentConversation(session: AgentSession): string; export { globalCircuitBreaker };