agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
276 lines • 12.4 kB
JavaScript
"use strict";
/**
* Row "It found" — what each call of this run returned, as the MODEL read it,
* then the earlier answers' results that were in front of the model.
*
* Branches on the call's outcome first: a call that did not run "found nothing"
* because it did not run; a withheld result is never judged empty (the model
* read the rule's refusal, not the rows). Emptiness is typed only, read by the
* one emptiness reader (`core/agent/emptiness.ts` · `readEmptiness`):
* a declared absence (or an empty rowset inside a declared boundary), a
* described result's data counted per kind, a question handed back, a
* zero-length top-level array, or the app's declared `rowsAt` (then the line
* is vouched `app`, because only the app's declaration makes it "empty").
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.readFoundRow = exports.beforePausePointers = exports.inViewPointers = exports.inViewVars = void 0;
const render_js_1 = require("../render.js");
const common_js_1 = require("./common.js");
const view_js_1 = require("../view.js");
const calls_js_1 = require("./calls.js");
const checked_js_1 = require("./checked.js");
const toolOf = (call) => call.tool;
/** The declaration pointer behind an app-counted emptiness. */
function rowsAtPointers(ctx, toolName, source) {
return source === 'app' ? [(0, common_js_1.declarationAt)(ctx.declarations, `tools.${toolName}.rowsAt`)] : [];
}
function foundForCall(ctx, call) {
if (call.unnamed) {
return ctx.say('found.unnamed', {
vars: { id: call.tool },
status: 'not-recorded',
missing: 'unreadable',
pointers: call.fact.pointers,
});
}
const tool = toolOf(call);
const end = call.end;
const endPointers = end ? [(0, calls_js_1.endPointer)(end, call.emptiness)] : [];
switch (call.fact.outcome) {
case 'failed':
return ctx.say('found.failed', { vars: { tool }, pointers: endPointers });
case 'refused':
return ctx.say('found.refused', { vars: { tool }, pointers: endPointers });
case 'declined':
return ctx.say('found.declined', { vars: { tool }, pointers: endPointers });
case 'not-dispatched':
return ctx.say('found.notDispatched', { vars: { tool }, pointers: endPointers });
case 'unknown':
return ctx.say('found.unknown', {
vars: { tool },
status: 'not-recorded',
missing: 'no-event',
pointers: endPointers,
});
case 'ran':
break;
}
if (call.fact.withheldBy !== undefined && call.ruleEvent !== undefined) {
return ctx.say('found.withheld', {
vars: { tool, by: (0, render_js_1.v)(call.fact.withheldBy, 'library', (0, common_js_1.at)(call.ruleEvent, 'middleware')) },
pointers: [(0, common_js_1.at)(call.ruleEvent, 'moment'), (0, common_js_1.at)(call.ruleEvent, 'outcome')],
});
}
const reading = call.emptiness;
const basis = [(0, common_js_1.emptinessSource)(reading)];
const extra = rowsAtPointers(ctx, call.toolName, reading.source);
switch (reading.emptiness) {
case 'declared-absent': {
const lookedFor = call.coverage?.lookedFor;
return lookedFor !== undefined
? ctx.say('found.absent', {
vars: {
tool,
lookedFor: (0, render_js_1.v)(lookedFor.text, `tool:${call.fact.toolName}`, lookedFor.pointer),
},
pointers: endPointers,
})
: ctx.say('found.bare', { vars: { tool }, pointers: endPointers });
}
case 'undeclared-empty':
return ctx.say('found.undeclaredEmpty', {
vars: { tool },
basis,
pointers: [...endPointers, ...extra],
chips: [(0, render_js_1.chip)('undeclared-empty', 'chip.undeclaredEmpty', 'warn')],
});
case 'non-empty':
if (reading.described !== undefined && call.described !== undefined) {
return describedLines(ctx, call, reading.described);
}
return ctx.say('found.rows', {
vars: { tool, n: (0, render_js_1.n)(reading.rows ?? 0, (0, common_js_1.emptinessSource)(reading)) },
pointers: [...endPointers, ...extra],
});
case 'clarify':
return ctx.say('found.clarify', {
vars: { tool },
pointers: call.described ? [(0, common_js_1.at)(call.described, 'toolCallId')] : endPointers,
});
case 'unknown':
return ctx.say('found.result', { vars: { tool }, pointers: endPointers });
}
}
const DESCRIBED_LINES = {
facts: 'found.described.facts',
series: 'found.described.series',
edges: 'found.described.edges',
};
/**
* A described result: one line per kind of data, counted by the library from
* the envelope the record keeps (the `tools.semantics_declared` row — the model
* read its projection), then the tool's own source and time when it declared
* both.
*/
function describedLines(ctx, call, counts) {
const event = call.described;
const lines = [];
for (const kind of ['facts', 'series', 'edges']) {
const count = counts[kind];
if (count === undefined)
continue;
lines.push(ctx.say(DESCRIBED_LINES[kind], {
vars: { tool: toolOf(call), n: (0, render_js_1.n)(count) },
pointers: [(0, common_js_1.at)(event, 'toolCallId')],
}));
}
const semantics = event.payload.semantics;
const provenance = (0, view_js_1.isRecord)(semantics) ? semantics.provenance : undefined;
const source = (0, view_js_1.isRecord)(provenance) ? (0, view_js_1.str)(provenance.source) : undefined;
const measuredAt = (0, view_js_1.isRecord)(provenance) ? (0, view_js_1.str)(provenance.measured_at) : undefined;
if (source !== undefined && measuredAt !== undefined) {
const by = `tool:${call.fact.toolName}`;
lines.push(ctx.say('found.described.provenance', {
vars: {
tool: toolOf(call),
source: (0, render_js_1.v)(source, by, (0, common_js_1.at)(event, 'semantics', 'provenance', 'source')),
measuredAt: (0, render_js_1.v)(measuredAt, by, (0, common_js_1.at)(event, 'semantics', 'provenance', 'measured_at')),
},
}));
}
return lines;
}
/** The vars every in-view line shares. */
function inViewVars(read) {
return {
tool: read.tool,
distance: (0, render_js_1.n)(read.fact.distance),
distanceWindowed: (0, render_js_1.n)(read.fact.windowed ? 1 : 0),
};
}
exports.inViewVars = inViewVars;
/** Pointers behind an in-view line: the witness, the history row, the derived emptiness. */
function inViewPointers(ctx, read) {
return [
(0, common_js_1.at)(read.witness, 'sourceId'),
...(read.reading.emptiness === 'unknown'
? []
: [(0, common_js_1.historyAt)(read.historyIndex, '#emptiness', read.fact.toolCallId)]),
...rowsAtPointers(ctx, read.toolName, read.reading.source),
];
}
exports.inViewPointers = inViewPointers;
function inViewLine(ctx, read) {
const vars = inViewVars(read);
const pointers = inViewPointers(ctx, read);
switch (read.reading.emptiness) {
case 'undeclared-empty':
return ctx.say('found.inView.undeclaredEmpty', {
vars,
basis: [(0, common_js_1.emptinessSource)(read.reading)],
pointers,
chips: [(0, render_js_1.chip)('undeclared-empty', 'chip.undeclaredEmpty', 'warn')],
});
case 'declared-absent':
return ctx.say('found.inView.absent', { vars, pointers });
default:
return ctx.say('found.inView', { vars, pointers });
}
}
/** Pointers behind a line about what came back from a call before the pause. */
function beforePausePointers(call) {
return [
(0, common_js_1.historyAt)(call.historyIndex, '/toolName', call.toolCallId),
...(call.reading.emptiness === 'unknown'
? []
: [(0, common_js_1.historyAt)(call.historyIndex, '#emptiness', call.toolCallId)]),
];
}
exports.beforePausePointers = beforePausePointers;
/**
* What came back from a call answered BEFORE the pause, as the model read it —
* the tool's own bytes in the committed history, with the door its
* `coverageDeclared` rows hold (`pausedLeg.ts`). Never "it ran": a rule's
* verdict on it is in that part's events.
*/
function foundBeforePause(ctx, call) {
const tool = call.tool;
const reading = call.reading;
const pointers = [
...beforePausePointers(call),
...rowsAtPointers(ctx, call.toolName, reading.source),
];
const chips = [(0, checked_js_1.heldChip)()];
switch (reading.emptiness) {
case 'declared-absent': {
const lookedFor = call.coverage?.lookedFor;
return lookedFor !== undefined
? ctx.say('found.beforePause.absent', {
vars: {
tool,
lookedFor: (0, render_js_1.v)(lookedFor.text, `tool:${call.toolName.slice(0, common_js_1.FACT_TEXT_CHARS)}`, lookedFor.pointer),
},
pointers,
chips,
})
: ctx.say('found.beforePause.bare', { vars: { tool }, pointers, chips });
}
case 'undeclared-empty':
return ctx.say('found.beforePause.undeclaredEmpty', {
vars: { tool },
basis: [(0, common_js_1.emptinessSource)(reading)],
pointers,
chips: [(0, render_js_1.chip)('undeclared-empty', 'chip.undeclaredEmpty', 'warn'), ...chips],
});
case 'non-empty':
if (reading.rows !== undefined) {
return ctx.say('found.beforePause.rows', {
vars: { tool, n: (0, render_js_1.n)(reading.rows, (0, common_js_1.emptinessSource)(reading)) },
pointers,
chips,
});
}
return ctx.say('found.beforePause.result', { vars: { tool }, pointers, chips });
case 'clarify':
return ctx.say('found.beforePause.clarify', { vars: { tool }, pointers, chips });
case 'unknown':
return ctx.say('found.beforePause.result', { vars: { tool }, pointers, chips });
}
}
function readFoundRow(ctx, calls, inView, pausedLeg) {
const lines = calls.calls.slice(0, checked_js_1.MAX_LISTED_CALLS).flatMap((c) => foundForCall(ctx, c));
// The same "…and N more tool calls" the other call rows carry, right after the listed calls.
const more = (0, checked_js_1.foldMore)(ctx, calls);
if (more !== undefined)
lines.push(more);
if (ctx.resumedLeg && pausedLeg.stateHeld) {
const before = pausedLeg.calls;
lines.push(...before.slice(0, checked_js_1.MAX_LISTED_CALLS).map((c) => foundBeforePause(ctx, c)));
const moreBefore = (0, checked_js_1.beforePauseMore)(ctx, before);
if (moreBefore !== undefined)
lines.push(moreBefore);
if (before.length === 0)
lines.push((0, checked_js_1.noResultsBeforePause)(ctx));
}
else if (ctx.resumedLeg) {
// No paused state in this record: nothing of the part before the pause can be read.
lines.push(ctx.say('found.beforePause', {
status: 'not-recorded',
missing: 'before-pause',
chips: [(0, render_js_1.chip)('before-pause', 'chip.beforePause')],
}));
}
if (!ctx.resumedLeg && calls.all.length === 0) {
lines.push(ctx.say('found.noCalls', { pointers: (0, checked_js_1.anchorPointer)(ctx) }));
}
lines.push(...inView.listed.map((read) => inViewLine(ctx, read)));
if (inView.more > 0) {
lines.push(ctx.say('found.inView.more', {
vars: { n: (0, render_js_1.n)(inView.more) },
pointers: inView.all.slice(inView.listed.length).map((r) => (0, common_js_1.at)(r.witness, 'sourceId')),
}));
}
return lines;
}
exports.readFoundRow = readFoundRow;
//# sourceMappingURL=found.js.map