agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
73 lines (72 loc) • 3.54 kB
TypeScript
/**
* act — PUBLIC. One bundle for every place a rule may speak.
*
* Pattern: Facade over five doors, with the facade's KEYS type-locked to the
* list of moments they cover.
* Role: core/ layer. `.act()` builds nothing new: it validates a bundle
* and calls `.messageMiddleware()`, `.toolMiddleware()` and
* `.window()` with exactly what a person would have passed by hand.
* Everything about a run is decided by those doors, here and there
* alike.
* Emits: N/A.
*
* ## Why a bundle at all, when the doors already exist
*
* Because the doors are findable one at a time and the POSTURE is not. An
* agent's governance currently reads as four unrelated calls scattered
* through a builder chain, and the question a reviewer actually has —
* "what does this agent do at each point in its loop?" — has no place to be
* answered. `.act({ … })` is that place: five optional keys, named for the
* five moments, so autocomplete on an empty object teaches the loop.
*
* ## The completeness lock
*
* The keys of {@link ActOptions} are pinned, at compile time, against
* `ActKey<LoopMoment>` — the moment list, camel-cased. Add a sixth moment to
* `LOOP_MOMENTS` and this file stops compiling until the bundle grows the key
* for it; delete a key and the same. A surface that claims to be complete has
* to be made unable to fall behind, or the claim is just a sentence in a doc.
*
* The runtime half is derived from the same list: the accepted key set is
* `LOOP_MOMENTS.map(actKeyFor)`, so a typo'd key is refused by a validator
* that cannot drift from the type it is validating.
*/
import type { MessageMiddleware, ToolMiddleware } from './middleware/types.js';
import { type ActKey } from '../../lib/moments.js';
import type { WindowStrategy } from './window/strategy.js';
/**
* The whole steering wheel: one key per moment of the loop, each optional.
*
* The declaration order below is the order the loop reaches them.
*/
export interface ActOptions {
/** The user's message, before the run commits it. Input-only rules do not
* withhold provider draft streaming. */
readonly input?: readonly MessageMiddleware[];
/** Every tool call, before it is dispatched. */
readonly beforeTool?: readonly ToolMiddleware[];
/** Every tool result, after the tool ran and before the model reads it. */
readonly afterTool?: readonly ToolMiddleware[];
/** What the live context window keeps, at each iteration boundary. */
readonly window?: WindowStrategy;
/** The answer before final capture. A nonempty output chain withholds
* provider drafts and releases the captured answer once after acceptance;
* refusal stops delivery and final memory writes. Not audit erasure. */
readonly output?: readonly MessageMiddleware[];
}
/** The keys `.act()` accepts, derived from the moment list rather than typed. */
export declare const ACT_KEYS: readonly ActKey[];
/** What `.act()` hands to the five doors. */
export interface ResolvedAct {
readonly message: readonly MessageMiddleware[];
readonly tool: readonly ToolMiddleware[];
readonly window?: WindowStrategy;
}
/**
* Validate a bundle and turn it into the arguments the five doors take.
*
* Pure — it throws or it returns; it touches no builder state. `.act()` is
* the caller that hands the result to the doors, which is what makes the
* sugar provably the same agent.
*/
export declare function resolveAct(options: ActOptions): ResolvedAct;