import type { ReplyPayload } from "../types.js";
export type PayloadKind = "delta" | "block" | "final" | "tool";
export interface PayloadContext {
    /** The turn's runId — for telemetry, dedup, transcript correlation. */
    runId: string;
    /** Session that owns this payload — for routing and transcript. */
    sessionKey?: string;
    /**
     * The kind of payload being delivered. Set by the caller before
     * invoking the handler — middlewares MAY look at it but should not
     * mutate it (the kind is an envelope property, not a payload field).
     */
    kind: PayloadKind;
    /** Surface tag — "glass-ui" | "tui" | "channel" | "cli" | "cron". */
    surface?: string;
    /**
     * True when the inbound message that triggered this turn was an audio
     * message. Drives TTS auto-mode in Phase 10's `withTtsApplication`.
     */
    inboundAudio?: boolean;
    /**
     * The channel string when surface="channel". E.g. "telegram" / "whatsapp"
     * / "slack" / "signal". Drives `withChannelRouting`.
     */
    channel?: string;
    /**
     * Abort signal — middlewares should respect it (e.g. drop the payload
     * if aborted) rather than blocking on a doomed delivery.
     */
    abortSignal?: AbortSignal;
}
export interface PayloadDelivery {
    /** The payload as it stands AFTER this layer's processing. May be the
     *  original reference if no mutation happened. */
    payload: ReplyPayload;
    /**
     * `true` → continue processing / deliver to downstream sink.
     * `false` → drop. Downstream layers see `delivered: false` and short-
     * circuit. The payload field still carries the (possibly mutated)
     * payload for telemetry.
     */
    delivered: boolean;
    /**
     * Optional verdict string for telemetry / debugging. E.g.
     * "deliver" / "drop:empty" / "drop:duplicate" / "deliver:tts-applied".
     * Phase 8+ adopters should pick a stable vocabulary.
     */
    reason?: string;
}
export type PayloadHandler = (payload: ReplyPayload, ctx: PayloadContext) => Promise<PayloadDelivery>;
/**
 * Onion-style wrapper around a PayloadHandler. Same composition algebra
 * as TurnMiddleware (Phase 3) — the first middleware in the array is
 * the OUTERMOST wrapper.
 */
export type PayloadMiddleware = (next: PayloadHandler) => PayloadHandler;
export declare function composePayloadMiddleware(middlewares: readonly PayloadMiddleware[], handler: PayloadHandler): PayloadHandler;
/** Convenience — same as composePayloadMiddleware with reversed args. */
export declare function wrapPayloadHandler(handler: PayloadHandler, middlewares: readonly PayloadMiddleware[]): PayloadHandler;
/**
 * Build a `PayloadDelivery` shorthand for the common deliver/drop cases.
 * Reduces boilerplate at call sites without changing the contract.
 */
export declare const PayloadDelivery: {
    deliver(payload: ReplyPayload, reason?: string): PayloadDelivery;
    drop(payload: ReplyPayload, reason?: string): PayloadDelivery;
};
/**
 * Pre/post telemetry — fires `onPayload` for every payload delivery
 * attempt with the verdict from downstream. Useful for diagnostic
 * traces without instrumenting every chain layer.
 */
export declare function withPayloadTrace(opts: {
    onPayload: (info: {
        payload: ReplyPayload;
        ctx: PayloadContext;
        delivery: PayloadDelivery;
    }) => void;
}): PayloadMiddleware;
/**
 * Drop payloads that have no deliverable content — empty/whitespace text
 * with no media. Common short-circuit at the top of the chain so empty
 * payloads don't burn through the dispatcher queue.
 *
 * Note: a payload with `isError: true` is NOT considered empty (errors
 * may be text-only diagnostic messages and must surface).
 */
export declare function withPayloadDropOnEmpty(): PayloadMiddleware;
/**
 * Deliver only the listed kinds; drop the rest with a structured reason.
 * Used by Phase 11 to deliver `final` only to the transcript while the
 * dispatcher queue handles all kinds, etc.
 */
export declare function withPayloadKindGate(opts: {
    allow: readonly PayloadKind[];
}): PayloadMiddleware;
