openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
125 lines (124 loc) • 4.19 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import { c as resolveUserPath } from "./home-dir-BPhrG-aM.js";
import { l as readFileDescriptorBoundedSync, s as openRootFileSync } from "./boundary-file-read-uaJcf6X6.js";
import { r as resolveRealpathOrAbsolute } from "./boundary-path-DMNeww4q.js";
import "./utils-P__uGsPB.js";
import { m as resolveAgentWorkspaceDir } from "./agent-scope-config-DcbEhP0R.js";
import "./agent-scope-DbtJyKUL.js";
import { a as isSupportedLocalAvatarExtension, c as resolveAvatarMime, f as isRenderableAvatarImageDataUrl, i as isPathWithinRoot, l as AVATAR_MAX_BYTES, n as isAvatarDataUrl, o as isWindowsAbsolutePath, r as isAvatarHttpUrl, t as hasAvatarUriScheme } from "./avatar-policy-D8FQ_Wte.js";
import fs from "node:fs";
import path from "node:path";
//#region src/agents/identity-avatar-file.ts
/** Resolve one local avatar source while retaining its canonical workspace root. */
function resolveLocalAgentAvatarPath(params) {
const workspaceRoot = resolveRealpathOrAbsolute(params.workspaceDir);
const resolved = params.raw.startsWith("~") || path.isAbsolute(params.raw) ? resolveUserPath(params.raw) : path.resolve(workspaceRoot, params.raw);
const filePath = resolveRealpathOrAbsolute(resolved);
if (!isPathWithinRoot(workspaceRoot, filePath)) return {
ok: false,
reason: "outside_workspace"
};
if (!isSupportedLocalAvatarExtension(filePath)) return {
ok: false,
reason: "unsupported_extension"
};
try {
const stat = fs.statSync(filePath);
if (!stat.isFile()) return {
ok: false,
reason: "missing"
};
if (stat.size > 2097152) return {
ok: false,
reason: "too_large"
};
} catch {
return {
ok: false,
reason: "missing"
};
}
return {
ok: true,
value: {
filePath,
workspaceRoot
}
};
}
function openResolvedLocalAgentAvatarFile(resolved) {
try {
const opened = openRootFileSync({
absolutePath: resolved.filePath,
rootPath: resolved.workspaceRoot,
rootRealPath: resolved.workspaceRoot,
boundaryLabel: "agent workspace",
maxBytes: AVATAR_MAX_BYTES,
rejectHardlinks: true,
skipLexicalRootCheck: true
});
if (!opened.ok) return null;
if (!isSupportedLocalAvatarExtension(opened.path)) {
fs.closeSync(opened.fd);
return null;
}
return {
path: opened.path,
fd: opened.fd,
stat: {
ctimeMs: opened.stat.ctimeMs,
dev: opened.stat.dev,
ino: opened.stat.ino,
mtimeMs: opened.stat.mtimeMs,
size: opened.stat.size
}
};
} catch {
return null;
}
}
/**
* Open one selected local avatar under its agent workspace.
* A successful caller owns `file.fd` and must close it exactly once.
*/
function openLocalAgentAvatarFile(params) {
const resolved = resolveLocalAgentAvatarPath({
raw: params.source,
workspaceDir: resolveAgentWorkspaceDir(params.cfg, params.agentId)
});
if (!resolved.ok) return resolved;
const file = openResolvedLocalAgentAvatarFile(resolved.value);
return file ? {
ok: true,
file
} : {
ok: false,
reason: "unreadable"
};
}
/** Consume a pinned local avatar descriptor into a data URL. Always closes it. */
function readOpenedLocalAgentAvatarDataUrl(opened) {
try {
const buffer = readFileDescriptorBoundedSync(opened.fd, AVATAR_MAX_BYTES);
return `data:${resolveAvatarMime(opened.path)};base64,${buffer.toString("base64")}`;
} catch {
return;
} finally {
fs.closeSync(opened.fd);
}
}
/** Resolve one configured avatar source for agent-list projections. */
function resolveAgentAvatarUrlFromSource(cfg, agentId, source) {
const normalized = normalizeOptionalString(source);
if (!normalized) return;
if (isAvatarHttpUrl(normalized) || isRenderableAvatarImageDataUrl(normalized)) return normalized;
if (isAvatarDataUrl(normalized) || hasAvatarUriScheme(normalized) && !isWindowsAbsolutePath(normalized)) return;
const opened = openLocalAgentAvatarFile({
cfg,
agentId,
source: normalized
});
return opened.ok ? readOpenedLocalAgentAvatarDataUrl(opened.file) : void 0;
}
//#endregion
export { resolveLocalAgentAvatarPath as i, readOpenedLocalAgentAvatarDataUrl as n, resolveAgentAvatarUrlFromSource as r, openLocalAgentAvatarFile as t };