agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
65 lines • 4.44 kB
JavaScript
import { attentionList, explain } from 'foottrace/cause';
import { snapshotCauseArtifacts } from './causeSnapshot.js';
import { causeGap, causeResponse } from './causeResponse.js';
import { causeContextAssessment } from './causeContext.js';
/** One public query, one cache/deadline/total ceiling. No model, rerun, storage URL or second walker. */
export async function readCause(operation, context, question, limits, deadline, signal) {
const assessed = causeContextAssessment(context);
if (assessed.kind === 'invalid')
return causeGap(operation, 'invalid-data');
const snapshotOnly = context.kind === 'snapshot' && context.artifacts.cause === undefined ? true : undefined;
const storedCapture = assessed.kind === 'stored' ? assessed.capture : undefined;
const storage = assessed.kind === 'stored' ? assessed.admission.storage : undefined;
if (signal?.aborted)
return causeGap(operation, 'cancelled', storedCapture ?? snapshotOnly, storage, limits.maxChars);
if (performance.now() >= deadline)
return causeGap(operation, 'timeout', storedCapture ?? snapshotOnly, storage, limits.maxChars);
const projection = context.kind === 'snapshot' && context.artifacts.cause === undefined
? snapshotCauseArtifacts(context.artifacts, context.nodes)
: undefined;
const source = context.kind === 'graph' ? context.cause : context.artifacts.cause ?? projection;
if (source === 'truncated')
return causeGap(operation, 'truncated', snapshotOnly);
if (source === undefined)
return causeGap(operation, 'not-collected', snapshotOnly);
const capture = storedCapture ?? (projection && projection !== 'truncated' ? projection.capture : undefined);
const remaining = Math.floor(deadline - performance.now());
if (signal?.aborted)
return causeGap(operation, 'cancelled', capture, storage, limits.maxChars);
if (remaining < 1)
return causeGap(operation, 'timeout', capture, storage, limits.maxChars);
const { maxChars, backward, impact, maxNodes, maxDepth, maxEdges, maxCalls } = limits;
const options = { maxNodes, maxDepth, maxEdges, maxCalls, timeoutMs: remaining, signal };
if (operation === 'attention_list') {
const result = await attentionList(source.graph, {
...options,
nodeIds: question.nodeIds ?? source.nodeIds,
});
// An empty legacy log has no node on which the reader could discover its missing capture.
const finding = capture?.status === 'incomplete' && !result.gaps.some((gap) => gap.code === 'not-collected')
? {
...result,
confidence: 'incomplete',
gaps: [...result.gaps, { code: 'not-collected', evidence: [] }],
}
: result;
return causeResponse(operation, finding, finding.confidence === 'incomplete'
? 'Not sure, because coverage is incomplete. An absent mark is not proof of a healthy or reached step.'
: 'Recorded attention within this query only. Cite the returned node and evidence IDs.', maxChars, capture, storage);
}
// Each invocation projects one bounded query. Separate root/impact calls do not share a result yet.
if (question.nodeId === undefined)
return causeGap(operation, 'invalid-data', capture, storage, limits.maxChars);
const finding = await explain(source.graph, question.nodeId, { ...options, backward, impact });
if (operation === 'impact') {
return causeResponse(operation, finding.impact, finding.impact.confidence === 'incomplete'
? 'Not sure of the full impact, because the returned gaps limit the recorded forward slice.'
: 'Recorded reachable impact only; this does not prove effects in unrecorded services or unreached branches.', maxChars, capture, storage);
}
return causeResponse(operation, finding, finding.rootCause !== undefined
? 'A unique recorded dependency root is supported. Cite its node ID and path; this is not proof of a provider-internal physical cause.'
: finding.confidence === 'incomplete'
? 'Not sure, because the returned gaps prevent a unique supported root. Alternatives are not confirmed causes.'
: 'No unique marked root in the checked graph. Cite alternatives without selecting one as fact.', maxChars, capture, storage);
}
//# sourceMappingURL=causeReader.js.map