mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-21 23:11:01 +00:00
fix(matrix): pass agentId to buildMentionRegexes for agent-level mention patterns (#51272)
* fix(matrix): pass agentId to buildMentionRegexes for agent-level mention patterns * fix(matrix): resolve conflicts from main branch * Retrigger CI --------- Co-authored-by: Dinakar Sarbada <dinakars777@users.noreply.github.com>
This commit is contained in:
@@ -40,6 +40,9 @@ function createHandlerHarness() {
|
||||
mainSessionKey: "agent:main:main",
|
||||
}),
|
||||
},
|
||||
mentions: {
|
||||
buildMentionRegexes: vi.fn().mockReturnValue([]),
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: vi.fn().mockReturnValue("/tmp/openclaw-test-session.json"),
|
||||
readSessionUpdatedAt: vi.fn().mockReturnValue(123),
|
||||
|
||||
@@ -134,6 +134,9 @@ export function createMatrixHandlerTestHarness(
|
||||
routing: {
|
||||
resolveAgentRoute,
|
||||
},
|
||||
mentions: {
|
||||
buildMentionRegexes: () => options.mentionRegexes ?? [],
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: options.resolveStorePath ?? (() => "/tmp/session-store"),
|
||||
readSessionUpdatedAt: options.readSessionUpdatedAt ?? (() => undefined),
|
||||
|
||||
@@ -261,7 +261,7 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
});
|
||||
|
||||
it("drops room messages from configured Matrix bot accounts when allowBots is off", async () => {
|
||||
const { handler, resolveAgentRoute, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
const { handler, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
isDirectMessage: false,
|
||||
configuredBotUserIds: new Set(["@ops:example.org"]),
|
||||
roomsConfig: {
|
||||
@@ -279,12 +279,11 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).not.toHaveBeenCalled();
|
||||
expect(recordInboundSession).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("accepts room messages from configured Matrix bot accounts when allowBots is true", async () => {
|
||||
const { handler, resolveAgentRoute, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
const { handler, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
isDirectMessage: false,
|
||||
accountAllowBots: true,
|
||||
configuredBotUserIds: new Set(["@ops:example.org"]),
|
||||
@@ -303,7 +302,6 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).toHaveBeenCalled();
|
||||
expect(recordInboundSession).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -331,7 +329,7 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
});
|
||||
|
||||
it('drops configured Matrix bot room messages without a mention when allowBots="mentions"', async () => {
|
||||
const { handler, resolveAgentRoute, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
const { handler, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
isDirectMessage: false,
|
||||
accountAllowBots: "mentions",
|
||||
configuredBotUserIds: new Set(["@ops:example.org"]),
|
||||
@@ -351,12 +349,11 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).not.toHaveBeenCalled();
|
||||
expect(recordInboundSession).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('accepts configured Matrix bot room messages with a mention when allowBots="mentions"', async () => {
|
||||
const { handler, resolveAgentRoute, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
const { handler, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
isDirectMessage: false,
|
||||
accountAllowBots: "mentions",
|
||||
configuredBotUserIds: new Set(["@ops:example.org"]),
|
||||
@@ -377,12 +374,11 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).toHaveBeenCalled();
|
||||
expect(recordInboundSession).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('accepts configured Matrix bot DMs without a mention when allowBots="mentions"', async () => {
|
||||
const { handler, resolveAgentRoute, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
const { handler, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
isDirectMessage: true,
|
||||
accountAllowBots: "mentions",
|
||||
configuredBotUserIds: new Set(["@ops:example.org"]),
|
||||
@@ -398,12 +394,11 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).toHaveBeenCalled();
|
||||
expect(recordInboundSession).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("lets room-level allowBots override a permissive account default", async () => {
|
||||
const { handler, resolveAgentRoute, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
const { handler, recordInboundSession } = createMatrixHandlerTestHarness({
|
||||
isDirectMessage: false,
|
||||
accountAllowBots: true,
|
||||
configuredBotUserIds: new Set(["@ops:example.org"]),
|
||||
@@ -422,7 +417,6 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).not.toHaveBeenCalled();
|
||||
expect(recordInboundSession).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -442,7 +436,6 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
expect(resolveAgentRoute).not.toHaveBeenCalled();
|
||||
expect(recordInboundSession).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -450,7 +443,7 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
const downloadContent = vi.fn(async () => Buffer.from("image"));
|
||||
const getMemberDisplayName = vi.fn(async () => "sender");
|
||||
const getRoomInfo = vi.fn(async () => ({ altAliases: [] }));
|
||||
const { handler, resolveAgentRoute } = createMatrixHandlerTestHarness({
|
||||
const { handler } = createMatrixHandlerTestHarness({
|
||||
client: {
|
||||
downloadContent,
|
||||
},
|
||||
@@ -479,7 +472,6 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
expect(downloadContent).not.toHaveBeenCalled();
|
||||
expect(getMemberDisplayName).not.toHaveBeenCalled();
|
||||
expect(getRoomInfo).not.toHaveBeenCalled();
|
||||
expect(resolveAgentRoute).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("skips poll snapshot fetches for unmentioned group poll responses", async () => {
|
||||
@@ -504,7 +496,7 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
}));
|
||||
const getMemberDisplayName = vi.fn(async () => "sender");
|
||||
const getRoomInfo = vi.fn(async () => ({ altAliases: [] }));
|
||||
const { handler, resolveAgentRoute } = createMatrixHandlerTestHarness({
|
||||
const { handler } = createMatrixHandlerTestHarness({
|
||||
client: {
|
||||
getEvent,
|
||||
getRelations,
|
||||
@@ -535,7 +527,6 @@ describe("matrix monitor handler pairing account scope", () => {
|
||||
expect(getRelations).not.toHaveBeenCalled();
|
||||
expect(getMemberDisplayName).not.toHaveBeenCalled();
|
||||
expect(getRoomInfo).not.toHaveBeenCalled();
|
||||
expect(resolveAgentRoute).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("records thread starter context for inbound thread replies", async () => {
|
||||
|
||||
@@ -45,6 +45,9 @@ describe("createMatrixRoomMessageHandler thread root media", () => {
|
||||
mainSessionKey: "agent:main:main",
|
||||
}),
|
||||
},
|
||||
mentions: {
|
||||
buildMentionRegexes: vi.fn().mockReturnValue([]),
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: vi.fn().mockReturnValue("/tmp/openclaw-test-session.json"),
|
||||
readSessionUpdatedAt: vi.fn().mockReturnValue(undefined),
|
||||
|
||||
@@ -527,11 +527,25 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
return;
|
||||
}
|
||||
|
||||
const _messageId = event.event_id ?? "";
|
||||
const _threadRootId = resolveMatrixThreadRootId({ event, content });
|
||||
const { route: _route, configuredBinding: _configuredBinding } = resolveMatrixInboundRoute({
|
||||
cfg,
|
||||
accountId,
|
||||
roomId,
|
||||
senderId,
|
||||
isDirectMessage,
|
||||
messageId: _messageId,
|
||||
threadRootId: _threadRootId,
|
||||
eventTs: eventTs ?? undefined,
|
||||
resolveAgentRoute: core.channel.routing.resolveAgentRoute,
|
||||
});
|
||||
const agentMentionRegexes = core.channel.mentions.buildMentionRegexes(cfg, _route.agentId);
|
||||
const { wasMentioned, hasExplicitMention } = resolveMentions({
|
||||
content,
|
||||
userId: selfUserId,
|
||||
text: mentionPrecheckText,
|
||||
mentionRegexes,
|
||||
mentionRegexes: agentMentionRegexes,
|
||||
});
|
||||
if (
|
||||
isConfiguredBotSender &&
|
||||
@@ -588,7 +602,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
!hasExplicitMention &&
|
||||
commandAuthorized &&
|
||||
hasControlCommandInMessage;
|
||||
const canDetectMention = mentionRegexes.length > 0 || hasExplicitMention;
|
||||
const canDetectMention = agentMentionRegexes.length > 0 || hasExplicitMention;
|
||||
if (isRoom && shouldRequireMention && !wasMentioned && !shouldBypassMention) {
|
||||
logger.info("skipping room message", { roomId, reason: "no-mention" });
|
||||
await commitInboundEventIfClaimed();
|
||||
@@ -674,54 +688,41 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
const roomInfo = isRoom ? await getRoomInfo(roomId) : undefined;
|
||||
const roomName = roomInfo?.name;
|
||||
|
||||
const messageId = event.event_id ?? "";
|
||||
const replyToEventId = content["m.relates_to"]?.["m.in_reply_to"]?.event_id;
|
||||
const threadRootId = resolveMatrixThreadRootId({ event, content });
|
||||
const threadTarget = resolveMatrixThreadTarget({
|
||||
threadReplies,
|
||||
messageId,
|
||||
threadRootId,
|
||||
messageId: _messageId,
|
||||
threadRootId: _threadRootId,
|
||||
isThreadRoot: false, // Raw event payload does not carry explicit thread-root metadata.
|
||||
});
|
||||
const threadContext = threadRootId
|
||||
? await resolveThreadContext({ roomId, threadRootId })
|
||||
const threadContext = _threadRootId
|
||||
? await resolveThreadContext({ roomId, threadRootId: _threadRootId })
|
||||
: undefined;
|
||||
|
||||
const { route, configuredBinding } = resolveMatrixInboundRoute({
|
||||
cfg,
|
||||
accountId,
|
||||
roomId,
|
||||
senderId,
|
||||
isDirectMessage,
|
||||
messageId,
|
||||
threadRootId,
|
||||
eventTs: eventTs ?? undefined,
|
||||
resolveAgentRoute: core.channel.routing.resolveAgentRoute,
|
||||
});
|
||||
if (configuredBinding) {
|
||||
if (_configuredBinding) {
|
||||
const ensured = await ensureConfiguredAcpBindingReady({
|
||||
cfg,
|
||||
configuredBinding,
|
||||
configuredBinding: _configuredBinding,
|
||||
});
|
||||
if (!ensured.ok) {
|
||||
logInboundDrop({
|
||||
log: logVerboseMessage,
|
||||
channel: "matrix",
|
||||
reason: "configured ACP binding unavailable",
|
||||
target: configuredBinding.spec.conversationId,
|
||||
target: _configuredBinding.spec.conversationId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
const envelopeFrom = isDirectMessage ? senderName : (roomName ?? roomId);
|
||||
const textWithId = `${bodyText}\n[matrix event id: ${messageId} room: ${roomId}]`;
|
||||
const textWithId = `${bodyText}\n[matrix event id: ${_messageId} room: ${roomId}]`;
|
||||
const storePath = core.channel.session.resolveStorePath(cfg.session?.store, {
|
||||
agentId: route.agentId,
|
||||
agentId: _route.agentId,
|
||||
});
|
||||
const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(cfg);
|
||||
const previousTimestamp = core.channel.session.readSessionUpdatedAt({
|
||||
storePath,
|
||||
sessionKey: route.sessionKey,
|
||||
sessionKey: _route.sessionKey,
|
||||
});
|
||||
const body = core.channel.reply.formatAgentEnvelope({
|
||||
channel: "Matrix",
|
||||
@@ -739,8 +740,8 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
CommandBody: bodyText,
|
||||
From: isDirectMessage ? `matrix:${senderId}` : `matrix:channel:${roomId}`,
|
||||
To: `room:${roomId}`,
|
||||
SessionKey: route.sessionKey,
|
||||
AccountId: route.accountId,
|
||||
SessionKey: _route.sessionKey,
|
||||
AccountId: _route.accountId,
|
||||
ChatType: isDirectMessage ? "direct" : "channel",
|
||||
ConversationLabel: envelopeFrom,
|
||||
SenderName: senderName,
|
||||
@@ -752,7 +753,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
Provider: "matrix" as const,
|
||||
Surface: "matrix" as const,
|
||||
WasMentioned: isRoom ? wasMentioned : undefined,
|
||||
MessageSid: messageId,
|
||||
MessageSid: _messageId,
|
||||
ReplyToId: threadTarget ? undefined : (replyToEventId ?? undefined),
|
||||
MessageThreadId: threadTarget,
|
||||
ThreadStarterBody: threadContext?.threadStarterBody,
|
||||
@@ -769,21 +770,21 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
|
||||
await core.channel.session.recordInboundSession({
|
||||
storePath,
|
||||
sessionKey: ctxPayload.SessionKey ?? route.sessionKey,
|
||||
sessionKey: ctxPayload.SessionKey ?? _route.sessionKey,
|
||||
ctx: ctxPayload,
|
||||
updateLastRoute: isDirectMessage
|
||||
? {
|
||||
sessionKey: route.mainSessionKey,
|
||||
sessionKey: _route.mainSessionKey,
|
||||
channel: "matrix",
|
||||
to: `room:${roomId}`,
|
||||
accountId: route.accountId,
|
||||
accountId: _route.accountId,
|
||||
}
|
||||
: undefined,
|
||||
onRecordError: (err) => {
|
||||
logger.warn("failed updating session meta", {
|
||||
error: String(err),
|
||||
storePath,
|
||||
sessionKey: ctxPayload.SessionKey ?? route.sessionKey,
|
||||
sessionKey: ctxPayload.SessionKey ?? _route.sessionKey,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -793,7 +794,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
|
||||
const { ackReaction, ackReactionScope: ackScope } = resolveMatrixAckReactionConfig({
|
||||
cfg,
|
||||
agentId: route.agentId,
|
||||
agentId: _route.agentId,
|
||||
accountId,
|
||||
});
|
||||
const shouldAckReaction = () =>
|
||||
@@ -810,8 +811,8 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
shouldBypassMention,
|
||||
}),
|
||||
);
|
||||
if (shouldAckReaction() && messageId) {
|
||||
reactMatrixMessage(roomId, messageId, ackReaction, client).catch((err) => {
|
||||
if (shouldAckReaction() && _messageId) {
|
||||
reactMatrixMessage(roomId, _messageId, ackReaction, client).catch((err) => {
|
||||
logVerboseMessage(`matrix react failed for room ${roomId}: ${String(err)}`);
|
||||
});
|
||||
}
|
||||
@@ -822,10 +823,10 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
return;
|
||||
}
|
||||
|
||||
if (messageId) {
|
||||
sendReadReceiptMatrix(roomId, messageId, client).catch((err) => {
|
||||
if (_messageId) {
|
||||
sendReadReceiptMatrix(roomId, _messageId, client).catch((err) => {
|
||||
logVerboseMessage(
|
||||
`matrix: read receipt failed room=${roomId} id=${messageId}: ${String(err)}`,
|
||||
`matrix: read receipt failed room=${roomId} id=${_messageId}: ${String(err)}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -833,16 +834,16 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
const tableMode = core.channel.text.resolveMarkdownTableMode({
|
||||
cfg,
|
||||
channel: "matrix",
|
||||
accountId: route.accountId,
|
||||
accountId: _route.accountId,
|
||||
});
|
||||
const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, route.agentId);
|
||||
const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, _route.agentId);
|
||||
let finalReplyDeliveryFailed = false;
|
||||
let nonFinalReplyDeliveryFailed = false;
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg,
|
||||
agentId: route.agentId,
|
||||
agentId: _route.agentId,
|
||||
channel: "matrix",
|
||||
accountId: route.accountId,
|
||||
accountId: _route.accountId,
|
||||
});
|
||||
const typingCallbacks = createTypingCallbacks({
|
||||
start: () => sendTypingMatrix(roomId, true, undefined, client),
|
||||
@@ -869,7 +870,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } =
|
||||
core.channel.reply.createReplyDispatcherWithTyping({
|
||||
...prefixOptions,
|
||||
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
|
||||
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, _route.agentId),
|
||||
deliver: async (payload: ReplyPayload) => {
|
||||
await deliverMatrixReplies({
|
||||
cfg,
|
||||
@@ -880,7 +881,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
textLimit,
|
||||
replyToMode,
|
||||
threadId: threadTarget,
|
||||
accountId: route.accountId,
|
||||
accountId: _route.accountId,
|
||||
mediaLocalRoots,
|
||||
tableMode,
|
||||
});
|
||||
@@ -921,13 +922,13 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
});
|
||||
if (finalReplyDeliveryFailed) {
|
||||
logVerboseMessage(
|
||||
`matrix: final reply delivery failed room=${roomId} id=${messageId}; leaving event uncommitted`,
|
||||
`matrix: final reply delivery failed room=${roomId} id=${_messageId}; leaving event uncommitted`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!queuedFinal && nonFinalReplyDeliveryFailed) {
|
||||
logVerboseMessage(
|
||||
`matrix: non-final reply delivery failed room=${roomId} id=${messageId}; leaving event uncommitted`,
|
||||
`matrix: non-final reply delivery failed room=${roomId} id=${_messageId}; leaving event uncommitted`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user