UNPKG

agentfootprint

Version:

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

187 lines • 8.7 kB
"use strict"; /** * The manifest bridge — which arm did this run belong to, according to the RUN * rather than according to the experimenter. * * Before 9.41.0 an arm label was bookkeeping: the consumer set a variable to * `'rerank'`, built an agent it believed re-ranked, and nothing in the library * could contradict it. `agentfootprint.agent.run_configured` names the adapters * and strategies a run is about to use, so the belief became checkable — and * {@link ArmFacets} is deliberately spelled in that event's own vocabulary so * the check is a field-by-field comparison and not a translation layer. * * Two directions, both here: * - **verify** — `checkArmApplied(arm, manifest)`: the arm said `retrieval: * 'rerank'`; did the run agree? A contradiction costs the arm its verdict * (`compare.ts`), because a difference measured between two arms that were * secretly one configuration is not evidence about either. * - **classify** — `matchArm(arms, manifest)`: hand it a recorded run's * manifest and it says which declared arm that run belongs to. This is the * door for grouping runs a study already made, offline, out of saved * recordings. * * ## Absence is a contradiction, not a wildcard * * The manifest's own rule is that an absent field means "not configured", never * a guessed default. So an arm declaring `window: 'tokenBudget'` against a * manifest with no `window` is a MISMATCH, reported with `observed` absent. The * alternative — treating absence as "could be anything" — would let a run with * no window stage pass as the token-budget arm, which is exactly the mis-wiring * this file exists to catch. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.matchArm = exports.checkArmApplied = exports.armLabel = exports.armFacetsFromManifest = void 0; const validate_js_1 = require("./validate.js"); /** * Project a manifest onto the arm-facet vocabulary — the inverse of what an arm * declares. Memory rows collapse to the FIRST one; a study varying retrieval * across several mounted memories should declare `memory.id` and read the rows * itself rather than trust a projection to pick. */ function armFacetsFromManifest(manifest) { const memory = manifest.memories?.[0]; const provider = manifest.llm?.provider; const model = manifest.llm?.model; const reactMode = manifest.reactMode; const scorer = manifest.skillGraph?.scorer; const routing = manifest.skillGraph?.routing; const continuity = manifest.skillGraph?.continuity; const evidenceGate = manifest.evidenceGate; return { ...(provider !== undefined && { provider }), ...(model !== undefined && { model }), ...(isReactMode(reactMode) && { reactMode }), ...(manifest.window !== undefined && { window: manifest.window }), ...(scorer !== undefined && { scorer }), ...(isPosture(routing) && { routing }), ...(isContinuity(continuity) && { continuity }), ...(isPosture(evidenceGate) && { evidenceGate }), ...(memory !== undefined && { memory: { ...memory } }), }; } exports.armFacetsFromManifest = armFacetsFromManifest; /** * A stable label for a set of facets — sorted `key=value`, so two runs of one * configuration produce the same string whatever order the fields were written * in. Useful as a grouping key for N recorded runs. */ function armLabel(facets) { const parts = []; for (const [key, value] of Object.entries(facets)) { if (value === undefined) continue; if (key === 'memory') { for (const [mk, mv] of Object.entries(value)) { if (mv !== undefined) parts.push(`memory.${mk}=${String(mv)}`); } continue; } parts.push(`${key}=${String(value)}`); } return parts.sort().join(','); } exports.armLabel = armLabel; /** * Compare one arm's DECLARED facets against a run's manifest. Empty result = * the run agreed with everything the arm claimed. * * Only declared facets are compared. An arm is a claim about the facets it * names and says nothing about the rest — checking undeclared fields would fail * every arm for differing from the manifest in ways it never claimed. */ function checkArmApplied(arm, manifest) { const facets = arm.facets; if (facets === undefined) return []; const out = []; compare(out, 'provider', facets.provider, manifest.llm?.provider); compare(out, 'model', facets.model, manifest.llm?.model); compare(out, 'reactMode', facets.reactMode, manifest.reactMode); compare(out, 'window', facets.window, manifest.window); compare(out, 'skillGraph.scorer', facets.scorer, manifest.skillGraph?.scorer); compare(out, 'skillGraph.routing', facets.routing, manifest.skillGraph?.routing); compare(out, 'skillGraph.continuity', facets.continuity, manifest.skillGraph?.continuity); compare(out, 'evidenceGate', facets.evidenceGate, manifest.evidenceGate); const memory = facets.memory; if (memory !== undefined) { const rows = manifest.memories ?? []; if (memory.id !== undefined) { // Narrowed to ONE row: a missing row is a mismatch on the id itself, and // the remaining fields are then compared against that row alone. const row = rows.find((r) => r.id === memory.id); if (row === undefined) { out.push({ facet: 'memory.id', declared: memory.id, ...(rows.length > 0 && { observed: rows.map((r) => r.id ?? '?').join(', ') }), }); } else { for (const field of MEMORY_FIELDS) { compare(out, `memory.${field}`, memory[field], row[field]); } } } else if (!rows.some((row) => MEMORY_FIELDS.every((f) => matches(memory[f], row[f])))) { // Un-narrowed: ANY mounted memory satisfying every declared field counts. // Reported as ONE mismatch — naming a per-field winner across rows would // invent a memory that does not exist. out.push({ facet: 'memory', declared: armLabel({ memory }), ...(rows.length > 0 && { observed: rows.map((row) => armLabel({ memory: row })).join(' | '), }), }); } } return out; } exports.checkArmApplied = checkArmApplied; /** * Which declared arm does this run belong to? The offline door: group N * recorded runs into arms by what each run's own manifest says. * * Rules, all conservative: * - only arms that DECLARE facets are candidates (an arm naming nothing matches * every run and would swallow the whole study); * - a candidate matches when the manifest contradicts none of its facets; * - the MOST SPECIFIC match wins (most declared facets), and a tie returns * `undefined` — two arms fitting one run equally well is an ambiguity, and * guessing which the experimenter meant is exactly the bookkeeping this * function replaces. */ function matchArm(arms, manifest) { const fits = arms .filter((arm) => (0, validate_js_1.declaredFacetCount)(arm.facets) > 0) .filter((arm) => checkArmApplied(arm, manifest).length === 0) .map((arm) => ({ arm, specificity: (0, validate_js_1.declaredFacetCount)(arm.facets) })) .sort((a, b) => b.specificity - a.specificity); if (fits.length === 0) return undefined; if (fits.length > 1 && fits[0].specificity === fits[1].specificity) return undefined; return fits[0].arm; } exports.matchArm = matchArm; // ─── internals ─────────────────────────────────────────────────────── const MEMORY_FIELDS = ['type', 'strategy', 'retrieval', 'embedderId', 'flavor']; function matches(declared, observed) { return declared === undefined || declared === observed; } function compare(out, facet, declared, observed) { if (matches(declared, observed)) return; out.push({ facet, declared: declared, ...(observed !== undefined && { observed }) }); } function isReactMode(value) { return value === 'classic' || value === 'dynamic' || value === 'dynamic-grouped'; } function isPosture(value) { return value === 'assist' || value === 'guard' || value === 'rails'; } function isContinuity(value) { return value === 'turn' || value === 'conversation'; } //# sourceMappingURL=manifest.js.map