UNPKG

agentfootprint

Version:

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

109 lines • 4.67 kB
/** * arguments/sources — where the MODEL says each argument value came from * (`_findings.from`), and the one reader of it. * * Pattern: Map. The vocabulary of a declared source and one pure reader that * judges the model's `from` array against the call it rides on. The * reader is called by the ONE reader of `_findings` * (`findings/reserved.ts` · `readDeclaration`, under declared * sources — `.inputsLayer({ argumentSources: true })` or * `.findings({ argumentSources: true })`), so the inputs layer and * ToolCalls' peel read one `_findings` the same way. * Role: core/ layer leaf of the inputs layer (honesty layer 2). Imports * nothing from `findings/` — the folder's one-way law. Small and * synchronous on purpose: the one reader is on every armed agent's * graph; the CHECKS (`checks.ts`) load with the layer. * Emits: N/A. * * ## What the model may say * * ```json * "_findings": { "basis": "direct", * "from": [ { "argument": "window", "source": "user", "quote": "over the last week" }, * { "argument": "host", "source": "result", "id": "toolu_01AbC" }, * { "argument": "limit", "source": "assumed" } ] } * ``` * * `user` (+ `quote`, the person's words copied exactly), `result` (+ `id`, a * tool_result id), `turn` (the person answered it, when asked, earlier), * `app` (the app's own text carries it), `assumed` (the model chose it). A * declaration is a CLAIM: the library checks it (`checks.ts` · `checkSource`) * and files its verdict beside it; an unchecked claim is never trusted. * * ## Never repaired * * An entry is dropped and COUNTED (never defaulted) when it is not an object; * its `source` is outside the five; a `user` entry has no string `quote` or a * `result` entry no string `id`; its `argument` is not a top-level argument * this call carries a value for (a key the call left out, a missing value, or * a nested / non-primitive value — not ruled in this version); or an earlier * entry already named the same argument (the first wins). */ import { isMissing } from '../../../tools/declare.js'; /** The five, in the order the served schema enumerates them. */ export const DECLARED_SOURCE_KINDS = Object.freeze([ 'user', 'result', 'turn', 'app', 'assumed', ]); const isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value); const isPrimitive = (value) => typeof value === 'string' || typeof value === 'boolean' || (typeof value === 'number' && Number.isFinite(value)); /** One entry, judged against the call's own arguments — `undefined` when malformed. */ function readEntry(raw, args) { if (!isPlainObject(raw)) return undefined; const { argument, source } = raw; if (typeof argument !== 'string') return undefined; if (typeof source !== 'string' || !DECLARED_SOURCE_KINDS.includes(source)) { return undefined; } if (isMissing(args, argument) || !isPrimitive(args[argument])) return undefined; const kind = source; if (kind === 'user') { return typeof raw.quote === 'string' ? { argument, source: kind, quote: raw.quote } : undefined; } if (kind === 'result') { return typeof raw.id === 'string' ? { argument, source: kind, id: raw.id } : undefined; } return { argument, source: kind }; } /** * The model's `from` array for ONE call, judged against the arguments that * call carries (`args` — the call's own arguments, `_findings` taken off). * Each entry that cannot be read is dropped and counted; nothing is defaulted * and nothing is inferred. A `from` that is not an array reads as nothing, * one malformed. * * @example * ```ts * readSources([{ argument: 'window', source: 'user', quote: 'the last week' }], { window: '7d' }); * // { from: [{ argument: 'window', source: 'user', quote: 'the last week' }], malformed: 0 } * readSources([{ argument: 'window', source: 'user' }], { window: '7d' }); // no quote * // { from: [], malformed: 1 } * ``` */ export function readSources(raw, args) { if (!Array.isArray(raw)) return { from: [], malformed: 1 }; const from = []; const named = new Set(); let malformed = 0; for (const item of raw) { const entry = readEntry(item, args); if (entry === undefined || named.has(entry.argument)) { malformed += 1; continue; } named.add(entry.argument); from.push(entry); } return { from, malformed }; } //# sourceMappingURL=sources.js.map