agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
84 lines (83 loc) • 4.3 kB
TypeScript
/**
* analyzeToolCatalog — the tool-catalog confusability lint
* (RFC-002 block C1, the adoption front door).
*
* Pattern: policy layer over `pairwiseSimilarity` (influence-core) — the
* geometry is computed there; thresholds, verdicts, hints and
* the structural rule pack live here. Everything is consumer-
* injectable with our defaults (the plug-and-play meta-pattern).
* Role: `src/tool-lint/`. ZERO stack buy-in — plain
* `{ name, description?, inputSchema? }[]` in, report out.
* `catalogFromTools` adapts the library's own `Tool[]`;
* `coerceCatalog` (cli.ts) normalizes OpenAI/Anthropic/MCP
* shapes.
*
* ## What is embedded (and why)
*
* `confusabilityText(tool)` = tokenized name + ': ' + description. The
* model differentiates tools by name AND description together, so two
* tools with near-identical names and overlapping descriptions ARE the
* confusability case (`get_fcns_database` vs `influx_get_fcns_database`)
* — embedding only the prose would miss the name signal.
*
* ## Calibration (RFC-002 §3 — read this before trusting verdicts)
*
* Absolute cosine ranges are PER-EMBEDDER. The default threshold (0.85)
* is a starting point for real sentence embedders. The test/demo
* `mockEmbedder` (character-frequency) compresses unrelated prose into
* ~0.85–0.97 — with it, use `MOCK_EMBEDDER_CALIBRATION` and trust only
* the RELATIVE ordering in `report.similarity.ranked` (the acceptance
* fixtures assert ordering, never absolute scores).
*/
import type { Tool } from '../tools/tools.js';
import type { AnalyzeToolCatalogOptions, CatalogTool, ToolCatalogReport } from './types.js';
/** Default `confusabilityThreshold` — a starting point for REAL sentence
* embedders (unrelated tool descriptions typically land 0.3–0.7).
* Calibrate per embedder; meaningless for the mock (see below). */
export declare const DEFAULT_CONFUSABILITY_THRESHOLD = 0.85;
/** Default `watchBand` below the threshold. */
export declare const DEFAULT_WATCH_BAND = 0.05;
/**
* Threshold/band calibrated for the char-frequency `mockEmbedder` on
* realistic tool prose (seed corpus: the host-app SAN catalog). The mock
* compresses unrelated descriptions into ~0.85–0.97 cosine, so expect
* false positives even at 0.94 — with the mock, the RELATIVE ordering
* of `report.similarity.ranked` is the trustworthy signal; absolute
* verdicts are only honest with a real embedder + per-embedder
* calibration.
*/
export declare const MOCK_EMBEDDER_CALIBRATION: Readonly<{
confusabilityThreshold: 0.94;
watchBand: 0.02;
}>;
/**
* Adapt the library's `Tool[]` (from `defineTool` / `Agent.tool`) to the
* lint's plain catalog shape. Trivial on purpose: `Tool.schema` already
* IS `{ name, description, inputSchema }`.
*/
export declare function catalogFromTools(tools: readonly Tool[]): readonly CatalogTool[];
/**
* The text the confusability analysis embeds for one tool: the name with
* `_`/`-`/camelCase boundaries opened into words, then the description.
* Exported so consumers can reproduce or replace the construction.
*/
export declare function confusabilityText(tool: CatalogTool): string;
/**
* Lint a tool catalog: pairwise confusability over what the model reads
* (when an embedder is supplied) + the structural rule pack. Returns a
* report whose `ok` is the CI gate.
*
* Duplicate tool names are themselves reported as structural errors
* (rule `duplicate-name`, built-in precondition — a catalog where two
* tools share a name is broken before any similarity question); the
* duplicates are dropped from the similarity analysis (first one wins).
*/
export declare function analyzeToolCatalog(tools: readonly CatalogTool[], options?: AnalyzeToolCatalogOptions): Promise<ToolCatalogReport>;
/**
* Suggest the DIFFERENTIATING AXIS for a flagged pair. Heuristic: when
* the names are near-twins (≤2 distinct tokens), the qualifier IS the
* axis — the descriptions must say when to choose each variant. When the
* names differ, surface the few description terms each tool does NOT
* share, as the place to anchor an explicit choice condition.
*/
export declare function differentiationHint(a: CatalogTool, b: CatalogTool): string;