UNPKG

agentfootprint

Version:

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

104 lines • 4.44 kB
"use strict"; /** * searchOf — the ONE door to a tool's `search`, judged once per tool object. * * Pattern: a WeakMap-cached verdict (the `hostFilled` declaration precedent). * Role: tools/ layer. Read by the agent's registration funnel * (`core/agent/buildToolRegistry.ts`, so a static tool is judged at * build) and by the dispatch funnel (`core/agent/stages/ * searchCoverage.ts`, so a provider's tool is judged when first * met). Composition never reads `tool.search` directly. * Emits: one console warning per refused tool object (not dev-gated: a * refused declaration is a rail that does not arm, and its symptom is * silence — the `toolExtras` rule). * * `defineTool` and the MCP ingest door judge a declaration, but a hand-built * `Tool` handed to `.tool()` skips both. So the verdict is taken HERE, by the * same rule (`assertToolSearch`, against the tool's own `inputSchema` and the * arguments its `period` names), and the accepted declaration is stored * frozen (`freezeSearch`). A `defineTool` tool is remembered as built, never * judged twice; a `hostFilled` wrapper keeps the verdict on the tool it wraps * (its schema no longer lists the filled arguments the search classifies). * * A REFUSED declaration composes nothing — not a `'remote'` row. A remote row * is a well-formed declaration the library does not trust; a refused one has * no shape any rule vetted, so no facet may be composed from it. Its * `checked: 'declared'` literal becomes the call's error, naming the fault. */ Object.defineProperty(exports, "__esModule", { value: true }); exports._resetSearchOfWarnings = exports.searchOf = exports.inheritSearch = exports.rememberSearch = void 0; const declaration_js_1 = require("../semantics/coverage/search/declaration.js"); const VERDICTS = new WeakMap(); /** Tool names already warned about — bounded, like every warn-once ledger fed by callers. */ const warned = new Set(); const MAX_WARNED = 500; function warnRefused(toolName, problem) { if (warned.has(toolName)) return; if (warned.size < MAX_WARNED) warned.add(toolName); // eslint-disable-next-line no-console console.warn(`[agentfootprint] tool '${toolName}' carries a \`search\` this library refused, so ` + 'nothing is composed for its calls and its checked: "declared" results are refused. ' + `The rule it broke: ${problem}`); } /** * Remember a declaration already judged and frozen — `defineTool` calls it for * the tool it builds. @internal */ function rememberSearch(tool, search) { VERDICTS.set(tool, { search }); } exports.rememberSearch = rememberSearch; /** * Carry `from`'s verdict to `to` — a wrapper whose schema changed (`hostFilled`) * keeps the verdict taken against the schema the search was declared for. * @internal */ function inheritSearch(from, to) { VERDICTS.set(to, searchOf(from)); } exports.inheritSearch = inheritSearch; /** * The tool's accepted `search`, or why it was refused, or `{}` when it * declares none. Judged on first sight of a tool object, then remembered. * * @example * ```ts * const { search, problem } = searchOf(tool); * if (search === undefined) return; // nothing to compose * ``` */ function searchOf(tool) { if (tool.search === undefined) return {}; const known = VERDICTS.get(tool); if (known !== undefined) return known; let verdict; try { const periodArguments = (0, declaration_js_1.periodArgumentsOf)(tool.period); (0, declaration_js_1.assertToolSearch)(tool.schema.name, tool.search, { inputSchema: tool.schema.inputSchema ?? { type: 'object', properties: {} }, ...(periodArguments !== undefined && { periodArguments }), }); verdict = { search: (0, declaration_js_1.freezeSearch)(tool.search) }; } catch (error) { const problem = error instanceof Error ? error.message : String(error); warnRefused(tool.schema.name, problem); verdict = { problem }; } VERDICTS.set(tool, verdict); return verdict; } exports.searchOf = searchOf; /** * Forget every warning issued so far. * @internal test seam — the ledger is process-wide and warn-ONCE. */ function _resetSearchOfWarnings() { warned.clear(); } exports._resetSearchOfWarnings = _resetSearchOfWarnings; //# sourceMappingURL=searchOf.js.map