@sema-agent/core
Version:
Stateless, task-oriented AI agent core
76 lines (75 loc) • 3.42 kB
JavaScript
import { sanitizeUntrustedText, SHELLED_BODY_ENVELOPE_TAGS } from "../untrusted-text.js";
export function foldListingWithin(items, spec) {
if (items.length === 0)
return undefined;
const bytes = (s) => Buffer.byteLength(s, "utf8");
const render = spec.frame;
const lineCost = (l) => bytes(l) + 1;
const bodyBudget = spec.blockMaxBytes - bytes(render([]));
const fullLines = items.map((it) => spec.full(it));
const fullTotal = fullLines.reduce((acc, l) => acc + lineCost(l), 0);
if (fullTotal <= bodyBudget)
return { text: render(fullLines), nameOnly: [], dropped: [] };
const nameLines = items.map((it) => spec.nameOnly(it));
const namePrefix = new Array(nameLines.length + 1);
namePrefix[0] = 0;
for (let i = 0; i < nameLines.length; i++)
namePrefix[i + 1] = namePrefix[i] + lineCost(nameLines[i]);
const markerCost = lineCost(spec.capMarker);
const floorCost = markerCost + namePrefix[nameLines.length];
if (floorCost <= bodyBudget) {
let slack = bodyBudget - floorCost;
const byPriority = items
.map((it, i) => ({ i, rank: spec.rank?.(it, i) ?? i }))
.toSorted((a, b) => a.rank - b.rank || a.i - b.i);
const withFull = new Set();
for (const { i } of byPriority) {
const delta = lineCost(fullLines[i]) - lineCost(nameLines[i]);
if (delta <= slack) {
withFull.add(i);
slack -= delta;
}
}
return {
text: render([spec.capMarker, ...items.map((_it, i) => (withFull.has(i) ? fullLines[i] : nameLines[i]))]),
nameOnly: items.filter((_it, i) => !withFull.has(i)).map((it) => spec.nameOf(it)),
dropped: [],
};
}
for (let m = items.length - 1; m >= 0; m--) {
const overflow = spec.overflowLine(items.length - m);
if (markerCost + namePrefix[m] + lineCost(overflow) <= bodyBudget) {
return {
text: render([spec.capMarker, ...nameLines.slice(0, m), overflow]),
nameOnly: items.slice(0, m).map((it) => spec.nameOf(it)),
dropped: items.slice(m).map((it) => spec.nameOf(it)),
};
}
}
return {
text: render([spec.capMarker, spec.overflowLine(items.length)]),
nameOnly: [],
dropped: items.map((it) => spec.nameOf(it)),
};
}
export function removalArmFloor(header, count) {
return [header, `(… +${count} more are no longer available)`].join("\n");
}
export function foldRemovalArmWithin(removed, header, maxBytes) {
const bytes = (s) => Buffer.byteLength(s, "utf8");
const lines = removed.map((n) => `- ${sanitizeUntrustedText(n, SHELLED_BODY_ENVELOPE_TAGS)}`);
const head = bytes(header);
const lineCost = (l) => bytes(l) + 1;
const prefix = new Array(lines.length + 1);
prefix[0] = 0;
for (let i = 0; i < lines.length; i++)
prefix[i + 1] = prefix[i] + lineCost(lines[i]);
if (head + prefix[lines.length] <= maxBytes)
return [header, ...lines].join("\n");
for (let m = lines.length - 1; m >= 0; m--) {
const tail = `(… +${lines.length - m} more are no longer available)`;
if (head + prefix[m] + lineCost(tail) <= maxBytes)
return [header, ...lines.slice(0, m), tail].join("\n");
}
return removalArmFloor(header, lines.length);
}