diff --git a/src/config/types.slack.ts b/src/config/types.slack.ts index 564248503..d2fdc4558 100644 --- a/src/config/types.slack.ts +++ b/src/config/types.slack.ts @@ -77,6 +77,10 @@ export type SlackThreadConfig = { export type SlackAccountConfig = { /** Optional display name for this account (used in CLI/UI lists). */ name?: string; + /** Custom loading messages shown while processing (rotates randomly). */ + loadingMessages?: string[]; + /** Status text shown while typing (default: "is typing..."). */ + typingStatus?: string; /** Slack connection mode (socket|http). Default: socket. */ mode?: "socket" | "http"; /** Slack signing secret (required for HTTP mode). */ diff --git a/src/slack/monitor/context.ts b/src/slack/monitor/context.ts index 83acfbae6..cf8e7970f 100644 --- a/src/slack/monitor/context.ts +++ b/src/slack/monitor/context.ts @@ -111,7 +111,10 @@ export type SlackMonitorContext = { channelId: string; threadTs?: string; status: string; + loadingMessages?: string[]; }) => Promise; + loadingMessages?: string[]; + typingStatus: string; }; export function createSlackMonitorContext(params: { @@ -148,6 +151,8 @@ export function createSlackMonitorContext(params: { ackReactionScope: string; mediaMaxBytes: number; removeAckAfterReply: boolean; + loadingMessages?: string[]; + typingStatus?: string; }): SlackMonitorContext { const channelHistories = new Map(); const logger = getChildLogger({ module: "slack-auto-reply" }); @@ -247,14 +252,18 @@ export function createSlackMonitorContext(params: { channelId: string; threadTs?: string; status: string; + loadingMessages?: string[]; }) => { if (!p.threadTs) return; - const payload = { + const payload: Record = { token: params.botToken, channel_id: p.channelId, thread_ts: p.threadTs, status: p.status, }; + if (p.loadingMessages && p.loadingMessages.length > 0) { + payload.loading_messages = p.loadingMessages; + } const client = params.app.client as unknown as { assistant?: { threads?: { @@ -400,5 +409,7 @@ export function createSlackMonitorContext(params: { resolveChannelName, resolveUserName, setSlackThreadStatus, + loadingMessages: params.loadingMessages, + typingStatus: params.typingStatus ?? "is typing...", }; } diff --git a/src/slack/monitor/message-handler/dispatch.ts b/src/slack/monitor/message-handler/dispatch.ts index d31885cfa..563f72d77 100644 --- a/src/slack/monitor/message-handler/dispatch.ts +++ b/src/slack/monitor/message-handler/dispatch.ts @@ -63,7 +63,8 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag await ctx.setSlackThreadStatus({ channelId: message.channel, threadTs: statusThreadTs, - status: "is typing...", + status: ctx.typingStatus, + loadingMessages: ctx.loadingMessages, }); }, stop: async () => { diff --git a/src/slack/monitor/provider.ts b/src/slack/monitor/provider.ts index 366a32a34..2a05634fd 100644 --- a/src/slack/monitor/provider.ts +++ b/src/slack/monitor/provider.ts @@ -123,6 +123,8 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) { const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions"; const mediaMaxBytes = (opts.mediaMaxMb ?? slackCfg.mediaMaxMb ?? 20) * 1024 * 1024; const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false; + const loadingMessages = slackCfg.loadingMessages; + const typingStatus = slackCfg.typingStatus; const receiver = slackMode === "http" @@ -204,6 +206,8 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) { ackReactionScope, mediaMaxBytes, removeAckAfterReply, + loadingMessages, + typingStatus, }); const handleSlackMessage = createSlackMessageHandler({ ctx, account });