agents
Version:
A home for your AI agents
98 lines (97 loc) • 4.31 kB
JavaScript
//#region src/chat/tool-output-truncation.ts
const DEFAULT_MAX_DEPTH = 8;
const TRUNCATED_FLAG = "__truncated";
const TRUNCATED_CHARS = "__truncatedChars";
function truncateToolOutput(output, maxChars) {
const original = stringifyForLength(output);
if (original.length <= maxChars) return {
output,
truncated: false,
originalLength: original.length
};
return {
output: truncateValue(output, maxChars, original.length, 0),
truncated: true,
originalLength: original.length
};
}
function truncatedSuffix(originalLength) {
return `... [truncated ${originalLength} chars]`;
}
function truncateValue(value, maxChars, originalLength, depth) {
if (typeof value === "string") return truncateString(value, maxChars, value.length);
if (value === null || typeof value !== "object") return value;
if (depth >= DEFAULT_MAX_DEPTH) return `[Nested output omitted ${truncatedSuffix(originalLength)}]`;
if (Array.isArray(value)) return truncateArray(value, maxChars, originalLength, depth);
return truncateObject(value, maxChars, originalLength, depth);
}
function truncateArray(value, maxChars, originalLength, depth) {
const childBudget = childMaxChars(maxChars, value.length);
const result = value.map((item) => truncateValue(item, childBudget, stringifyForLength(item).length, depth + 1));
while (result.length > 1 && stringifyForLength(result).length > maxChars) result.pop();
if (result.length < value.length) result.push(`Array output truncated ${truncatedSuffix(originalLength)}`);
if (stringifyForLength(result).length > maxChars) return compactArrayMarker(maxChars, originalLength);
return result;
}
function truncateObject(value, maxChars, originalLength, depth) {
const entries = Object.entries(value);
const childBudget = childMaxChars(maxChars, entries.length);
const result = {};
for (const [key, entryValue] of entries) result[key] = truncateValue(entryValue, childBudget, stringifyForLength(entryValue).length, depth + 1);
const resultLength = stringifyForLength(result).length;
if (resultLength <= maxChars) return result;
shrinkStringFields(result, maxChars);
if (stringifyForLength(result).length > maxChars) {
result[TRUNCATED_FLAG] = true;
result[TRUNCATED_CHARS] = resultLength;
}
if (stringifyForLength(result).length > maxChars) return compactObjectMarker(maxChars, originalLength);
return result;
}
function shrinkStringFields(value, maxChars) {
const stringEntries = Object.entries(value).filter((entry) => typeof entry[1] === "string").sort((a, b) => b[1].length - a[1].length);
for (const [key, str] of stringEntries) {
if (stringifyForLength(value).length <= maxChars) return;
value[key] = truncateString(str, Math.max(0, Math.floor(maxChars / 4)), str.length);
}
}
function truncateString(value, maxChars, originalLength) {
if (value.length <= maxChars) return value;
const suffix = truncatedSuffix(originalLength);
if (maxChars <= suffix.length) return suffix.slice(0, maxChars);
return `${value.slice(0, maxChars - suffix.length)}${suffix}`;
}
function compactObjectMarker(maxChars, originalLength) {
const marker = {
[TRUNCATED_FLAG]: true,
[TRUNCATED_CHARS]: originalLength,
note: "Tool output omitted because it was too large to preserve structurally."
};
if (stringifyForLength(marker).length <= maxChars) return marker;
return {
[TRUNCATED_FLAG]: true,
[TRUNCATED_CHARS]: originalLength
};
}
function compactArrayMarker(maxChars, originalLength) {
const structuredMarker = compactObjectMarker(maxChars, originalLength);
if (stringifyForLength([structuredMarker]).length <= maxChars) return [structuredMarker];
const marker = [`Array output omitted because it was too large to preserve structurally ${truncatedSuffix(originalLength)}`];
if (stringifyForLength(marker).length <= maxChars) return marker;
return [truncatedSuffix(originalLength).slice(0, maxChars)];
}
function childMaxChars(maxChars, childCount) {
if (childCount <= 1) return maxChars;
return Math.max(80, Math.floor(maxChars / Math.min(childCount, 10)));
}
function stringifyForLength(value) {
try {
if (typeof value === "string") return value;
return JSON.stringify(value) ?? String(value);
} catch {
return String(value);
}
}
//#endregion
export { truncateToolOutput as t };
//# sourceMappingURL=tool-output-truncation-CNnnGZQ3.js.map