agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
114 lines • 4.15 kB
JavaScript
/**
* @internal — not part of the public agentfootprint API. Imported only
* by RunStepRecorder. Subject to change without notice.
*
* RootInferrer — small state machine deciding whether a run's root is
* a single leaf primitive (Agent / LLMCall) or a composition (Sequence
* / Parallel / Conditional / Loop).
*
* Extracted from RunStepRecorder per Convention 1.
*
* Inputs: subflow entries (with their depth + parsed primitiveKind),
* fork events (depth 0 → Parallel root), decision events (depth 0 →
* Conditional root), loop events (depth 0 → Loop root).
*
* Output: query `kind()` for the inferred root. Returns `undefined`
* until a signal arrives.
*
* Inference rules:
* - Decisive composition signals (fork / decide / loop AT DEPTH 0)
* lock the root and are never overridden.
* - Shallowest primitive boundary IS a composition kind → root is
* that composition.
* - Two+ leaf siblings at the shallowest depth → implicit Sequence
* root (Sequence-as-runner case where the Sequence itself doesn't
* fire its own subflow.entry).
* - Single leaf at the shallowest depth → root is "leaf".
*/
const KNOWN_PRIMITIVES = new Set([
'Agent',
'LLMCall',
'Sequence',
'Parallel',
'Conditional',
'Loop',
]);
const LEAF_PRIMITIVES = new Set(['Agent', 'LLMCall']);
export class RootInferrer {
inferred;
shallowestDepth = Number.POSITIVE_INFINITY;
shallowestSiblings = 0;
/** Currently-inferred root kind, or undefined if no signal yet. */
kind() {
return this.inferred;
}
/** True when the root is a single leaf primitive (or unknown,
* which should be treated as leaf for kind-filter purposes). */
isLeafRoot() {
return this.inferred === 'leaf' || this.inferred === undefined;
}
/** Observe a subflow entry. */
observeSubflowEntry(depth, primitiveKind) {
if (!primitiveKind || !KNOWN_PRIMITIVES.has(primitiveKind))
return;
if (depth < this.shallowestDepth) {
this.shallowestDepth = depth;
this.shallowestSiblings = 1;
this.tryInfer(primitiveKind);
}
else if (depth === this.shallowestDepth) {
this.shallowestSiblings++;
this.tryInfer(undefined);
}
}
/** Observe a fork event. Locks root to Parallel if at depth 0 and
* no decisive root has been inferred yet. */
observeFork(depth) {
if (depth === 0 && this.inferred === undefined) {
this.inferred = 'parallel';
}
}
/** Observe a decision event. Locks root to Conditional if at depth 0
* and no decisive root has been inferred yet. */
observeDecision(depth) {
if (depth === 0 && this.inferred === undefined) {
this.inferred = 'conditional';
}
}
/** Observe a loop event. Locks root to Loop if at depth 0 and no
* decisive root has been inferred yet. */
observeLoop(depth) {
if (depth === 0 && this.inferred === undefined) {
this.inferred = 'loop';
}
}
clear() {
this.inferred = undefined;
this.shallowestDepth = Number.POSITIVE_INFINITY;
this.shallowestSiblings = 0;
}
tryInfer(primitiveKind) {
// Decisive signals lock the root.
if (this.inferred === 'parallel' ||
this.inferred === 'conditional' ||
this.inferred === 'loop') {
return;
}
// Shallowest IS a composition kind → root is that composition.
if (primitiveKind === 'Sequence' ||
primitiveKind === 'Parallel' ||
primitiveKind === 'Conditional' ||
primitiveKind === 'Loop') {
this.inferred = primitiveKind.toLowerCase();
return;
}
// 2+ leaf siblings at shallowest depth → Sequence-as-runner.
if (this.shallowestSiblings >= 2) {
this.inferred = 'sequence';
}
else if (primitiveKind && LEAF_PRIMITIVES.has(primitiveKind)) {
this.inferred = 'leaf';
}
}
}
//# sourceMappingURL=RootInferrer.js.map