agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
156 lines • 7.39 kB
JavaScript
;
/**
* subflowRecords — where a subflow mount's OWN log is, read through the
* library's door.
*
* Pattern: pure lookups over `RuntimeSnapshot.subflowResults`.
* Role: what `inspect_subflow` opens, and what every outer tool asks when
* it is handed an id it does not know. Nothing here formats an
* answer beyond the absence reasons, which belong to the record.
*
* WHY THE MAP, AND WHY `getSubtreeSnapshot`. A subflow runs in an isolated
* runtime and commits to its own log; the run's `commitLog` holds only the
* mount boundary (seed in, merge-back out). footprintjs keeps each mount's log
* in `subflowResults`, DUAL-KEYED — the subflow path (latest iteration) and
* each mount's `runtimeStageId` (`sf-tools#11`) — and nested mounts are
* merged UP into the same flat map (`sf-a/sf-b#7`). `getSubtreeSnapshot` is
* the library's public door to one entry (history, fold base, tree, state);
* this module only decides WHICH entry, and says why when there is none.
*
* Mounts are addressed by `runtimeStageId`, never by path: a mount inside a
* loop runs several times, and the path key names only the last one.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.openSubflow = exports.innerCommitCount = exports.opensWithSeed = exports.subflowWrote = exports.mountChain = exports.homeMountOf = exports.subflowResultsOf = void 0;
const footprintjs_1 = require("footprintjs");
/** The subflow results map, when the snapshot carries one as a map. */
function subflowResultsOf(snapshot) {
const results = snapshot.subflowResults;
return results !== null && typeof results === 'object' && !Array.isArray(results)
? results
: undefined;
}
exports.subflowResultsOf = subflowResultsOf;
/** The inner history of one entry, when it carries one. */
function historyOf(entry) {
const tree = entry?.treeContext;
return Array.isArray(tree?.history)
? tree.history
: undefined;
}
/**
* The mount whose OWN log holds step `id` — the one level directly above it.
*
* Only per-mount keys (`…#n`) are asked: a path key is an alias of its last
* iteration, and asking it would name the wrong iteration. The mount's own id
* is excluded — a subflow's log opens with its mount's seed commit, so every
* mount id is ALSO in the log one level down.
*/
function homeMountOf(results, id) {
for (const [key, entry] of Object.entries(results)) {
if (key === id || !key.includes('#'))
continue;
if (historyOf(entry)?.some((bundle) => bundle.runtimeStageId === id))
return key;
}
return undefined;
}
exports.homeMountOf = homeMountOf;
/**
* The chain of mounts from the outer run down to `mount` — outermost first,
* `mount` last — so a nested subflow is opened one level at a time. Undefined
* when no chain reaches a step of the outer run (`isOuterStep`).
*/
function mountChain(results, mount, isOuterStep) {
const chain = [mount];
// Depth is bounded by the map itself: each hop names a different key.
for (let hops = 0; hops <= Object.keys(results).length; hops++) {
const top = chain[0];
if (isOuterStep(top))
return chain;
const parent = homeMountOf(results, top);
if (parent === undefined || chain.includes(parent))
return undefined;
chain.unshift(parent);
}
return undefined;
}
exports.mountChain = mountChain;
/** Did this mount's own log write `path` (engine path form)? */
function subflowWrote(entry, path) {
return (historyOf(entry)?.some((bundle) => (bundle.trace ?? []).some((row) => row.path === path)) ?? false);
}
exports.subflowWrote = subflowWrote;
/** Does `mount`'s own log open with the mount's seed commit (its own id first)? */
function opensWithSeed(results, mount) {
return historyOf(results?.[mount])?.[0]?.runtimeStageId === mount;
}
exports.opensWithSeed = opensWithSeed;
/** Commits in `mount`'s own log (the mount's seed included); 0 when it kept none. */
function innerCommitCount(results, mount) {
return historyOf(results?.[mount])?.length ?? 0;
}
exports.innerCommitCount = innerCommitCount;
/** Optional metadata is copied as captured data; accessors never stand in for evidence. */
function capturedField(source, key) {
if (source === null || typeof source !== 'object')
return undefined;
try {
const field = Object.getOwnPropertyDescriptor(source, key);
return field && 'value' in field ? field.value : undefined;
}
catch {
return undefined;
}
}
/**
* Open `mount`'s own record — or say, in the record's terms, why it cannot be.
*
* The inner snapshot is the subflow's own: its history as the commit log, its
* OWN fold base (`treeContext.initialState`, normally `{}` — the seed is a
* commit), its tree, and its served state (under `getSnapshot({ redact: true
* })` the nested mirror, so the redacted view stays redacted). It keeps the
* whole flat results map, so a mount nested inside it opens the same way.
*/
function openSubflow(snapshot, mount) {
const results = subflowResultsOf(snapshot);
if (results === undefined) {
return (`this snapshot carries no subflow results, so no subflow's own log is here — the record ` +
`was saved or served without them (a stripped recording or a trimmed view). What the run ` +
`holds of '${mount}' is its boundary in the run's own log: trace_node('${mount}').`);
}
if (!(mount in results)) {
return (`no subflow result was kept for mount '${mount}'. A mount gets one when its subflow ` +
`returns: a lazy mount that never ran, or a subflow that failed or paused before it ` +
`returned, leaves none — the record does not say which. Its boundary in the run's own ` +
`log is all there is: trace_node('${mount}').`);
}
if (historyOf(results[mount]) === undefined) {
return (`the subflow result for mount '${mount}' carries no inner log — it was kept without its ` +
`history (a pause checkpoint keeps subflow results lean). Its boundary in the run's own ` +
`log is all there is: trace_node('${mount}').`);
}
const subtree = (0, footprintjs_1.getSubtreeSnapshot)(snapshot, mount);
const treeContext = capturedField(results[mount], 'treeContext');
const logAddress = capturedField(subtree, 'logAddress') ??
capturedField(treeContext, 'logAddress');
const runId = capturedField(subtree, 'runId') ??
capturedField(snapshot, 'runId');
const writeProvenance = capturedField(subtree, 'writeProvenance') ??
capturedField(snapshot, 'writeProvenance');
const history = (subtree?.history ?? []);
return {
commitLog: history,
executionTree: subtree?.executionTree,
sharedState: subtree?.sharedState ?? {},
initialState: subtree?.initialState,
subflowResults: results,
// A dial propagates into every subflow, so the encoding is the run's.
commitValues: snapshot.commitValues,
...(runId !== undefined && { runId }),
...(logAddress !== undefined && { logAddress }),
...(writeProvenance !== undefined && { writeProvenance }),
};
}
exports.openSubflow = openSubflow;
//# sourceMappingURL=subflowRecords.js.map