UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

133 lines • 5.98 kB
"use strict"; /** * assessment/witness — the answer layer's committed witness rows: two verdicts * the Route decider computes that were EVENTS only until the answer layer * (honesty layer 4) needed them on the record. * * Pattern: Map. Three row types, their builders and their well-formedness * check — the one owner of the `grounded`, `steps-unfinished` and * `script-shown` row kinds. * `findings/types.ts` · `FindingsRow` imports the types; the rows * are filed through the one writer (`findings/ledger.ts` · * `recordFindings`) by the Route decider, and ONLY while the answer * layer is armed (`stages/route.ts` · `judgeEvidence`, * `judgeUnfinishedSteps`). * Role: core/ layer leaf of the answer layer. Static on purpose: the * checkpoint door (`core/runCheckpoint.ts` · `validateCheckpoint`, * a synchronous door) asks `witnessRowIsWellFormed`, so this module * imports nothing but the script labels (`../scripts/label.ts`, a * leaf) and stays small. * Emits: N/A. A witness row emits nothing of its own — the verdict's event * (`agentfootprint.agent.evidence_checked`, * `agentfootprint.skill.steps_unfinished`) already fired, beside the * row, from the same stage. * * ## Why a row, when the event already says it * * The answer's standing is folded from COMMITTED rows only * (`assessment/assess.ts` · `assessAnswer`), never from events, so the running * agent and every later reader fold the same bytes. A verdict that exists only * as an event cannot be folded: the gate's clean pass could not say "the names * and numbers check ran", and an answer given before its declared steps * finished could not say so at all. Each row is the verdict, not a copy of the * event: names, enums and counts — never a value from the answer, a quote, or * a step's note. * * ## Always stamped with the turn * * The ledger crosses turns on a continued conversation and `iteration` * restarts at 1 every run, so a witness row always carries `turn` * (`AgentState.turnNumber`): the fold reads this turn's witness rows only. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.witnessRowIsWellFormed = exports.stepsUnfinishedRowFrom = exports.groundedRowFrom = exports.scriptShownRowsFrom = void 0; const match_js_1 = require("../scripts/match.js"); const POSTURES = Object.freeze(['assist', 'guard', 'rails']); /** The script match's verdicts as rows — one per block read, ids and labels only. */ function scriptShownRowsFrom(blocks, at) { return blocks.map((b) => b.label === 'unmatched' ? { kind: 'script-shown', turn: at.turn, iteration: at.iteration, block: b.block, label: 'unmatched', reason: b.reason, } : { kind: 'script-shown', turn: at.turn, iteration: at.iteration, block: b.block, label: b.label, toolCallId: b.toolCallId, tool: b.tool, dispatch: b.dispatch, ...(b.exitCode !== undefined && { exitCode: b.exitCode }), }); } exports.scriptShownRowsFrom = scriptShownRowsFrom; /** The gate's clean verdict as a row — built from the event's own counts. */ function groundedRowFrom(verdict) { return { kind: 'grounded', turn: verdict.turn, iteration: verdict.iteration, posture: verdict.posture, candidates: verdict.candidates, lookedUp: verdict.lookedUp, ...(verdict.afterRevision && { afterRevision: true }), }; } exports.groundedRowFrom = groundedRowFrom; /** The step judge's accepted or cut-short verdict as a row — each step's position and tool only. */ function stepsUnfinishedRowFrom(verdict) { return { kind: 'steps-unfinished', turn: verdict.turn, iteration: verdict.iteration, skillId: verdict.skillId, remaining: verdict.remaining.map((s) => ({ index: s.index, tool: s.tool })), total: verdict.total, action: verdict.action, }; } exports.stepsUnfinishedRowFrom = stepsUnfinishedRowFrom; const isCount = (value) => typeof value === 'number' && Number.isInteger(value) && value >= 0; /** * Whether a value read from a stored checkpoint is a witness row this library * could have written: the kind, a numeric `turn` and `iteration`, and every * other field in its own shape. The checkpoint door's two arms * (`core/runCheckpoint.ts`). An older runtime refuses a checkpoint that * carries either kind. */ function witnessRowIsWellFormed(r) { if (typeof r.turn !== 'number' || typeof r.iteration !== 'number') return false; if (r.kind === 'grounded') { return (typeof r.posture === 'string' && POSTURES.includes(r.posture) && isCount(r.candidates) && isCount(r.lookedUp) && (r.afterRevision === undefined || r.afterRevision === true)); } if (r.kind === 'script-shown') { // The verdict's fields, by the ONE rule every reader of the shape uses // (`scripts/match.ts` · `blockVerdictOf`) — an exit code its label does // not carry included. A row never carries `alsoMatches`. return r.alsoMatches === undefined && (0, match_js_1.blockVerdictOf)(r) !== undefined; } if (r.kind === 'steps-unfinished') { return (typeof r.skillId === 'string' && isCount(r.total) && (r.action === 'accepted' || r.action === 'cut-short') && Array.isArray(r.remaining) && r.remaining.every((s) => s !== null && typeof s === 'object' && isCount(s.index) && typeof s.tool === 'string')); } return false; } exports.witnessRowIsWellFormed = witnessRowIsWellFormed; //# sourceMappingURL=witness.js.map