openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
145 lines (144 loc) • 5.83 kB
JavaScript
import { d as resolveAgentWorkspaceDir } from "./agent-scope-config-BEk6-ThS.mjs";
import "./agent-scope-bJOokm5r.mjs";
import { d as validateAgentsWorkspaceGetParams, f as validateAgentsWorkspaceListParams } from "./src-D6kL8tMP.mjs";
import { t as ErrorCodes } from "./gateway-error-details-gTekQWj2.mjs";
import { d as errorShape } from "./error-codes-D0WRV4Bq.mjs";
import { n as detectMime } from "./mime-C3j3dfQb.mjs";
import { t as WORKSPACE_PREVIEW_MAX_BYTES } from "./workspace-file-limits-loc-yzkf.mjs";
import { a as normalizeRelativePath, d as sortWorkspaceEntries, f as statWorkspacePath, i as listWorkspacePath, l as resolveWorkspacePath, m as toWorkspaceBrowserEntry, n as decodeUtf8Strict, p as toUpdatedAtMs, s as readWorkspaceFile } from "./workspace-fs-CsgcGxTx.mjs";
import { t as assertValidParams } from "./validation-UW_NLjlV.mjs";
import { n as resolveConfiguredAgentIdOrRespondError } from "./agent-id-shared-BvQwtL4x.mjs";
import path from "node:path";
//#region src/gateway/server-methods/agents-workspace.ts
const MAX_IMAGE_BYTES = 5242880;
const DEFAULT_LIST_LIMIT = 250;
const MAX_LIST_LIMIT = 500;
const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
".avif",
".bmp",
".gif",
".heic",
".heif",
".jpeg",
".jpg",
".png",
".webp"
]);
const SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
"image/avif",
"image/bmp",
"image/gif",
"image/heic",
"image/heif",
"image/jpeg",
"image/png",
"image/webp"
]);
function workspaceError(type, message, details) {
return errorShape(ErrorCodes.INVALID_REQUEST, message, { details: {
type,
...details
} });
}
function resolveWorkspaceScopeOrRespond(params, cfg, respond) {
const agentId = resolveConfiguredAgentIdOrRespondError(params.agentId, cfg, respond);
if (!agentId) return null;
const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
const rawPath = params.path ?? "";
const portablePath = rawPath.replaceAll("\\", "/");
if (path.posix.isAbsolute(portablePath) || path.win32.isAbsolute(rawPath)) {
respond(false, void 0, workspaceError("workspace_path_invalid", "path must be workspace-relative", { path: rawPath }));
return null;
}
const browserPath = normalizeRelativePath(params.path);
if (!resolveWorkspacePath(workspaceDir, browserPath || ".")) {
respond(false, void 0, workspaceError("workspace_path_invalid", "path escapes the agent workspace", { path: params.path ?? "" }));
return null;
}
return {
agentId,
workspaceDir,
browserPath
};
}
const agentsWorkspaceHandlers = {
"agents.workspace.list": async ({ params, respond, context }) => {
if (!assertValidParams(params, validateAgentsWorkspaceListParams, "agents.workspace.list", respond)) return;
const scope = resolveWorkspaceScopeOrRespond(params, context.getRuntimeConfig(), respond);
if (!scope) return;
const { agentId, workspaceDir, browserPath } = scope;
const dirents = (await statWorkspacePath(workspaceDir, browserPath))?.isDirectory ? await listWorkspacePath(workspaceDir, browserPath) : void 0;
if (!dirents) {
respond(false, void 0, workspaceError("workspace_path_not_found", "workspace directory not found", { path: browserPath }));
return;
}
const entries = sortWorkspaceEntries(dirents.map((dirent) => toWorkspaceBrowserEntry(browserPath ? `${browserPath}/${dirent.name}` : dirent.name, dirent)).filter((entry) => entry !== void 0));
const offset = Math.min(params.offset ?? 0, entries.length);
const limit = Math.min(params.limit ?? DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT);
const parent = path.dirname(browserPath);
respond(true, {
agentId,
path: browserPath,
...browserPath ? { parentPath: parent === "." ? "" : parent } : {},
entries: entries.slice(offset, offset + limit),
totalEntries: entries.length,
offset
});
},
"agents.workspace.get": async ({ params, respond, context }) => {
if (!assertValidParams(params, validateAgentsWorkspaceGetParams, "agents.workspace.get", respond)) return;
const scope = resolveWorkspaceScopeOrRespond(params, context.getRuntimeConfig(), respond);
if (!scope) return;
const { agentId, workspaceDir, browserPath } = scope;
const respondNotFound = () => {
respond(false, void 0, workspaceError("workspace_file_not_found", "workspace file not found", { path: browserPath }));
};
if (!browserPath) {
respondNotFound();
return;
}
const stat = await statWorkspacePath(workspaceDir, browserPath);
if (!stat?.isFile) {
respondNotFound();
return;
}
const expectsImage = IMAGE_EXTENSIONS.has(path.extname(browserPath).toLowerCase());
const maxBytes = expectsImage ? MAX_IMAGE_BYTES : WORKSPACE_PREVIEW_MAX_BYTES;
const read = stat.size > maxBytes ? "too-large" : await readWorkspaceFile(workspaceDir, browserPath, { maxBytes });
if (read === "too-large") {
respond(false, void 0, workspaceError("workspace_file_too_large", "workspace file is too large to preview", {
maxBytes,
path: browserPath,
size: stat.size
}));
return;
}
if (!read) {
respondNotFound();
return;
}
const file = {
path: browserPath,
name: path.basename(browserPath),
size: read.stat.size,
updatedAtMs: toUpdatedAtMs(read.stat.mtimeMs)
};
const mimeType = expectsImage ? await detectMime({ buffer: read.buffer }) : "text/plain";
const content = expectsImage ? mimeType && SUPPORTED_IMAGE_MIME_TYPES.has(mimeType) ? read.buffer.toString("base64") : void 0 : decodeUtf8Strict(read.buffer);
if (content === void 0) {
respond(false, void 0, workspaceError("workspace_file_unsupported", "workspace file is not UTF-8 text or a supported image", { path: browserPath }));
return;
}
respond(true, {
agentId,
file: {
...file,
mimeType,
encoding: expectsImage ? "base64" : "utf8",
content
}
});
}
};
//#endregion
export { agentsWorkspaceHandlers };