mirror of https://github.com/openclaw/openclaw.git
Matrix: dedupe monitor handler tests
This commit is contained in:
parent
272509ec4b
commit
22addcd6ec
|
|
@ -1,9 +1,11 @@
|
|||
import type { RuntimeEnv, RuntimeLogger } from "openclaw/plugin-sdk/matrix";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { setMatrixRuntime } from "../../runtime.js";
|
||||
import type { MatrixClient } from "../sdk.js";
|
||||
import { createMatrixRoomMessageHandler } from "./handler.js";
|
||||
import { EventType, type MatrixRawEvent } from "./types.js";
|
||||
import {
|
||||
createMatrixHandlerTestHarness,
|
||||
createMatrixTextMessageEvent,
|
||||
} from "./handler.test-helpers.js";
|
||||
import type { MatrixRawEvent } from "./types.js";
|
||||
|
||||
describe("createMatrixRoomMessageHandler inbound body formatting", () => {
|
||||
beforeEach(() => {
|
||||
|
|
@ -26,117 +28,34 @@ describe("createMatrixRoomMessageHandler inbound body formatting", () => {
|
|||
});
|
||||
|
||||
it("records thread metadata for group thread messages", async () => {
|
||||
const recordInboundSession = vi.fn(async () => {});
|
||||
const finalizeInboundContext = vi.fn((ctx) => ctx);
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
getEvent: async () => ({
|
||||
event_id: "$thread-root",
|
||||
sender: "@alice:example.org",
|
||||
type: EventType.RoomMessage,
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
body: "Root topic",
|
||||
},
|
||||
}),
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore: async () => [] as string[],
|
||||
upsertPairingRequest: async () => ({ code: "ABCDEFGH", created: false }),
|
||||
},
|
||||
commands: {
|
||||
shouldHandleTextCommands: () => false,
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: () => false,
|
||||
resolveMarkdownTableMode: () => "preserve",
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute: () => ({
|
||||
agentId: "ops",
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
sessionKey: "agent:ops:main",
|
||||
mainSessionKey: "agent:ops:main",
|
||||
matchedBy: "binding.account",
|
||||
const { handler, finalizeInboundContext, recordInboundSession } =
|
||||
createMatrixHandlerTestHarness({
|
||||
client: {
|
||||
getEvent: async () =>
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$thread-root",
|
||||
sender: "@alice:example.org",
|
||||
body: "Root topic",
|
||||
}),
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: () => "/tmp/session-store",
|
||||
readSessionUpdatedAt: () => undefined,
|
||||
recordInboundSession,
|
||||
},
|
||||
reply: {
|
||||
resolveEnvelopeFormatOptions: () => ({}),
|
||||
formatAgentEnvelope: ({ body }: { body: string }) => body,
|
||||
finalizeInboundContext,
|
||||
createReplyDispatcherWithTyping: () => ({
|
||||
dispatcher: {},
|
||||
replyOptions: {},
|
||||
markDispatchIdle: () => {},
|
||||
}),
|
||||
resolveHumanDelayConfig: () => undefined,
|
||||
dispatchReplyFromConfig: async () => ({
|
||||
queuedFinal: false,
|
||||
counts: { final: 0, block: 0, tool: 0 },
|
||||
}),
|
||||
},
|
||||
reactions: {
|
||||
shouldAckReaction: () => false,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
cfg: {} as never,
|
||||
accountId: "ops",
|
||||
runtime: {
|
||||
error: () => {},
|
||||
} as RuntimeEnv,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
} as RuntimeLogger,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
dmPolicy: "open",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => false,
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
getMemberDisplayName: async (_roomId, userId) =>
|
||||
userId === "@alice:example.org" ? "Alice" : "sender",
|
||||
});
|
||||
isDirectMessage: false,
|
||||
getMemberDisplayName: async (_roomId, userId) =>
|
||||
userId === "@alice:example.org" ? "Alice" : "sender",
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.RoomMessage,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$reply1",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$reply1",
|
||||
body: "follow up",
|
||||
"m.relates_to": {
|
||||
relatesTo: {
|
||||
rel_type: "m.thread",
|
||||
event_id: "$thread-root",
|
||||
"m.in_reply_to": { event_id: "$thread-root" },
|
||||
},
|
||||
"m.mentions": { room: true },
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
mentions: { room: true },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(finalizeInboundContext).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
|
@ -152,123 +71,47 @@ describe("createMatrixRoomMessageHandler inbound body formatting", () => {
|
|||
});
|
||||
|
||||
it("records formatted poll results for inbound poll response events", async () => {
|
||||
const recordInboundSession = vi.fn(async () => {});
|
||||
const finalizeInboundContext = vi.fn((ctx) => ctx);
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
getEvent: async () => ({
|
||||
event_id: "$poll",
|
||||
sender: "@bot:example.org",
|
||||
type: "m.poll.start",
|
||||
origin_server_ts: 1,
|
||||
content: {
|
||||
"m.poll.start": {
|
||||
question: { "m.text": "Lunch?" },
|
||||
kind: "m.poll.disclosed",
|
||||
max_selections: 1,
|
||||
answers: [
|
||||
{ id: "a1", "m.text": "Pizza" },
|
||||
{ id: "a2", "m.text": "Sushi" },
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
getRelations: async () => ({
|
||||
events: [
|
||||
{
|
||||
type: "m.poll.response",
|
||||
event_id: "$vote1",
|
||||
sender: "@user:example.org",
|
||||
origin_server_ts: 2,
|
||||
content: {
|
||||
"m.poll.response": { answers: ["a1"] },
|
||||
"m.relates_to": { rel_type: "m.reference", event_id: "$poll" },
|
||||
const { handler, finalizeInboundContext, recordInboundSession } =
|
||||
createMatrixHandlerTestHarness({
|
||||
client: {
|
||||
getEvent: async () => ({
|
||||
event_id: "$poll",
|
||||
sender: "@bot:example.org",
|
||||
type: "m.poll.start",
|
||||
origin_server_ts: 1,
|
||||
content: {
|
||||
"m.poll.start": {
|
||||
question: { "m.text": "Lunch?" },
|
||||
kind: "m.poll.disclosed",
|
||||
max_selections: 1,
|
||||
answers: [
|
||||
{ id: "a1", "m.text": "Pizza" },
|
||||
{ id: "a2", "m.text": "Sushi" },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
nextBatch: null,
|
||||
prevBatch: null,
|
||||
}),
|
||||
} as unknown as MatrixClient,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore: async () => [] as string[],
|
||||
upsertPairingRequest: async () => ({ code: "ABCDEFGH", created: false }),
|
||||
},
|
||||
commands: {
|
||||
shouldHandleTextCommands: () => false,
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: () => false,
|
||||
resolveMarkdownTableMode: () => "preserve",
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute: () => ({
|
||||
agentId: "ops",
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
sessionKey: "agent:ops:main",
|
||||
mainSessionKey: "agent:ops:main",
|
||||
matchedBy: "binding.account",
|
||||
}),
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: () => "/tmp/session-store",
|
||||
readSessionUpdatedAt: () => undefined,
|
||||
recordInboundSession,
|
||||
},
|
||||
reply: {
|
||||
resolveEnvelopeFormatOptions: () => ({}),
|
||||
formatAgentEnvelope: ({ body }: { body: string }) => body,
|
||||
finalizeInboundContext,
|
||||
createReplyDispatcherWithTyping: () => ({
|
||||
dispatcher: {},
|
||||
replyOptions: {},
|
||||
markDispatchIdle: () => {},
|
||||
}),
|
||||
resolveHumanDelayConfig: () => undefined,
|
||||
dispatchReplyFromConfig: async () => ({
|
||||
queuedFinal: false,
|
||||
counts: { final: 0, block: 0, tool: 0 },
|
||||
}),
|
||||
},
|
||||
reactions: {
|
||||
shouldAckReaction: () => false,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
cfg: {} as never,
|
||||
accountId: "ops",
|
||||
runtime: {
|
||||
error: () => {},
|
||||
} as RuntimeEnv,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
} as RuntimeLogger,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
dmPolicy: "open",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => true,
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
getMemberDisplayName: async (_roomId, userId) =>
|
||||
userId === "@bot:example.org" ? "Bot" : "sender",
|
||||
});
|
||||
}),
|
||||
getRelations: async () => ({
|
||||
events: [
|
||||
{
|
||||
type: "m.poll.response",
|
||||
event_id: "$vote1",
|
||||
sender: "@user:example.org",
|
||||
origin_server_ts: 2,
|
||||
content: {
|
||||
"m.poll.response": { answers: ["a1"] },
|
||||
"m.relates_to": { rel_type: "m.reference", event_id: "$poll" },
|
||||
},
|
||||
},
|
||||
],
|
||||
nextBatch: null,
|
||||
prevBatch: null,
|
||||
}),
|
||||
} as unknown as Partial<MatrixClient>,
|
||||
isDirectMessage: true,
|
||||
getMemberDisplayName: async (_roomId, userId) =>
|
||||
userId === "@bot:example.org" ? "Bot" : "sender",
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: "m.poll.response",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,219 @@
|
|||
import type { RuntimeEnv, RuntimeLogger } from "openclaw/plugin-sdk/matrix";
|
||||
import { vi } from "vitest";
|
||||
import type { MatrixRoomConfig, ReplyToMode } from "../../types.js";
|
||||
import type { MatrixClient } from "../sdk.js";
|
||||
import { createMatrixRoomMessageHandler, type MatrixMonitorHandlerParams } from "./handler.js";
|
||||
import { EventType, type MatrixRawEvent, type RoomMessageEventContent } from "./types.js";
|
||||
|
||||
const DEFAULT_ROUTE = {
|
||||
agentId: "ops",
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
sessionKey: "agent:ops:main",
|
||||
mainSessionKey: "agent:ops:main",
|
||||
matchedBy: "binding.account" as const,
|
||||
};
|
||||
|
||||
type MatrixHandlerTestHarnessOptions = {
|
||||
accountId?: string;
|
||||
cfg?: unknown;
|
||||
client?: Partial<MatrixClient>;
|
||||
runtime?: RuntimeEnv;
|
||||
logger?: RuntimeLogger;
|
||||
logVerboseMessage?: (message: string) => void;
|
||||
allowFrom?: string[];
|
||||
groupAllowFrom?: string[];
|
||||
roomsConfig?: Record<string, MatrixRoomConfig>;
|
||||
mentionRegexes?: MatrixMonitorHandlerParams["mentionRegexes"];
|
||||
groupPolicy?: "open" | "allowlist" | "disabled";
|
||||
replyToMode?: ReplyToMode;
|
||||
threadReplies?: "off" | "inbound" | "always";
|
||||
dmEnabled?: boolean;
|
||||
dmPolicy?: "pairing" | "allowlist" | "open" | "disabled";
|
||||
textLimit?: number;
|
||||
mediaMaxBytes?: number;
|
||||
startupMs?: number;
|
||||
startupGraceMs?: number;
|
||||
isDirectMessage?: boolean;
|
||||
readAllowFromStore?: MatrixMonitorHandlerParams["core"]["channel"]["pairing"]["readAllowFromStore"];
|
||||
upsertPairingRequest?: MatrixMonitorHandlerParams["core"]["channel"]["pairing"]["upsertPairingRequest"];
|
||||
buildPairingReply?: () => string;
|
||||
shouldHandleTextCommands?: () => boolean;
|
||||
hasControlCommand?: () => boolean;
|
||||
resolveMarkdownTableMode?: () => string;
|
||||
resolveAgentRoute?: () => typeof DEFAULT_ROUTE;
|
||||
resolveStorePath?: () => string;
|
||||
readSessionUpdatedAt?: () => number | undefined;
|
||||
recordInboundSession?: (...args: unknown[]) => Promise<void>;
|
||||
resolveEnvelopeFormatOptions?: () => Record<string, never>;
|
||||
formatAgentEnvelope?: ({ body }: { body: string }) => string;
|
||||
finalizeInboundContext?: (ctx: unknown) => unknown;
|
||||
createReplyDispatcherWithTyping?: () => {
|
||||
dispatcher: Record<string, unknown>;
|
||||
replyOptions: Record<string, unknown>;
|
||||
markDispatchIdle: () => void;
|
||||
};
|
||||
resolveHumanDelayConfig?: () => undefined;
|
||||
dispatchReplyFromConfig?: () => Promise<{
|
||||
queuedFinal: boolean;
|
||||
counts: { final: number; block: number; tool: number };
|
||||
}>;
|
||||
shouldAckReaction?: () => boolean;
|
||||
enqueueSystemEvent?: (...args: unknown[]) => void;
|
||||
getRoomInfo?: MatrixMonitorHandlerParams["getRoomInfo"];
|
||||
getMemberDisplayName?: MatrixMonitorHandlerParams["getMemberDisplayName"];
|
||||
};
|
||||
|
||||
export function createMatrixHandlerTestHarness(options: MatrixHandlerTestHarnessOptions = {}) {
|
||||
const readAllowFromStore = options.readAllowFromStore ?? vi.fn(async () => [] as string[]);
|
||||
const upsertPairingRequest =
|
||||
options.upsertPairingRequest ?? vi.fn(async () => ({ code: "ABCDEFGH", created: false }));
|
||||
const resolveAgentRoute = options.resolveAgentRoute ?? vi.fn(() => DEFAULT_ROUTE);
|
||||
const recordInboundSession = options.recordInboundSession ?? vi.fn(async () => {});
|
||||
const finalizeInboundContext = options.finalizeInboundContext ?? vi.fn((ctx) => ctx);
|
||||
const dispatchReplyFromConfig =
|
||||
options.dispatchReplyFromConfig ??
|
||||
(async () => ({
|
||||
queuedFinal: false,
|
||||
counts: { final: 0, block: 0, tool: 0 },
|
||||
}));
|
||||
const enqueueSystemEvent = options.enqueueSystemEvent ?? vi.fn();
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
getEvent: async () => ({ sender: "@bot:example.org" }),
|
||||
...options.client,
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore,
|
||||
upsertPairingRequest,
|
||||
buildPairingReply: options.buildPairingReply ?? (() => "pairing"),
|
||||
},
|
||||
commands: {
|
||||
shouldHandleTextCommands: options.shouldHandleTextCommands ?? (() => false),
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: options.hasControlCommand ?? (() => false),
|
||||
resolveMarkdownTableMode: options.resolveMarkdownTableMode ?? (() => "preserve"),
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute,
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: options.resolveStorePath ?? (() => "/tmp/session-store"),
|
||||
readSessionUpdatedAt: options.readSessionUpdatedAt ?? (() => undefined),
|
||||
recordInboundSession,
|
||||
},
|
||||
reply: {
|
||||
resolveEnvelopeFormatOptions: options.resolveEnvelopeFormatOptions ?? (() => ({})),
|
||||
formatAgentEnvelope: options.formatAgentEnvelope ?? (({ body }) => body),
|
||||
finalizeInboundContext,
|
||||
createReplyDispatcherWithTyping:
|
||||
options.createReplyDispatcherWithTyping ??
|
||||
(() => ({
|
||||
dispatcher: {},
|
||||
replyOptions: {},
|
||||
markDispatchIdle: () => {},
|
||||
})),
|
||||
resolveHumanDelayConfig: options.resolveHumanDelayConfig ?? (() => undefined),
|
||||
dispatchReplyFromConfig,
|
||||
},
|
||||
reactions: {
|
||||
shouldAckReaction: options.shouldAckReaction ?? (() => false),
|
||||
},
|
||||
},
|
||||
system: {
|
||||
enqueueSystemEvent,
|
||||
},
|
||||
} as never,
|
||||
cfg: (options.cfg ?? {}) as never,
|
||||
accountId: options.accountId ?? "ops",
|
||||
runtime: (options.runtime ??
|
||||
({
|
||||
error: () => {},
|
||||
} as RuntimeEnv)) as RuntimeEnv,
|
||||
logger: (options.logger ??
|
||||
({
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
} as RuntimeLogger)) as RuntimeLogger,
|
||||
logVerboseMessage: options.logVerboseMessage ?? (() => {}),
|
||||
allowFrom: options.allowFrom ?? [],
|
||||
groupAllowFrom: options.groupAllowFrom ?? [],
|
||||
roomsConfig: options.roomsConfig,
|
||||
mentionRegexes: options.mentionRegexes ?? [],
|
||||
groupPolicy: options.groupPolicy ?? "open",
|
||||
replyToMode: options.replyToMode ?? "off",
|
||||
threadReplies: options.threadReplies ?? "inbound",
|
||||
dmEnabled: options.dmEnabled ?? true,
|
||||
dmPolicy: options.dmPolicy ?? "open",
|
||||
textLimit: options.textLimit ?? 8_000,
|
||||
mediaMaxBytes: options.mediaMaxBytes ?? 10_000_000,
|
||||
startupMs: options.startupMs ?? 0,
|
||||
startupGraceMs: options.startupGraceMs ?? 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => options.isDirectMessage ?? true,
|
||||
},
|
||||
getRoomInfo: options.getRoomInfo ?? (async () => ({ altAliases: [] })),
|
||||
getMemberDisplayName: options.getMemberDisplayName ?? (async () => "sender"),
|
||||
});
|
||||
|
||||
return {
|
||||
dispatchReplyFromConfig,
|
||||
enqueueSystemEvent,
|
||||
finalizeInboundContext,
|
||||
handler,
|
||||
readAllowFromStore,
|
||||
recordInboundSession,
|
||||
resolveAgentRoute,
|
||||
upsertPairingRequest,
|
||||
};
|
||||
}
|
||||
|
||||
export function createMatrixTextMessageEvent(params: {
|
||||
eventId: string;
|
||||
sender?: string;
|
||||
body: string;
|
||||
originServerTs?: number;
|
||||
relatesTo?: RoomMessageEventContent["m.relates_to"];
|
||||
mentions?: RoomMessageEventContent["m.mentions"];
|
||||
}): MatrixRawEvent {
|
||||
return {
|
||||
type: EventType.RoomMessage,
|
||||
sender: params.sender ?? "@user:example.org",
|
||||
event_id: params.eventId,
|
||||
origin_server_ts: params.originServerTs ?? Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
body: params.body,
|
||||
...(params.relatesTo ? { "m.relates_to": params.relatesTo } : {}),
|
||||
...(params.mentions ? { "m.mentions": params.mentions } : {}),
|
||||
},
|
||||
} as MatrixRawEvent;
|
||||
}
|
||||
|
||||
export function createMatrixReactionEvent(params: {
|
||||
eventId: string;
|
||||
targetEventId: string;
|
||||
key: string;
|
||||
sender?: string;
|
||||
originServerTs?: number;
|
||||
}): MatrixRawEvent {
|
||||
return {
|
||||
type: EventType.Reaction,
|
||||
sender: params.sender ?? "@user:example.org",
|
||||
event_id: params.eventId,
|
||||
origin_server_ts: params.originServerTs ?? Date.now(),
|
||||
content: {
|
||||
"m.relates_to": {
|
||||
rel_type: "m.annotation",
|
||||
event_id: params.targetEventId,
|
||||
key: params.key,
|
||||
},
|
||||
},
|
||||
} as MatrixRawEvent;
|
||||
}
|
||||
|
|
@ -3,8 +3,12 @@ import {
|
|||
__testing as sessionBindingTesting,
|
||||
registerSessionBindingAdapter,
|
||||
} from "../../../../../src/infra/outbound/session-binding-service.js";
|
||||
import { createMatrixRoomMessageHandler } from "./handler.js";
|
||||
import { EventType, type MatrixRawEvent } from "./types.js";
|
||||
import {
|
||||
createMatrixHandlerTestHarness,
|
||||
createMatrixReactionEvent,
|
||||
createMatrixTextMessageEvent,
|
||||
} from "./handler.test-helpers.js";
|
||||
import type { MatrixRawEvent } from "./types.js";
|
||||
|
||||
const sendMessageMatrixMock = vi.hoisted(() =>
|
||||
vi.fn(async (..._args: unknown[]) => ({ messageId: "evt", roomId: "!room" })),
|
||||
|
|
@ -30,149 +34,47 @@ function createReactionHarness(params?: {
|
|||
isDirectMessage?: boolean;
|
||||
senderName?: string;
|
||||
}) {
|
||||
const readAllowFromStore = vi.fn(async () => params?.storeAllowFrom ?? []);
|
||||
const upsertPairingRequest = vi.fn(async () => ({ code: "ABCDEFGH", created: false }));
|
||||
const resolveAgentRoute = vi.fn(() => ({
|
||||
agentId: "ops",
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
sessionKey: "agent:ops:main",
|
||||
mainSessionKey: "agent:ops:main",
|
||||
matchedBy: "binding.account",
|
||||
}));
|
||||
const enqueueSystemEvent = vi.fn();
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
return createMatrixHandlerTestHarness({
|
||||
cfg: params?.cfg,
|
||||
dmPolicy: params?.dmPolicy,
|
||||
allowFrom: params?.allowFrom,
|
||||
readAllowFromStore: vi.fn(async () => params?.storeAllowFrom ?? []),
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
getEvent: async () => ({ sender: params?.targetSender ?? "@bot:example.org" }),
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore,
|
||||
upsertPairingRequest,
|
||||
buildPairingReply: () => "pairing",
|
||||
},
|
||||
commands: {
|
||||
shouldHandleTextCommands: () => false,
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: () => false,
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute,
|
||||
},
|
||||
},
|
||||
system: {
|
||||
enqueueSystemEvent,
|
||||
},
|
||||
} as never,
|
||||
cfg: (params?.cfg ?? {}) as never,
|
||||
accountId: "ops",
|
||||
runtime: {
|
||||
error: () => {},
|
||||
} as never,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
} as never,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: params?.allowFrom ?? [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
dmPolicy: params?.dmPolicy ?? "open",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => params?.isDirectMessage ?? true,
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
isDirectMessage: params?.isDirectMessage,
|
||||
getMemberDisplayName: async () => params?.senderName ?? "sender",
|
||||
});
|
||||
|
||||
return {
|
||||
handler,
|
||||
enqueueSystemEvent,
|
||||
readAllowFromStore,
|
||||
resolveAgentRoute,
|
||||
upsertPairingRequest,
|
||||
};
|
||||
}
|
||||
|
||||
describe("matrix monitor handler pairing account scope", () => {
|
||||
it("caches account-scoped allowFrom store reads on hot path", async () => {
|
||||
const readAllowFromStore = vi.fn(async () => [] as string[]);
|
||||
const upsertPairingRequest = vi.fn(async () => ({ code: "ABCDEFGH", created: false }));
|
||||
sendMessageMatrixMock.mockClear();
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore,
|
||||
upsertPairingRequest,
|
||||
buildPairingReply: () => "pairing",
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
cfg: {} as never,
|
||||
accountId: "ops",
|
||||
runtime: {} as never,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
} as never,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
const { handler } = createMatrixHandlerTestHarness({
|
||||
readAllowFromStore,
|
||||
dmPolicy: "pairing",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => true,
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
getMemberDisplayName: async () => "sender",
|
||||
buildPairingReply: () => "pairing",
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.RoomMessage,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$event1",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$event1",
|
||||
body: "hello",
|
||||
"m.mentions": { room: true },
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
mentions: { room: true },
|
||||
}),
|
||||
);
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.RoomMessage,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$event2",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$event2",
|
||||
body: "hello again",
|
||||
"m.mentions": { room: true },
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
mentions: { room: true },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(readAllowFromStore).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
|
@ -182,60 +84,22 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
vi.setSystemTime(new Date("2026-03-01T10:00:00.000Z"));
|
||||
try {
|
||||
const readAllowFromStore = vi.fn(async () => [] as string[]);
|
||||
const upsertPairingRequest = vi.fn(async () => ({ code: "ABCDEFGH", created: false }));
|
||||
sendMessageMatrixMock.mockClear();
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore,
|
||||
upsertPairingRequest,
|
||||
buildPairingReply: () => "Pairing code: ABCDEFGH",
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
cfg: {} as never,
|
||||
accountId: "ops",
|
||||
runtime: {} as never,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
} as never,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
const { handler } = createMatrixHandlerTestHarness({
|
||||
readAllowFromStore,
|
||||
dmPolicy: "pairing",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => true,
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
buildPairingReply: () => "Pairing code: ABCDEFGH",
|
||||
isDirectMessage: true,
|
||||
getMemberDisplayName: async () => "sender",
|
||||
});
|
||||
|
||||
const makeEvent = (id: string): MatrixRawEvent =>
|
||||
({
|
||||
type: EventType.RoomMessage,
|
||||
sender: "@user:example.org",
|
||||
event_id: id,
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
body: "hello",
|
||||
"m.mentions": { room: true },
|
||||
},
|
||||
}) as MatrixRawEvent;
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: id,
|
||||
body: "hello",
|
||||
mentions: { room: true },
|
||||
});
|
||||
|
||||
await handler("!room:example.org", makeEvent("$event1"));
|
||||
await handler("!room:example.org", makeEvent("$event2"));
|
||||
|
|
@ -256,55 +120,22 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
const readAllowFromStore = vi.fn(async () => [] as string[]);
|
||||
const upsertPairingRequest = vi.fn(async () => ({ code: "ABCDEFGH", created: false }));
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore,
|
||||
upsertPairingRequest,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
cfg: {} as never,
|
||||
accountId: "ops",
|
||||
runtime: {} as never,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
} as never,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
const { handler } = createMatrixHandlerTestHarness({
|
||||
readAllowFromStore,
|
||||
upsertPairingRequest,
|
||||
dmPolicy: "pairing",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => true,
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
isDirectMessage: true,
|
||||
getMemberDisplayName: async () => "sender",
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.RoomMessage,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$event1",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$event1",
|
||||
body: "hello",
|
||||
"m.mentions": { room: true },
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
mentions: { room: true },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(readAllowFromStore).toHaveBeenCalledWith({
|
||||
channel: "matrix",
|
||||
|
|
@ -329,66 +160,20 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
matchedBy: "binding.account",
|
||||
}));
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore: async () => [] as string[],
|
||||
upsertPairingRequest: async () => ({ code: "ABCDEFGH", created: false }),
|
||||
},
|
||||
commands: {
|
||||
shouldHandleTextCommands: () => false,
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: () => false,
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
cfg: {} as never,
|
||||
accountId: "ops",
|
||||
runtime: {
|
||||
error: () => {},
|
||||
} as never,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
} as never,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
dmPolicy: "open",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => true,
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
const { handler } = createMatrixHandlerTestHarness({
|
||||
resolveAgentRoute,
|
||||
isDirectMessage: true,
|
||||
getMemberDisplayName: async () => "sender",
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.RoomMessage,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$event2",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$event2",
|
||||
body: "hello",
|
||||
"m.mentions": { room: true },
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
mentions: { room: true },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
|
@ -399,116 +184,34 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
});
|
||||
|
||||
it("records thread starter context for inbound thread replies", async () => {
|
||||
const recordInboundSession = vi.fn(async () => {});
|
||||
const finalizeInboundContext = vi.fn((ctx) => ctx);
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
getEvent: async () => ({
|
||||
event_id: "$root",
|
||||
sender: "@alice:example.org",
|
||||
type: EventType.RoomMessage,
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
body: "Root topic",
|
||||
},
|
||||
}),
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore: async () => [] as string[],
|
||||
upsertPairingRequest: async () => ({ code: "ABCDEFGH", created: false }),
|
||||
},
|
||||
commands: {
|
||||
shouldHandleTextCommands: () => false,
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: () => false,
|
||||
resolveMarkdownTableMode: () => "preserve",
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute: () => ({
|
||||
agentId: "ops",
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
sessionKey: "agent:ops:main",
|
||||
mainSessionKey: "agent:ops:main",
|
||||
matchedBy: "binding.account",
|
||||
const { handler, finalizeInboundContext, recordInboundSession } =
|
||||
createMatrixHandlerTestHarness({
|
||||
client: {
|
||||
getEvent: async () =>
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$root",
|
||||
sender: "@alice:example.org",
|
||||
body: "Root topic",
|
||||
}),
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: () => "/tmp/session-store",
|
||||
readSessionUpdatedAt: () => undefined,
|
||||
recordInboundSession,
|
||||
},
|
||||
reply: {
|
||||
resolveEnvelopeFormatOptions: () => ({}),
|
||||
formatAgentEnvelope: ({ body }: { body: string }) => body,
|
||||
finalizeInboundContext,
|
||||
createReplyDispatcherWithTyping: () => ({
|
||||
dispatcher: {},
|
||||
replyOptions: {},
|
||||
markDispatchIdle: () => {},
|
||||
}),
|
||||
resolveHumanDelayConfig: () => undefined,
|
||||
dispatchReplyFromConfig: async () => ({
|
||||
queuedFinal: false,
|
||||
counts: { final: 0, block: 0, tool: 0 },
|
||||
}),
|
||||
},
|
||||
reactions: {
|
||||
shouldAckReaction: () => false,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
cfg: {} as never,
|
||||
accountId: "ops",
|
||||
runtime: {
|
||||
error: () => {},
|
||||
} as never,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
} as never,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
dmPolicy: "open",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => false,
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
getMemberDisplayName: async (_roomId, userId) =>
|
||||
userId === "@alice:example.org" ? "Alice" : "sender",
|
||||
});
|
||||
isDirectMessage: false,
|
||||
getMemberDisplayName: async (_roomId, userId) =>
|
||||
userId === "@alice:example.org" ? "Alice" : "sender",
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.RoomMessage,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$reply1",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$reply1",
|
||||
body: "follow up",
|
||||
"m.relates_to": {
|
||||
relatesTo: {
|
||||
rel_type: "m.thread",
|
||||
event_id: "$root",
|
||||
"m.in_reply_to": { event_id: "$root" },
|
||||
},
|
||||
"m.mentions": { room: true },
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
mentions: { room: true },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(finalizeInboundContext).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
|
@ -549,114 +252,33 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
: null,
|
||||
touch: vi.fn(),
|
||||
});
|
||||
const recordInboundSession = vi.fn(async () => {});
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
const { handler, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
client: {
|
||||
getUserId: async () => "@bot:example.org",
|
||||
getEvent: async () => ({
|
||||
event_id: "$root",
|
||||
sender: "@alice:example.org",
|
||||
type: EventType.RoomMessage,
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
getEvent: async () =>
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$root",
|
||||
sender: "@alice:example.org",
|
||||
body: "Root topic",
|
||||
},
|
||||
}),
|
||||
} as never,
|
||||
core: {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore: async () => [] as string[],
|
||||
upsertPairingRequest: async () => ({ code: "ABCDEFGH", created: false }),
|
||||
},
|
||||
commands: {
|
||||
shouldHandleTextCommands: () => false,
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: () => false,
|
||||
resolveMarkdownTableMode: () => "preserve",
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute: () => ({
|
||||
agentId: "ops",
|
||||
channel: "matrix",
|
||||
accountId: "ops",
|
||||
sessionKey: "agent:ops:main",
|
||||
mainSessionKey: "agent:ops:main",
|
||||
matchedBy: "binding.account",
|
||||
}),
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: () => "/tmp/session-store",
|
||||
readSessionUpdatedAt: () => undefined,
|
||||
recordInboundSession,
|
||||
},
|
||||
reply: {
|
||||
resolveEnvelopeFormatOptions: () => ({}),
|
||||
formatAgentEnvelope: ({ body }: { body: string }) => body,
|
||||
finalizeInboundContext: (ctx: unknown) => ctx,
|
||||
createReplyDispatcherWithTyping: () => ({
|
||||
dispatcher: {},
|
||||
replyOptions: {},
|
||||
markDispatchIdle: () => {},
|
||||
}),
|
||||
resolveHumanDelayConfig: () => undefined,
|
||||
dispatchReplyFromConfig: async () => ({
|
||||
queuedFinal: false,
|
||||
counts: { final: 0, block: 0, tool: 0 },
|
||||
}),
|
||||
},
|
||||
reactions: {
|
||||
shouldAckReaction: () => false,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
cfg: {} as never,
|
||||
accountId: "ops",
|
||||
runtime: {
|
||||
error: () => {},
|
||||
} as never,
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
} as never,
|
||||
logVerboseMessage: () => {},
|
||||
allowFrom: [],
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "off",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
dmPolicy: "open",
|
||||
textLimit: 8_000,
|
||||
mediaMaxBytes: 10_000_000,
|
||||
startupMs: 0,
|
||||
startupGraceMs: 0,
|
||||
directTracker: {
|
||||
isDirectMessage: async () => false,
|
||||
}),
|
||||
},
|
||||
getRoomInfo: async () => ({ altAliases: [] }),
|
||||
isDirectMessage: false,
|
||||
finalizeInboundContext: (ctx: unknown) => ctx,
|
||||
getMemberDisplayName: async () => "sender",
|
||||
});
|
||||
|
||||
await handler("!room:example", {
|
||||
type: EventType.RoomMessage,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$reply1",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
await handler(
|
||||
"!room:example",
|
||||
createMatrixTextMessageEvent({
|
||||
eventId: "$reply1",
|
||||
body: "follow up",
|
||||
"m.relates_to": {
|
||||
relatesTo: {
|
||||
rel_type: "m.thread",
|
||||
event_id: "$root",
|
||||
"m.in_reply_to": { event_id: "$root" },
|
||||
},
|
||||
"m.mentions": { room: true },
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
mentions: { room: true },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(recordInboundSession).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
|
@ -770,19 +392,14 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
it("enqueues system events for reactions on bot-authored messages", async () => {
|
||||
const { handler, enqueueSystemEvent, resolveAgentRoute } = createReactionHarness();
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.Reaction,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$reaction1",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
"m.relates_to": {
|
||||
rel_type: "m.annotation",
|
||||
event_id: "$msg1",
|
||||
key: "👍",
|
||||
},
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixReactionEvent({
|
||||
eventId: "$reaction1",
|
||||
targetEventId: "$msg1",
|
||||
key: "👍",
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
|
@ -804,19 +421,14 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
targetSender: "@other:example.org",
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.Reaction,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$reaction2",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
"m.relates_to": {
|
||||
rel_type: "m.annotation",
|
||||
event_id: "$msg2",
|
||||
key: "👀",
|
||||
},
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixReactionEvent({
|
||||
eventId: "$reaction2",
|
||||
targetEventId: "$msg2",
|
||||
key: "👀",
|
||||
}),
|
||||
);
|
||||
|
||||
expect(enqueueSystemEvent).not.toHaveBeenCalled();
|
||||
expect(resolveAgentRoute).not.toHaveBeenCalled();
|
||||
|
|
@ -827,19 +439,14 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
dmPolicy: "pairing",
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.Reaction,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$reaction3",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
"m.relates_to": {
|
||||
rel_type: "m.annotation",
|
||||
event_id: "$msg3",
|
||||
key: "🔥",
|
||||
},
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixReactionEvent({
|
||||
eventId: "$reaction3",
|
||||
targetEventId: "$msg3",
|
||||
key: "🔥",
|
||||
}),
|
||||
);
|
||||
|
||||
expect(upsertPairingRequest).not.toHaveBeenCalled();
|
||||
expect(enqueueSystemEvent).not.toHaveBeenCalled();
|
||||
|
|
@ -861,19 +468,14 @@ describe("matrix monitor handler pairing account scope", () => {
|
|||
},
|
||||
});
|
||||
|
||||
await handler("!room:example.org", {
|
||||
type: EventType.Reaction,
|
||||
sender: "@user:example.org",
|
||||
event_id: "$reaction4",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
"m.relates_to": {
|
||||
rel_type: "m.annotation",
|
||||
event_id: "$msg4",
|
||||
key: "✅",
|
||||
},
|
||||
},
|
||||
} as MatrixRawEvent);
|
||||
await handler(
|
||||
"!room:example.org",
|
||||
createMatrixReactionEvent({
|
||||
eventId: "$reaction4",
|
||||
targetEventId: "$msg4",
|
||||
key: "✅",
|
||||
}),
|
||||
);
|
||||
|
||||
expect(enqueueSystemEvent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue