import type { TaskCardView } from "#channel/task-card.js"; import type { SessionContext } from "#public/definitions/callback-context.js"; import type { UnstampedMessageStreamEvent } from "#protocol/message.js"; import type { BlockKitBlock } from "#public/channels/slack/blocks.js"; import type { SlackMessage } from "#public/channels/slack/inbound.js"; import type { SlackAuthorizationEventContext, SlackChannelInternalEvents, SlackContext, SlackEventContext } from "#public/channels/slack/slackChannel.js"; type EventData = Extract extends { data: infer D; } ? D : undefined; /** The session events a Slack renderer can handle, in no particular order. */ declare const SLACK_RENDERED_EVENTS: readonly ["action.partial", "action.result", "actions.requested", "approval.candidate", "approval.settled", "authorization.completed", "authorization.required", "input.requested", "input.resolved", "message.appended", "message.completed", "reasoning.appended", "reasoning.completed", "session.completed", "session.failed", "session.waiting", "step.started", "task.settled", "task.started", "turn.cancelled", "turn.completed", "turn.failed", "turn.started", "turn.waiting"]; export type SlackRenderedEvent = (typeof SLACK_RENDERED_EVENTS)[number]; type SlackSessionEvent = Exclude; /** * Runs the rest of the chain, ending with eve's default. Pass changed data to * hand it on instead of the event; the rest of the chain runs at most once. * Await it, so the rest of the chain finishes before the event does. */ export type SlackRenderNext = (data?: EventData) => Promise; /** Renders one session event, before, after, around, or instead of the rest of the chain. */ export type SlackRenderHandler = (data: EventData, channel: SlackEventContext, ctx: SessionContext, next: SlackRenderNext) => void | Promise; /** * Session event handlers of one {@link SlackRenderer}. `authorization.required` * receives the private delivery surface, because the challenge is a * credential; its `next` reaches eve's default, which posts the public, * link-free status. `session.failed` has no session context. */ export type SlackRendererEvents = { readonly [T in SlackSessionEvent]?: SlackRenderHandler; } & { readonly "authorization.required"?: (data: EventData<"authorization.required">, channel: SlackAuthorizationEventContext, ctx: SessionContext, next: SlackRenderNext<"authorization.required">) => void | Promise; readonly "session.failed"?: (data: EventData<"session.failed">, channel: SlackEventContext, next: SlackRenderNext<"session.failed">) => void | Promise; }; /** The message eve posts for a turn's tasks: Block Kit blocks and notification text. */ export interface SlackTaskCard { readonly blocks: readonly BlockKitBlock[]; readonly text: string; } /** * One link in a Slack channel's rendering chain. Every part is optional and * wraps the renderers after it, ending with eve's default renderer. */ export interface SlackRenderer { /** * Acknowledges a mention or DM as soon as it arrives, while the message hook * is still deciding, and another channel message once `onMessage` * dispatches it. eve's default sets the `Thinking...` status. If the hook * drops the message, eve clears the thread status. */ readonly received?: (message: SlackMessage, channel: SlackContext, next: () => Promise) => void | Promise; /** Handlers for session events, such as posting replies and questions. */ readonly events?: SlackRendererEvents; /** * Returns the message for a turn's task card, or `null` for none. Runs for * every turn that calls a tool; the view carries the turn's tasks and its * other tool calls with their input. Pure and synchronous: eve posts the * card, updates it as the turn changes, and handles Slack's rate limits. * `next` returns eve's default card, which is `null` for a turn without tasks. */ readonly taskCard?: (view: TaskCardView, next: (view: TaskCardView) => SlackTaskCard | null) => SlackTaskCard | null; } /** Types a Slack renderer. */ export declare function defineSlackRenderer(renderer: SlackRenderer): SlackRenderer; /** * A complete chain, whose handlers take no `next`: eve's default renderer, * which is the innermost link, and the composed chain a channel runs. */ export interface SlackRenderChain { readonly events: SlackChannelInternalEvents; readonly received: (message: SlackMessage, channel: SlackContext) => Promise; readonly taskCard: (view: TaskCardView) => SlackTaskCard | null; } export declare function composeSlackRenderers(renderers: readonly SlackRenderer[], defaults: SlackRenderChain): SlackRenderChain; export {};