import type { PlatformAdapter, IncomingMessage } from '../platform/index.js'; type Enqueuer = (channel: string, fn: () => Promise) => boolean; type Tracker = (delta: number) => void; type Executor = (ctx: AgentRunnerCtx) => Promise; interface AgentConfig { effectiveMessage: string; profileForRun: string; defaultAgentName: string | null; claudeAgent: string | null; systemPrompt: string | null; outputStyle: string | null; tools: string | null; pluginDirs: string[] | null; } export interface AgentRunnerCtx { message: IncomingMessage; channel: string; adapter: PlatformAdapter; threadAnchorId: string | null; hasFiles: boolean; userMessage: string; agentMessage: string; } export declare class AgentRunner { readonly _enqueue: Enqueuer; readonly _track: Tracker; /** Injectable for unit tests — allows verification of track(-1)-in-finally without spawning Claude. */ readonly _execute: Executor; constructor(opts?: { enqueue?: Enqueuer; track?: Tracker; execute?: Executor; }); route(ctx: AgentRunnerCtx): Promise; private _executeReal; } export declare const agentRunner: AgentRunner; /** Exposed for unit testing. */ export declare function resolveDefaultAgent(agentMessage: string, channel?: string): AgentConfig; export declare function resolveSessionName(sessionId: string | null, channel: string, userMessage: string, adapter: PlatformAdapter): Promise; /** * Build interactive callbacks for plan_written, ask_user_question, and tool_use events. * These fire during the turn (not after) and publish bus events so the existing * Slack interaction flow handles them. * * Exported so that all runThread call sites (thread-executor, scheduled-task, * task-dispatch) can wire these callbacks — without them, ask_user_question * events are silently dropped and the subprocess blocks forever. * * ORDERING INVARIANT: onToolUse fires synchronously before onAskUserQuestion * within the same event-loop tick (guaranteed by the PI adapter's sequential * event processing in event-parser.ts). The closure variables pendingAskInput * and pendingExitPlanMode rely on this ordering — onToolUse captures state * that onAskUserQuestion consumes. If the adapter ever processes events * asynchronously or out of order, this contract breaks silently. */ export declare function buildInteractiveCallbacks(channel: string, sessionId: string | null, threadId?: string | null): { onPlanWritten: (event: { path: string; content: string; toolUseId: string; }) => void; onAskUserQuestion: (event: { toolUseId: string; questions: Array<{ question: string; options?: string[]; multi?: boolean; }>; }) => void; onToolUse: (name: string, input: any) => void; }; export {};