UNPKG

agentfootprint

Version:

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

53 lines • 2.55 kB
/** * provenance — who registered this name. * * Pattern: a small value type + one formatter. Pure, no dependencies beyond * the recipe types. * Role: recipes/ layer. `AgentBuilder` records a {@link RecipeSource} beside * every tool name and injection id it takes, and reads it back when * two registrations collide. * Emits: N/A. * * ## Why provenance at all * * The builder has always refused a duplicate tool name — the model dispatches * by name, so two tools called `search` is a coin flip. What it could not say * was WHERE each one came from. With one recipe in the chain that answer stops * being obvious ("I never registered a `search` tool") and with two it is * unrecoverable without reading both recipes' source. A refusal that names both * sides turns a hunt into a sentence. * * ## Three arms, because three things are true and one of them is "I do not know" * * `local` and `unattributed` are NOT the same fact, and collapsing them would * make the refusal lie. `local` means: this builder watched you call * `.tool()` / `.injection()` yourself. `unattributed` means: the name was * already taken when the ledger was consulted and no source was recorded for * it — the honest answer is that this builder does not know, and saying * "you registered it" would send the reader to look in the one place it is not. * * The arm exists because there is more than one way into the injection list: * `.injection()` is the funnel for the named flavors, and `.outputSchema()` * mounts an instruction of its own. Both record a source today. A third site * added later would not, and this arm is what keeps that omission honest * instead of blaming the caller. */ /** The one `local` value. A frozen singleton — it carries no data. */ export const LOCAL_SOURCE = Object.freeze({ kind: 'local' }); /** * Describe a source in a sentence fragment that reads inside a refusal. * * `undefined` is the unattributed case — see the header. It is a separate * answer, never folded into `local`. */ export function describeRecipeSource(source) { if (source === undefined) { return ('an earlier registration with no recorded source (a builder method mounted it; ' + 'this builder did not attribute it)'); } if (source.kind === 'local') return 'this agent, directly'; const chain = [...source.stack].reverse().map((r) => `recipe '${r.id}' ${r.version}`); return chain.join(' ← applied by '); } //# sourceMappingURL=provenance.js.map