import type { SessionAuthContext } from "#channel/types.js";
import type { CardElement } from "#compiled/chat/index.js";
import type { SessionContext } from "#public/definitions/callback-context.js";
import type { ChannelSessionOps } from "#public/definitions/defineChannel.js";
import type { HandleMessageStreamEvent } from "#protocol/message.js";
import { type SlackBotToken, type SlackHandle, type SlackThread } from "#public/channels/slack/api.js";
import { type SlackMessage } from "#public/channels/slack/inbound.js";
import { type UploadPolicyInput } from "#public/channels/upload-policy.js";
import { type SlackWebhookVerifier } from "#public/channels/slack/verify.js";
import { type Channel } from "#public/definitions/defineChannel.js";
type EventData<T extends HandleMessageStreamEvent["type"]> = Extract<HandleMessageStreamEvent, {
    type: T;
}> extends {
    data: infer D;
} ? D : undefined;
/**
 * Pre-dispatch Slack context passed to `onAppMention` and
 * `onInteraction`. These hooks run on the inbound webhook side before the
 * runtime hydrates session state, so `state` is absent here.
 * {@link thread} owns thread-scoped operations (`post`, `postEphemeral`,
 * `startTyping`, `refresh`, `recentMessages`, `mentionUser`); {@link slack}
 * owns Slack identity (`channelId`, `threadTs`, `teamId`) plus the raw-API
 * escape hatch (`request`, `uploadFiles`).
 */
export interface SlackContext {
    readonly thread: SlackThread;
    readonly slack: SlackHandle;
}
/**
 * {@link SlackContext} plus the persisted per-session
 * {@link SlackChannelState}. Built by the channel's `context()` hook and
 * extended by {@link SlackEventContext}.
 */
export interface SlackChannelContext extends SlackContext {
    state: SlackChannelState;
}
/**
 * Slack context handed to `events[type]` handlers. Extends
 * {@link SlackChannelContext} (`thread`, `slack`, hydrated `state`) with
 * session operations ({@link ChannelSessionOps}). Unlike the pre-dispatch
 * {@link SlackContext}, `state` is hydrated here.
 */
export interface SlackEventContext extends SlackChannelContext, ChannelSessionOps {
}
export type { SlackApiResponse, SlackBotToken, SlackHandle, SlackThread, } from "#public/channels/slack/api.js";
export type { SlackWebhookVerifier } from "#public/channels/slack/verify.js";
type SlackEventHandler<T extends HandleMessageStreamEvent["type"]> = (data: EventData<T>, channel: SlackEventContext, ctx: SessionContext) => void | Promise<void>;
/**
 * Delivery surface handed to `authorization.required` overrides. The
 * connection challenge is a credential: anyone who completes the sign-in
 * binds their identity to this session's connection. So the only
 * delivery capabilities here are private ones, an ephemeral reply in the
 * thread or a direct message. There is deliberately no public `post`,
 * no raw `slack.request` escape hatch, and no full thread handle. An
 * override can change the words, not the audience.
 */
export interface SlackAuthorizationEventContext {
    /**
     * Ephemeral message in the current thread, visible only to `userId`.
     * Same contract as {@link SlackThread.postEphemeral}.
     */
    readonly postEphemeral: SlackThread["postEphemeral"];
    /**
     * Direct message to `userId`'s IM conversation with the bot. Same
     * contract as {@link SlackThread.postDirectMessage} (requires the
     * `im:write` scope).
     */
    readonly postDirectMessage: SlackThread["postDirectMessage"];
    /**
     * Hydrated per-session channel state — read `triggeringUserId` to
     * target the delivery.
     */
    readonly state: SlackChannelState;
}
/**
 * Signature of an `authorization.required` override. Unlike every other
 * event handler, it receives {@link SlackAuthorizationEventContext}
 * instead of the full {@link SlackEventContext} — see the context type
 * for why.
 */
export type SlackAuthorizationRequiredHandler = (data: EventData<"authorization.required">, channel: SlackAuthorizationEventContext, ctx: SessionContext) => void | Promise<void>;
type SlackSessionFailedHandler = (data: EventData<"session.failed">, channel: SlackEventContext) => void | Promise<void>;
/**
 * JSON-serializable per-session state, stored verbatim across workflow
 * step boundaries. Anything written here must round-trip through
 * `JSON.stringify` / `JSON.parse`.
 */
export interface SlackChannelState {
    /** Slack channel id seeded by the inbound mention. */
    channelId: string | null;
    /** Slack thread root ts. */
    threadTs: string | null;
    /** Slack team id, when the inbound event carried one. */
    teamId: string | null;
    /**
     * Slack user id of the actor that triggered the current session/turn.
     * Captured on every inbound mention so default handlers (e.g.
     * `authorization.required`) can target ephemeral feedback at the right
     * user without re-parsing the mention payload.
     */
    triggeringUserId?: string | null;
    /**
     * Buffered text from a `message.completed` event whose `finishReason`
     * was `"tool-calls"`. The default `actions.requested` handler uses the
     * first non-empty line as the next typing indicator, surfacing the
     * model's pre-tool narration instead of "Running ...". Cleared at
     * `turn.started` and after use.
     */
    pendingToolCallMessage?: string | null;
    /**
     * Connection name to Slack message ts. Each entry is the public
     * link-free fallback status post created by the default
     * `authorization.required` handler when the challenge could not be
     * delivered ephemerally; the matching `authorization.completed`
     * handler edits it in place to surface the resolution outcome. The
     * normal ephemeral path stores nothing here.
     */
    pendingAuthMessageTs?: Record<string, string>;
}
/**
 * Per-session metadata attached to tracing spans, projected by the
 * channel's `metadata(state)` hook. Fields mirror the inbound mention
 * (channel, team, thread, triggering user) and are `null` until an inbound
 * event seeds them. Open-ended (`Record<string, unknown>`) so deployments
 * can attach extra span attributes.
 */
export interface SlackInstrumentationMetadata extends Record<string, unknown> {
    readonly channelId: string | null;
    readonly teamId: string | null;
    readonly threadTs: string | null;
    readonly triggeringUserId: string | null;
}
/**
 * Slack channel credentials: outbound bot token plus inbound webhook
 * verification. Any field may be omitted to fall back to its env-var /
 * signing-secret default.
 */
export interface SlackChannelCredentials {
    /**
     * Bot token for all outbound Slack Web API calls. Falls back to
     * `process.env.SLACK_BOT_TOKEN` when omitted.
     */
    readonly botToken?: SlackBotToken;
    /**
     * Signing secret used to HMAC-verify inbound webhook requests. Falls
     * back to `process.env.SLACK_SIGNING_SECRET` when neither this nor
     * `webhookVerifier` is supplied.
     */
    readonly signingSecret?: string;
    /**
     * Custom inbound webhook verifier. When supplied, eve skips the
     * `SLACK_SIGNING_SECRET` fallback and delegates to it. Typically set by
     * integrations (e.g. Connect) that authenticate webhooks out-of-band.
     */
    readonly webhookVerifier?: SlackWebhookVerifier;
}
/** Target accepted by `receive(slack, { target })` for proactive sessions. */
export interface SlackReceiveTarget {
    readonly channelId: string;
    readonly threadTs?: string;
    /**
     * Optional message posted into the Slack channel before the agent runs.
     * The post becomes the thread root and the first turn is threaded under
     * it, giving cross-channel handoffs a visible context anchor. Mutually
     * exclusive with {@link threadTs}.
     */
    readonly initialMessage?: SlackInitialMessage;
}
/**
 * Pre-agent post issued by `slackChannel().receive` when the caller
 * provides `target.initialMessage`. Mirrors `ctx.thread.post`'s card
 * variant so the same `Card({...})` construction can be reused.
 */
export interface SlackInitialMessage {
    readonly card: CardElement;
    readonly fallbackText?: string;
}
export interface SlackInteractionAction {
    readonly actionId: string;
    readonly value?: string;
    readonly blockId?: string;
    /**
     * `selected_option.value` for radio / select / external_select
     * widgets. `undefined` for buttons and multi-select widgets.
     */
    readonly selectedOptionValue?: string;
    /**
     * `ts` of the Slack message hosting the clicked component. Required to
     * update that message in place via `chat.update`, since `ctx.slack.threadTs`
     * resolves to the thread root (not the clicked message) for components
     * inside thread replies.
     */
    readonly messageTs?: string;
    /**
     * Display label of the clicked widget: `text.text` for buttons,
     * `selected_option.text.text` for radio/static_select. Renders the
     * "answered" card without re-fetching the original request.
     */
    readonly label?: string;
    /**
     * Slack actor who triggered the interaction, letting `onInteraction`
     * handlers attribute resolutions back to the clicker without re-parsing
     * the raw payload. Always present, since Slack requires `user` on every
     * `block_actions` payload.
     */
    readonly user: SlackInteractionUser;
}
/** Slack actor on {@link SlackInteractionAction.user}, mirroring `body.user`. */
export interface SlackInteractionUser {
    readonly id: string;
    /** Modern canonical display handle. */
    readonly username?: string;
    /** Legacy display handle, kept for older workspaces. */
    readonly name?: string;
}
/**
 * Result of an `onAppMention` or `onDirectMessage` callback. Return an
 * object (auth may be `null`) to dispatch a turn, or `null` to drop the
 * inbound message. `context` strings are appended as user messages to
 * session history before the delivery message.
 */
export type SlackMentionResult = {
    readonly auth: SessionAuthContext | null;
    readonly context?: readonly string[];
} | null;
export type SlackMentionResultOrPromise = SlackMentionResult | Promise<SlackMentionResult>;
/**
 * Alias of {@link SlackMentionResult} for the `onDirectMessage` signature,
 * so DM handlers do not read in terms of "mention".
 */
export type SlackInboundResult = SlackMentionResult;
/** {@link SlackInboundResult}, or a promise resolving to one. */
export type SlackInboundResultOrPromise = SlackMentionResultOrPromise;
/**
 * Per-event Slack handlers keyed by harness stream-event type, passed to
 * `slackChannel({ events })`. Each key is optional; supplying one replaces
 * only that event's built-in default (see {@link defaultEvents}). Handlers
 * receive the event data, the {@link SlackEventContext}, and the session
 * {@link SessionContext}; `session.failed` receives only data and context.
 */
export interface SlackChannelEvents {
    readonly "turn.started"?: SlackEventHandler<"turn.started">;
    readonly "actions.requested"?: SlackEventHandler<"actions.requested">;
    readonly "action.result"?: SlackEventHandler<"action.result">;
    readonly "message.completed"?: SlackEventHandler<"message.completed">;
    readonly "message.appended"?: SlackEventHandler<"message.appended">;
    readonly "input.requested"?: SlackEventHandler<"input.requested">;
    readonly "turn.failed"?: SlackEventHandler<"turn.failed">;
    readonly "turn.completed"?: SlackEventHandler<"turn.completed">;
    readonly "session.failed"?: SlackSessionFailedHandler;
    readonly "session.completed"?: SlackEventHandler<"session.completed">;
    readonly "session.waiting"?: SlackEventHandler<"session.waiting">;
    /**
     * Override receives {@link SlackAuthorizationEventContext}, a
     * private-delivery context (ephemeral or DM), not the full
     * {@link SlackEventContext}. The challenge is a credential, so a
     * public post is not expressible here.
     */
    readonly "authorization.required"?: SlackAuthorizationRequiredHandler;
    readonly "authorization.completed"?: SlackEventHandler<"authorization.completed">;
}
/**
 * Full-context variant of {@link SlackChannelEvents} consumed by the
 * channel internals. The framework's default `authorization.required`
 * handler keeps the full {@link SlackEventContext} because it owns the
 * public link-free fallback for sessions with no user to target
 * privately. The factory adapts user overrides into this shape with
 * {@link constrainAuthorizationRequired}.
 */
export interface SlackChannelInternalEvents extends Omit<SlackChannelEvents, "authorization.required"> {
    readonly "authorization.required"?: SlackEventHandler<"authorization.required">;
}
export interface SlackChannelConfig {
    readonly credentials?: SlackChannelCredentials;
    readonly botName?: string;
    /** Override the default webhook route path (`/eve/v1/slack`). */
    readonly route?: string;
    /**
     * Inbound upload policy applied to file attachments before they reach
     * the harness. Violating attachments are dropped with a warning so the
     * mention's text portion still gets delivered. Pass `"disabled"` to
     * reject every attachment. Defaults to the framework's 25 MB cap with
     * unrestricted media types.
     */
    readonly uploadPolicy?: UploadPolicyInput;
    /**
     * Invoked when a Slack `app_mention` event arrives (only `app_mention`;
     * other event types are ignored). Decides whether to dispatch and with
     * what auth, and may run pre-dispatch side effects (e.g.
     * `ctx.thread.startTyping("Thinking...")`) on the inbound webhook side
     * before the runtime cold-starts.
     *
     * Return `{ auth }` to dispatch with that session auth context, or `null`
     * to drop the mention. May be sync or async; the result is awaited before
     * dispatching. Thrown errors are caught and logged and the mention is
     * dropped; wrap best-effort side effects in `try/catch` to keep them
     * non-fatal. Defaults to a workspace-scoped auth derivation that posts a
     * `"Thinking..."` typing indicator; replacing this replaces both.
     */
    onAppMention?(ctx: SlackContext, message: SlackMessage): SlackMentionResultOrPromise;
    /**
     * Invoked on a direct message: a Slack `message` event with
     * `channel_type: "im"`. Subtype messages (edits, deletes, joins, etc.)
     * and bot messages (`bot_id` set, including the bot's own replies) are
     * filtered out first, so handlers only see plain user-authored DMs.
     * Decides whether to dispatch and with what auth, and may run
     * pre-dispatch side effects on the inbound webhook side before cold-start.
     *
     * Return `{ auth }` to dispatch with that session auth context, or `null`
     * to drop the message. May be sync or async; the result is awaited before
     * dispatching. Thrown errors are caught and logged and the message is
     * dropped; wrap best-effort side effects in `try/catch` to keep them
     * non-fatal. Defaults to a workspace-scoped auth derivation that posts a
     * `"Thinking..."` typing indicator; replacing this replaces both.
     * Requires the bot's Slack app to subscribe to `message.im` with the
     * `im:history` scope.
     */
    onDirectMessage?(ctx: SlackContext, message: SlackMessage): SlackInboundResultOrPromise;
    /**
     * Handler for Slack `block_actions` interactive callbacks (button
     * clicks, select changes, etc.) **not** consumed by the framework's
     * HITL pipeline. Slack POSTs interactive payloads to the same webhook
     * route as mentions; the framework decodes them, routes any action whose
     * `action_id` starts with `eve_input:` to the runtime as an HITL
     * response (resuming a paused session), and forwards everything else
     * here, one invocation per non-HITL action.
     *
     * Runs on the inbound webhook side via `waitUntil()`, so the channel
     * returns `200 OK` immediately. Errors are caught and logged; they do
     * not affect the webhook response or sibling invocations.
     *
     * The `SlackContext` here is rebuilt from the interaction payload
     * (channel id, thread ts, team id), **not** the persisted thread state
     * used by event handlers. Use `ctx.slack.request(...)` for arbitrary
     * Slack Web API calls and `action.messageTs` to target `chat.update`.
     */
    onInteraction?(action: SlackInteractionAction, ctx: SlackContext): void | Promise<void>;
    readonly events?: SlackChannelEvents;
}
/**
 * Concrete return type of {@link slackChannel}. Named so consumers can
 * default-export a `slackChannel(...)` call under `declaration: true`
 * without TypeScript emitting an internal path for `Channel`.
 */
export interface SlackChannel extends Channel<SlackChannelState, SlackReceiveTarget, SlackInstrumentationMetadata> {
}
/**
 * Slack channel factory. Wires up the webhook route, mention dispatch,
 * interaction handling, and a baseline set of typing / error /
 * connection-auth event handlers. Defaults apply per field: pass
 * `onAppMention` to fully replace the default mention pipeline (auth
 * derivation plus `"Thinking..."` typing), or an `events[type]` handler to
 * replace only that one event. Unsupplied fields keep their defaults.
 */
export declare function slackChannel(config?: SlackChannelConfig): SlackChannel;
/**
 * Adapts a user-supplied `authorization.required` override to the full
 * internal event signature while handing it only the private-delivery
 * surface ({@link SlackAuthorizationEventContext}). Override code never
 * receives `thread.post` or the raw `slack.request` escape hatch, so the
 * challenge it renders cannot be addressed to the shared thread.
 */
export declare function constrainAuthorizationRequired(handler: SlackAuthorizationRequiredHandler): NonNullable<SlackChannelInternalEvents["authorization.required"]>;
