import type { TypingController } from "./reply/typing.js"; export type BlockReplyContext = { abortSignal?: AbortSignal; timeoutMs?: number; }; /** Context passed to onModelSelected callback with actual model used. */ export type ModelSelectedContext = { provider: string; model: string; thinkLevel: string | undefined; }; export type GetReplyOptions = { onReplyStart?: () => Promise | void; onTypingController?: (typing: TypingController) => void; isHeartbeat?: boolean; onPartialReply?: (payload: ReplyPayload) => Promise | void; onReasoningStream?: (payload: ReplyPayload) => Promise | void; onBlockReply?: (payload: ReplyPayload, context?: BlockReplyContext) => Promise | void; onToolResult?: (payload: ReplyPayload) => Promise | void; /** Called when the actual model is selected (including after fallback). * Use this to get model/provider/thinkLevel for responsePrefix template interpolation. */ onModelSelected?: (ctx: ModelSelectedContext) => void; disableBlockStreaming?: boolean; /** Timeout for block reply delivery (ms). */ blockReplyTimeoutMs?: number; /** If provided, only load these skills for this session (empty = no skills). */ skillFilter?: string[]; /** Mutable ref to track if a reply was sent (for Slack "first" threading mode). */ hasRepliedRef?: { value: boolean }; }; export type ReplyPayload = { text?: string; mediaUrl?: string; mediaUrls?: string[]; replyToId?: string; replyToTag?: boolean; /** True when [[reply_to_current]] was present but not yet mapped to a message id. */ replyToCurrent?: boolean; /** Send audio as voice message (bubble) instead of audio file. Defaults to false. */ audioAsVoice?: boolean; isError?: boolean; };