import type { ThreadRecord, AgentSlotConfig, AgentSlotId, AgentStep, TransitionResult } from '../../core/types/thread-types.js'; /** DR-0017 W2 checkpoint gate predicate: true iff the thread HAS a recorded step-start * baseline and the artifact content still matches it (i.e. the agent has not written its * checkpoint this step). Every uncertain case — no artifactPath, no baseline — returns * false so the gate FAILS OPEN (never blocks a legitimate wait). */ export declare function isArtifactUnchangedSinceStepStart(threadId: string): boolean; /** Templates whose dispatch threads keep their artifact on the TASK node instead of the * tmp workspace (DR-0017 W1): durable, git-versioned with the context repo, survives * thread death/rotation/cleanup. */ export declare function isTaskArtifactTemplate(templateName: string | null | undefined): boolean; export declare function createThread(channel: string, options: { templateName?: string | null; agentName?: string | null; userMessage: string; userMessageTs: string; platformThreadId?: string | null; projectId?: string; metadata?: import('../../core/types/thread-types.js').ThreadMetadata | null; }): ThreadRecord; export declare function addAgentToThread(threadId: string, agentName: string, userMessage?: string | null): Promise; interface NextStepInfo { agentSlotId: AgentSlotId; agentConfig: AgentSlotConfig; isFirstStep: boolean; stage: string | null; } export declare function resolveNextStep(threadId: string): NextStepInfo | null; /** Prepare the slot's session ids for a step about to run, mirroring the direct path's * trackSessionId/backendSessionId split (conversation-runner): * - `trackSessionId` (slot.sessionId) — stable Cortex id, the conversation-history / UI * transcript key + CORTEX_SESSION_ID. Minted HERE (before the agent spawns) and persisted, * so a RUNNING step is queryable/streamable by the web UI. persistSession slots keep it * across steps; non-persist slots get a fresh one per step (fresh conversation). * - `resumeSessionId` (slot.backendSessionId) — the backend `--resume` target, resolved at * the previous settle. Legacy records (field absent) held the backend id in slot.sessionId: * migrated in place, keeping that id as BOTH keys for history continuity. * Publishes `thread.step.started` after persisting, so subscribers refetching `threads.get` * already see the new sessionId. */ export declare function beginStepSession(threadId: string, agentSlotId: AgentSlotId, stage: string | null): Promise<{ trackSessionId: string; resumeSessionId: string | null; }>; interface StepResultInput { sessionId?: string | null; backendSessionId?: string | null; sessionName?: string | null; executionId?: string | null; input?: string | null; startedAt?: string | null; output: string | null; costUsd: number | null; numTurns: number | null; durationS: number | null; stage?: string | null; } export declare function recordStepResult(threadId: string, agentSlotId: AgentSlotId, result: StepResultInput): Promise; export declare function evaluateTransitions(threadId: string): TransitionResult; export declare function cancelThread(threadId: string): Promise; export type PendingControl = NonNullable['pendingControl']; /** Peek the thread's pending control signal (does NOT clear it). Returns null when none set. */ export declare function peekPendingControl(threadId: string): PendingControl | null; /** Clear the thread's pending control signal so an intent fires exactly once. */ export declare function clearPendingControl(threadId: string): Promise; /** Derive a split detection from a thread's pending control signal — the dispatch path's * injected `detect` (replaces the old artifact-scanning detectSplitMarker). The subtask array * was validated as a typed tool argument, so the only "error" case is an empty array. */ export declare function detectSplitFromControl(threadId: string): SplitDetection; interface WaitTargets { onTasks?: string[] | null; onThreads?: string[] | null; } /** Try to suspend the thread until its waited-on children finish. With no targets, infer * live task/thread children; supplying either target list replaces the entire inferred set. * Inside one store mutation, persist both resolved sets and enter waiting when either is non-empty. * Returns true iff the thread entered waiting. * Either interleaving with the completion callback converges: callback-first → nothing * left to wait on (results already in pendingMessages); runner-first → callback sees * waiting and resumes when both lists empty. The task-side race (a child completing * between the snapshot and the waiting persist, its event missed) is closed by * reconcileWaitingTasks right after suspension. */ export declare function tryEnterWaiting(threadId: string, targets?: WaitTargets): Promise; export interface SplitDetection { split: boolean; subtasks: any[] | null; error: string | null; } /** Terminate the thread with status='aborted'. Idempotent — returns false if thread is already terminal. */ export declare function abortThread(threadId: string, reason: string | null): Promise; export declare function completeThread(threadId: string): Promise; export declare function failThread(threadId: string, error: string): Promise; /** Pause a thread that was interrupted mid-run by an API rate limit. Non-terminal: the * thread keeps its currentStepIndex/agents and is re-entered (from the interrupted step) * by the resume-dispatcher when the rate-limit window resets. Does NOT set endedAt. * Idempotent. */ export declare function markThreadRateLimited(threadId: string, provider?: string | null, note?: string): Promise; export {};