/**
 * Slot-release dispatch helpers for the long-poll concurrency protocol.
 *
 * When a concurrency-group slot frees (run completed, run cancelled, run
 * superseded), the orchestrator picks the FIFO-oldest queued row and wakes up
 * the agent that's parked on its second `waitForConcurrencyAck` call. The
 * agent then continues with normal step execution against the same WS
 * connection it received the original dispatch on.
 *
 * If the in-memory waiter is missing (orchestrator restart, agent already
 * disconnected), the dequeued DB row is marked completed so the slot doesn't
 * get permanently stuck on a phantom holder.
 */
import type { AgentRegistry } from '../agent/registry.js';
import type { ConcurrencyGroupTracker } from './group-tracker.js';
import type { ConcurrencyQueueManager } from './queue-manager.js';
import type { ConcurrencyWaiters } from './waiters.js';
export interface DispatchNextQueuedDeps {
    /** In-memory tracker — kept in sync with the DB on dequeue. */
    tracker: ConcurrencyGroupTracker;
    /** DB-backed queue manager. */
    queueManager: ConcurrencyQueueManager;
    /** Agent registry for finding the waiter's WS. */
    registry: AgentRegistry;
    /** In-memory waiter map. */
    waiters: ConcurrencyWaiters;
    /**
     * Default max for `acquireSlot` when re-syncing the in-memory tracker after
     * a dequeue. The runtime concurrency config (per-workflow `max`) is not
     * available at slot-release time; the dequeued waiter has already been
     * accounted for under that policy when it was originally enqueued, so any
     * value `>= 1` is safe here. We pass 1 because the v1 contract documents
     * single-slot semantics (max>1 is out of scope).
     */
    trackerMaxFallback?: number;
}
/**
 * Try to dequeue the next queued entry for `(group, routingKey)` and notify
 * the waiting agent's WS with `concurrency.ack { action: 'proceed' }`.
 *
 * No-op if the queue is empty. When a dequeued waiter is missing or its
 * agent is gone (orphaned row, agent disconnected), the helper LOOPS to the
 * next queued row instead of stopping — otherwise a single orphan would
 * permanently mask all live waiters behind it (orphans sort first by
 * `created_at ASC`).
 *
 * Bounded by a defensive iteration cap so we never accidentally infinite-loop
 * on a queue manager that returns the same row repeatedly.
 */
export declare function tryDispatchNextQueued(deps: DispatchNextQueuedDeps, group: string, routingKey: string): Promise<void>;
export interface AgentDisconnectDeps {
    waiters: ConcurrencyWaiters;
    queueManager: ConcurrencyQueueManager;
}
/**
 * Build the agent-disconnect cleanup callback. Drops every waiter owned by
 * the disconnecting agent and marks their `concurrency_groups` rows as
 * cancelled so the queue manager doesn't try to dispatch a phantom run.
 *
 * Returns a no-arg-async closure suitable for passing to the agent WS handler.
 */
export declare function buildOnConcurrencyAgentDisconnect(deps: AgentDisconnectDeps): (agentId: string) => Promise<void>;
//# sourceMappingURL=dispatch-next-queued.d.ts.map