agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
152 lines • 7.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.evidenceSnapshot = exports.finalizeEvidence = exports.captureReturnedEvidence = exports.captureDispatch = exports.readResultIdentity = exports.resultIdentityOf = void 0;
/**
* Internal dispatch/return/delivery receipt boundary, not mounted in the Agent.
* The eventual runtime adapter reserves a namespace/run/ordinal before await,
* captures at actual execute, then finalizes against the authorized served value.
*/
const encode_js_1 = require("../../memory/identity/encode.js");
const boundedJson_js_1 = require("../../lib/boundedJson.js");
const canonicalJson_js_1 = require("../../lib/canonicalJson.js");
const envelope_js_1 = require("../../semantics/envelope.js");
const ledger_js_1 = require("../unsupported-claim/ledger.js");
const scope_js_1 = require("./scope.js");
function resultIdentityOf(identity) {
if (!(0, scope_js_1.boundedText)(identity.namespace) ||
!(0, scope_js_1.boundedText)(identity.runId) ||
!Number.isSafeInteger(identity.ordinal) ||
identity.ordinal < 1)
throw new Error('Invalid runtime result identity.');
return `claim-result/${(0, encode_js_1.encodeIdentityField)(identity.namespace)}/${(0, encode_js_1.encodeIdentityField)(identity.runId)}/${identity.ordinal}`;
}
exports.resultIdentityOf = resultIdentityOf;
/** Decode only canonical runtime result occurrences; no lookup or authority is inferred. */
function readResultIdentity(raw) {
if (typeof raw !== 'string' || raw.length > scope_js_1.BINDING_LIMITS.resultIdText)
throw new TypeError('Invalid saved result identity.');
const parts = raw.split('/');
if (parts.length !== 4 || parts[0] !== 'claim-result')
throw new TypeError('Invalid saved result identity.');
const identity = Object.freeze({
namespace: (0, encode_js_1.decodePresentIdentityField)(parts[1]),
runId: (0, encode_js_1.decodePresentIdentityField)(parts[2]),
ordinal: Number(parts[3]),
});
if (resultIdentityOf(identity) !== raw)
throw new TypeError('Noncanonical saved result identity.');
return identity;
}
exports.readResultIdentity = readResultIdentity;
/** Capture selected scope now; a later mutation of args cannot change it. */
function captureDispatch(identity, tool, executedArgs, declaration) {
declaration = (0, scope_js_1.scopeDeclarationOf)(declaration);
const id = resultIdentityOf(identity);
if (!(0, scope_js_1.boundedText)(tool.toolName) ||
!(0, scope_js_1.boundedText)(tool.toolCallId) ||
!Number.isSafeInteger(tool.iteration) ||
tool.iteration < 0)
throw new Error('Invalid tool identity.');
const common = {
identity: { ...identity },
id,
toolName: tool.toolName,
toolCallId: tool.toolCallId,
iteration: tool.iteration,
scopeDeclaration: { id: declaration.id, version: declaration.version },
...(declaration.periodDimension !== undefined && {
periodDimension: declaration.periodDimension,
}),
};
try {
return (0, boundedJson_js_1.copyJson)({ ...common, scope: (0, scope_js_1.executedScope)(executedArgs, declaration) }, scope_js_1.BINDING_LIMITS.scopeBytes * 2, true);
}
catch {
return (0, boundedJson_js_1.copyJson)({ ...common, unavailable: 'missing-scope' }, scope_js_1.BINDING_LIMITS.scopeBytes * 2, true);
}
}
exports.captureDispatch = captureDispatch;
/** Preserve the returned reading before any async result rule can mutate it. */
function captureReturnedEvidence(dispatch, original) {
try {
const semantics = (0, envelope_js_1.readSemantics)((0, boundedJson_js_1.copyJson)(original, scope_js_1.BINDING_LIMITS.resultBytes, true));
if (semantics === undefined)
throw new Error('No recognized evidence.');
return Object.freeze({ resultId: dispatch.id, semantics });
}
catch {
return Object.freeze({ resultId: dispatch.id, unavailable: 'invalid-evidence' });
}
}
exports.captureReturnedEvidence = captureReturnedEvidence;
/**
* returned is the return-time copy from that invocation. served is
* the final model-facing payload AFTER all governance, placement and caps.
* Visibility is a trusted adapter decision; equality alone grants no access.
* Rewrites need a future explicit association, and are unavailable here.
*/
function finalizeEvidence(dispatch, returned, served, access) {
const unavailable = (reason) => (0, boundedJson_js_1.copyJson)({
identity: dispatch.identity,
id: dispatch.id,
toolName: dispatch.toolName,
toolCallId: dispatch.toolCallId,
iteration: dispatch.iteration,
scopeDeclaration: dispatch.scopeDeclaration,
unavailable: reason,
}, scope_js_1.BINDING_LIMITS.scopeBytes * 2, true);
if (dispatch.id !== resultIdentityOf(dispatch.identity))
return unavailable('invalid-evidence');
if (access.completed !== true)
return unavailable('incomplete-result');
if (access.resultVisible !== true || access.scopeVisible !== true)
return unavailable('withheld-evidence');
if (dispatch.unavailable !== undefined)
return unavailable(dispatch.unavailable);
if (returned.resultId !== dispatch.id)
return unavailable('unassociated-result');
if (returned.unavailable !== undefined)
return unavailable(returned.unavailable);
try {
const raw = (0, boundedJson_js_1.copyJson)(returned.semantics, scope_js_1.BINDING_LIMITS.resultBytes, true);
const semantics = (0, envelope_js_1.readSemantics)(raw);
if (semantics === undefined)
return unavailable('invalid-evidence');
const model = typeof served === 'string'
? JSON.parse(served.length <= scope_js_1.BINDING_LIMITS.resultBytes ? served : '')
: served;
const allowed = (0, boundedJson_js_1.copyJson)(model, scope_js_1.BINDING_LIMITS.resultBytes, true);
const projection = (0, boundedJson_js_1.copyJson)((0, envelope_js_1.semanticsForModel)(semantics), scope_js_1.BINDING_LIMITS.resultBytes, true);
if ((0, canonicalJson_js_1.canonicalJson)(allowed) !== (0, canonicalJson_js_1.canonicalJson)(projection))
return unavailable('unassociated-result');
const period = (0, envelope_js_1.periodOfSemantics)(semantics);
return (0, boundedJson_js_1.copyJson)({
...dispatch,
facts: (0, ledger_js_1.claimRowsOf)(semantics, {
toolName: dispatch.toolName,
toolCallId: dispatch.toolCallId,
iteration: dispatch.iteration,
}),
...((semantics.coverage !== undefined || period !== undefined) && {
coverage: (0, envelope_js_1.coverageOfSemantics)(semantics),
}),
...(period !== undefined && { period }),
}, scope_js_1.BINDING_LIMITS.resultBytes, true);
}
catch {
return unavailable('invalid-evidence');
}
}
exports.finalizeEvidence = finalizeEvidence;
/** Freeze the caller's completed evidence universe at the declaration moment. */
function evidenceSnapshot(namespace, verifiedRunIds, results) {
if (!(0, scope_js_1.boundedText)(namespace) ||
verifiedRunIds.length > scope_js_1.BINDING_LIMITS.results ||
!verifiedRunIds.every(scope_js_1.boundedText) ||
new Set(verifiedRunIds).size !== verifiedRunIds.length ||
results.length > scope_js_1.BINDING_LIMITS.results)
throw new Error('Invalid evidence snapshot boundary.');
return (0, boundedJson_js_1.copyJson)({ version: 1, namespace, runIds: verifiedRunIds, results }, scope_js_1.BINDING_LIMITS.snapshotBytes, true);
}
exports.evidenceSnapshot = evidenceSnapshot;
//# sourceMappingURL=capture.js.map