fix: allow agent workspace directories in media local roots

Modifies getDefaultLocalRoots() to dynamically scan STATE_DIR for
workspace-* directories (e.g., workspace-<agentId>) and include them
in the allowed local roots for media file access.

This fixes the issue where the message tool rejects file attachments
from agent-specific workspace directories like ~/.openclaw/workspace-clawdy/.

Fixes openclaw/openclaw#17133
This commit is contained in:
OpenClaw Bot
2026-02-15 13:09:26 +00:00
committed by Gustavo Madeira Santana
parent 0c57f5e62e
commit 36ca0e5c13

View File

@@ -1,3 +1,4 @@
import fsSync from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
@@ -34,14 +35,44 @@ type WebMediaOptions = {
readFile?: (filePath: string) => Promise<Buffer>;
};
/**
* Scans STATE_DIR for agent workspace directories matching the pattern "workspace-*"
* and returns them as additional allowed local roots.
*/
function getAgentWorkspaceDirsSync(): string[] {
try {
// Note: Synchronous scan on each call - acceptable for now since this is only
// used when validating local media paths, which is not a hot path.
// For better performance, could add caching with invalidation.
const entries = fsSync.readdirSync(STATE_DIR, { withFileTypes: true });
return entries
.filter(
(entry) =>
entry.isDirectory() &&
entry.name.startsWith("workspace-") &&
// Exclude the default "workspace" directory (handled separately)
entry.name !== "workspace",
)
.map((entry) => path.join(STATE_DIR, entry.name));
} catch {
// If STATE_DIR doesn't exist or isn't readable, return empty array
return [];
}
}
export function getDefaultLocalRoots(): readonly string[] {
return [
const staticRoots = [
os.tmpdir(),
path.join(STATE_DIR, "media"),
path.join(STATE_DIR, "agents"),
path.join(STATE_DIR, "workspace"),
path.join(STATE_DIR, "sandboxes"),
];
// Dynamically discover agent workspace directories (e.g., workspace-<agentId>)
const workspaceDirs = getAgentWorkspaceDirsSync();
return [...staticRoots, ...workspaceDirs];
}
async function assertLocalMediaAllowed(