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 • 2.87 kB
JavaScript
/**
* detect — the prose grammar: which units of a reply state a negative claim, by a fixed list of
* phrases and nothing else (no model, no score).
*
* Pattern: units (`units.ts`) → language (`language.ts`) → the `none` and `complete` packs
* (`phrases.ts`, matched by `matcher.ts`). A hedge is not scope and changes nothing here:
* "based on the logs, there are no incidents" is a claim. A unit in a fenced block, or a
* claim phrase entirely inside inline code, is NOTED (`in-code-block`, with the
* phrase's span), not judged; a unit the English grammar cannot read is NOTED
* (`language-unsupported`) — never a silent pass.
* Role: integrity/ layer (L3), read by `prose.ts`. Pure and deterministic; linear in the text.
*
* A claim carries its span, its unit, its phrase id and the pack version. Its unit's tokens ride
* along for the resolver; rows built from a claim carry none of the text.
*/
import { isSupportedLanguage } from './language.js';
import { NEGATIVE_CLAIM_PHRASES, NEGATIVE_CLAIM_PHRASES_VERSION, } from './phrases.js';
import { insideAny, unitsOf } from './units.js';
import { firstHit, tokensOf } from './matcher.js';
const spanOf = (tokens, hit) => ({
start: tokens[hit.first].start,
end: tokens[hit.last].end,
});
/** Detect the negative claims of a reply. */
export function detectNegativeClaims(text, phrases) {
const claims = [];
const notes = [];
const { units, inlineCode } = unitsOf(text);
const packVersion = phrases?.version ?? NEGATIVE_CLAIM_PHRASES_VERSION;
const packs = phrases?.packs ?? NEGATIVE_CLAIM_PHRASES;
for (const unit of units) {
const tokens = tokensOf(text, unit.start, unit.end);
if (tokens.length === 0)
continue;
const readable = unit.fenced || isSupportedLanguage(text.slice(unit.start, unit.end), tokens);
if (!readable) {
notes.push({
code: 'language-unsupported',
span: { start: unit.start, end: unit.end },
packVersion,
});
continue;
}
for (const kind of ['none', 'complete']) {
const hit = firstHit(text, tokens, packs[kind]);
if (hit === undefined)
continue;
const span = spanOf(tokens, hit);
if (unit.fenced || insideAny(span, inlineCode)) {
notes.push({ code: 'in-code-block', span, phraseId: hit.phrase.id, packVersion });
continue;
}
claims.push({
kind,
phraseId: hit.phrase.id,
packVersion,
span,
unit: { start: unit.start, end: unit.end },
tokens,
});
}
}
return { claims, notes };
}
//# sourceMappingURL=detect.js.map