agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
68 lines • 3.61 kB
JavaScript
;
/**
* resultCeiling — the refusing ceiling a tool declares on its OWN result
* (9.20.0). One owner of the measurement and the refusal sentence; the
* tool-dispatch loop (`stages/toolCalls.ts`) calls it at every boundary where
* a handler's return becomes final, so a resumed call is refused exactly as an
* inline one.
*
* Pattern: measured refusal at the dispatch boundary — the sibling of
* `toolResultCap.ts`, with the OPPOSITE answer to overflow, because
* the two serve different owners:
*
* • `maxToolResultChars` (agent-level, 9.11.0) TRUNCATES: the operator caps
* tools they did not write, so the most honest deliverable is a marker
* plus a verbatim head of whatever came back.
* • `resultCeiling` (per-tool, this module) REFUSES: the AUTHOR declared
* what a sane result is and which parameters (`narrowBy`) make a retry
* smaller. A truncated result reads as a complete one — the model cannot
* tell the data ends where the cut happened and fabricates from the part
* it saw — while a refusal that says "No data was returned" and names the
* narrowing parameters produces a clean retry (field-verified on a
* ~191k-char return).
*
* The oversized payload never leaves the dispatch: not into history, not into
* `stream.tool_end`, not into any recorder. The RECORD keeps the truth as the
* typed `agentfootprint.tools.result_refused` event (true size, ceiling,
* suggestions), emitted by the caller beside the replacement; the delivered
* result carries status `'invalid'` — the closed-set member whose corrective
* action is "fix the call" — so `onToolStatus` edges can route on it.
*
* Emits: nothing itself (pure measurement); zero-cost-when-unused — no
* declared ceiling means one `undefined` check and byte-identical behavior.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.applyResultCeiling = void 0;
const validators_js_1 = require("./validators.js");
// LENS · tool-result · persistent-history
// reads: the tool's OWN declared ceiling and columns — one owner of the measurement and of the refusal sentence
// law: may omit, never deny; every clause anchored to the call it was composed on.
/**
* Measure one handler result against the tool's declared ceiling.
*
* Returns `undefined` when there is no ceiling or the result fits — the caller
* keeps every byte of today's path. Over the ceiling, returns the refusal to
* deliver INSTEAD of the payload. What is measured is the string the model
* would have read (strings as-is, everything else `safeStringify`d) — the same
* rule `toolResultCap.ts` measures by, so the two ceilings always argue about
* the same number.
*/
function applyResultCeiling(value, opts) {
const ceiling = opts.ceiling;
if (ceiling === undefined)
return undefined;
const text = typeof value === 'string' ? value : (0, validators_js_1.safeStringify)(value);
if (text.length <= ceiling.maxChars)
return undefined;
const narrow = ceiling.narrowBy !== undefined && ceiling.narrowBy.length > 0
? ` — e.g. pass ${ceiling.narrowBy.map((n) => `'${n}'`).join(', ')}`
: '';
return {
refusal: `Result too large: ${opts.toolName} returned ${text.length} chars, over its declared ` +
`${ceiling.maxChars}-char ceiling. Narrow the request and call again${narrow}. ` +
`No data was returned.`,
sizeChars: text.length,
};
}
exports.applyResultCeiling = applyResultCeiling;
//# sourceMappingURL=resultCeiling.js.map