agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
77 lines • 3.98 kB
TypeScript
/**
* promptTemplate — an instruction that can SAY a run-time fact, from a closed
* vocabulary the library owns.
*
* Pattern: Pure functions over a string (no scope, no I/O, no clock).
* Role: lib/ layer. Used at DEFINE time to refuse a template naming
* something that does not exist, and at EVALUATE time to render one
* — the single moment the context and the content are both in scope
* (`projectActiveInjection`).
* Emits: N/A.
*
* ## Why a closed vocabulary and not a function
*
* `Injection.inject` is static data, so an instruction could be GATED on the
* iteration and could never SAY it: `activeWhen: (ctx) => ctx.iteration > 22`
* is expressible, "you have used 23 of your 30 actions" is not. The framework
* hit this three times itself — `defineStepsHint`, `defineMenuHint` and
* `defineRelevanceHint` each carry a STATIC body and push their DATA through a
* tool description, because `inject` cannot render. That workaround only works
* for content the framework can attach to a tool it owns, which is exactly
* what a consumer reported: they had to ride the count on their own tool
* results.
*
* The obvious fix — let `inject` be `(ctx) => InjectionContent` — fails on
* ABSENCE. Given a function, an author writes `${ctx.maxIterations}` and ships
* *"23 of undefined"*, or writes `?? 0` and ships a fabricated denominator the
* library cannot tell from a real zero. With named slots the LIBRARY owns
* absence and applies one rule: if any fact a template names is unavailable,
* the whole instruction is skipped, by name, on the record. Never a fake zero,
* never a gap, never the literal placeholder.
*
* ## The vocabulary
*
* Three words, all about the turn's action budget, because that is the fact
* the field report measured:
*
* `{{action}}` the action about to be taken (1-based)
* `{{actionBudget}}` how many the turn is allowed
* `{{actionsRemaining}}` how many are left, never negative
*
* It is closed on purpose. A name this file does not know is refused at define
* time, when a person is looking at the error — not at iteration 23 of a paid
* run.
*/
import type { InjectionContext } from './types.js';
/** Every fact a `promptTemplate` may name. Closed. */
export declare const TEMPLATE_FACTS: readonly ["action", "actionBudget", "actionsRemaining"];
export type TemplateFact = (typeof TEMPLATE_FACTS)[number];
/** Every name the template asks for, in order of appearance, deduplicated. */
export declare function placeholdersIn(template: string): readonly string[];
/** True when this string asks for anything at all. */
export declare function isTemplate(template: string): boolean;
/**
* Refuse a template naming something this library cannot supply — at define
* time, by name, listing what it CAN supply.
*
* @param label the factory + id, so the error names the door the author used
*/
export declare function assertKnownFacts(template: string, label: string): void;
/**
* The facts a template names that this context cannot supply.
*
* `{{action}}` is always available — every evaluation has an iteration. The
* other two need `ctx.maxIterations`, which an engine driven without an agent
* (a foreign host, a hand-built evaluation) does not have.
*/
export declare function missingFactsFor(template: string, ctx: Pick<InjectionContext, 'iteration' | 'maxIterations'>): readonly string[];
/**
* Render, or `undefined` when any named fact is unavailable.
*
* ALL-OR-NOTHING by design: a template that says "action 25 of {{gap}}" is
* worse than no instruction at all, and a template that quietly renders
* "action 25 of 0" is worse again — the library cannot tell a fabricated zero
* from a real one, and neither can the model.
*/
export declare function renderTemplate(template: string, ctx: Pick<InjectionContext, 'iteration' | 'maxIterations'>): string | undefined;
//# sourceMappingURL=promptTemplate.d.ts.map