mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
Matrix: honor scoped media roots
This commit is contained in:
@@ -60,6 +60,7 @@ describe("matrixMessageActions account propagation", () => {
|
||||
accountId: "ops",
|
||||
}),
|
||||
expect.any(Object),
|
||||
{ mediaLocalRoots: undefined },
|
||||
);
|
||||
});
|
||||
|
||||
@@ -80,6 +81,7 @@ describe("matrixMessageActions account propagation", () => {
|
||||
accountId: "ops",
|
||||
}),
|
||||
expect.any(Object),
|
||||
{ mediaLocalRoots: undefined },
|
||||
);
|
||||
});
|
||||
|
||||
@@ -103,6 +105,7 @@ describe("matrixMessageActions account propagation", () => {
|
||||
avatarUrl: "mxc://example/avatar",
|
||||
}),
|
||||
expect.any(Object),
|
||||
{ mediaLocalRoots: undefined },
|
||||
);
|
||||
});
|
||||
|
||||
@@ -124,6 +127,32 @@ describe("matrixMessageActions account propagation", () => {
|
||||
avatarPath: "/tmp/avatar.jpg",
|
||||
}),
|
||||
expect.any(Object),
|
||||
{ mediaLocalRoots: undefined },
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards mediaLocalRoots for media sends", async () => {
|
||||
await matrixMessageActions.handleAction?.(
|
||||
createContext({
|
||||
action: "send",
|
||||
accountId: "ops",
|
||||
mediaLocalRoots: ["/tmp/openclaw-matrix-test"],
|
||||
params: {
|
||||
to: "room:!room:example",
|
||||
message: "hello",
|
||||
media: "file:///tmp/photo.png",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(mocks.handleMatrixAction).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
action: "sendMessage",
|
||||
accountId: "ops",
|
||||
mediaUrl: "file:///tmp/photo.png",
|
||||
}),
|
||||
expect.any(Object),
|
||||
{ mediaLocalRoots: ["/tmp/openclaw-matrix-test"] },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -93,7 +93,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
||||
return { to };
|
||||
},
|
||||
handleAction: async (ctx: ChannelMessageActionContext) => {
|
||||
const { action, params, cfg, accountId } = ctx;
|
||||
const { action, params, cfg, accountId, mediaLocalRoots } = ctx;
|
||||
const dispatch = async (actionParams: Record<string, unknown>) =>
|
||||
await handleMatrixAction(
|
||||
{
|
||||
@@ -101,6 +101,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
||||
...(accountId ? { accountId } : {}),
|
||||
},
|
||||
cfg as CoreConfig,
|
||||
{ mediaLocalRoots },
|
||||
);
|
||||
const resolveRoomId = () =>
|
||||
readStringParam(params, "roomId") ??
|
||||
|
||||
@@ -26,6 +26,7 @@ export async function sendMatrixMessage(
|
||||
return await sendMessageMatrix(to, content, {
|
||||
cfg: opts.cfg,
|
||||
mediaUrl: opts.mediaUrl,
|
||||
mediaLocalRoots: opts.mediaLocalRoots,
|
||||
replyToId: opts.replyToId,
|
||||
threadId: opts.threadId,
|
||||
accountId: opts.accountId ?? undefined,
|
||||
|
||||
@@ -26,7 +26,10 @@ export async function updateMatrixOwnProfile(
|
||||
avatarPath: avatarPath || undefined,
|
||||
loadAvatarFromUrl: async (url, maxBytes) => await runtime.media.loadWebMedia(url, maxBytes),
|
||||
loadAvatarFromPath: async (path, maxBytes) =>
|
||||
await runtime.media.loadWebMedia(path, maxBytes),
|
||||
await runtime.media.loadWebMedia(path, {
|
||||
maxBytes,
|
||||
localRoots: opts.mediaLocalRoots,
|
||||
}),
|
||||
});
|
||||
},
|
||||
"persist",
|
||||
|
||||
@@ -48,6 +48,7 @@ export type RoomTopicEventContent = {
|
||||
export type MatrixActionClientOpts = {
|
||||
client?: MatrixClient;
|
||||
cfg?: CoreConfig;
|
||||
mediaLocalRoots?: readonly string[];
|
||||
timeoutMs?: number;
|
||||
accountId?: string | null;
|
||||
readiness?: "none" | "prepared" | "started";
|
||||
|
||||
@@ -232,9 +232,27 @@ describe("sendMessageMatrix media", () => {
|
||||
});
|
||||
|
||||
expect(loadConfigMock).not.toHaveBeenCalled();
|
||||
expect(loadWebMediaMock).toHaveBeenCalledWith("file:///tmp/photo.png", 1024 * 1024);
|
||||
expect(loadWebMediaMock).toHaveBeenCalledWith("file:///tmp/photo.png", {
|
||||
maxBytes: 1024 * 1024,
|
||||
localRoots: undefined,
|
||||
});
|
||||
expect(resolveTextChunkLimitMock).toHaveBeenCalledWith(explicitCfg, "matrix", "ops");
|
||||
});
|
||||
|
||||
it("passes caller mediaLocalRoots to media loading", async () => {
|
||||
const { client } = makeClient();
|
||||
|
||||
await sendMessageMatrix("room:!room:example", "caption", {
|
||||
client,
|
||||
mediaUrl: "file:///tmp/photo.png",
|
||||
mediaLocalRoots: ["/tmp/openclaw-matrix-test"],
|
||||
});
|
||||
|
||||
expect(loadWebMediaMock).toHaveBeenCalledWith("file:///tmp/photo.png", {
|
||||
maxBytes: undefined,
|
||||
localRoots: ["/tmp/openclaw-matrix-test"],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("sendMessageMatrix threads", () => {
|
||||
|
||||
@@ -109,7 +109,10 @@ export async function sendMessageMatrix(
|
||||
let lastMessageId = "";
|
||||
if (opts.mediaUrl) {
|
||||
const maxBytes = resolveMediaMaxBytes(opts.accountId, cfg);
|
||||
const media = await getCore().media.loadWebMedia(opts.mediaUrl, maxBytes);
|
||||
const media = await getCore().media.loadWebMedia(opts.mediaUrl, {
|
||||
maxBytes,
|
||||
localRoots: opts.mediaLocalRoots,
|
||||
});
|
||||
const uploaded = await uploadMediaMaybeEncrypted(client, roomId, media.buffer, {
|
||||
contentType: media.contentType,
|
||||
filename: media.fileName,
|
||||
|
||||
@@ -88,6 +88,7 @@ export type MatrixSendOpts = {
|
||||
client?: import("../sdk.js").MatrixClient;
|
||||
cfg?: CoreConfig;
|
||||
mediaUrl?: string;
|
||||
mediaLocalRoots?: readonly string[];
|
||||
accountId?: string;
|
||||
replyToId?: string;
|
||||
threadId?: string | number | null;
|
||||
|
||||
@@ -75,6 +75,7 @@ describe("matrixOutbound cfg threading", () => {
|
||||
to: "room:!room:example",
|
||||
text: "caption",
|
||||
mediaUrl: "file:///tmp/cat.png",
|
||||
mediaLocalRoots: ["/tmp/openclaw"],
|
||||
accountId: "default",
|
||||
});
|
||||
|
||||
@@ -84,6 +85,7 @@ describe("matrixOutbound cfg threading", () => {
|
||||
expect.objectContaining({
|
||||
cfg,
|
||||
mediaUrl: "file:///tmp/cat.png",
|
||||
mediaLocalRoots: ["/tmp/openclaw"],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -23,13 +23,24 @@ export const matrixOutbound: ChannelOutboundAdapter = {
|
||||
roomId: result.roomId,
|
||||
};
|
||||
},
|
||||
sendMedia: async ({ cfg, to, text, mediaUrl, deps, replyToId, threadId, accountId }) => {
|
||||
sendMedia: async ({
|
||||
cfg,
|
||||
to,
|
||||
text,
|
||||
mediaUrl,
|
||||
mediaLocalRoots,
|
||||
deps,
|
||||
replyToId,
|
||||
threadId,
|
||||
accountId,
|
||||
}) => {
|
||||
const send = deps?.sendMatrix ?? sendMessageMatrix;
|
||||
const resolvedThreadId =
|
||||
threadId !== undefined && threadId !== null ? String(threadId) : undefined;
|
||||
const result = await send(to, text, {
|
||||
cfg,
|
||||
mediaUrl,
|
||||
mediaLocalRoots,
|
||||
replyToId: replyToId ?? undefined,
|
||||
threadId: resolvedThreadId,
|
||||
accountId: accountId ?? undefined,
|
||||
|
||||
@@ -24,6 +24,7 @@ export async function applyMatrixProfileUpdate(params: {
|
||||
displayName?: string;
|
||||
avatarUrl?: string;
|
||||
avatarPath?: string;
|
||||
mediaLocalRoots?: readonly string[];
|
||||
}): Promise<MatrixProfileUpdateResult> {
|
||||
const runtime = getMatrixRuntime();
|
||||
const persistedCfg = runtime.config.loadConfig() as CoreConfig;
|
||||
@@ -41,6 +42,7 @@ export async function applyMatrixProfileUpdate(params: {
|
||||
displayName: displayName ?? undefined,
|
||||
avatarUrl: avatarUrl ?? undefined,
|
||||
avatarPath: avatarPath ?? undefined,
|
||||
mediaLocalRoots: params.mediaLocalRoots,
|
||||
});
|
||||
const persistedAvatarUrl =
|
||||
synced.uploadedAvatarSource && synced.resolvedAvatarUrl ? synced.resolvedAvatarUrl : avatarUrl;
|
||||
|
||||
@@ -194,17 +194,41 @@ describe("handleMatrixAction pollVote", () => {
|
||||
threadId: "$thread",
|
||||
},
|
||||
cfg,
|
||||
{ mediaLocalRoots: ["/tmp/openclaw-matrix-test"] },
|
||||
);
|
||||
|
||||
expect(mocks.sendMatrixMessage).toHaveBeenCalledWith("room:!room:example", "hello", {
|
||||
cfg,
|
||||
accountId: "ops",
|
||||
mediaUrl: undefined,
|
||||
mediaLocalRoots: ["/tmp/openclaw-matrix-test"],
|
||||
replyToId: undefined,
|
||||
threadId: "$thread",
|
||||
});
|
||||
});
|
||||
|
||||
it("passes mediaLocalRoots to profile updates", async () => {
|
||||
const cfg = { channels: { matrix: { actions: { profile: true } } } } as CoreConfig;
|
||||
await handleMatrixAction(
|
||||
{
|
||||
action: "setProfile",
|
||||
accountId: "ops",
|
||||
avatarPath: "/tmp/avatar.jpg",
|
||||
},
|
||||
cfg,
|
||||
{ mediaLocalRoots: ["/tmp/openclaw-matrix-test"] },
|
||||
);
|
||||
|
||||
expect(mocks.applyMatrixProfileUpdate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
cfg,
|
||||
account: "ops",
|
||||
avatarPath: "/tmp/avatar.jpg",
|
||||
mediaLocalRoots: ["/tmp/openclaw-matrix-test"],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("passes account-scoped opts to pin listing", async () => {
|
||||
const cfg = { channels: { matrix: { actions: { pins: true } } } } as CoreConfig;
|
||||
await handleMatrixAction(
|
||||
|
||||
@@ -129,6 +129,7 @@ function readNumericArrayParam(
|
||||
export async function handleMatrixAction(
|
||||
params: Record<string, unknown>,
|
||||
cfg: CoreConfig,
|
||||
opts: { mediaLocalRoots?: readonly string[] } = {},
|
||||
): Promise<AgentToolResult<unknown>> {
|
||||
const action = readStringParam(params, "action", { required: true });
|
||||
const accountId = readStringParam(params, "accountId") ?? undefined;
|
||||
@@ -204,6 +205,7 @@ export async function handleMatrixAction(
|
||||
const threadId = readStringParam(params, "threadId");
|
||||
const result = await sendMatrixMessage(to, content, {
|
||||
mediaUrl: mediaUrl ?? undefined,
|
||||
mediaLocalRoots: opts.mediaLocalRoots,
|
||||
replyToId: replyToId ?? undefined,
|
||||
threadId: threadId ?? undefined,
|
||||
...clientOpts,
|
||||
@@ -278,6 +280,7 @@ export async function handleMatrixAction(
|
||||
displayName: readStringParam(params, "displayName") ?? readStringParam(params, "name"),
|
||||
avatarUrl: readStringParam(params, "avatarUrl"),
|
||||
avatarPath,
|
||||
mediaLocalRoots: opts.mediaLocalRoots,
|
||||
});
|
||||
return jsonResult({ ok: true, ...result });
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ type SendMatrixMessage = (
|
||||
cfg?: OpenClawConfig;
|
||||
accountId?: string;
|
||||
mediaUrl?: string;
|
||||
mediaLocalRoots?: readonly string[];
|
||||
replyToId?: string;
|
||||
threadId?: string;
|
||||
timeoutMs?: number;
|
||||
|
||||
Reference in New Issue
Block a user