UNPKG

agentfootprint

Version:

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

115 lines • 5.5 kB
/** * Compile the explicit verifier's authored rules and retention permission. * Role: closure-only configuration; callbacks never enter recorded state. */ import { bindingRuleOf } from '../../../integrity/claim-binding/admit.js'; import { resultIdentityOf } from '../../../integrity/claim-binding/capture.js'; import { BINDING_LIMITS, boundedText, ownConfigArray, } from '../../../integrity/claim-binding/scope.js'; import { copyJson, ownData } from '../../../lib/boundedJson.js'; import { canonicalJson } from '../../../lib/canonicalJson.js'; import { readSemantics } from '../../../semantics/envelope.js'; const WITHHELD = Object.freeze({ resultVisible: false, scopeVisible: false, }); const GRANTED = Object.freeze({ resultVisible: true, scopeVisible: true }); function sameScope(left, right) { // Functions are author-owned identities, not JSON or a stringified source. if (left.dimensions.length !== right.dimensions.length || left.dimensions.some((dimension, index) => dimension.normalize !== right.dimensions[index].normalize)) return false; const data = (scope) => ({ ...scope, dimensions: scope.dimensions.map((dimension) => ({ ...dimension, normalize: undefined })), }); return canonicalJson(data(left)) === canonicalJson(data(right)); } /** Only the existing detached capture ports can enter the author's callback. */ function authorizationInputOf(raw) { const source = ownData(raw, ['dispatch', 'returned', 'served']); const dispatch = ownData(copyJson(source.dispatch, BINDING_LIMITS.scopeBytes * 2, true), [ 'identity', 'id', 'toolName', 'toolCallId', 'iteration', 'scopeDeclaration', 'scope', 'periodDimension', 'unavailable', ]); const identity = ownData(dispatch.identity, ['namespace', 'runId', 'ordinal']); const declaration = ownData(dispatch.scopeDeclaration, ['id', 'version']); const returned = ownData(copyJson(source.returned, BINDING_LIMITS.resultBytes + BINDING_LIMITS.scopeBytes, true), ['resultId', 'semantics', 'unavailable']); if (dispatch.unavailable !== undefined || returned.unavailable !== undefined || !boundedText(identity.namespace) || !boundedText(identity.runId) || typeof identity.ordinal !== 'number' || dispatch.id !== resultIdentityOf({ namespace: identity.namespace, runId: identity.runId, ordinal: identity.ordinal, }) || returned.resultId !== dispatch.id || !boundedText(dispatch.toolName) || !boundedText(dispatch.toolCallId) || typeof dispatch.iteration !== 'number' || !Number.isSafeInteger(dispatch.iteration) || dispatch.iteration < 0 || !boundedText(declaration.id) || !boundedText(declaration.version) || (Object.hasOwn(dispatch, 'periodDimension') && !boundedText(dispatch.periodDimension)) || readSemantics(returned.semantics) === undefined) throw new Error('Invalid verification authorization input.'); ownData(copyJson(dispatch.scope, BINDING_LIMITS.scopeBytes, true)); return Object.freeze({ dispatch: Object.freeze(dispatch), returned: Object.freeze(returned), served: copyJson(source.served, BINDING_LIMITS.resultBytes, true), }); } /** Strict configuration admission runs once, not at every verification. */ export function compileVerificationConfig(raw) { const source = ownData(raw, ['rules', 'authorizeEvidence']); const rules = ownConfigArray(source.rules, BINDING_LIMITS.results).map(bindingRuleOf); if (rules.length === 0 || typeof source.authorizeEvidence !== 'function') throw new Error('findings.verify requires rules and an explicit authorizeEvidence callback.'); const authorize = source.authorizeEvidence; const ids = new Set(); const scopes = new Map(); for (const rule of rules) { if (ids.has(rule.id)) throw new Error('Duplicate findings verification rule.'); ids.add(rule.id); const prior = scopes.get(rule.toolName); if (prior !== undefined && !sameScope(prior, rule.scopeDeclaration)) throw new Error('Conflicting findings verification scopes for one tool.'); scopes.set(rule.toolName, rule.scopeDeclaration); } return Object.freeze({ rules: Object.freeze(rules), scopeForTool: (toolName) => scopes.get(toolName), authorizeEvidence: (input) => { try { const response = authorize(authorizationInputOf(input)); // A mistaken async callback cannot grant access. Consume rejection of // a genuine Promise without awaiting it or invoking an arbitrary then. if (response instanceof Promise) { void Promise.prototype.then.call(response, undefined, () => undefined); return WITHHELD; } const decision = ownData(response, ['resultVisible', 'scopeVisible']); return decision.resultVisible === true && decision.scopeVisible === true ? GRANTED : WITHHELD; } catch { // Never record policy exception text, return values or private inputs. return WITHHELD; } }, }); } //# sourceMappingURL=verificationConfig.js.map