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 (63 loc) • 3.15 kB
TypeScript
/**
* context-ledger/gates.ts — L2: the ledger's rows feed what gets included.
*
* Three gates, one policy, each hooking an EXISTING seam (no new framework
* surface): `gatedTools(inner, predicate)` for tools, `skillGraph().entryBy`
* for skills, and a rule-trigger wrapper for injections.
*
* THE POLICY PRINCIPLE — demote, never starve: a piece the ledger judges
* poorly is demoted, but every `refreshEvery`-th decision lets it through
* anyway ("parole"), so it keeps generating fresh ledger data. Without
* parole a piece demoted once could never earn again — a self-fulfilling
* verdict. And the ledger never judges a piece it barely knows: below
* `minOffers` everything passes.
*/
import type { EntryScorer } from '../injection-engine/entryScorer.js';
import type { Injection } from '../injection-engine/types.js';
import type { ToolGatePredicate } from '../tools/toolProvider.js';
import type { ContextLedger } from './types.js';
/**
* When the ledger is allowed to judge, and how harshly.
* Plain-named knobs — a bookkeeper's rules, not ML hyperparameters.
*/
export interface LedgerPolicy {
/** Don't judge a piece until it has been offered this many times. Default 5. */
readonly minOffers?: number;
/** Demote below this used÷offered rate. Default 0.05 (essentially "never used"). */
readonly earnRateFloor?: number;
/**
* Parole: let a demoted piece through anyway every Nth demotion decision,
* so it keeps earning fresh data. Default 10. `Infinity` disables parole
* (NOT recommended — a starved piece can never redeem itself).
*/
readonly refreshEvery?: number;
}
/**
* TOOL GATE — plug into the existing provider combinator:
*
* ```ts
* import { gatedTools, staticTools } from 'agentfootprint/providers';
* builder.toolProvider(gatedTools(staticTools(tools), ledgerToolGate(ledger)));
* ```
*
* Unused tool schemas are usually the biggest silent token cost — this is
* the gate to start with.
*/
export declare function ledgerToolGate(ledger: ContextLedger, policy?: LedgerPolicy): ToolGatePredicate;
/**
* SKILL GATE — an `EntryScorer` for `skillGraph().entryBy(...)` that wraps
* another scorer (keyword, embedding, …) and demotes candidates the ledger
* says never earn. Demotion multiplies the inner score toward the floor —
* ranking pressure, not exclusion — and parole restores full weight
* periodically, so a demoted skill can still win when nothing else fits.
*/
export declare function ledgerEntryScorer(ledger: ContextLedger, inner: EntryScorer, policy?: LedgerPolicy): EntryScorer;
/**
* INJECTION GATE — wrap ONE injection so the ledger's verdict joins its
* trigger. `always` becomes a ledger-backed rule; an existing `rule` is
* AND-ed with the verdict. `on-tool-return` / `llm-activated` are returned
* UNCHANGED (they are already demand-driven — the ledger has nothing to
* add). `always` pieces are exempt unless you explicitly wrap them — the
* safety-first default from the design.
*/
export declare function ledgerGated(injection: Injection, ledger: ContextLedger, policy?: LedgerPolicy): Injection;