import { type PendingControl } from './index.js'; import type { OutputStream } from '../../platform/output-stream.js'; import type { RunningExecution } from '../../core/running-executions.js'; import { type StepTranscriptRecorder } from './thread-transcript.js'; import type { ThreadRecord, AgentSlotId, AgentSlotConfig, ThreadTemplate, RunThreadOptions, TransitionResult } from '../../core/types/thread-types.js'; /** Why the step loop stopped scheduling, in the transition engine's own terms. `transition` is * excluded because it is the one verdict that does not stop the loop. */ export type ThreadStopReason = Exclude; export declare class BenchmarkRateLimitError extends Error { readonly provider: string | null; readonly code = "BENCHMARK_RATE_LIMITED"; constructor(provider: string | null, options?: ErrorOptions); } interface ThreadRunResult { thread: ThreadRecord; /** Final output from the last completed step (for Slack display) */ finalOutput: string | null; /** Aggregated cost across all steps */ totalCostUsd: number; /** Total number of turns across all steps */ totalNumTurns: number; /** The result object from the last agent call (for backward compat with handleAgentSuccess) */ lastAgentResult: any; /** The execution ID from the last completed step — used by handleAgentSuccess in the wrapper. */ executionId: string | null; /** Why the transition engine stopped scheduling steps, in its own typed terms. Null when the * loop left for a reason the engine never judged. */ stopReason: ThreadStopReason | null; } /** Outer-scope state shared across the whole runThread() lifecycle. */ interface ThreadContext { thread: ThreadRecord; template: ThreadTemplate | null; meta: ThreadRecord['metadata']; stream: OutputStream; lastAgentResult: any; totalNumTurns: number; /** Set when a step was interrupted by a provider throttle. * Pauses the thread (status='rate_limited') instead of completing/failing it. */ rateLimited?: boolean; /** Why the transition engine stopped scheduling steps. Null when the loop left for a reason the * engine never judged — an abort, a wait or a throttle. */ stopReason: ThreadStopReason | null; } /** Per-step config built once by buildStepConfig — fully populated, no placeholders. */ interface StepContext { agentSlotId: AgentSlotId; agentConfig: AgentSlotConfig; isFirstStep: boolean; multiAgent: boolean; /** Stage this step runs. Null for single-stage agents (no `stages` map declared). */ stage: string | null; /** Index this step occupies in the thread's step list, captured before the step runs (the * record advances it once the step's result is recorded). */ stepIndex: number; prompt: string; /** True when this step re-enters an interrupted attempt's backend session: the prompt is the * continuation reminder, and first-step files are not re-attached. */ interruptedResume: boolean; /** Flipped by the step callbacks on the first streamed assistant/tool event. Gates capturing * the interrupted backend session — an attempt with no activity has nothing worth resuming. */ sawActivity: boolean; /** The last non-empty assistant message this step emitted, captured off the normalized event * channel every backend populates. Stays null when the step emitted none. */ terminalAssistantText: string | null; /** Backend `--resume` target (slot.backendSessionId via beginStepSession); null → fresh. */ resumeSessionId: string | null; /** Stable Cortex track id (slot.sessionId, minted at step start) — the conversation-history / * UI transcript key + CORTEX_SESSION_ID. Known BEFORE the agent spawns, so the web UI can * query/stream the running step. */ trackSessionId: string; sessionKey: string | null; sessionName: string; profileName: string; profileBackend: string; rateLimitProvider: string | null; execution: { id: string; [k: string]: any; }; /** Always set in buildStepConfig — never an empty placeholder. */ stepStartTime: string; /** Live per-event transcript recorder keyed by trackSessionId: appends each streamed * assistant/tool event to conversation-history immediately + publishes session.message * (shared ts) — the running step streams into the UI and survives reloads/restarts. */ recorder: StepTranscriptRecorder; } /** Per-step callbacks resolved from opts/vm by setupStepCallbacks. */ interface StepCallbacks { onAssistantMessage: ((text: string) => void) | null | undefined; onProgress: ((progress: any) => void) | null; onToolUse: ((name: string, input: any, toolUseId: string) => void) | null; onToolResult: ((toolUseId: string, content: string, isError: boolean) => void) | null; } type StepInfo = Pick; /** Validate thread, load template/metadata, init the aggregating OutputStream. */ declare function initThreadContext(threadId: string, opts: RunThreadOptions): ThreadContext; /** Resolve next step, post boundary notifications, update the status message. * Returns null if the loop should break (cancelled, no next step). */ declare function resolveAndNotifyStep(threadId: string, ctx: ThreadContext, opts: RunThreadOptions): Promise; /** Build prompt, resolve session config, profile, register execution, generate session name + start time. * Returns a fully-populated StepContext — no placeholder fields. */ declare function buildStepConfig(threadId: string, stepInfo: StepInfo, ctx: ThreadContext, opts: RunThreadOptions): Promise; /** Resolve onAssistantMessage/onProgress callbacks and mark slot as running. * Returns the callbacks instead of mutating the StepContext. */ declare function setupStepCallbacks(threadId: string, stepCtx: StepContext, ctx: ThreadContext, opts: RunThreadOptions): StepCallbacks; /** Run the agent, manage its live handle, and balance failed executions. */ declare function executeAndAwaitAgent(threadId: string, stepCtx: StepContext, callbacks: StepCallbacks, ctx: ThreadContext, opts: RunThreadOptions): Promise; /** Record step result, register session, finalize execution; update aggregate counters. */ declare function recordStepOutcome(threadId: string, stepCtx: StepContext, result: any, ctx: ThreadContext, opts: RunThreadOptions): Promise; /** Decide whether the loop continues; run onTransition hook when transitioning. * Returns false to break the loop. */ declare function evaluateAndTransition(threadId: string, stepCtx: StepContext, ctx: ThreadContext, opts: RunThreadOptions): Promise; /** Read final artifact, flush VM, build the run result. */ declare function finalizeThread(threadId: string, ctx: ThreadContext): Promise; /** Terminate a thread by agent abort and, BEFORE onEnd hooks run, hand the owning task to the * caller's onAbort so it can reach a terminal (blocked) state in time (DR-0015 problem 2). * No-op on the task side for non-dispatch threads (metadata has no taskId) or when the caller * did not inject onAbort. Exported for unit testing. */ export declare function finalizeAbortedThread(threadId: string, meta: ThreadRecord['metadata'], reason: string | null, opts: Pick): Promise; declare function runThread(threadId: string, opts: RunThreadOptions): Promise; declare function continueThread(threadId: string, userMessage: string, opts: RunThreadOptions): Promise; /** Consume one wait intent exactly once, preserving its explicit target selectors. */ export declare function consumeWaitControl(threadId: string, control: Pick, 'onTasks' | 'onThreads'>): Promise; /** Re-enter a thread paused by a provider throttle (status==='rate_limited'). Like resumeThread, * the userMessage is NOT overwritten — the thread re-runs its interrupted step from the original * prompt/contract. Called when the owning provider window resets. */ declare function resumeRateLimitedThread(threadId: string, opts: RunThreadOptions): Promise; /** Re-enter a parent thread that was suspended via [WAIT_CHILDREN]. Unlike continueThread, * the userMessage is NOT overwritten — the original contract stays in {{input}}; the child * results arrive through metadata.pendingMessages (injected by the prompt builder). */ declare function resumeThread(threadId: string, opts: RunThreadOptions): Promise; declare function buildThreadSummary(result: ThreadRunResult): string; declare function cancelActiveThread(channel: string): boolean; declare function getActiveHandle(channel: string): RunningExecution | null; export { runThread, continueThread, resumeThread, resumeRateLimitedThread, buildThreadSummary, cancelActiveThread, getActiveHandle, initThreadContext, resolveAndNotifyStep, buildStepConfig, setupStepCallbacks, executeAndAwaitAgent, recordStepOutcome, evaluateAndTransition, finalizeThread, }; export type { ThreadRunResult, ThreadContext, StepContext, StepCallbacks, StepInfo };