UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

101 lines (100 loc) 3.96 kB
import { t as asNonArrayRecord } from "./record-coerce-DItp3I4t.js"; import { t as asBoolean } from "./boolean-DmBL0YJK.js"; import { u as readMediaBuffer } from "./store-Ph57PZ9P.js"; import "./string-coerce-runtime-GQa0ehRA.js"; import "./media-store-4cRisQA1.js"; import { d as FILE_WRITE_TOOL_DESCRIPTOR, l as FILE_TRANSFER_SUBDIR, u as FILE_WRITE_HARD_MAX_BYTES } from "./descriptors-Cun0f4Hd.js"; import { t as inspectStrictBase64 } from "./base64-DHgbKH6a.js"; import { t as appendFileTransferAudit } from "./audit-Cw95_l64.js"; import { n as readRequiredNodePath, r as humanSize, t as invokeNodeToolPayload } from "./node-tool-invoke-CBLfLEy7.js"; import crypto from "node:crypto"; //#region extensions/file-transfer/src/tools/file-write-tool.ts function normalizeBase64ForCompare(value) { return value.replace(/=+$/u, "").replace(/-/gu, "+").replace(/_/gu, "/"); } function decodeStrictBase64(value) { const decodedBytes = inspectStrictBase64(value); if (decodedBytes === void 0) throw new Error("contentBase64 is not valid base64"); if (decodedBytes > 16777216) throw new Error(`decoded content is ${decodedBytes} bytes; maximum is ${FILE_WRITE_HARD_MAX_BYTES} bytes (${humanSize(FILE_WRITE_HARD_MAX_BYTES)})`); const buffer = Buffer.from(value, "base64"); if (normalizeBase64ForCompare(buffer.toString("base64")) !== normalizeBase64ForCompare(value)) throw new Error("contentBase64 is not valid base64"); return buffer; } async function readSourceBytes(input) { const sourceMediaId = input.sourceMediaId?.trim(); if (sourceMediaId) { const { buffer } = await readMediaBuffer(sourceMediaId, FILE_TRANSFER_SUBDIR, FILE_WRITE_HARD_MAX_BYTES); return { buffer, contentBase64: buffer.toString("base64"), source: "media" }; } if (input.contentBase64 === void 0) throw new Error("contentBase64 or sourceMediaId required"); return { buffer: decodeStrictBase64(input.contentBase64), contentBase64: input.contentBase64, source: "inline" }; } function createFileWriteTool() { return { ...FILE_WRITE_TOOL_DESCRIPTOR, async execute(_toolCallId, params) { const raw = asNonArrayRecord(params); const { node: nodeQuery, requestedPath: filePath } = readRequiredNodePath(raw); const contentBase64 = typeof raw.contentBase64 === "string" ? raw.contentBase64 : void 0; const sourceMediaId = typeof raw.sourceMediaId === "string" ? raw.sourceMediaId : void 0; const overwrite = asBoolean(raw.overwrite) ?? false; const createParents = asBoolean(raw.createParents) ?? false; const sourceBytes = await readSourceBytes({ contentBase64, sourceMediaId }); const buffer = sourceBytes.buffer; const expectedSha256 = crypto.createHash("sha256").update(buffer).digest("hex"); const { nodeId, nodeDisplayName, payload, startedAt } = await invokeNodeToolPayload({ node: nodeQuery, params: raw, command: "file.write", commandParams: { path: filePath, contentBase64: sourceBytes.contentBase64, overwrite, createParents, expectedSha256 }, invalidPayloadMessage: "unexpected response from node", invalidPayloadError: "unexpected file.write response from node", errorAuditExtra: { sizeBytes: buffer.byteLength }, requireOk: true, requestedPath: filePath }); const typed = payload; await appendFileTransferAudit({ op: "file.write", nodeId, nodeDisplayName, requestedPath: filePath, canonicalPath: typed.path, decision: "allowed", sizeBytes: typed.size, sha256: typed.sha256, durationMs: Date.now() - startedAt }); const overwriteNote = typed.overwritten ? " (overwrote existing file)" : ""; return { content: [{ type: "text", text: `Wrote ${typed.path} (${humanSize(typed.size)}, sha256:${typed.sha256.slice(0, 12)})${overwriteNote}` }], details: { ...typed, source: sourceBytes.source } }; } }; } //#endregion export { createFileWriteTool };