UNPKG

agents

Version:

A home for your AI agents

59 lines (58 loc) • 2.89 kB
//#region src/core/base64-redaction.ts const BASE64_REDACTION_THRESHOLD = 4096; const MAX_REDACTION_DEPTH = 20; const MAX_REDACTION_NODES = 1e4; function base64Details(value, minimumLength = BASE64_REDACTION_THRESHOLD) { if (value.length < minimumLength) return null; const dataUrl = /^data:([^;,]+)(?:;[^;,]*)*;base64,([A-Za-z0-9+/]*={0,2})$/i.exec(value); const encoded = dataUrl?.[2] ?? value; if (encoded.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) return null; const padding = encoded.endsWith("==") ? 2 : encoded.endsWith("=") ? 1 : 0; return { mediaType: dataUrl?.[1], chars: encoded.length, bytes: encoded.length / 4 * 3 - padding }; } function base64Redaction(value, mediaType, minimumLength) { const details = base64Details(value, minimumLength); if (!details) return value; const type = mediaType ?? details.mediaType; return `[base64${type ? ` ${type}` : ""} data omitted: ${details.chars.toLocaleString()} chars, approximately ${details.bytes.toLocaleString()} bytes]`; } function redactBase64Payloads(value) { const ancestors = /* @__PURE__ */ new WeakSet(); let nodes = 0; function visit(current, depth) { if (depth > MAX_REDACTION_DEPTH) return "[nested value omitted]"; if (++nodes > MAX_REDACTION_NODES) return "[remaining values omitted]"; if (typeof current === "string") return base64Redaction(current); if (typeof current !== "object" || current === null) return current; if (current instanceof ArrayBuffer || ArrayBuffer.isView(current) || current instanceof Date || current instanceof Map || current instanceof Set) return current; if (ancestors.has(current)) return "[circular reference omitted]"; ancestors.add(current); try { if (Array.isArray(current)) return current.map((entry) => visit(entry, depth + 1)); const record = current; const screenshot = record.type === "browser_screenshot" && typeof record.mediaType === "string"; return Object.fromEntries(Object.entries(record).map(([key, entry]) => [key, screenshot && key === "data" && typeof entry === "string" ? base64Redaction(entry, record.mediaType, 0) : visit(entry, depth + 1)])); } finally { ancestors.delete(current); } } return visit(value, 0); } /** * `JSON.stringify` replacer applying the same rules as * {@link redactBase64Payloads}. Because it runs inside `JSON.stringify`, * `toJSON`, cycles and unsupported values behave exactly as they do without * it, and no depth or node limits are needed. */ function redactBase64Replacer(key, value) { if (typeof value !== "string") return value; const holder = this; return key === "data" && holder.type === "browser_screenshot" && typeof holder.mediaType === "string" ? base64Redaction(value, holder.mediaType, 0) : base64Redaction(value); } //#endregion export { redactBase64Replacer as n, redactBase64Payloads as t }; //# sourceMappingURL=base64-redaction-C1Uu29t5.js.map