UNPKG

agentfootprint

Version:

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

64 lines • 3.14 kB
/** * middleware/rewrites — which arguments a before-tool middleware rewrote, read * off the record: the ONE reading the answer's standing and the answer's * "Assumed" block both take. * * Pattern: One pure function over committed rows. No scope, no clock; the * input is read, never trusted. * Role: core/agent leaf (honesty layer 2). Under the inputs layer, a * before-tool rewrite of a RULED tool's arguments is filed on * `middlewareDecisions` with the NAMES of the keys it changed * (`MiddlewareDecision.changedKeys`, stamped by * `arguments/dispatch.ts` · `withChangedKeys`) and, when the middleware * declared one, where each value came from * (`allow(args, why, { from })`). The layer checked the value BEFORE * the chain ran, so a rewrite supersedes the layer's row: the value * the call ran with is the rewrite's. Two readers must agree on that — * `assessment/assess.ts` · `readArgumentVerdicts` (the standing) and * `arguments/serve.ts` · `assumedBlockOf` (the "Assumed" block) — * and both load through `import()` (the fold on first use, the block * under the arm), so neither can own the reading for the other: it * lives here, once, and a plain agent's graph carries it for neither. * Emits: N/A. * * @example * ```ts * argumentRewritesOf([ * { at: 'tool', toolCallId: 'c1', changedKeys: ['window'], from: { window: 'person' }, … }, * ]).get('c1')?.get('window'); // { index: 0, origin: 'person' } * ``` */ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value); // FOLD · the one owner of "which argument of which call a before-tool rewrite superseded" // consumers read this and never re-derive it: assessment/assess.ts · readArgumentVerdicts, // arguments/serve.ts · assumedBlockOf // detached: yes — fresh maps of plain entries, rebuilt per read. /** * The before-tool middleware rewrites on the record — `middlewareDecisions` * rows at `'tool'` that carry `changedKeys` — keyed by call, then argument, * the LAST rewrite winning, because the value the call ran with is the last * link's. Anything that is not such a row is skipped. */ export function argumentRewritesOf(decisions) { const byCall = new Map(); if (!Array.isArray(decisions)) return byCall; decisions.forEach((row, index) => { if (!isRecord(row) || row.at !== 'tool' || !Array.isArray(row.changedKeys)) return; const toolCallId = row.toolCallId; if (typeof toolCallId !== 'string') return; const from = isRecord(row.from) ? row.from : {}; const forCall = byCall.get(toolCallId) ?? new Map(); for (const key of row.changedKeys) { if (typeof key !== 'string') continue; const origin = from[key]; forCall.set(key, { index, ...(typeof origin === 'string' && { origin }) }); } byCall.set(toolCallId, forCall); }); return byCall; } //# sourceMappingURL=rewrites.js.map