UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

97 lines • 4.66 kB
"use strict"; /** * invariant-violation at the WIRE seam — the composed frame and the * serialized body disagree about what the model was shown. * * Pattern: pure function over two name lists; same algebra, new seam. * Role: the check the compose seam CANNOT do. The recorded defect: the * internal frame said a subsystem's tools were removed, and the * adapter still serialized four schemas. Every check over the * pre-serialization IR read a clean frame — the bug lived in the * gap between the frame and the body. So the comparison here is * IR against `LLMResponse.wireManifest`, the manifest an adapter * reads back from the FINAL request body after every transform * (adapters/llm/wireManifest.ts). * * BOTH DIRECTIONS are defects, distinguished in the message: a name on the * wire the frame never composed (the recorded bug — the adapter retained or * invented it) and a composed name that never crossed (the model was * promised a capability it cannot call). One finding per direction, all * offending names aboard, so ten leaked schemas are one defect, not ten. * * HONEST ABSENCE: an adapter that states no manifest leaves the request * INCOMPARABLE — no finding, never a guess; the disposition for that call * is `unreachable`, not `checked-pass`. An EMPTY manifest is a stated zero * and compares normally. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.wireViolationsOf = void 0; const conflicts_js_1 = require("../assertion/conflicts.js"); const uniq = (names) => [...new Set(names)]; /** * Compare one call's composed frame against its wire manifest. * * Returns findings (usually none). Equal sets — whatever the order or * duplication — return nothing, which the caller files as `checked-pass`. */ function wireViolationsOf(composed, wire, epoch) { if (wire === undefined) return []; // no manifest stated: incomparable, never a guess const composedSet = new Set(composed.names); const wireSet = new Set(wire.names); const added = uniq(wire.names).filter((n) => !composedSet.has(n)); const dropped = uniq(composed.names).filter((n) => !wireSet.has(n)); if (added.length === 0 && dropped.length === 0) return []; const findings = []; const fileDirection = (names, onWireValue, message) => { if (names.length === 0) return; const subjects = names.map((id) => ({ kind: 'tool', id })); const witnesses = names.flatMap((name) => { const subject = { kind: 'tool', id: name }; return [ { subject, predicate: 'on-wire', value: onWireValue === 'present' ? 'absent' : 'present', epoch, stratum: 'asserted', provenance: `${composed.provenance}: composed frame`, }, { subject, predicate: 'on-wire', value: onWireValue, epoch, stratum: 'asserted', provenance: `${wire.provenance}: serialized body`, }, ]; }); // Run the algebra rather than asserting the conflict directly — the // fences (quotation, unknowns, epochs) apply for free, and one // comparison owns the definition of "contradict". if ((0, conflicts_js_1.conflictsOf)(witnesses).length === 0) return; findings.push({ kind: 'invariant-violation', seam: 'wire', subjects, witnesses, epoch, message, }); }; fileDirection(added, 'present', `${String(added.length)} tool(s) crossed the wire that the composed frame never carried ` + `(${added.join(', ')}). The adapter's serialized body and the frame it was built from ` + `disagree — the model was shown capabilities the composition had removed or never held. ` + `Nothing here resolves which side is right, and the call was already made.`); fileDirection(dropped, 'absent', `${String(dropped.length)} composed tool(s) never crossed the wire ` + `(${dropped.join(', ')}). The frame promised the model capabilities the serialized body ` + `dropped — a call the model makes against them cannot land. Nothing here resolves which ` + `side is right, and the call was already made.`); return findings; } exports.wireViolationsOf = wireViolationsOf; //# sourceMappingURL=wire.js.map