/**
 * OutboundCoordinator — owns the post-turn outbound pipeline.
 *
 * Concentrates the responsibilities that used to be scattered across
 * `AgentService`:
 *  - typing-on / typing-off lifecycle for channels that surface "is typing…"
 *  - final assistant response delivery (silence guard + hook + bus publish)
 *  - cross-cutting `webchat_turn_complete` hook + `/goal` post-turn
 *  - thin pass-through for extension `message_sending` / `message_sent` hooks
 *
 * The class is intentionally framework-agnostic: it pulls everything it needs
 * via the constructor config (no direct AgentService reference), so it is
 * unit-testable and lets the parent `AgentService` shrink to a coordinator.
 */
import type { MessageBus, InboundMessage } from '../../infra/bus/index.js';
import type { Config } from '../../config/schema.js';
import type { HookHandler } from '../lifecycle/hook-handler.js';
import type { SessionContext } from '../session/index.js';
import { type TypingController } from '../lifecycle/typing.js';
import type { StreamManager } from './stream-manager.js';
export interface OutboundCoordinatorConfig {
    bus: MessageBus;
    hookHandler: HookHandler;
    streamManager: StreamManager;
    /** Reads the effective config snapshot (honours runtime overrides). */
    getConfig: () => Config | undefined;
    /** Resolves the last visible assistant text for a session (in-memory + agent fallback). */
    getLastAssistantPlainText: (sessionKey: string) => string;
    /**
     * Run the `/goal` post-turn verdict for a completed user turn. Owned by
     * `PersistentGoalService`; OutboundCoordinator only forwards.
     */
    runPersistentGoalPostTurn: (payload: SessionTurnCompletePayload) => Promise<void>;
}
export interface SessionTurnCompletePayload {
    sessionKey: string;
    channel: string;
    chatId: string;
    inboundUserText: string;
    assistantPlainText: string;
    aborted: boolean;
    streamError?: string;
    skipPersistentGoalPostTurn?: boolean;
    outboundMetadata?: Record<string, unknown>;
}
export declare class OutboundCoordinator {
    private readonly bus;
    private readonly hookHandler;
    private readonly streamManager;
    private readonly getConfig;
    private readonly getLastAssistantPlainText;
    private readonly runPersistentGoalPostTurn;
    constructor(config: OutboundCoordinatorConfig);
    /**
     * Build the typing indicator controller for an inbound message. Returns
     * `null` for the CLI channel (no typing UI). Caller is responsible for
     * `start()` and `stop()` (`stop()` should run AFTER the final outbound so
     * Telegram/Weixin see `typing_off` only once the message is delivered).
     */
    createTypingControllerForInbound(msg: InboundMessage): TypingController | null;
    /**
     * Publish the assistant's visible text as the final bus message. Honours the
     * stream-manager "channel already streamed the final text" hint, the heartbeat
     * silence guard, and the extension `message_sending` hook.
     */
    sendFinalResponse(msg: InboundMessage, sessionContext: SessionContext): Promise<void>;
    /**
     * Post-turn hook + `/goal` checklist evaluation. Wired into both the bus-driven
     * inbound finally block and the webchat direct-stream finally. The goal verdict
     * itself lives in `PersistentGoalService`; we just trigger the extension hook
     * here and delegate the `/goal` work.
     */
    emitSessionTurnComplete(payload: SessionTurnCompletePayload): Promise<void>;
    /** Extension hook pass-through (Gateway ChannelManager). */
    invokeOutboundMessageSending(to: string, content: string, channel: string): Promise<{
        send: boolean;
        content?: string;
        reason?: string;
    }>;
    /** Extension hook pass-through (Gateway ChannelManager). */
    invokeOutboundMessageSent(to: string, content: string, success: boolean, error: string | undefined, channel: string): Promise<void>;
}
