agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
94 lines • 4.43 kB
JavaScript
;
/**
* findings/peel — the answer's `_findings` peel and the stream's filter, in
* the ONE module an unarmed agent never loads.
*
* Both run `answerText.ts`'s scanner, which only `.findings()` agents use.
* The stages that need it (`callLLM`, `route`) load this module through
* `import()` when the arm is on — the optional-family law of docs-next's site
* budget, the same as `judge.ts` and `toolChoice/compose.ts` — so a plain
* agent's bundle carries none of it. Keep every static import of
* `answerText.ts` inside this file and `answerText.ts` itself;
* test/core/agent/findings/peel-lazy.test.ts pins that.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.peelAnswerFindings = exports.withoutReservedMembers = exports.reservedMemberFilter = void 0;
const types_js_1 = require("./types.js");
const reserved_js_1 = require("./reserved.js");
const answerText_js_1 = require("./answerText.js");
var answerText_js_2 = require("./answerText.js");
Object.defineProperty(exports, "reservedMemberFilter", { enumerable: true, get: function () { return answerText_js_2.reservedMemberFilter; } });
Object.defineProperty(exports, "withoutReservedMembers", { enumerable: true, get: function () { return answerText_js_2.withoutReservedMembers; } });
/**
* Take the answer's `_findings` off, wherever the answer's TEXT carries it
* (9.114.2; `answerText.ts` is the rule, shared with the stream). Every JSON
* object in the answer that is not inside another object — the whole answer,
* a code block holding one, one written in the prose — loses its own
* `_findings` member and the separator that joined it, and nothing else moves:
* the model's layout and the prose around it stay as written. Identity when
* nothing was removed.
*
* The removed values are the answer's declaration: per object the LAST one
* (JSON's own rule for a repeated key — what a whole-answer `JSON.parse` read
* before 9.114.2), across objects in text order, their `previous` lists
* joined. A value that is not JSON, or that a cut-off text left unfinished, is
* dropped and counted (`malformed`), never guessed at.
*/
function peelAnswerFindings(raw, options) {
if (typeof raw !== 'string')
return { content: raw };
const { text, removed } = (0, answerText_js_1.withoutReservedMembers)(raw, types_js_1.RESERVED_ANSWER_KEY);
if (removed.length === 0)
return { content: raw };
const lastPerObject = new Map();
for (const member of removed)
lastPerObject.set(member.object, member);
let findings;
let malformed = 0;
let attempted = '';
let attemptedTruncated = false;
for (const member of lastPerObject.values()) {
const read = readRemovedValue(member);
malformed += read.malformed;
if (options?.captureMalformed === true && read.malformed > 0) {
const remaining = 8192 - attempted.length;
if (member.valueText.length > remaining)
attemptedTruncated = true;
if (remaining > 0)
attempted += member.valueText.slice(0, remaining);
}
if (read.declaration !== undefined)
findings = joinDeclarations(findings, read.declaration);
}
return {
content: text,
...(findings !== undefined && { findings }),
...(malformed > 0 && { malformed }),
...(attempted.length > 0 && { attemptedMalformed: attempted }),
...(attemptedTruncated && { attemptedTruncated: true }),
};
}
exports.peelAnswerFindings = peelAnswerFindings;
/** One removed value, read as a declaration — or counted, when it cannot be read. */
function readRemovedValue(member) {
if (!member.complete)
return { malformed: 1 };
let value;
try {
value = JSON.parse(member.valueText);
}
catch {
return { malformed: 1 };
}
return (0, reserved_js_1.readDeclaration)(value);
}
/** Two objects' declarations as one: later fields win, `previous` lists join in text order. */
function joinDeclarations(earlier, later) {
if (earlier === undefined)
return later;
const previous = earlier.previous === undefined && later.previous === undefined
? undefined
: [...(earlier.previous ?? []), ...(later.previous ?? [])];
return { ...earlier, ...later, ...(previous !== undefined && { previous }) };
}
//# sourceMappingURL=peel.js.map