import type { EventStream } from "../llm/index.js"; import { type AgentCoreStreamRuntimeDeps } from "./runtime-deps.js"; import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, StreamFn } from "./types.js"; /** Callback used by synchronous loop runners to publish agent lifecycle events. */ export type AgentEventSink = (event: AgentEvent) => Promise | void; /** Named reasons the loop goes around again. Assertable in tests via the trace sink. */ export type LoopContinueReason = /** A turn finished with executable tool calls (or injected messages) still driving work. */ "next_turn" /** Drain point A (mid-work boundary): steering messages were injected after a turn. */ | "steer_injected" /** Drain point B (agent would otherwise stop): follow-up messages were injected. */ | "follow_up_injected" /** ④b recovery: a prompt-too-long failure was recovered (compacted context) and retried in-turn. */ | "reactive_compact_retry" /** ④b recovery: a `length`-stopped answer triggered a synthetic continue nudge for another turn. */ | "max_output_tokens_recovery" /** S2 recovery (design/119): a `toolUse` stop with ZERO parseable tool calls got a retry nudge. */ | "malformed_tool_use_retry" /** S2 recovery (design/119): a thinking-only turn (no visible text, no tools) got a retry nudge. */ | "thinking_only_retry" /** design/124 tier A: a partially-finalized "stop" (mid-stream cut promoted to content) got a * bounded continue nudge so an autonomous run doesn't book the cut as an incomplete success. */ | "midstream_partial_recovery" /** T1-4 recovery: a degenerate-repetition cutoff got a bounded "different approach" continue. */ | "degenerate_output_recovery" /** design/130 P2b: a walltime-cutoff turn (soft per-call deadline crossed) got a bounded * write-out continue — the remaining cushion fits one short final turn. */ | "walltime_cutoff_recovery"; /** Named reasons the loop exits. Assertable in tests via the trace sink. */ export type LoopTerminalReason = /** Natural end: no tool calls, no steering, no follow-ups. */ "completed" /** A-1 layer ② guard: the abort signal was already set before the next provider request. */ | "aborted_before_stream" /** The assistant message itself ended with stopReason "error" or "aborted". */ | "assistant_error" /** `shouldStopAfterTurn` requested a clean stop at the turn boundary (mod #16 one-shot). */ | "stop_requested"; export type LoopStep = { kind: "continue"; reason: LoopContinueReason; } | { kind: "terminal"; reason: LoopTerminalReason; }; /** * Optional per-transition observer, for tests that assert WHICH path ran. * Attribution notes: `reactive_compact_retry` is traced IN-TURN at each retry (a turn may trace * several); the turn's boundary then traces at most ONE more Continue by priority — a recovery * reason (`max_output_tokens_recovery` / `midstream_partial_recovery` / `malformed_tool_use_retry` / * `thinking_only_retry`, mutually exclusive by stopReason/flag) wins, then `steer_injected` (masking the same turn's * `next_turn`), then `next_turn`. Don't read the trace as a complete enumeration of concurrent causes. */ export type LoopTraceSink = (step: LoopStep) => void; /** * Start an agent loop with a new prompt message. * The prompt is added to the context and events are emitted for it. */ export declare function agentLoop(prompts: AgentMessage[], context: AgentContext, config: AgentLoopConfig, signal?: AbortSignal, streamFn?: StreamFn, runtime?: AgentCoreStreamRuntimeDeps): EventStream; /** * Continue an agent loop from the current context without adding a new message. * Used for retries - context already has user message or tool results. * * **Important:** The last message in context must convert to a `user` or `toolResult` message * via `convertToLlm`. If it doesn't, the LLM provider will reject the request. * This cannot be validated here since `convertToLlm` is only called once per turn. */ export declare function agentLoopContinue(context: AgentContext, config: AgentLoopConfig, signal?: AbortSignal, streamFn?: StreamFn, runtime?: AgentCoreStreamRuntimeDeps): EventStream; /** Run a prompt-started loop and emit events through a caller-owned sink. */ export declare function runAgentLoop(prompts: AgentMessage[], context: AgentContext, config: AgentLoopConfig, emit: AgentEventSink, signal?: AbortSignal, streamFn?: StreamFn, runtime?: AgentCoreStreamRuntimeDeps, trace?: LoopTraceSink): Promise; /** Continue an existing loop context and emit only newly produced messages. */ export declare function runAgentLoopContinue(context: AgentContext, config: AgentLoopConfig, emit: AgentEventSink, signal?: AbortSignal, streamFn?: StreamFn, runtime?: AgentCoreStreamRuntimeDeps, trace?: LoopTraceSink): Promise; //# sourceMappingURL=agent-loop.d.ts.map