refactor(matrix): dedupe sender label resolution for inbound bodies
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
||||
import type { PluginRuntime, RuntimeEnv, RuntimeLogger } from "openclaw/plugin-sdk";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createMatrixRoomMessageHandler } from "./handler.js";
|
||||
import { EventType, type MatrixRawEvent } from "./types.js";
|
||||
|
||||
describe("createMatrixRoomMessageHandler BodyForAgent sender label", () => {
|
||||
it("stores sender-labeled BodyForAgent for group thread messages", async () => {
|
||||
const recordInboundSession = vi.fn().mockResolvedValue(undefined);
|
||||
const formatInboundEnvelope = vi
|
||||
.fn()
|
||||
.mockImplementation((params: { senderLabel?: string; body: string }) => params.body);
|
||||
const finalizeInboundContext = vi
|
||||
.fn()
|
||||
.mockImplementation((ctx: Record<string, unknown>) => ctx);
|
||||
|
||||
const core = {
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore: vi.fn().mockResolvedValue([]),
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute: vi.fn().mockReturnValue({
|
||||
agentId: "main",
|
||||
accountId: undefined,
|
||||
sessionKey: "agent:main:matrix:channel:!room:example.org",
|
||||
mainSessionKey: "agent:main:main",
|
||||
}),
|
||||
},
|
||||
session: {
|
||||
resolveStorePath: vi.fn().mockReturnValue("/tmp/openclaw-test-session.json"),
|
||||
readSessionUpdatedAt: vi.fn().mockReturnValue(123),
|
||||
recordInboundSession,
|
||||
},
|
||||
reply: {
|
||||
resolveEnvelopeFormatOptions: vi.fn().mockReturnValue({}),
|
||||
formatInboundEnvelope,
|
||||
formatAgentEnvelope: vi
|
||||
.fn()
|
||||
.mockImplementation((params: { body: string }) => params.body),
|
||||
finalizeInboundContext,
|
||||
resolveHumanDelayConfig: vi.fn().mockReturnValue(undefined),
|
||||
createReplyDispatcherWithTyping: vi.fn().mockReturnValue({
|
||||
dispatcher: {},
|
||||
replyOptions: {},
|
||||
markDispatchIdle: vi.fn(),
|
||||
}),
|
||||
withReplyDispatcher: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ queuedFinal: false, counts: { final: 0, partial: 0, tool: 0 } }),
|
||||
},
|
||||
commands: {
|
||||
shouldHandleTextCommands: vi.fn().mockReturnValue(true),
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: vi.fn().mockReturnValue(false),
|
||||
resolveMarkdownTableMode: vi.fn().mockReturnValue("code"),
|
||||
},
|
||||
},
|
||||
system: {
|
||||
enqueueSystemEvent: vi.fn(),
|
||||
},
|
||||
} as unknown as PluginRuntime;
|
||||
|
||||
const runtime = {
|
||||
error: vi.fn(),
|
||||
} as unknown as RuntimeEnv;
|
||||
const logger = {
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
} as unknown as RuntimeLogger;
|
||||
const logVerboseMessage = vi.fn();
|
||||
|
||||
const client = {
|
||||
getUserId: vi.fn().mockResolvedValue("@bot:matrix.example.org"),
|
||||
} as unknown as MatrixClient;
|
||||
|
||||
const handler = createMatrixRoomMessageHandler({
|
||||
client,
|
||||
core,
|
||||
cfg: {},
|
||||
runtime,
|
||||
logger,
|
||||
logVerboseMessage,
|
||||
allowFrom: [],
|
||||
roomsConfig: undefined,
|
||||
mentionRegexes: [],
|
||||
groupPolicy: "open",
|
||||
replyToMode: "first",
|
||||
threadReplies: "inbound",
|
||||
dmEnabled: true,
|
||||
dmPolicy: "open",
|
||||
textLimit: 4000,
|
||||
mediaMaxBytes: 5 * 1024 * 1024,
|
||||
startupMs: Date.now(),
|
||||
startupGraceMs: 60_000,
|
||||
directTracker: {
|
||||
isDirectMessage: vi.fn().mockResolvedValue(false),
|
||||
},
|
||||
getRoomInfo: vi.fn().mockResolvedValue({
|
||||
name: "Dev Room",
|
||||
canonicalAlias: "#dev:matrix.example.org",
|
||||
altAliases: [],
|
||||
}),
|
||||
getMemberDisplayName: vi.fn().mockResolvedValue("Bu"),
|
||||
accountId: undefined,
|
||||
});
|
||||
|
||||
const event = {
|
||||
type: EventType.RoomMessage,
|
||||
event_id: "$event1",
|
||||
sender: "@bu:matrix.example.org",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
body: "show me my commits",
|
||||
"m.mentions": { user_ids: ["@bot:matrix.example.org"] },
|
||||
"m.relates_to": {
|
||||
rel_type: "m.thread",
|
||||
event_id: "$thread-root",
|
||||
},
|
||||
},
|
||||
} as unknown as MatrixRawEvent;
|
||||
|
||||
await handler("!room:example.org", event);
|
||||
|
||||
expect(formatInboundEnvelope).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
chatType: "channel",
|
||||
senderLabel: "Bu (bu)",
|
||||
}),
|
||||
);
|
||||
expect(recordInboundSession).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
ctx: expect.objectContaining({
|
||||
ChatType: "thread",
|
||||
BodyForAgent: "Bu (bu): show me my commits",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -26,7 +26,11 @@ import {
|
||||
resolveMatrixAllowListMatch,
|
||||
resolveMatrixAllowListMatches,
|
||||
} from "./allowlist.js";
|
||||
import { resolveMatrixBodyForAgent } from "./inbound-body.js";
|
||||
import {
|
||||
resolveMatrixBodyForAgent,
|
||||
resolveMatrixInboundSenderLabel,
|
||||
resolveMatrixSenderUsername,
|
||||
} from "./inbound-body.js";
|
||||
import { resolveMatrixLocation, type MatrixLocationPayload } from "./location.js";
|
||||
import { downloadMatrixMedia } from "./media.js";
|
||||
import { resolveMentions } from "./mentions.js";
|
||||
@@ -216,7 +220,12 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
}
|
||||
|
||||
const senderName = await getMemberDisplayName(roomId, senderId);
|
||||
const senderUsername = senderId.split(":")[0]?.replace(/^@/, "");
|
||||
const senderUsername = resolveMatrixSenderUsername(senderId);
|
||||
const senderLabel = resolveMatrixInboundSenderLabel({
|
||||
senderName,
|
||||
senderId,
|
||||
senderUsername,
|
||||
});
|
||||
const storeAllowFrom = isDirectMessage
|
||||
? await readStoreAllowFromForDmPolicy({
|
||||
provider: "matrix",
|
||||
@@ -531,7 +540,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
envelope: envelopeOptions,
|
||||
body: textWithId,
|
||||
chatType: isDirectMessage ? "direct" : "channel",
|
||||
sender: { name: senderName, username: senderUsername },
|
||||
senderLabel,
|
||||
});
|
||||
|
||||
const groupSystemPrompt = roomConfig?.systemPrompt?.trim() || undefined;
|
||||
@@ -540,8 +549,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
BodyForAgent: resolveMatrixBodyForAgent({
|
||||
isDirectMessage,
|
||||
bodyText,
|
||||
senderName,
|
||||
senderId,
|
||||
senderLabel,
|
||||
}),
|
||||
RawBody: bodyText,
|
||||
CommandBody: bodyText,
|
||||
|
||||
@@ -1,7 +1,27 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveMatrixBodyForAgent, resolveMatrixInboundSenderLabel } from "./inbound-body.js";
|
||||
import {
|
||||
resolveMatrixBodyForAgent,
|
||||
resolveMatrixInboundSenderLabel,
|
||||
resolveMatrixSenderUsername,
|
||||
} from "./inbound-body.js";
|
||||
|
||||
describe("resolveMatrixSenderUsername", () => {
|
||||
it("extracts localpart without leading @", () => {
|
||||
expect(resolveMatrixSenderUsername("@bu:matrix.example.org")).toBe("bu");
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveMatrixInboundSenderLabel", () => {
|
||||
it("uses provided senderUsername when present", () => {
|
||||
expect(
|
||||
resolveMatrixInboundSenderLabel({
|
||||
senderName: "Bu",
|
||||
senderId: "@bu:matrix.example.org",
|
||||
senderUsername: "BU_CUSTOM",
|
||||
}),
|
||||
).toBe("Bu (BU_CUSTOM)");
|
||||
});
|
||||
|
||||
it("includes sender username when it differs from display name", () => {
|
||||
expect(
|
||||
resolveMatrixInboundSenderLabel({
|
||||
@@ -36,8 +56,7 @@ describe("resolveMatrixBodyForAgent", () => {
|
||||
resolveMatrixBodyForAgent({
|
||||
isDirectMessage: true,
|
||||
bodyText: "show me my commits",
|
||||
senderName: "Bu",
|
||||
senderId: "@bu:matrix.example.org",
|
||||
senderLabel: "Bu (bu)",
|
||||
}),
|
||||
).toBe("show me my commits");
|
||||
});
|
||||
@@ -47,8 +66,7 @@ describe("resolveMatrixBodyForAgent", () => {
|
||||
resolveMatrixBodyForAgent({
|
||||
isDirectMessage: false,
|
||||
bodyText: "show me my commits",
|
||||
senderName: "Bu",
|
||||
senderId: "@bu:matrix.example.org",
|
||||
senderLabel: "Bu (bu)",
|
||||
}),
|
||||
).toBe("Bu (bu): show me my commits");
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function resolveMatrixSenderUsername(senderId: string): string | undefined {
|
||||
export function resolveMatrixSenderUsername(senderId: string): string | undefined {
|
||||
const username = senderId.split(":")[0]?.replace(/^@/, "").trim();
|
||||
return username ? username : undefined;
|
||||
}
|
||||
@@ -6,9 +6,10 @@ function resolveMatrixSenderUsername(senderId: string): string | undefined {
|
||||
export function resolveMatrixInboundSenderLabel(params: {
|
||||
senderName: string;
|
||||
senderId: string;
|
||||
senderUsername?: string;
|
||||
}): string {
|
||||
const senderName = params.senderName.trim();
|
||||
const senderUsername = resolveMatrixSenderUsername(params.senderId);
|
||||
const senderUsername = params.senderUsername ?? resolveMatrixSenderUsername(params.senderId);
|
||||
if (senderName && senderUsername && senderName !== senderUsername) {
|
||||
return `${senderName} (${senderUsername})`;
|
||||
}
|
||||
@@ -18,15 +19,10 @@ export function resolveMatrixInboundSenderLabel(params: {
|
||||
export function resolveMatrixBodyForAgent(params: {
|
||||
isDirectMessage: boolean;
|
||||
bodyText: string;
|
||||
senderName: string;
|
||||
senderId: string;
|
||||
senderLabel: string;
|
||||
}): string {
|
||||
if (params.isDirectMessage) {
|
||||
return params.bodyText;
|
||||
}
|
||||
const senderLabel = resolveMatrixInboundSenderLabel({
|
||||
senderName: params.senderName,
|
||||
senderId: params.senderId,
|
||||
});
|
||||
return `${senderLabel}: ${params.bodyText}`;
|
||||
return `${params.senderLabel}: ${params.bodyText}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user