mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 17:51:24 +00:00
fix: allow agent workspace directories in media local roots (#17136)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 7545ef1e19
Co-authored-by: MisterGuy420 <255743668+MisterGuy420@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
@@ -532,6 +532,7 @@ export async function runHeartbeatOnce(opts: {
|
||||
to: delivery.to,
|
||||
accountId: delivery.accountId,
|
||||
payloads: [{ text: heartbeatOkText }],
|
||||
agentId,
|
||||
deps: opts.deps,
|
||||
});
|
||||
return true;
|
||||
@@ -710,6 +711,7 @@ export async function runHeartbeatOnce(opts: {
|
||||
channel: delivery.channel,
|
||||
to: delivery.to,
|
||||
accountId: deliveryAccountId,
|
||||
agentId,
|
||||
payloads: [
|
||||
...reasoningPayloads,
|
||||
...(shouldSkipMain
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { signalOutbound } from "../../channels/plugins/outbound/signal.js";
|
||||
import { telegramOutbound } from "../../channels/plugins/outbound/telegram.js";
|
||||
import { whatsappOutbound } from "../../channels/plugins/outbound/whatsapp.js";
|
||||
import { STATE_DIR } from "../../config/paths.js";
|
||||
import { setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||
import { markdownToSignalTextChunks } from "../../signal/format.js";
|
||||
import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js";
|
||||
@@ -116,6 +118,31 @@ describe("deliverOutboundPayloads", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("scopes media local roots to the active agent workspace when agentId is provided", async () => {
|
||||
const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m1", chatId: "c1" });
|
||||
const cfg: OpenClawConfig = {
|
||||
channels: { telegram: { botToken: "tok-1", textChunkLimit: 2 } },
|
||||
};
|
||||
|
||||
await deliverOutboundPayloads({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
to: "123",
|
||||
agentId: "work",
|
||||
payloads: [{ text: "hi", mediaUrl: "file:///tmp/f.png" }],
|
||||
deps: { sendTelegram },
|
||||
});
|
||||
|
||||
expect(sendTelegram).toHaveBeenCalledWith(
|
||||
"123",
|
||||
"hi",
|
||||
expect.objectContaining({
|
||||
mediaUrl: "file:///tmp/f.png",
|
||||
mediaLocalRoots: expect.arrayContaining([path.join(STATE_DIR, "workspace-work")]),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("uses signal media maxBytes from config", async () => {
|
||||
const sendSignal = vi.fn().mockResolvedValue({ messageId: "s1", timestamp: 123 });
|
||||
const cfg: OpenClawConfig = { channels: { signal: { mediaMaxMb: 2 } } };
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
appendAssistantMessageToSessionTranscript,
|
||||
resolveMirroredTranscriptText,
|
||||
} from "../../config/sessions.js";
|
||||
import { getAgentScopedMediaLocalRoots } from "../../media/local-roots.js";
|
||||
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
||||
import { markdownToSignalTextChunks, type SignalTextStyleRange } from "../../signal/format.js";
|
||||
import { sendMessageSignal } from "../../signal/send.js";
|
||||
@@ -90,6 +91,7 @@ async function createChannelHandler(params: {
|
||||
deps?: OutboundSendDeps;
|
||||
gifPlayback?: boolean;
|
||||
silent?: boolean;
|
||||
mediaLocalRoots?: readonly string[];
|
||||
}): Promise<ChannelHandler> {
|
||||
const outbound = await loadChannelOutboundAdapter(params.channel);
|
||||
if (!outbound?.sendText || !outbound?.sendMedia) {
|
||||
@@ -107,6 +109,7 @@ async function createChannelHandler(params: {
|
||||
deps: params.deps,
|
||||
gifPlayback: params.gifPlayback,
|
||||
silent: params.silent,
|
||||
mediaLocalRoots: params.mediaLocalRoots,
|
||||
});
|
||||
if (!handler) {
|
||||
throw new Error(`Outbound not configured for channel: ${params.channel}`);
|
||||
@@ -126,6 +129,7 @@ function createPluginHandler(params: {
|
||||
deps?: OutboundSendDeps;
|
||||
gifPlayback?: boolean;
|
||||
silent?: boolean;
|
||||
mediaLocalRoots?: readonly string[];
|
||||
}): ChannelHandler | null {
|
||||
const outbound = params.outbound;
|
||||
if (!outbound?.sendText || !outbound?.sendMedia) {
|
||||
@@ -153,6 +157,7 @@ function createPluginHandler(params: {
|
||||
gifPlayback: params.gifPlayback,
|
||||
deps: params.deps,
|
||||
silent: params.silent,
|
||||
mediaLocalRoots: params.mediaLocalRoots,
|
||||
payload,
|
||||
})
|
||||
: undefined,
|
||||
@@ -168,6 +173,7 @@ function createPluginHandler(params: {
|
||||
gifPlayback: params.gifPlayback,
|
||||
deps: params.deps,
|
||||
silent: params.silent,
|
||||
mediaLocalRoots: params.mediaLocalRoots,
|
||||
}),
|
||||
sendMedia: async (caption, mediaUrl) =>
|
||||
sendMedia({
|
||||
@@ -182,6 +188,7 @@ function createPluginHandler(params: {
|
||||
gifPlayback: params.gifPlayback,
|
||||
deps: params.deps,
|
||||
silent: params.silent,
|
||||
mediaLocalRoots: params.mediaLocalRoots,
|
||||
}),
|
||||
};
|
||||
}
|
||||
@@ -203,6 +210,8 @@ type DeliverOutboundPayloadsCoreParams = {
|
||||
bestEffort?: boolean;
|
||||
onError?: (err: unknown, payload: NormalizedOutboundPayload) => void;
|
||||
onPayload?: (payload: NormalizedOutboundPayload) => void;
|
||||
/** Active agent id for media local-root scoping. */
|
||||
agentId?: string;
|
||||
mirror?: {
|
||||
sessionKey: string;
|
||||
agentId?: string;
|
||||
@@ -286,6 +295,10 @@ async function deliverOutboundPayloadsCore(
|
||||
const deps = params.deps;
|
||||
const abortSignal = params.abortSignal;
|
||||
const sendSignal = params.deps?.sendSignal ?? sendMessageSignal;
|
||||
const mediaLocalRoots = getAgentScopedMediaLocalRoots(
|
||||
cfg,
|
||||
params.agentId ?? params.mirror?.agentId,
|
||||
);
|
||||
const results: OutboundDeliveryResult[] = [];
|
||||
const handler = await createChannelHandler({
|
||||
cfg,
|
||||
@@ -298,6 +311,7 @@ async function deliverOutboundPayloadsCore(
|
||||
identity: params.identity,
|
||||
gifPlayback: params.gifPlayback,
|
||||
silent: params.silent,
|
||||
mediaLocalRoots,
|
||||
});
|
||||
const textLimit = handler.chunker
|
||||
? resolveTextChunkLimit(cfg, channel, accountId, {
|
||||
@@ -400,6 +414,7 @@ async function deliverOutboundPayloadsCore(
|
||||
accountId: accountId ?? undefined,
|
||||
textMode: "plain",
|
||||
textStyles: formatted.styles,
|
||||
mediaLocalRoots,
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { SessionEntry, SessionMaintenanceWarning } from "../config/sessions.js";
|
||||
import { resolveSessionAgentId } from "../agents/agent-scope.js";
|
||||
import { isDeliverableMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
|
||||
import { resolveSessionDeliveryTarget } from "./outbound/targets.js";
|
||||
import { enqueueSystemEvent } from "./system-events.js";
|
||||
@@ -100,6 +101,7 @@ export async function deliverSessionMaintenanceWarning(params: WarningParams): P
|
||||
accountId: target.accountId,
|
||||
threadId: target.threadId,
|
||||
payloads: [{ text }],
|
||||
agentId: resolveSessionAgentId({ sessionKey: params.sessionKey, config: params.cfg }),
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn(`Failed to deliver session maintenance warning: ${String(err)}`);
|
||||
|
||||
Reference in New Issue
Block a user