mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 02:04:34 +00:00
Slack: register typed channel/group message event handlers
This commit is contained in:
committed by
Peter Steinberger
parent
6513c42d2d
commit
06306501ab
@@ -72,6 +72,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- CLI/Cron: clarify `cron list` output by renaming `Agent` to `Agent ID` and adding a `Model` column for isolated agent-turn jobs. (#26259) Thanks @openperf.
|
- CLI/Cron: clarify `cron list` output by renaming `Agent` to `Agent ID` and adding a `Model` column for isolated agent-turn jobs. (#26259) Thanks @openperf.
|
||||||
- Feishu/Reply media attachments: send Feishu reply `mediaUrl`/`mediaUrls` payloads as attachments alongside text/streamed replies in the reply dispatcher, including legacy fallback when `mediaUrls` is empty. (#28959) Thanks @icesword0760.
|
- Feishu/Reply media attachments: send Feishu reply `mediaUrl`/`mediaUrls` payloads as attachments alongside text/streamed replies in the reply dispatcher, including legacy fallback when `mediaUrls` is empty. (#28959) Thanks @icesword0760.
|
||||||
- Slack/User-token resolution: normalize Slack account user-token sourcing through resolved account metadata (`SLACK_USER_TOKEN` env + config) so monitor reads, Slack actions, directory lookups, onboarding allow-from resolution, and capabilities probing consistently use the effective user token. (#28103) Thanks @Glucksberg.
|
- Slack/User-token resolution: normalize Slack account user-token sourcing through resolved account metadata (`SLACK_USER_TOKEN` env + config) so monitor reads, Slack actions, directory lookups, onboarding allow-from resolution, and capabilities probing consistently use the effective user token. (#28103) Thanks @Glucksberg.
|
||||||
|
- Slack/Channel message subscriptions: register explicit `message.channels` and `message.groups` monitor handlers (alongside generic `message`) so channel/group event subscriptions are consumed even when Slack dispatches typed message event names. Fixes #31674.
|
||||||
- Feishu/Outbound session routing: stop assuming bare `oc_` identifiers are always group chats, honor explicit `dm:`/`group:` prefixes for `oc_` chat IDs, and default ambiguous bare `oc_` targets to direct routing to avoid DM session misclassification. (#10407) Thanks @Bermudarat.
|
- Feishu/Outbound session routing: stop assuming bare `oc_` identifiers are always group chats, honor explicit `dm:`/`group:` prefixes for `oc_` chat IDs, and default ambiguous bare `oc_` targets to direct routing to avoid DM session misclassification. (#10407) Thanks @Bermudarat.
|
||||||
- Feishu/Group session routing: add configurable group session scopes (`group`, `group_sender`, `group_topic`, `group_topic_sender`) with legacy `topicSessionMode=enabled` compatibility so Feishu group conversations can isolate sessions by sender/topic as configured. (#17798) Thanks @yfge.
|
- Feishu/Group session routing: add configurable group session scopes (`group`, `group_sender`, `group_topic`, `group_topic_sender`) with legacy `topicSessionMode=enabled` compatibility so Feishu group conversations can isolate sessions by sender/topic as configured. (#17798) Thanks @yfge.
|
||||||
- Feishu/Reply-in-thread routing: add `replyInThread` config (`disabled|enabled`) for group replies, propagate `reply_in_thread` across text/card/media/streaming sends, and align topic-scoped session routing so newly created reply threads stay on the same session root. (#27325) Thanks @kcinzgg.
|
- Feishu/Reply-in-thread routing: add `replyInThread` config (`disabled|enabled`) for group replies, propagate `reply_in_thread` across text/card/media/streaming sends, and align topic-scoped session routing so newly created reply threads stay on the same session root. (#27325) Thanks @kcinzgg.
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ function createMessageHandlers(overrides?: SlackSystemEventTestOverrides) {
|
|||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
handler: harness.getHandler("message") as MessageHandler | null,
|
handler: harness.getHandler("message") as MessageHandler | null,
|
||||||
|
channelHandler: harness.getHandler("message.channels") as MessageHandler | null,
|
||||||
|
groupHandler: harness.getHandler("message.groups") as MessageHandler | null,
|
||||||
handleSlackMessage,
|
handleSlackMessage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -156,4 +158,38 @@ describe("registerSlackMessageEvents", () => {
|
|||||||
expect(handleSlackMessage).toHaveBeenCalledTimes(1);
|
expect(handleSlackMessage).toHaveBeenCalledTimes(1);
|
||||||
expect(messageQueueMock).not.toHaveBeenCalled();
|
expect(messageQueueMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("registers and forwards message.channels and message.groups events", async () => {
|
||||||
|
messageQueueMock.mockClear();
|
||||||
|
messageAllowMock.mockReset().mockResolvedValue([]);
|
||||||
|
const { channelHandler, groupHandler, handleSlackMessage } = createMessageHandlers({
|
||||||
|
dmPolicy: "open",
|
||||||
|
channelType: "channel",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(channelHandler).toBeTruthy();
|
||||||
|
expect(groupHandler).toBeTruthy();
|
||||||
|
|
||||||
|
const channelMessage = {
|
||||||
|
type: "message",
|
||||||
|
channel: "C1",
|
||||||
|
channel_type: "channel",
|
||||||
|
user: "U1",
|
||||||
|
text: "hello channel",
|
||||||
|
ts: "123.100",
|
||||||
|
};
|
||||||
|
await channelHandler!({ event: channelMessage, body: {} });
|
||||||
|
await groupHandler!({
|
||||||
|
event: {
|
||||||
|
...channelMessage,
|
||||||
|
channel_type: "group",
|
||||||
|
channel: "G1",
|
||||||
|
ts: "123.200",
|
||||||
|
},
|
||||||
|
body: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(handleSlackMessage).toHaveBeenCalledTimes(2);
|
||||||
|
expect(messageQueueMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function registerSlackMessageEvents(params: {
|
|||||||
const resolveThreadBroadcastSenderId = (thread: SlackThreadBroadcastEvent): string | undefined =>
|
const resolveThreadBroadcastSenderId = (thread: SlackThreadBroadcastEvent): string | undefined =>
|
||||||
thread.user ?? thread.message?.user ?? thread.message?.bot_id;
|
thread.user ?? thread.message?.user ?? thread.message?.bot_id;
|
||||||
|
|
||||||
ctx.app.event("message", async ({ event, body }: SlackEventMiddlewareArgs<"message">) => {
|
const handleIncomingMessageEvent = async ({ event, body }: { event: unknown; body: unknown }) => {
|
||||||
try {
|
try {
|
||||||
if (ctx.shouldDropMismatchedSlackEvent(body)) {
|
if (ctx.shouldDropMismatchedSlackEvent(body)) {
|
||||||
return;
|
return;
|
||||||
@@ -95,6 +95,18 @@ export function registerSlackMessageEvents(params: {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
ctx.runtime.error?.(danger(`slack handler failed: ${String(err)}`));
|
ctx.runtime.error?.(danger(`slack handler failed: ${String(err)}`));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.app.event("message", async ({ event, body }: SlackEventMiddlewareArgs<"message">) => {
|
||||||
|
await handleIncomingMessageEvent({ event, body });
|
||||||
|
});
|
||||||
|
// Slack may dispatch channel/group message subscriptions under typed event
|
||||||
|
// names. Register explicit handlers so both delivery styles are supported.
|
||||||
|
ctx.app.event("message.channels", async ({ event, body }: SlackEventMiddlewareArgs) => {
|
||||||
|
await handleIncomingMessageEvent({ event, body });
|
||||||
|
});
|
||||||
|
ctx.app.event("message.groups", async ({ event, body }: SlackEventMiddlewareArgs) => {
|
||||||
|
await handleIncomingMessageEvent({ event, body });
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.app.event("app_mention", async ({ event, body }: SlackEventMiddlewareArgs<"app_mention">) => {
|
ctx.app.event("app_mention", async ({ event, body }: SlackEventMiddlewareArgs<"app_mention">) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user