diff --git a/extensions/matrix/src/matrix/monitor/handler.ts b/extensions/matrix/src/matrix/monitor/handler.ts index 7ef3aa7f331..8412ba4dfd4 100644 --- a/extensions/matrix/src/matrix/monitor/handler.ts +++ b/extensions/matrix/src/matrix/monitor/handler.ts @@ -3,6 +3,7 @@ import { createTypingCallbacks, ensureConfiguredAcpRouteReady, formatAllowlistMatchMeta, + getAgentScopedMediaLocalRoots, logInboundDrop, logTypingFailure, resolveControlCommandGate, @@ -662,6 +663,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam channel: "matrix", accountId: route.accountId, }); + const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, route.agentId); const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({ cfg, agentId: route.agentId, @@ -705,6 +707,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam replyToMode, threadId: threadTarget, accountId: route.accountId, + mediaLocalRoots, tableMode, }); didSendReply = true; diff --git a/extensions/matrix/src/matrix/monitor/replies.test.ts b/extensions/matrix/src/matrix/monitor/replies.test.ts index f56a6e0e387..33ed0bba226 100644 --- a/extensions/matrix/src/matrix/monitor/replies.test.ts +++ b/extensions/matrix/src/matrix/monitor/replies.test.ts @@ -96,18 +96,27 @@ describe("deliverMatrixReplies", () => { runtime: runtimeEnv, textLimit: 4000, replyToMode: "all", + mediaLocalRoots: ["/tmp/openclaw-matrix-test"], }); expect(sendMessageMatrixMock).toHaveBeenCalledTimes(3); expect(sendMessageMatrixMock.mock.calls[0]).toEqual([ "room:2", "caption", - expect.objectContaining({ mediaUrl: "https://example.com/a.jpg", replyToId: "reply-media" }), + expect.objectContaining({ + mediaUrl: "https://example.com/a.jpg", + mediaLocalRoots: ["/tmp/openclaw-matrix-test"], + replyToId: "reply-media", + }), ]); expect(sendMessageMatrixMock.mock.calls[1]).toEqual([ "room:2", "", - expect.objectContaining({ mediaUrl: "https://example.com/b.jpg", replyToId: "reply-media" }), + expect.objectContaining({ + mediaUrl: "https://example.com/b.jpg", + mediaLocalRoots: ["/tmp/openclaw-matrix-test"], + replyToId: "reply-media", + }), ]); expect(sendMessageMatrixMock.mock.calls[2]?.[2]).toEqual( expect.objectContaining({ replyToId: "reply-text" }), diff --git a/extensions/matrix/src/matrix/monitor/replies.ts b/extensions/matrix/src/matrix/monitor/replies.ts index 5b47a8d1d98..8874b688591 100644 --- a/extensions/matrix/src/matrix/monitor/replies.ts +++ b/extensions/matrix/src/matrix/monitor/replies.ts @@ -43,6 +43,7 @@ export async function deliverMatrixReplies(params: { replyToMode: "off" | "first" | "all"; threadId?: string; accountId?: string; + mediaLocalRoots?: readonly string[]; tableMode?: MarkdownTableMode; }): Promise { const core = getMatrixRuntime(); @@ -122,6 +123,7 @@ export async function deliverMatrixReplies(params: { client: params.client, cfg: params.cfg, mediaUrl, + mediaLocalRoots: params.mediaLocalRoots, replyToId: replyToIdForReply, threadId: params.threadId, audioAsVoice: reply.audioAsVoice, diff --git a/src/plugin-sdk/matrix.ts b/src/plugin-sdk/matrix.ts index f64749e638b..84984d083a0 100644 --- a/src/plugin-sdk/matrix.ts +++ b/src/plugin-sdk/matrix.ts @@ -122,6 +122,7 @@ export { resolveMatrixMigrationSnapshotMarkerPath, resolveMatrixMigrationSnapshotOutputDir, } from "../infra/matrix-migration-snapshot.js"; +export { getAgentScopedMediaLocalRoots } from "../media/local-roots.js"; export { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js"; export { isPrivateOrLoopbackHost } from "../gateway/net.js"; export {