agents
Version:
A home for your AI agents
59 lines (58 loc) • 2.89 kB
JavaScript
//#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