UNPKG

agentfootprint

Version:

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

68 lines • 3.04 kB
"use strict"; /** * gatedTools — wrap any ToolProvider with a per-tool gating predicate. * * The DECORATOR for tool providers. Filters the inner provider's * output by running the predicate against each tool name. Composes * freely: * * gatedTools( * gatedTools(staticTools(allTools), readOnlyPredicate), * skillGatePredicate, * ) * * Reads as: "static list of all tools, filtered by readonly policy, * then further filtered by the active skill's tool set." Each gate * is one concern; composition handles the rest. * * Pattern: Decorator (GoF) — wraps any ToolProvider with an additional * filter. Mirrors `withRetry` / `withFallback` over LLMProvider. * * @example Read-only enforcement * const readOnly = gatedTools( * staticTools([read, write]), * (toolName) => toolName.startsWith('read_'), * ); * readOnly.list(ctx); // → [read] * * @example Skill-gated dispatch (autoActivate use case) * const skillGated = gatedTools( * staticTools(allTools), * (toolName, ctx) => ctx.activeSkillId * ? skillToolMap[ctx.activeSkillId].includes(toolName) * : alwaysVisible.includes(toolName), * ); */ Object.defineProperty(exports, "__esModule", { value: true }); exports.gatedTools = void 0; // LENS · tool-list · request-ephemeral // reads: nothing of its own — a caller-supplied predicate over the inner provider, recomputed per iteration // known gap: the omission is unclassified and unrecorded here. The predicate may be an AUTHORITY gate (a // permission policy, which must be invisible) or an ATTENTION gate (a budget or scope, which must be // visible); this seam cannot tell them apart. src/security/index.ts · "A local allowlist and a remote policy engine differ in one way that // matters here" states the distinction. // law: may omit, never deny; every clause anchored to the call it was composed on. // #region gatedTools function gatedTools(inner, predicate) { return { id: 'gated', list(ctx) { // Pull from the inner provider first; each recomputation sees // the freshest state from any nested gates. Inner may be sync // or async — we mirror what we get back so a sync chain stays // sync (zero microtask overhead) and an async chain stays // async (no premature `Promise.resolve` wrapping). const innerResult = inner.list(ctx); const filter = (innerTools) => // Filter by predicate — tool name from `tool.schema.name`. // Predicates throwing escape: a buggy predicate should crash // loudly, not silently allow tools through. Per the // permission-as-defense-in-depth principle. innerTools.filter((t) => predicate(t.schema.name, ctx)); return innerResult instanceof Promise ? innerResult.then(filter) : filter(innerResult); }, }; } exports.gatedTools = gatedTools; // #endregion gatedTools //# sourceMappingURL=gatedTools.js.map