agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
159 lines • 8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.queriedPeriodMatches = exports.scopesMatch = exports.executedScope = exports.scopeDeclarationOf = exports.ownConfigArray = exports.boundedResultId = exports.boundedText = exports.BINDING_LIMITS = void 0;
/** Authored scope projection over the arguments actually delivered to execute. */
const boundedJson_js_1 = require("../../lib/boundedJson.js");
const canonicalJson_js_1 = require("../../lib/canonicalJson.js");
const instant_js_1 = require("../../time/instant.js");
const period_js_1 = require("../../semantics/coverage/period.js");
exports.BINDING_LIMITS = Object.freeze({
text: 512,
resultIdText: 3104,
dimensions: 16,
path: 16,
scopeBytes: 8192,
resultBytes: 256 * 1024,
snapshotBytes: 1024 * 1024,
results: 256,
});
function boundedText(value) {
return typeof value === 'string' && value.trim() !== '' && value.length <= exports.BINDING_LIMITS.text;
}
exports.boundedText = boundedText;
function boundedResultId(value) {
return (typeof value === 'string' &&
value.startsWith('claim-result/') &&
value.length <= exports.BINDING_LIMITS.resultIdText);
}
exports.boundedResultId = boundedResultId;
/** Shallow descriptor-only admission for authored arrays containing callbacks. */
function ownConfigArray(value, maximum) {
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype)
throw new Error('Expected a plain configuration array.');
const length = Object.getOwnPropertyDescriptor(value, 'length')?.value;
if (typeof length !== 'number' ||
!Number.isSafeInteger(length) ||
length > maximum ||
Reflect.ownKeys(value).length !== length + 1)
throw new Error('Invalid configuration array.');
const items = [];
for (let index = 0; index < length; index++) {
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
if (!descriptor?.enumerable || !('value' in descriptor))
throw new Error('Expected dense configuration data.');
items.push(descriptor.value);
}
return Object.freeze(items);
}
exports.ownConfigArray = ownConfigArray;
/** Inspect authored configuration without evaluating getters or inherited fields. */
function scopeDeclarationOf(raw) {
const source = (0, boundedJson_js_1.ownData)(raw, ['id', 'version', 'dimensions', 'periodDimension']);
const sourceDimensions = ownConfigArray(source.dimensions, exports.BINDING_LIMITS.dimensions);
if (!boundedText(source.id) || !boundedText(source.version) || sourceDimensions.length === 0)
throw new Error('Invalid scope declaration.');
const names = new Set();
const dimensions = sourceDimensions.map((rawDimension) => {
const dimension = (0, boundedJson_js_1.ownData)(rawDimension, ['name', 'argumentPath', 'default', 'normalize']);
const path = (0, boundedJson_js_1.copyJson)(dimension.argumentPath, exports.BINDING_LIMITS.scopeBytes, true);
if (!boundedText(dimension.name) ||
names.has(dimension.name) ||
!Array.isArray(path) ||
path.length === 0 ||
path.length > exports.BINDING_LIMITS.path ||
!path.every(boundedText) ||
(Object.hasOwn(dimension, 'normalize') && typeof dimension.normalize !== 'function'))
throw new Error('Invalid scope dimension.');
names.add(dimension.name);
return Object.freeze({
name: dimension.name,
argumentPath: path,
...(Object.hasOwn(dimension, 'default') && {
default: (0, boundedJson_js_1.copyJson)(dimension.default, exports.BINDING_LIMITS.scopeBytes, true),
}),
...(typeof dimension.normalize === 'function' && {
normalize: dimension.normalize,
}),
});
});
if (Object.hasOwn(source, 'periodDimension') &&
(!boundedText(source.periodDimension) || !names.has(source.periodDimension)))
throw new Error('Invalid period dimension.');
return Object.freeze({
id: source.id,
version: source.version,
dimensions: Object.freeze(dimensions),
...(typeof source.periodDimension === 'string' && { periodDimension: source.periodDimension }),
});
}
exports.scopeDeclarationOf = scopeDeclarationOf;
/** Own data properties only: inherited names and accessors supply no scope. */
function argumentAt(args, path) {
if (path.length === 0 || path.length > exports.BINDING_LIMITS.path || !path.every(boundedText))
throw new Error('Invalid scope path.');
let cursor = args;
for (const key of path) {
if (cursor === null || typeof cursor !== 'object')
return undefined;
const descriptor = Object.getOwnPropertyDescriptor(cursor, key);
if (descriptor === undefined) {
if (key in cursor)
throw new Error('Inherited scope is not executed own-data.');
return undefined;
}
if (!descriptor.enumerable || !('value' in descriptor))
throw new Error('Scope requires own data.');
cursor = descriptor.value;
}
return cursor;
}
function executedScope(args, declaration) {
declaration = scopeDeclarationOf(declaration);
const scope = {};
for (const dimension of declaration.dimensions) {
if (!boundedText(dimension.name) || Object.hasOwn(scope, dimension.name))
throw new Error('Invalid scope dimension.');
let value = argumentAt(args, dimension.argumentPath);
if (value === undefined && Object.hasOwn(dimension, 'default'))
value = dimension.default;
if (value === undefined)
throw new Error('Required scope is missing.');
// Detach BEFORE invoking an authored normalizer: it cannot mutate dispatch.
value = (0, boundedJson_js_1.copyJson)(value, exports.BINDING_LIMITS.scopeBytes, true);
if (dimension.normalize !== undefined)
value = dimension.normalize(value);
Object.defineProperty(scope, dimension.name, {
value: (0, boundedJson_js_1.copyJson)(value, exports.BINDING_LIMITS.scopeBytes, true),
enumerable: true,
});
}
if (declaration.periodDimension !== undefined &&
!Object.hasOwn(scope, declaration.periodDimension))
throw new Error('The period dimension is missing.');
return (0, boundedJson_js_1.copyJson)(scope, exports.BINDING_LIMITS.scopeBytes, true);
}
exports.executedScope = executedScope;
/** Exact declared dimensions; no inferred subset, defaults or currency conversion. */
function scopesMatch(evidence, intended) {
const expected = (0, boundedJson_js_1.ownData)((0, boundedJson_js_1.copyJson)(intended, exports.BINDING_LIMITS.scopeBytes, true));
return (0, canonicalJson_js_1.canonicalJson)(evidence) === (0, canonicalJson_js_1.canonicalJson)(expected);
}
exports.scopesMatch = scopesMatch;
/** The existing period/instant owners decide validity and temporal equivalence. */
function queriedPeriodMatches(scopeValue, period) {
const query = (0, boundedJson_js_1.ownData)(scopeValue, ['from', 'to']);
if ((0, period_js_1.periodProblem)({ queried: query, held: 'unknown' }, 'camel') !== undefined)
return false;
const from = (0, instant_js_1.instantOf)(query.from, 'lenient');
const to = (0, instant_js_1.instantOf)(query.to, 'lenient');
const actualFrom = (0, instant_js_1.instantOf)(period.queried.from, 'lenient');
const actualTo = (0, instant_js_1.instantOf)(period.queried.to, 'lenient');
return (from !== undefined &&
to !== undefined &&
actualFrom !== undefined &&
actualTo !== undefined &&
(0, instant_js_1.compareInstants)(from, actualFrom) === 0 &&
(0, instant_js_1.compareInstants)(to, actualTo) === 0);
}
exports.queriedPeriodMatches = queriedPeriodMatches;
//# sourceMappingURL=scope.js.map