diff --git a/src/slack/monitor/events/interactions.test.ts b/src/slack/monitor/events/interactions.test.ts index 5ce37174421..94a9bdd43cb 100644 --- a/src/slack/monitor/events/interactions.test.ts +++ b/src/slack/monitor/events/interactions.test.ts @@ -11,7 +11,11 @@ type RegisteredHandler = (args: { ack: () => Promise; body: { user: { id: string }; + team?: { id?: string }; + trigger_id?: string; + response_url?: string; channel?: { id?: string }; + container?: { channel_id?: string; message_ts?: string; thread_ts?: string }; message?: { ts?: string; text?: string; blocks?: unknown[] }; }; action: Record; @@ -100,7 +104,11 @@ describe("registerSlackInteractionEvents", () => { respond, body: { user: { id: "U123" }, + team: { id: "T9" }, + trigger_id: "123.trigger", + response_url: "https://hooks.slack.test/response", channel: { id: "C1" }, + container: { channel_id: "C1", message_ts: "100.200", thread_ts: "100.100" }, message: { ts: "100.200", text: "fallback", @@ -131,16 +139,24 @@ describe("registerSlackInteractionEvents", () => { actionType: string; value: string; userId: string; + teamId?: string; + triggerId?: string; + responseUrl?: string; channelId: string; messageTs: string; + threadTs?: string; }; expect(payload).toMatchObject({ actionId: "openclaw:verify", actionType: "button", value: "approved", userId: "U123", + teamId: "T9", + triggerId: "123.trigger", + responseUrl: "https://hooks.slack.test/response", channelId: "C1", messageTs: "100.200", + threadTs: "100.100", }); expect(resolveSessionKey).toHaveBeenCalledWith({ channelId: "C1", @@ -192,6 +208,52 @@ describe("registerSlackInteractionEvents", () => { expect(app.client.chat.update).not.toHaveBeenCalled(); }); + it("falls back to container channel and message timestamps", async () => { + enqueueSystemEventMock.mockReset(); + const { ctx, app, getHandler, resolveSessionKey } = createContext(); + registerSlackInteractionEvents({ ctx: ctx as never }); + const handler = getHandler(); + expect(handler).toBeTruthy(); + + const ack = vi.fn().mockResolvedValue(undefined); + await handler!({ + ack, + body: { + user: { id: "U111" }, + team: { id: "T111" }, + container: { channel_id: "C222", message_ts: "222.333", thread_ts: "222.111" }, + }, + action: { + type: "button", + action_id: "openclaw:container", + block_id: "container_block", + value: "ok", + text: { type: "plain_text", text: "Container" }, + }, + }); + + expect(ack).toHaveBeenCalled(); + expect(resolveSessionKey).toHaveBeenCalledWith({ + channelId: "C222", + channelType: undefined, + }); + expect(enqueueSystemEventMock).toHaveBeenCalledTimes(1); + const [eventText] = enqueueSystemEventMock.mock.calls[0] as [string]; + const payload = JSON.parse(eventText.replace("Slack interaction: ", "")) as { + channelId?: string; + messageTs?: string; + threadTs?: string; + teamId?: string; + }; + expect(payload).toMatchObject({ + channelId: "C222", + messageTs: "222.333", + threadTs: "222.111", + teamId: "T111", + }); + expect(app.client.chat.update).not.toHaveBeenCalled(); + }); + it("captures expanded selection and temporal payload fields", async () => { enqueueSystemEventMock.mockReset(); const { ctx, getHandler } = createContext(); diff --git a/src/slack/monitor/events/interactions.ts b/src/slack/monitor/events/interactions.ts index 91fd554d894..ccdda9c331d 100644 --- a/src/slack/monitor/events/interactions.ts +++ b/src/slack/monitor/events/interactions.ts @@ -31,8 +31,12 @@ type InteractionSummary = { selectedDateTime?: number; inputValue?: string; userId?: string; + teamId?: string; + triggerId?: string; + responseUrl?: string; channelId?: string; messageTs?: string; + threadTs?: string; }; type ModalInputSummary = { @@ -205,7 +209,11 @@ export function registerSlackInteractionEvents(params: { ctx: SlackMonitorContex const { ack, body, action, respond } = args; const typedBody = body as unknown as { user?: { id?: string }; + team?: { id?: string }; + trigger_id?: string; + response_url?: string; channel?: { id?: string }; + container?: { channel_id?: string; message_ts?: string; thread_ts?: string }; message?: { ts?: string; text?: string; blocks?: unknown[] }; }; @@ -222,8 +230,9 @@ export function registerSlackInteractionEvents(params: { ctx: SlackMonitorContex const actionId = typedAction.action_id ?? "unknown"; const blockId = typedAction.block_id; const userId = typedBody.user?.id ?? "unknown"; - const channelId = typedBody.channel?.id; - const messageTs = typedBody.message?.ts; + const channelId = typedBody.channel?.id ?? typedBody.container?.channel_id; + const messageTs = typedBody.message?.ts ?? typedBody.container?.message_ts; + const threadTs = typedBody.container?.thread_ts; const actionSummary = summarizeAction(typedAction); const eventPayload: InteractionSummary = { interactionType: "block_action", @@ -231,8 +240,12 @@ export function registerSlackInteractionEvents(params: { ctx: SlackMonitorContex blockId, ...actionSummary, userId, + teamId: typedBody.team?.id, + triggerId: typedBody.trigger_id, + responseUrl: typedBody.response_url, channelId, messageTs, + threadTs, }; // Log the interaction for debugging