mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 21:20:22 +00:00
refactor: split browser context/actions and unify CDP timeout policy
This commit is contained in:
72
src/slack/monitor/events/message-subtype-handlers.test.ts
Normal file
72
src/slack/monitor/events/message-subtype-handlers.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { SlackMessageEvent } from "../../types.js";
|
||||
import { resolveSlackMessageSubtypeHandler } from "./message-subtype-handlers.js";
|
||||
|
||||
describe("resolveSlackMessageSubtypeHandler", () => {
|
||||
it("resolves message_changed metadata and identifiers", () => {
|
||||
const event = {
|
||||
type: "message",
|
||||
subtype: "message_changed",
|
||||
channel: "D1",
|
||||
event_ts: "123.456",
|
||||
message: { ts: "123.456", user: "U1" },
|
||||
previous_message: { ts: "123.450", user: "U2" },
|
||||
} as unknown as SlackMessageEvent;
|
||||
|
||||
const handler = resolveSlackMessageSubtypeHandler(event);
|
||||
expect(handler?.eventKind).toBe("message_changed");
|
||||
expect(handler?.resolveSenderId(event)).toBe("U1");
|
||||
expect(handler?.resolveChannelId(event)).toBe("D1");
|
||||
expect(handler?.resolveChannelType(event)).toBeUndefined();
|
||||
expect(handler?.contextKey(event)).toBe("slack:message:changed:D1:123.456");
|
||||
expect(handler?.describe("DM with @user")).toContain("edited");
|
||||
});
|
||||
|
||||
it("resolves message_deleted metadata and identifiers", () => {
|
||||
const event = {
|
||||
type: "message",
|
||||
subtype: "message_deleted",
|
||||
channel: "C1",
|
||||
deleted_ts: "123.456",
|
||||
event_ts: "123.457",
|
||||
previous_message: { ts: "123.450", user: "U1" },
|
||||
} as unknown as SlackMessageEvent;
|
||||
|
||||
const handler = resolveSlackMessageSubtypeHandler(event);
|
||||
expect(handler?.eventKind).toBe("message_deleted");
|
||||
expect(handler?.resolveSenderId(event)).toBe("U1");
|
||||
expect(handler?.resolveChannelId(event)).toBe("C1");
|
||||
expect(handler?.resolveChannelType(event)).toBeUndefined();
|
||||
expect(handler?.contextKey(event)).toBe("slack:message:deleted:C1:123.456");
|
||||
expect(handler?.describe("general")).toContain("deleted");
|
||||
});
|
||||
|
||||
it("resolves thread_broadcast metadata and identifiers", () => {
|
||||
const event = {
|
||||
type: "message",
|
||||
subtype: "thread_broadcast",
|
||||
channel: "C1",
|
||||
event_ts: "123.456",
|
||||
message: { ts: "123.456", user: "U1" },
|
||||
user: "U1",
|
||||
} as unknown as SlackMessageEvent;
|
||||
|
||||
const handler = resolveSlackMessageSubtypeHandler(event);
|
||||
expect(handler?.eventKind).toBe("thread_broadcast");
|
||||
expect(handler?.resolveSenderId(event)).toBe("U1");
|
||||
expect(handler?.resolveChannelId(event)).toBe("C1");
|
||||
expect(handler?.resolveChannelType(event)).toBeUndefined();
|
||||
expect(handler?.contextKey(event)).toBe("slack:thread:broadcast:C1:123.456");
|
||||
expect(handler?.describe("general")).toContain("broadcast");
|
||||
});
|
||||
|
||||
it("returns undefined for regular messages", () => {
|
||||
const event = {
|
||||
type: "message",
|
||||
channel: "D1",
|
||||
user: "U1",
|
||||
text: "hello",
|
||||
} as unknown as SlackMessageEvent;
|
||||
expect(resolveSlackMessageSubtypeHandler(event)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
98
src/slack/monitor/events/message-subtype-handlers.ts
Normal file
98
src/slack/monitor/events/message-subtype-handlers.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import type { SlackMessageEvent } from "../../types.js";
|
||||
import type {
|
||||
SlackMessageChangedEvent,
|
||||
SlackMessageDeletedEvent,
|
||||
SlackThreadBroadcastEvent,
|
||||
} from "../types.js";
|
||||
|
||||
type SupportedSubtype = "message_changed" | "message_deleted" | "thread_broadcast";
|
||||
|
||||
export type SlackMessageSubtypeHandler = {
|
||||
subtype: SupportedSubtype;
|
||||
eventKind: SupportedSubtype;
|
||||
describe: (channelLabel: string) => string;
|
||||
contextKey: (event: SlackMessageEvent) => string;
|
||||
resolveSenderId: (event: SlackMessageEvent) => string | undefined;
|
||||
resolveChannelId: (event: SlackMessageEvent) => string | undefined;
|
||||
resolveChannelType: (event: SlackMessageEvent) => string | null | undefined;
|
||||
};
|
||||
|
||||
const changedHandler: SlackMessageSubtypeHandler = {
|
||||
subtype: "message_changed",
|
||||
eventKind: "message_changed",
|
||||
describe: (channelLabel) => `Slack message edited in ${channelLabel}.`,
|
||||
contextKey: (event) => {
|
||||
const changed = event as SlackMessageChangedEvent;
|
||||
const channelId = changed.channel ?? "unknown";
|
||||
const messageId =
|
||||
changed.message?.ts ?? changed.previous_message?.ts ?? changed.event_ts ?? "unknown";
|
||||
return `slack:message:changed:${channelId}:${messageId}`;
|
||||
},
|
||||
resolveSenderId: (event) => {
|
||||
const changed = event as SlackMessageChangedEvent;
|
||||
return (
|
||||
changed.message?.user ??
|
||||
changed.previous_message?.user ??
|
||||
changed.message?.bot_id ??
|
||||
changed.previous_message?.bot_id
|
||||
);
|
||||
},
|
||||
resolveChannelId: (event) => (event as SlackMessageChangedEvent).channel,
|
||||
resolveChannelType: () => undefined,
|
||||
};
|
||||
|
||||
const deletedHandler: SlackMessageSubtypeHandler = {
|
||||
subtype: "message_deleted",
|
||||
eventKind: "message_deleted",
|
||||
describe: (channelLabel) => `Slack message deleted in ${channelLabel}.`,
|
||||
contextKey: (event) => {
|
||||
const deleted = event as SlackMessageDeletedEvent;
|
||||
const channelId = deleted.channel ?? "unknown";
|
||||
const messageId = deleted.deleted_ts ?? deleted.event_ts ?? "unknown";
|
||||
return `slack:message:deleted:${channelId}:${messageId}`;
|
||||
},
|
||||
resolveSenderId: (event) => {
|
||||
const deleted = event as SlackMessageDeletedEvent;
|
||||
return deleted.previous_message?.user ?? deleted.previous_message?.bot_id;
|
||||
},
|
||||
resolveChannelId: (event) => (event as SlackMessageDeletedEvent).channel,
|
||||
resolveChannelType: () => undefined,
|
||||
};
|
||||
|
||||
const threadBroadcastHandler: SlackMessageSubtypeHandler = {
|
||||
subtype: "thread_broadcast",
|
||||
eventKind: "thread_broadcast",
|
||||
describe: (channelLabel) => `Slack thread reply broadcast in ${channelLabel}.`,
|
||||
contextKey: (event) => {
|
||||
const thread = event as SlackThreadBroadcastEvent;
|
||||
const channelId = thread.channel ?? "unknown";
|
||||
const messageId = thread.message?.ts ?? thread.event_ts ?? "unknown";
|
||||
return `slack:thread:broadcast:${channelId}:${messageId}`;
|
||||
},
|
||||
resolveSenderId: (event) => {
|
||||
const thread = event as SlackThreadBroadcastEvent;
|
||||
return thread.user ?? thread.message?.user ?? thread.message?.bot_id;
|
||||
},
|
||||
resolveChannelId: (event) => (event as SlackThreadBroadcastEvent).channel,
|
||||
resolveChannelType: () => undefined,
|
||||
};
|
||||
|
||||
const SUBTYPE_HANDLER_REGISTRY: Record<SupportedSubtype, SlackMessageSubtypeHandler> = {
|
||||
message_changed: changedHandler,
|
||||
message_deleted: deletedHandler,
|
||||
thread_broadcast: threadBroadcastHandler,
|
||||
};
|
||||
|
||||
export function resolveSlackMessageSubtypeHandler(
|
||||
event: SlackMessageEvent,
|
||||
): SlackMessageSubtypeHandler | undefined {
|
||||
const subtype = event.subtype;
|
||||
if (
|
||||
subtype !== "message_changed" &&
|
||||
subtype !== "message_deleted" &&
|
||||
subtype !== "thread_broadcast"
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return SUBTYPE_HANDLER_REGISTRY[subtype];
|
||||
}
|
||||
@@ -4,11 +4,7 @@ import { enqueueSystemEvent } from "../../../infra/system-events.js";
|
||||
import type { SlackAppMentionEvent, SlackMessageEvent } from "../../types.js";
|
||||
import type { SlackMonitorContext } from "../context.js";
|
||||
import type { SlackMessageHandler } from "../message-handler.js";
|
||||
import type {
|
||||
SlackMessageChangedEvent,
|
||||
SlackMessageDeletedEvent,
|
||||
SlackThreadBroadcastEvent,
|
||||
} from "../types.js";
|
||||
import { resolveSlackMessageSubtypeHandler } from "./message-subtype-handlers.js";
|
||||
import { authorizeAndResolveSlackSystemEventContext } from "./system-event-context.js";
|
||||
|
||||
export function registerSlackMessageEvents(params: {
|
||||
@@ -17,16 +13,6 @@ export function registerSlackMessageEvents(params: {
|
||||
}) {
|
||||
const { ctx, handleSlackMessage } = params;
|
||||
|
||||
const resolveChangedSenderId = (changed: SlackMessageChangedEvent): string | undefined =>
|
||||
changed.message?.user ??
|
||||
changed.previous_message?.user ??
|
||||
changed.message?.bot_id ??
|
||||
changed.previous_message?.bot_id;
|
||||
const resolveDeletedSenderId = (deleted: SlackMessageDeletedEvent): string | undefined =>
|
||||
deleted.previous_message?.user ?? deleted.previous_message?.bot_id;
|
||||
const resolveThreadBroadcastSenderId = (thread: SlackThreadBroadcastEvent): string | undefined =>
|
||||
thread.user ?? thread.message?.user ?? thread.message?.bot_id;
|
||||
|
||||
const handleIncomingMessageEvent = async ({ event, body }: { event: unknown; body: unknown }) => {
|
||||
try {
|
||||
if (ctx.shouldDropMismatchedSlackEvent(body)) {
|
||||
@@ -34,59 +20,22 @@ export function registerSlackMessageEvents(params: {
|
||||
}
|
||||
|
||||
const message = event as SlackMessageEvent;
|
||||
if (message.subtype === "message_changed") {
|
||||
const changed = event as SlackMessageChangedEvent;
|
||||
const channelId = changed.channel;
|
||||
const subtypeHandler = resolveSlackMessageSubtypeHandler(message);
|
||||
if (subtypeHandler) {
|
||||
const channelId = subtypeHandler.resolveChannelId(message);
|
||||
const ingressContext = await authorizeAndResolveSlackSystemEventContext({
|
||||
ctx,
|
||||
senderId: resolveChangedSenderId(changed),
|
||||
senderId: subtypeHandler.resolveSenderId(message),
|
||||
channelId,
|
||||
eventKind: "message_changed",
|
||||
channelType: subtypeHandler.resolveChannelType(message),
|
||||
eventKind: subtypeHandler.eventKind,
|
||||
});
|
||||
if (!ingressContext) {
|
||||
return;
|
||||
}
|
||||
const messageId = changed.message?.ts ?? changed.previous_message?.ts;
|
||||
enqueueSystemEvent(`Slack message edited in ${ingressContext.channelLabel}.`, {
|
||||
enqueueSystemEvent(subtypeHandler.describe(ingressContext.channelLabel), {
|
||||
sessionKey: ingressContext.sessionKey,
|
||||
contextKey: `slack:message:changed:${channelId ?? "unknown"}:${messageId ?? changed.event_ts ?? "unknown"}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (message.subtype === "message_deleted") {
|
||||
const deleted = event as SlackMessageDeletedEvent;
|
||||
const channelId = deleted.channel;
|
||||
const ingressContext = await authorizeAndResolveSlackSystemEventContext({
|
||||
ctx,
|
||||
senderId: resolveDeletedSenderId(deleted),
|
||||
channelId,
|
||||
eventKind: "message_deleted",
|
||||
});
|
||||
if (!ingressContext) {
|
||||
return;
|
||||
}
|
||||
enqueueSystemEvent(`Slack message deleted in ${ingressContext.channelLabel}.`, {
|
||||
sessionKey: ingressContext.sessionKey,
|
||||
contextKey: `slack:message:deleted:${channelId ?? "unknown"}:${deleted.deleted_ts ?? deleted.event_ts ?? "unknown"}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (message.subtype === "thread_broadcast") {
|
||||
const thread = event as SlackThreadBroadcastEvent;
|
||||
const channelId = thread.channel;
|
||||
const ingressContext = await authorizeAndResolveSlackSystemEventContext({
|
||||
ctx,
|
||||
senderId: resolveThreadBroadcastSenderId(thread),
|
||||
channelId,
|
||||
eventKind: "thread_broadcast",
|
||||
});
|
||||
if (!ingressContext) {
|
||||
return;
|
||||
}
|
||||
const messageId = thread.message?.ts ?? thread.event_ts;
|
||||
enqueueSystemEvent(`Slack thread reply broadcast in ${ingressContext.channelLabel}.`, {
|
||||
sessionKey: ingressContext.sessionKey,
|
||||
contextKey: `slack:thread:broadcast:${channelId ?? "unknown"}:${messageId ?? "unknown"}`,
|
||||
contextKey: subtypeHandler.contextKey(message),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user