openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
647 lines (646 loc) • 23.9 kB
JavaScript
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { m as FsSafeError } from "./path-BlG8lhgR.js";
import { l as movePathToTrash } from "./fs-safe-aqmM_n6V.js";
import { a as root } from "./secure-temp-dir-XAWcZnE2.js";
import { p as resolveUserPath } from "./utils-CCC-BEJH.js";
import "./agent-scope-MrLta7Pq.js";
import { t as DEFAULT_AGENT_ID, u as normalizeAgentId } from "./session-key-B_NoIfpX.js";
import { a as resolveAgentDir, n as listAgentIds, o as resolveAgentWorkspaceDir, t as listAgentEntries } from "./agent-scope-config-CgCYpZfK.js";
import { r as mutateConfigFileWithRetry } from "./config-C9RxTsn1.js";
import { l as resolveSessionTranscriptsDirForAgent } from "./paths-NEwU8m3X.js";
import { t as purgeAgentSessionStoreEntries } from "./sessions-D6zZvoxX.js";
import { S as resolveWorkspaceAttestationPaths, a as DEFAULT_MEMORY_FILENAME, c as DEFAULT_USER_FILENAME, d as ensureAgentWorkspace, g as isWorkspaceSetupCompleted, i as DEFAULT_IDENTITY_FILENAME, n as DEFAULT_BOOTSTRAP_FILENAME, o as DEFAULT_SOUL_FILENAME, r as DEFAULT_HEARTBEAT_FILENAME, s as DEFAULT_TOOLS_FILENAME, t as DEFAULT_AGENTS_FILENAME, w as shouldRemoveWorkspaceAttestation } from "./workspace-B0bmoo98.js";
import { o as listAgentsForGateway } from "./session-utils-CHNCuY8a.js";
import { n as resolveAgentIdentity } from "./identity-Qcvvo6SY.js";
import { in as errorShape, rn as ErrorCodes } from "./schema-BwaBORnA.js";
import { a as validateAgentsCreateParams, c as validateAgentsFilesListParams, d as validateAgentsUpdateParams, l as validateAgentsFilesSetParams, o as validateAgentsDeleteParams, s as validateAgentsFilesGetParams, t as formatValidationErrors, u as validateAgentsListParams } from "./src-oj0IwW6K.js";
import "./browser-maintenance-Ci06Nj8x.js";
import { r as mergeIdentityMarkdownContent } from "./identity-file-DZ2jIsKe.js";
import { t as loadOptionalServerMethodModelCatalog } from "./optional-model-catalog-lfLlMqV0.js";
import { a as pruneAgentConfig, r as findAgentEntryIndex, t as applyAgentConfig } from "./agents.config-DfQl3_hl.js";
import { t as findOverlappingWorkspaceAgentIds } from "./agent-delete-safety-ClMBBhZN.js";
import path from "node:path";
import fs from "node:fs/promises";
//#region src/gateway/server-methods/agents-config-mutations.ts
/** Typed precondition failure surfaced by agent mutation handlers as gateway errors. */
var AgentConfigPreconditionError = class extends Error {
constructor(kind, agentId) {
super(kind === "already-exists" ? `agent "${agentId}" already exists` : `agent "${agentId}" not found`);
this.kind = kind;
this.agentId = agentId;
this.name = "AgentConfigPreconditionError";
}
};
/** Checks the current config snapshot for a concrete agent entry. */
function isConfiguredAgent(cfg, agentId) {
return findAgentEntryIndex(listAgentEntries(cfg), agentId) >= 0;
}
/** Adds a new agent entry through the retrying config mutation path. */
async function createAgentConfigEntry(params) {
await mutateConfigFileWithRetry({
afterWrite: { mode: "auto" },
mutate: (draft) => {
if (isConfiguredAgent(draft, params.agentId)) throw new AgentConfigPreconditionError("already-exists", params.agentId);
const latestNextConfig = applyAgentConfig(draft, {
agentId: params.agentId,
name: params.name,
workspace: params.workspace,
model: params.model,
identity: params.identity,
agentDir: params.agentDir
});
Object.assign(draft, latestNextConfig);
}
});
}
/** Updates an existing agent entry while preserving omitted fields. */
async function updateAgentConfigEntry(params) {
await mutateConfigFileWithRetry({
afterWrite: { mode: "auto" },
mutate: (draft) => {
if (!isConfiguredAgent(draft, params.agentId)) throw new AgentConfigPreconditionError("not-found", params.agentId);
const latestNextConfig = applyAgentConfig(draft, {
agentId: params.agentId,
...params.name ? { name: params.name } : {},
...params.workspace ? { workspace: params.workspace } : {},
...params.model ? { model: params.model } : {},
...params.identity ? { identity: params.identity } : {}
});
Object.assign(draft, latestNextConfig);
}
});
}
/** Removes an agent entry and returns filesystem roots the caller should clean up. */
async function deleteAgentConfigEntry(params) {
const committed = await mutateConfigFileWithRetry({
afterWrite: { mode: "auto" },
mutate: (draft) => {
if (!isConfiguredAgent(draft, params.agentId)) throw new AgentConfigPreconditionError("not-found", params.agentId);
const workspaceDir = resolveAgentWorkspaceDir(draft, params.agentId);
const agentDir = resolveAgentDir(draft, params.agentId);
const sessionsDir = resolveSessionTranscriptsDirForAgent(params.agentId);
const result = pruneAgentConfig(draft, params.agentId);
Object.assign(draft, result.config);
return {
workspaceDir,
agentDir,
sessionsDir,
removedBindings: result.removedBindings
};
}
});
return {
nextConfig: committed.nextConfig,
result: committed.result
};
}
//#endregion
//#region src/gateway/server-methods/agents.ts
const BOOTSTRAP_FILE_NAMES = [
DEFAULT_AGENTS_FILENAME,
DEFAULT_SOUL_FILENAME,
DEFAULT_TOOLS_FILENAME,
DEFAULT_IDENTITY_FILENAME,
DEFAULT_USER_FILENAME,
DEFAULT_HEARTBEAT_FILENAME,
DEFAULT_BOOTSTRAP_FILENAME
];
const BOOTSTRAP_FILE_NAMES_POST_ONBOARDING = BOOTSTRAP_FILE_NAMES.filter((name) => name !== DEFAULT_BOOTSTRAP_FILENAME);
const agentsHandlerDeps = {
root,
isWorkspaceSetupCompleted
};
const testing = {
setDepsForTests(overrides) {
if (overrides.isWorkspaceSetupCompleted) agentsHandlerDeps.isWorkspaceSetupCompleted = overrides.isWorkspaceSetupCompleted;
if (overrides.root) agentsHandlerDeps.root = overrides.root;
},
resetDepsForTests() {
agentsHandlerDeps.root = root;
agentsHandlerDeps.isWorkspaceSetupCompleted = isWorkspaceSetupCompleted;
}
};
const MEMORY_FILE_NAMES = [DEFAULT_MEMORY_FILENAME];
const ALLOWED_FILE_NAMES = new Set([...BOOTSTRAP_FILE_NAMES, ...MEMORY_FILE_NAMES]);
function resolveAgentWorkspaceFileOrRespondError(params, respond, cfg) {
const rawAgentId = params.agentId;
const agentId = resolveAgentIdOrError(typeof rawAgentId === "string" || typeof rawAgentId === "number" ? String(rawAgentId) : "", cfg);
if (!agentId) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unknown agent id"));
return null;
}
const rawName = params.name;
const name = (typeof rawName === "string" || typeof rawName === "number" ? String(rawName) : "").trim();
if (!ALLOWED_FILE_NAMES.has(name)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `unsupported file "${name}"`));
return null;
}
return {
cfg,
agentId,
workspaceDir: resolveAgentWorkspaceDir(cfg, agentId),
name
};
}
function isRegularWorkspaceFileStat(stat) {
const isFile = typeof stat.isFile === "function" ? stat.isFile() : stat.isFile;
const isSymbolicLink = typeof stat.isSymbolicLink === "function" ? stat.isSymbolicLink() : stat.isSymbolicLink;
return isFile && !isSymbolicLink && stat.nlink <= 1;
}
function toWorkspaceFileMeta(stat) {
if (!isRegularWorkspaceFileStat(stat)) return null;
return {
size: stat.size,
updatedAtMs: Math.floor(stat.mtimeMs)
};
}
async function statWorkspaceFileSafely(workspaceRoot, workspaceDir, name) {
try {
return toWorkspaceFileMeta(workspaceRoot ? await workspaceRoot.stat(name) : await fs.lstat(path.join(workspaceDir, name)));
} catch {
if (!workspaceRoot) return null;
try {
return toWorkspaceFileMeta(await fs.lstat(path.join(workspaceDir, name)));
} catch {
return null;
}
}
}
async function openWorkspaceRootSafely(workspaceDir) {
try {
return await agentsHandlerDeps.root(workspaceDir);
} catch {
return null;
}
}
async function listAgentFiles(workspaceDir, options) {
const files = [];
const workspaceRoot = await openWorkspaceRootSafely(workspaceDir);
if (!workspaceRoot) return [...options?.hideBootstrap ? BOOTSTRAP_FILE_NAMES_POST_ONBOARDING : BOOTSTRAP_FILE_NAMES, DEFAULT_MEMORY_FILENAME].map((name) => ({
name,
path: path.join(workspaceDir, name),
missing: true
}));
const bootstrapFileNames = options?.hideBootstrap ? BOOTSTRAP_FILE_NAMES_POST_ONBOARDING : BOOTSTRAP_FILE_NAMES;
for (const name of bootstrapFileNames) {
const filePath = path.join(workspaceDir, name);
const meta = await statWorkspaceFileSafely(workspaceRoot, workspaceDir, name);
if (meta) files.push({
name,
path: filePath,
missing: false,
size: meta.size,
updatedAtMs: meta.updatedAtMs
});
else files.push({
name,
path: filePath,
missing: true
});
}
const primaryMeta = await statWorkspaceFileSafely(workspaceRoot, workspaceDir, DEFAULT_MEMORY_FILENAME);
if (primaryMeta) files.push({
name: DEFAULT_MEMORY_FILENAME,
path: path.join(workspaceDir, DEFAULT_MEMORY_FILENAME),
missing: false,
size: primaryMeta.size,
updatedAtMs: primaryMeta.updatedAtMs
});
else files.push({
name: DEFAULT_MEMORY_FILENAME,
path: path.join(workspaceDir, DEFAULT_MEMORY_FILENAME),
missing: true
});
return files;
}
function resolveAgentIdOrError(agentIdRaw, cfg) {
const agentId = normalizeAgentId(agentIdRaw);
if (!new Set(listAgentIds(cfg)).has(agentId)) return null;
return agentId;
}
function sanitizeIdentityLine(value) {
return value.replace(/\s+/g, " ").trim();
}
function respondInvalidMethodParams(respond, method, errors) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid ${method} params: ${formatValidationErrors(errors)}`));
}
function respondAgentNotFound(respond, agentId) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `agent "${agentId}" not found`));
}
function respondAgentConfigPreconditionError(respond, error) {
if (error.kind === "not-found") {
respondAgentNotFound(respond, error.agentId);
return;
}
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `agent "${error.agentId}" already exists`));
}
async function moveToTrashBestEffort(pathname) {
if (!pathname) return;
try {
await fs.access(pathname);
} catch {
return;
}
try {
await movePathToTrash(pathname);
} catch {}
}
function respondWorkspaceFileUnsafe(respond, name) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `unsafe workspace file "${name}"`));
}
function respondWorkspaceFileMissing(params) {
params.respond(true, {
agentId: params.agentId,
workspace: params.workspaceDir,
file: {
name: params.name,
path: params.filePath,
missing: true
}
}, void 0);
}
async function writeWorkspaceFileOrRespond(params) {
await fs.mkdir(params.workspaceDir, { recursive: true });
try {
await (await agentsHandlerDeps.root(params.workspaceDir)).write(params.name, params.content, { encoding: "utf8" });
} catch (err) {
if (err instanceof FsSafeError) {
respondWorkspaceFileUnsafe(params.respond, params.name);
return false;
}
throw err;
}
return true;
}
function normalizeIdentityForFile(identity) {
if (!identity) return;
const resolved = {
name: identity.name?.trim() || void 0,
theme: identity.theme?.trim() || void 0,
emoji: identity.emoji?.trim() || void 0,
avatar: identity.avatar?.trim() || void 0
};
if (!resolved.name && !resolved.theme && !resolved.emoji && !resolved.avatar) return;
return resolved;
}
function createAgentIdentityConfig(params) {
const emoji = normalizeOptionalString(params.emoji);
const avatar = normalizeOptionalString(params.avatar);
const identity = {
...params.safeName ? { name: params.safeName } : {},
...emoji ? { emoji: sanitizeIdentityLine(emoji) } : {},
...avatar ? { avatar: sanitizeIdentityLine(avatar) } : {}
};
return identity.name || identity.emoji || identity.avatar ? identity : void 0;
}
function buildAgentConfigUpdate(params) {
return {
agentId: params.agentId,
...params.safeName ? { name: params.safeName } : {},
...params.workspaceDir ? { workspace: params.workspaceDir } : {},
...params.model ? { model: params.model } : {},
...params.identity ? { identity: params.identity } : {}
};
}
async function readWorkspaceFileContent(workspaceDir, name) {
try {
return (await (await agentsHandlerDeps.root(workspaceDir)).read(name, {
hardlinks: "reject",
nonBlockingRead: true
})).buffer.toString("utf-8");
} catch (err) {
if (err instanceof FsSafeError && err.code === "not-found") return;
throw err;
}
}
async function buildIdentityMarkdownForWrite(params) {
let baseContent;
if (params.preferFallbackWorkspaceContent && params.fallbackWorkspaceDir) {
baseContent = await readWorkspaceFileContent(params.fallbackWorkspaceDir, DEFAULT_IDENTITY_FILENAME);
if (baseContent === void 0) baseContent = await readWorkspaceFileContent(params.workspaceDir, DEFAULT_IDENTITY_FILENAME);
} else {
baseContent = await readWorkspaceFileContent(params.workspaceDir, DEFAULT_IDENTITY_FILENAME);
if (baseContent === void 0 && params.fallbackWorkspaceDir) baseContent = await readWorkspaceFileContent(params.fallbackWorkspaceDir, DEFAULT_IDENTITY_FILENAME);
}
return mergeIdentityMarkdownContent(baseContent, params.identity);
}
async function buildIdentityMarkdownOrRespondUnsafe(params) {
try {
return await buildIdentityMarkdownForWrite(params);
} catch (err) {
if (err instanceof FsSafeError) {
respondWorkspaceFileUnsafe(params.respond, DEFAULT_IDENTITY_FILENAME);
return null;
}
throw err;
}
}
const agentsHandlers = {
"agents.list": async ({ params, respond, context }) => {
if (!validateAgentsListParams(params)) {
respondInvalidMethodParams(respond, "agents.list", validateAgentsListParams.errors);
return;
}
respond(true, listAgentsForGateway(context.getRuntimeConfig(), await loadOptionalServerMethodModelCatalog(context, "agents.list", { logOnceKey: "agents.list" })), void 0);
},
"agents.create": async ({ params, respond, context }) => {
if (!validateAgentsCreateParams(params)) {
respondInvalidMethodParams(respond, "agents.create", validateAgentsCreateParams.errors);
return;
}
const cfg = context.getRuntimeConfig();
const rawName = params.name.trim();
const agentId = normalizeAgentId(rawName);
if (agentId === "main") {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `"${DEFAULT_AGENT_ID}" is reserved`));
return;
}
if (isConfiguredAgent(cfg, agentId)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `agent "${agentId}" already exists`));
return;
}
const workspaceDir = resolveUserPath(params.workspace.trim());
const safeName = sanitizeIdentityLine(rawName);
const model = normalizeOptionalString(params.model);
const identity = createAgentIdentityConfig({
safeName,
emoji: params.emoji,
avatar: params.avatar
}) ?? { name: safeName };
let nextConfig = applyAgentConfig(cfg, {
agentId,
name: safeName,
workspace: workspaceDir,
model,
identity
});
const agentDir = resolveAgentDir(nextConfig, agentId);
nextConfig = applyAgentConfig(nextConfig, {
agentId,
agentDir
});
await ensureAgentWorkspace({
dir: workspaceDir,
ensureBootstrapFiles: !Boolean(nextConfig.agents?.defaults?.skipBootstrap),
skipOptionalBootstrapFiles: nextConfig.agents?.defaults?.skipOptionalBootstrapFiles
});
await fs.mkdir(resolveSessionTranscriptsDirForAgent(agentId), { recursive: true });
const persistedIdentity = normalizeIdentityForFile(resolveAgentIdentity(nextConfig, agentId));
if (persistedIdentity) {
const identityContent = await buildIdentityMarkdownOrRespondUnsafe({
respond,
workspaceDir,
identity: persistedIdentity
});
if (identityContent === null) return;
if (!await writeWorkspaceFileOrRespond({
respond,
workspaceDir,
name: "IDENTITY.md",
content: identityContent
})) return;
}
try {
await createAgentConfigEntry({
agentId,
name: safeName,
workspace: workspaceDir,
model,
identity,
agentDir
});
} catch (error) {
if (error instanceof AgentConfigPreconditionError) {
respondAgentConfigPreconditionError(respond, error);
return;
}
throw error;
}
respond(true, {
ok: true,
agentId,
name: safeName,
workspace: workspaceDir,
model
}, void 0);
},
"agents.update": async ({ params, respond, context }) => {
if (!validateAgentsUpdateParams(params)) {
respondInvalidMethodParams(respond, "agents.update", validateAgentsUpdateParams.errors);
return;
}
const cfg = context.getRuntimeConfig();
const agentId = normalizeAgentId(params.agentId);
if (!isConfiguredAgent(cfg, agentId)) {
respondAgentNotFound(respond, agentId);
return;
}
const workspaceDir = typeof params.workspace === "string" && params.workspace.trim() ? resolveUserPath(params.workspace.trim()) : void 0;
const model = normalizeOptionalString(params.model);
const safeName = typeof params.name === "string" && params.name.trim() ? sanitizeIdentityLine(params.name.trim()) : void 0;
const identity = createAgentIdentityConfig({
safeName,
emoji: params.emoji,
avatar: params.avatar
});
const hasIdentityFields = Boolean(identity);
const agentConfigUpdate = buildAgentConfigUpdate({
agentId,
safeName,
workspaceDir,
model,
identity
});
const nextConfig = applyAgentConfig(cfg, agentConfigUpdate);
let ensuredWorkspace;
if (workspaceDir) ensuredWorkspace = await ensureAgentWorkspace({
dir: workspaceDir,
ensureBootstrapFiles: !Boolean(nextConfig.agents?.defaults?.skipBootstrap),
skipOptionalBootstrapFiles: nextConfig.agents?.defaults?.skipOptionalBootstrapFiles
});
const persistedIdentity = normalizeIdentityForFile(resolveAgentIdentity(nextConfig, agentId));
if (persistedIdentity && (workspaceDir || hasIdentityFields)) {
const identityWorkspaceDir = resolveAgentWorkspaceDir(nextConfig, agentId);
const previousWorkspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
const fallbackWorkspaceDir = workspaceDir && identityWorkspaceDir !== previousWorkspaceDir ? previousWorkspaceDir : void 0;
const identityContent = await buildIdentityMarkdownOrRespondUnsafe({
respond,
workspaceDir: identityWorkspaceDir,
identity: persistedIdentity,
fallbackWorkspaceDir,
preferFallbackWorkspaceContent: Boolean(fallbackWorkspaceDir) && ensuredWorkspace?.identityPathCreated === true
});
if (identityContent === null) return;
if (!await writeWorkspaceFileOrRespond({
respond,
workspaceDir: identityWorkspaceDir,
name: "IDENTITY.md",
content: identityContent
})) return;
}
try {
await updateAgentConfigEntry(agentConfigUpdate);
} catch (error) {
if (error instanceof AgentConfigPreconditionError) {
respondAgentConfigPreconditionError(respond, error);
return;
}
throw error;
}
respond(true, {
ok: true,
agentId
}, void 0);
},
"agents.delete": async ({ params, respond, context }) => {
if (!validateAgentsDeleteParams(params)) {
respondInvalidMethodParams(respond, "agents.delete", validateAgentsDeleteParams.errors);
return;
}
const cfg = context.getRuntimeConfig();
const agentId = normalizeAgentId(params.agentId);
if (agentId === "main") {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `"${DEFAULT_AGENT_ID}" cannot be deleted`));
return;
}
if (!isConfiguredAgent(cfg, agentId)) {
respondAgentNotFound(respond, agentId);
return;
}
const deleteFiles = typeof params.deleteFiles === "boolean" ? params.deleteFiles : true;
let committed;
try {
committed = await deleteAgentConfigEntry({ agentId });
} catch (error) {
if (error instanceof AgentConfigPreconditionError) {
respondAgentConfigPreconditionError(respond, error);
return;
}
throw error;
}
const deleteResult = committed.result;
if (!deleteResult) {
respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "agent delete did not commit"));
return;
}
await purgeAgentSessionStoreEntries(cfg, agentId);
if (deleteFiles) {
const deleteWorkspace = findOverlappingWorkspaceAgentIds(committed.nextConfig, agentId, deleteResult.workspaceDir).length === 0;
const pathsToTrash = [deleteResult.agentDir, deleteResult.sessionsDir];
if (deleteWorkspace) {
pathsToTrash.unshift(deleteResult.workspaceDir);
for (const [index, attestationPath] of resolveWorkspaceAttestationPaths(deleteResult.workspaceDir).entries()) if (await shouldRemoveWorkspaceAttestation(attestationPath, { trustUnknown: index === 0 })) pathsToTrash.push(attestationPath);
}
await Promise.all(pathsToTrash.map((pathname) => moveToTrashBestEffort(pathname)));
}
respond(true, {
ok: true,
agentId,
removedBindings: deleteResult.removedBindings
}, void 0);
},
"agents.files.list": async ({ params, respond, context }) => {
if (!validateAgentsFilesListParams(params)) {
respondInvalidMethodParams(respond, "agents.files.list", validateAgentsFilesListParams.errors);
return;
}
const cfg = context.getRuntimeConfig();
const agentId = resolveAgentIdOrError(params.agentId, cfg);
if (!agentId) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unknown agent id"));
return;
}
const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
let hideBootstrap = false;
try {
hideBootstrap = await agentsHandlerDeps.isWorkspaceSetupCompleted(workspaceDir);
} catch {}
respond(true, {
agentId,
workspace: workspaceDir,
files: await listAgentFiles(workspaceDir, { hideBootstrap })
}, void 0);
},
"agents.files.get": async ({ params, respond, context }) => {
if (!validateAgentsFilesGetParams(params)) {
respondInvalidMethodParams(respond, "agents.files.get", validateAgentsFilesGetParams.errors);
return;
}
const resolved = resolveAgentWorkspaceFileOrRespondError(params, respond, context.getRuntimeConfig());
if (!resolved) return;
const { agentId, workspaceDir, name } = resolved;
const filePath = path.join(workspaceDir, name);
let safeRead;
try {
safeRead = await (await agentsHandlerDeps.root(workspaceDir)).read(name, {
hardlinks: "reject",
nonBlockingRead: true
});
} catch (err) {
if (err instanceof FsSafeError && err.code === "not-found") {
respondWorkspaceFileMissing({
respond,
agentId,
workspaceDir,
name,
filePath
});
return;
}
if (err instanceof FsSafeError) {
respondWorkspaceFileUnsafe(respond, name);
return;
}
throw err;
}
respond(true, {
agentId,
workspace: workspaceDir,
file: {
name,
path: filePath,
missing: false,
size: safeRead.stat.size,
updatedAtMs: Math.floor(safeRead.stat.mtimeMs),
content: safeRead.buffer.toString("utf-8")
}
}, void 0);
},
"agents.files.set": async ({ params, respond, context }) => {
if (!validateAgentsFilesSetParams(params)) {
respondInvalidMethodParams(respond, "agents.files.set", validateAgentsFilesSetParams.errors);
return;
}
const resolved = resolveAgentWorkspaceFileOrRespondError(params, respond, context.getRuntimeConfig());
if (!resolved) return;
const { agentId, workspaceDir, name } = resolved;
await fs.mkdir(workspaceDir, { recursive: true });
const filePath = path.join(workspaceDir, name);
const content = params.content;
let workspaceRoot;
try {
workspaceRoot = await agentsHandlerDeps.root(workspaceDir);
await workspaceRoot.write(name, content, { encoding: "utf8" });
} catch (err) {
if (!(err instanceof FsSafeError)) throw err;
respondWorkspaceFileUnsafe(respond, name);
return;
}
const meta = await statWorkspaceFileSafely(workspaceRoot, workspaceDir, name);
respond(true, {
ok: true,
agentId,
workspace: workspaceDir,
file: {
name,
path: filePath,
missing: false,
size: meta?.size,
updatedAtMs: meta?.updatedAtMs,
content
}
}, void 0);
}
};
//#endregion
export { testing as __testing, testing, agentsHandlers };