import type { AgentTurnParams, AgentTurnResult } from "../../agents/unified-runner.js";
/**
 * The shape of `runAgentTurn` itself, from the runner's POV. A middleware
 * receives this as `next` and returns the same shape (post-wrapping).
 */
export type TurnRunner = (params: AgentTurnParams) => Promise<AgentTurnResult>;
/**
 * Onion-style wrapper around a TurnRunner. The middleware receives the
 * inner `next` and returns a new runner that may pre-process params,
 * call `next`, post-process the result, or short-circuit.
 *
 * Example:
 *
 *   const withTiming: TurnMiddleware = (next) => async (params) => {
 *     const t0 = Date.now();
 *     const result = await next(params);
 *     log.debug(`turn took ${Date.now() - t0}ms`);
 *     return result;
 *   };
 *
 * Composition is left-to-right: the first middleware in the array is the
 * outermost wrapper (sees params first, result last). This matches Express
 * and Koa conventions.
 */
export type TurnMiddleware = (next: TurnRunner) => TurnRunner;
/**
 * Compose middlewares into a single wrapped runner.
 *
 * Order matters: the first middleware in the array is the OUTERMOST
 * wrapper. So `compose(A, B, C)(runner)` is equivalent to `A(B(C(runner)))`
 * — A sees params first, C calls the underlying runner.
 *
 * Empty arrays return the inner runner unchanged (identity).
 */
export declare function composeTurnMiddleware(middlewares: readonly TurnMiddleware[], runner: TurnRunner): TurnRunner;
/**
 * Convenience: wrap an existing `runAgentTurn`-shaped function with a list
 * of middlewares and return a callable. Functionally identical to
 * `composeTurnMiddleware(middlewares, runner)` but reads more naturally at
 * call sites:
 *
 *   const wrapped = wrapRunner(runAgentTurn, [withTiming, withQueueing]);
 *   const result = await wrapped(params);
 */
export declare function wrapRunner(runner: TurnRunner, middlewares: readonly TurnMiddleware[]): TurnRunner;
/**
 * Pre/post telemetry — measure wall-clock duration around the inner runner
 * and forward it to a sink. Useful for identifying slow turns without
 * instrumenting every caller.
 *
 * The sink receives the FINAL result (after the inner runner returns)
 * along with the measured duration. If the inner runner throws, the sink
 * is called with `error` set instead of `result`.
 */
export declare function withTimingTelemetry(opts: {
    onTurn: (info: {
        durationMs: number;
        params: AgentTurnParams;
        result?: AgentTurnResult;
        error?: unknown;
    }) => void;
}): TurnMiddleware;
/**
 * Pre-flight validation — refuse to call the runner if `runId` is missing
 * or empty. Inside `runAgentTurn` a missing runId leads to the run-context
 * lookup returning the wrong thing (or nothing) and silently dropping the
 * verbose / sessionKey state.
 *
 * Throws synchronously before invoking the inner runner, so the caller
 * gets a clear error instead of a half-executed turn.
 */
export declare function withRunIdValidation(): TurnMiddleware;
/**
 * Post-process — when the Phase 1 outbound filter says `action: "drop"`
 * (bare NO_REPLY), invoke a side-effect hook so callers
 * can suppress downstream delivery uniformly. The middleware does NOT
 * mutate the result — it just notifies. Callers decide what to do
 * (typically: skip transcript append, skip channel send, log).
 */
export declare function withOutboundDropSuppression(opts: {
    onDrop: (info: {
        params: AgentTurnParams;
        result: AgentTurnResult;
    }) => void;
}): TurnMiddleware;
