agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
94 lines • 3.61 kB
JavaScript
import { measureArtifactBytes } from './payload.js';
import { DETAIL_LIMITS, detailTokens } from './detailRequest.js';
import { invalidDetail, unavailableDetail } from './detailError.js';
const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
const container = (value) => object(value) || Array.isArray(value);
// The payload owner counts bare strings as text; a one-element JSON array also counts quotes.
const jsonBytes = (value) => measureArtifactBytes([value]) - 2;
const kind = (value) => value === null
? 'null'
: Array.isArray(value)
? 'array'
: typeof value;
function select(root, path) {
let value = root;
for (const key of detailTokens(path)) {
if (Array.isArray(value) && !/^(0|[1-9]\d*)$/.test(key))
return invalidDetail();
if (!container(value) || !Object.hasOwn(value, key))
return unavailableDetail();
value = Array.isArray(value) ? value[Number(key)] : value[key];
}
return value;
}
function childPath(parent, key) {
return `${parent}/${key.replace(/~/g, '~0').replace(/\//g, '~1')}`;
}
function bounded(value) {
if (jsonBytes(value) > DETAIL_LIMITS.outputBytes)
return unavailableDetail();
return value;
}
/** Navigate only detached ordinary JSON; this function reads no store and authorizes no claim. */
export function projectArtifactDetail(root, args, tool, context) {
const value = select(root, args.path);
const base = {
ref: args.ref,
path: args.path,
kind: kind(value),
...(context === undefined ? {} : { context }),
};
const keys = container(value) ? Object.keys(value) : [];
const inline = { ...base, mode: 'value', value, complete: true };
if (args.offset === 0 &&
keys.length <= args.limit &&
jsonBytes(value) <= DETAIL_LIMITS.valueBytes &&
jsonBytes(inline) <= DETAIL_LIMITS.outputBytes)
return inline;
if (!container(value)) {
if (args.offset !== 0)
return invalidDetail();
return bounded({
...base,
mode: 'scalar-omitted',
omitted: true,
scalarBytes: jsonBytes(value),
complete: false,
reason: 'Selected scalar exceeds the bounded view; no partial value was returned.',
});
}
if (args.offset > keys.length)
return invalidDetail();
const children = [];
const response = () => ({
...base,
mode: 'children',
children,
offset: args.offset,
shown: children.length,
total: keys.length,
complete: args.offset + children.length === keys.length,
...(args.offset + children.length < keys.length
? { nextOffset: args.offset + children.length }
: {}),
});
for (const key of keys.slice(args.offset, args.offset + args.limit)) {
const path = childPath(args.path, key);
detailTokens(path);
const child = Array.isArray(value) ? value[Number(key)] : value[key];
children.push({
path,
type: kind(child),
...(container(child) ? { count: Object.keys(child).length } : {}),
action: { tool, args: { ref: args.ref, path } },
});
if (jsonBytes(response()) > DETAIL_LIMITS.outputBytes - DETAIL_LIMITS.reserveBytes) {
children.pop();
break;
}
}
if (!children.length && args.offset < keys.length)
return unavailableDetail();
return bounded(response());
}
//# sourceMappingURL=detailView.js.map