import type { Chat, Adapter, CardElement, ChatConfig, Message, StateAdapter, Thread } from 'chat';
import type { Agent } from '../agent/agent.js';
import type { IMastraLogger } from '../logger/logger.js';
import type { Mastra } from '../mastra/index.js';
import type { InputProcessor, InputProcessorOrWorkflow } from '../processors/index.js';
import type { ApiRoute, CorsOptions } from '../server/types.js';
/** Message content that can be posted to a channel. */
export type PostableMessage = string | CardElement;
/** Per-adapter configuration. */
export interface ChannelAdapterConfig {
    adapter: Adapter;
    /**
     * CORS configuration for the generated webhook route for this adapter.
     */
    cors?: CorsOptions;
    /**
     * Start a persistent Gateway WebSocket listener for this adapter
     * (default: `true`).
     *
     * Only relevant for adapters that support it (e.g. Discord).
     * Required for receiving DMs, @mentions, and reactions. Set to `false` for
     * serverless deployments that only need slash commands via HTTP Interactions.
     */
    gateway?: boolean;
    /**
     * Use rich card formatting for tool calls, approvals, and results.
     * Set to `false` to use plain text formatting instead.
     *
     * Some platforms (e.g. Discord) may have rendering issues with cards.
     * @default true
     */
    cards?: boolean;
    /**
     * Override how tool calls are rendered in the chat.
     * Called once per tool invocation after the result is available.
     * Return `null` to suppress the message entirely.
     *
     * @default - A Card showing the function-call signature and result.
     */
    formatToolCall?: (info: {
        toolName: string;
        args: Record<string, unknown>;
        result: unknown;
        isError?: boolean;
    }) => PostableMessage | null;
    /**
     * Override how errors are rendered in the chat.
     * Return a user-friendly message instead of exposing the raw error.
     *
     * @default `"❌ Error: <error.message>"`
     */
    formatError?: (error: Error) => PostableMessage;
}
/**
 * Handler function for channel events.
 * Receives the thread, message, and the default handler implementation.
 * Call `defaultHandler` to run the built-in behavior, or ignore it to fully replace.
 */
export type ChannelHandler = (thread: Thread, message: Message, defaultHandler: (thread: Thread, message: Message) => Promise<void>) => Promise<void>;
/**
 * Handler configuration for channel events.
 * - `undefined` or omitted → use default handler
 * - `false` → disable handler entirely
 * - function → custom handler (receives defaultHandler as 3rd arg to wrap/extend)
 */
export type ChannelHandlerConfig = ChannelHandler | false | undefined;
/** Handler overrides for built-in channel event handlers. */
export interface ChannelHandlers {
    /**
     * Handler for direct messages to the bot.
     * Default: Routes to agent.stream and posts the response.
     */
    onDirectMessage?: ChannelHandlerConfig;
    /**
     * Handler for @mentions of the bot in channels.
     * Default: Routes to agent.stream and posts the response.
     */
    onMention?: ChannelHandlerConfig;
    /**
     * Handler for messages in subscribed threads.
     * Default: Routes to agent.stream and posts the response.
     */
    onSubscribedMessage?: ChannelHandlerConfig;
}
/** Configuration for agent chat channels. */
export interface ChannelConfig {
    /** Platform adapters keyed by name (e.g. 'slack', 'discord'). */
    adapters: Record<string, Adapter | ChannelAdapterConfig>;
    /**
     * Override built-in event handlers.
     * Use this to customize how the agent responds to DMs, mentions, etc.
     *
     * @example
     * ```ts
     * handlers: {
     *   // Wrap the default handler with logging
     *   onDirectMessage: async (thread, message, defaultHandler) => {
     *     console.log('Received DM:', message.text);
     *     await defaultHandler(thread, message);
     *   },
     *   // Disable mention handling entirely
     *   onMention: false,
     * }
     * ```
     */
    handlers?: ChannelHandlers;
    /**
     * Which media types to send inline to the model (as file parts).
     * Everything else is described as text metadata so the agent knows about the
     * file without crashing models that reject unsupported types.
     *
     * - **Array of globs** — e.g. `['image/png', 'image/jpeg', 'image/webp', 'application/pdf']` (default), `['image/*', 'video/*']`
     * - **Function** — `(mimeType: string) => boolean`
     *
     * @default `['image/png', 'image/jpeg', 'image/webp', 'application/pdf']`
     *
     * @example
     * ```ts
     * // Gemini supports video/audio natively
     * inlineMedia: ['image/*', 'video/*', 'audio/*']
     *
     * // Send everything inline
     * inlineMedia: () => true
     * ```
     */
    inlineMedia?: string[] | ((mimeType: string) => boolean);
    /**
     * Promote URLs found in message text to file parts so the model can "see" linked
     * content (images, videos, PDFs, etc.) instead of just the raw URL text.
     *
     * Each entry matches a domain. When a URL in the message matches, it's added as
     * a `file` part alongside the text. Use a string for domains where a HEAD request
     * determines the Content-Type, or an object to force a specific mime type (useful
     * for sites like YouTube where HEAD returns `text/html` but the model treats the
     * URL as video).
     *
     * - **String** — domain to match; HEAD determines the mime type
     * - **Object** `{ match, mimeType }` — domain + forced mime type (skips HEAD)
     * - `'*'` — match all URLs (HEAD each one)
     * - `undefined` (default) — disabled, no URLs are promoted
     *
     * For string entries (or `'*'`), the resolved Content-Type is checked against
     * `inlineMedia` — only matching types become file parts. For object entries with
     * a forced `mimeType`, the file part is always added.
     *
     * @example
     * ```ts
     * // Gemini can process YouTube URLs natively as video
     * inlineLinks: [
     *   { match: 'youtube.com', mimeType: 'video/*' },
     *   { match: 'youtu.be', mimeType: 'video/*' },
     * ]
     *
     * // HEAD-check linked images from any domain
     * inlineLinks: ['*']
     *
     * // Mix: force YouTube, HEAD-check everything else
     * inlineLinks: [
     *   { match: 'youtube.com', mimeType: 'video/*' },
     *   'imgur.com',
     *   'i.redd.it',
     * ]
     * ```
     */
    inlineLinks?: InlineLinkEntry[];
    /** State adapter for deduplication, locking, and subscriptions. Defaults to in-memory. */
    state?: StateAdapter;
    /** The bot's display name (default: agent's name, or `'Mastra'`). */
    userName?: string;
    /**
     * Fetch recent thread messages from the platform to provide context when the agent
     * is mentioned mid-conversation. Only fetches on the first mention in a thread —
     * once subscribed, the agent has full history via Mastra's memory system.
     *
     * @example
     * ```ts
     * threadContext: { maxMessages: 15 } // Fetch more context
     * threadContext: { maxMessages: 0 }  // Disable (opt-out)
     * ```
     */
    threadContext?: {
        /**
         * Maximum number of recent platform messages to fetch (default: 10).
         * Only applies to non-DM threads where the agent isn't already subscribed.
         * Set to 0 to disable.
         */
        maxMessages?: number;
    };
    /**
     * Whether to include channel tools (add_reaction, remove_reaction).
     * Set to `false` for models that don't support function calling.
     *
     * @default true
     */
    tools?: boolean;
    /**
     * Additional options passed directly to the Chat SDK.
     * Use this for advanced configuration not exposed by Mastra.
     *
     * @see https://github.com/vercel/chat
     * @example
     * ```ts
     * chatOptions: {
     *   dedupeTtlMs: 600000, // 10 minute deduplication window
     *   fallbackStreamingPlaceholderText: '⏳',
     * }
     * ```
     */
    chatOptions?: Omit<ChatConfig, 'adapters' | 'state' | 'userName'>;
}
/** A single entry in the `inlineLinks` config. */
export type InlineLinkEntry = string | {
    match: string;
    mimeType: string;
};
/** Check if a URL's hostname matches a domain pattern. @internal */
export declare function matchesDomain(url: string, pattern: string): boolean;
export declare function extractUrls(text: string): string[];
/**
 * Manages a single Chat SDK instance for an agent, wiring all adapters
 * to the Mastra pipeline (thread mapping → agent.stream → thread.post).
 *
 * One AgentChannels = one bot identity across multiple platforms.
 *
 * @internal Created automatically by the Agent when `channels` config is provided.
 */
export declare class AgentChannels {
    readonly adapters: Record<string, Adapter>;
    private chat;
    /** Stored initialization promise so webhook handlers can await readiness on serverless cold starts. */
    private initPromise;
    private agent;
    private logger?;
    private customState;
    private stateAdapter;
    private userName;
    /** Normalized per-adapter configs (gateway flags, hooks, etc.). */
    private adapterConfigs;
    /** Handler overrides from config. */
    private handlerOverrides;
    /** Additional Chat SDK options. */
    private chatOptions;
    /** Thread context config for fetching prior messages. */
    private threadContext;
    /** Determines whether a mime type should be sent inline to the model. */
    private shouldInline;
    /** Inline-link rules for promoting URLs in message text to file parts. */
    private inlineLinkRules;
    /** Whether channel tools (reactions, etc.) are enabled. */
    private toolsEnabled;
    /**
     * The original `ChannelConfig` passed to the constructor.
     *
     * Useful for rebuilding `AgentChannels` while preserving existing adapters/handlers,
     * e.g. when a `ChannelProvider` wants to inject its own adapter without clobbering
     * adapters configured by the agent author:
     *
     * @example
     * ```ts
     * const existing = agent.getChannels();
     * existing?.close();
     * const next = new AgentChannels({
     *   ...existing?.channelConfig,
     *   adapters: { ...existing?.channelConfig.adapters, slack: slackAdapter },
     * });
     * agent.setChannels(next);
     * ```
     */
    readonly channelConfig: ChannelConfig;
    /** Channel tool names whose effects are already visible on the platform (skip rendering cards). */
    private channelToolNames;
    /** Platforms whose routes are managed externally (e.g., by SlackProvider). */
    private externallyManagedPlatforms;
    /**
     * Per-Mastra-thread subscriptions. We lazily open one `agent.subscribeToThread()` per channel
     * thread on the first message we route through it, so any signals we send (and any signals
     * other callers send to the same thread) are rendered exactly once to the platform. The
     * subscription stays open until `close()` is called or the consumer errors out — we don't
     * eagerly subscribe at startup because the per-thread chunk consumer needs the `sdkThread`
     * handle, which only exists after a platform event arrives.
     */
    private threadSubscriptions;
    /**
     * Tool-approval cards that have been clicked and are about to be resumed via `approveToolCall` /
     * `declineToolCall`. The resumed run's `tool-result` chunks arrive through the thread
     * subscription consumer rather than the click handler, so we stash the approval card's
     * platform `messageId` (plus the tool's display metadata) here for the consumer to pick up
     * when it renders the result. Entries are removed as soon as the consumer consumes them.
     */
    private pendingApprovalCards;
    constructor(config: ChannelConfig);
    /**
     * Bind this AgentChannels to its owning agent. Called by Agent constructor.
     * @internal
     */
    __setAgent(agent: Agent<any, any, any, any>): void;
    /**
     * Set the logger. Called by Mastra.addAgent.
     * @internal
     */
    __setLogger(logger: IMastraLogger): void;
    /**
     * Register an adapter dynamically.
     * When `managesRoutes` is true, AgentChannels will NOT create webhook routes for this platform
     * (the ChannelProvider handles routing and calls handleWebhookEvent directly).
     * @internal
     */
    __registerAdapter(platform: string, adapter: Adapter, config?: ChannelAdapterConfig, options?: {
        managesRoutes?: boolean;
    }): void;
    /**
     * Check if an adapter is registered for the given platform.
     */
    hasAdapter(platform: string): boolean;
    /**
     * Get the underlying Chat SDK instance.
     * Available after Mastra initialization. Use this to register additional
     * event handlers or access adapter-specific methods.
     *
     * @example
     * ```ts
     * agent.channels.sdk.onReaction((thread, reaction) => {
     *   console.log('Reaction received:', reaction);
     * });
     * ```
     */
    get sdk(): Chat | null;
    /**
     * Initialize the Chat SDK, register handlers, and start gateway listeners.
     * Called by Mastra.addAgent after the server is ready.
     */
    initialize(mastra: Mastra): Promise<void>;
    /**
     * Returns API routes for receiving webhook events from each adapter.
     * One POST route per adapter at `/api/agents/{agentId}/channels/{platform}/webhook`.
     * Skips platforms that are externally managed (e.g., by SlackProvider).
     */
    getWebhookRoutes(): ApiRoute[];
    /**
     * Handle a webhook event from an external source (e.g., SlackProvider).
     * Use this when a ChannelProvider manages its own routes but wants AgentChannels
     * to process the actual message handling (threading, agent responses, etc.).
     *
     * @param platform - The platform name (e.g., 'slack')
     * @param request - The raw HTTP request
     * @param options - Optional execution context for serverless environments
     * @returns The response from the Chat SDK webhook handler
     */
    handleWebhookEvent(platform: string, request: Request, options?: {
        waitUntil?: (p: Promise<unknown>) => void;
    }): Promise<Response>;
    /**
     * Returns channel input processors (e.g. system prompt injection).
     * Skips if the user already added a processor with the same id.
     */
    getInputProcessors(configuredProcessors?: InputProcessorOrWorkflow[]): InputProcessor[];
    /**
     * Returns generic channel tools (send_message, add_reaction, etc.)
     * that resolve the target adapter from the current request context.
     */
    getTools(): Record<string, unknown>;
    /**
     * Tear down all live thread subscriptions opened by this AgentChannels. Safe to call
     * multiple times. Useful for tests and for graceful shutdown of long-lived processes —
     * each cached subscription holds a handler in the agent's thread-stream runtime that
     * would otherwise stay registered for the lifetime of the process.
     */
    close(): void;
    /**
     * Resolve the adapter for the current conversation from request context.
     */
    private getAdapterFromContext;
    /**
     * Derive the three per-event shapes we hand off to downstream systems from one set of
     * inputs. Keeping this in one place ensures the LLM (`attributes`), input processors
     * (`requestContext`), and memory (`metadata`) all see consistent author / thread facts.
     *
     *   - `channelContext` — goes on `requestContext` under the 'channel' key, consumed by
     *     `ChatChannelProcessor` and other input processors.
     *   - `attributes` — serialized as XML on the signal element the LLM sees (e.g. on
     *     `<user-message messageId=... authorId=... />`). Strings only.
     *   - `providerOptions` — written to the stored message's `content.providerMetadata`
     *     under `mastra.channels.<platform>` so UI/query callers can read author/channel
     *     facts off the message (e.g. show a Slack icon + author name) without unpacking
     *     the signal envelope. The LLM ignores `providerOptions.mastra.*` since only
     *     provider-keyed entries (openai, anthropic, …) are forwarded to the model.
     */
    private buildEventContext;
    /**
     * Core handler wired to Chat SDK's onDirectMessage, onNewMention,
     * and onSubscribedMessage. Streams the Mastra agent response and
     * updates the channel message in real-time via edits.
     */
    private handleChatMessage;
    private processChatMessage;
    /**
     * Fetch recent messages from the platform thread to provide context.
     * Returns messages in chronological order (oldest first), excluding the
     * current triggering message.
     */
    private fetchThreadHistory;
    /**
     * Consume the agent stream and render all chunks to the chat platform.
     *
     * Iterates the outer `fullStream` to handle all chunk types:
     * - `text-delta`: Accumulates text and posts when flushed.
     * - `tool-call`: Posts a "Running…" card eagerly.
     * - `tool-result`: Edits the "Running…" card with the result.
     * - `tool-call-approval`: Edits the card to show Approve/Deny buttons.
     * - `step-finish` / `finish`: Flushes accumulated text.
     */
    private editOrPost;
    /**
     * Lazily open (and cache) an `agent.subscribeToThread()` for a Mastra thread, attaching a
     * background chunk consumer that renders run output to the originating chat platform. We
     * cache by `mastraThreadId` so multiple incoming messages on the same thread share one
     * subscription and run output is never rendered twice.
     *
     * If the underlying consumer throws (e.g. the platform `sdkThread` becomes unusable), we
     * tear down the cache entry so the next message can reopen a fresh subscription.
     */
    private ensureThreadSubscription;
    private consumeAgentStream;
    /**
     * Resolves an existing Mastra thread for the given external IDs, or creates one.
     */
    private getOrCreateThread;
    /**
     * Generate generic channel tools that resolve the adapter from request context.
     * Tool names are platform-agnostic (e.g. `send_message`, not `discord_send_message`).
     */
    private makeChannelTools;
    /**
     * Persistent reconnection loop for Gateway-based adapters (e.g. Discord).
     */
    private startGatewayLoop;
    private log;
}
//# sourceMappingURL=agent-channels.d.ts.map