agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
86 lines • 3.6 kB
JavaScript
;
/**
* Bounded serialization helpers for the trace toolpack.
*
* Pattern: pure functions — no state, no events.
* Role: The token-economics layer. EVERY value the toolpack serves goes
* through these: previews are capped, truncation is EXPLICIT
* (never silent), and nested-path keys round-trip between the
* engine's DELIM encoding and LLM-friendly dot notation.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.clampParam = exports.renderPreview = exports.boundedPreview = exports.safeStringify = exports.displayText = exports.normalizeKey = exports.displayKey = exports.FP_PATH_DELIM = void 0;
/**
* footprintjs's canonical nested-path delimiter (ASCII unit separator,
* `src/lib/memory/utils.ts`). Internal to the engine — the toolpack
* translates it to/from dot notation so the LLM never sees a control char.
*/
exports.FP_PATH_DELIM = '\u001F';
/** Engine path → LLM-friendly dotted display form. */
function displayKey(path) {
return path.includes(exports.FP_PATH_DELIM) ? path.split(exports.FP_PATH_DELIM).join('.') : path;
}
exports.displayKey = displayKey;
/**
* LLM-supplied key → engine path. Exact keys pass through; a dotted key
* that doesn't exist verbatim but matches a known DELIM-joined path is
* translated back. `knownPaths` is the set of every path seen in the
* commit log's trace entries.
*/
function normalizeKey(key, knownPaths) {
if (knownPaths.has(key))
return key;
if (key.includes('.')) {
const delimForm = key.split('.').join(exports.FP_PATH_DELIM);
if (knownPaths.has(delimForm))
return delimForm;
}
return key;
}
exports.normalizeKey = normalizeKey;
/** Replace every DELIM in an already-formatted text block with '.' for display. */
function displayText(text) {
return text.split(exports.FP_PATH_DELIM).join('.');
}
exports.displayText = displayText;
/**
* Serialize a value to compact JSON, total-function style: cycles, BigInt
* and other non-JSON values degrade to a tagged placeholder instead of
* throwing — a debugger tool must never crash on the evidence it serves.
*/
function safeStringify(value) {
if (value === undefined)
return 'undefined';
try {
const json = JSON.stringify(value);
return json === undefined ? String(value) : json;
}
catch {
return '[unserializable value]';
}
}
exports.safeStringify = safeStringify;
/** Serialize + cap at `maxChars`. Truncation is reported, never silent. */
function boundedPreview(value, maxChars) {
const full = safeStringify(value);
if (full.length <= maxChars) {
return { text: full, totalChars: full.length, truncated: false };
}
return { text: `${full.slice(0, maxChars)}…`, totalChars: full.length, truncated: true };
}
exports.boundedPreview = boundedPreview;
/** Render a preview with its honesty suffix when truncated. */
function renderPreview(preview, fetchHint) {
if (!preview.truncated)
return preview.text;
const hint = fetchHint ? ` — ${fetchHint}` : '';
return `${preview.text} (${preview.totalChars} chars total${hint})`;
}
exports.renderPreview = renderPreview;
/** Clamp an LLM-supplied numeric param into [min, hardCap], with a default. */
function clampParam(requested, fallback, min, hardCap) {
const value = typeof requested === 'number' && Number.isFinite(requested) ? requested : fallback;
return Math.max(min, Math.min(Math.floor(value), hardCap));
}
exports.clampParam = clampParam;
//# sourceMappingURL=bounded.js.map