/** * 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): 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): string | undefined;