/** * The conclusion-over-graph tool contract (spec domain: `mcp-quality`). * * OpenLore's value proposition is that the *server* does graph traversal so the * *agent* never has to. A tool that returns a raw node-and-edge list silently * pushes the BFS back onto the model — the exact failure mode (multi-hop context * exhaustion, edge confabulation) the substrate exists to prevent. * * This module turns that convention into a checked invariant: * - {@link TOOL_OUTPUT_CLASS} classifies every dispatched MCP tool as either * `conclusion` (returns a path / ranked list / set / metric / verdict that * directly answers the query) or `explicit-topology` (intentionally returns * a node-and-edge graph). * - {@link assertConclusionShape} enforces that a `conclusion` tool's response * does not regress into a graph dump. * * The companion `tool-contract.test.ts` cross-checks the table against the live * `TOOL_DEFINITIONS` registration so a newly added tool that forgets to declare * a class fails CI. */ import type { GovernanceFinding } from './enforcement-policy.js'; export type ToolOutputClass = 'conclusion' | 'explicit-topology'; /** * Every dispatched MCP tool (see `dispatchTool` in * `src/core/services/tool-dispatch.ts`) and its output class. * * Only two tools are `explicit-topology` — they exist to expose graph-level * structure and are exempt from the conclusion predicate: * - `get_subgraph` — a true `nodes[]` + `edges[]` neighbourhood dump. * - `get_call_graph` — a graph-level summary (stats, hub/entry lists, layer * violations). It currently returns bounded lists rather than raw edges, * but stays `explicit-topology` so the "exactly two graph tools" model * holds for future authors and so widening it back to raw topology needs * no reclassification. * * Everything else is `conclusion`. Adding a tool without an entry here makes the * completeness test fail, forcing the author to declare a class. */ export declare const TOOL_OUTPUT_CLASS: Record; /** The tools intentionally allowed to emit raw topology, sorted for stable assertions. */ export declare const EXPLICIT_TOPOLOGY_TOOLS: readonly string[]; export type CapabilityFamily = 'navigate' | 'change' | 'remember' | 'verify' | 'coordinate' | 'federate'; /** The closed, source-declared family set, in presentation order. */ export declare const CAPABILITY_FAMILIES: readonly CapabilityFamily[]; /** One-line human label per family, for grouped rendering in docs and `--help`. */ export declare const CAPABILITY_FAMILY_LABELS: Record; /** * Every dispatched MCP tool and its capability family. Parallel to * {@link TOOL_OUTPUT_CLASS}: adding a tool without an entry here makes the * completeness test fail, forcing the author to declare a family. */ export declare const TOOL_CAPABILITY_FAMILY: Record; /** The capability family of a tool, or `undefined` if it is unclassified. */ export declare function capabilityFamily(name: string): CapabilityFamily | undefined; /** * Adjacent tool groups (NoRedundantConclusions, `mcp-quality`). Each group is a * set of tools IN THE SAME FAMILY whose purposes could be read as answering the * same question. These are deliberately NOT merged — each returns a separately * useful conclusion — so the contract instead requires each member's description * to name a near-sibling, making the distinction legible to a selecting agent. * `tool-contract.test.ts` fails if a member does not cross-reference its group. */ export declare const ADJACENT_TOOL_GROUPS: ReadonlyArray; /** * Group a tool list by capability family, preserving {@link CAPABILITY_FAMILIES} * order and dropping empty families. Used to render the full surface grouped by * family (docs / `--help`) instead of as a flat list (CapabilityFamilyTaxonomy). */ export declare function groupToolsByFamily(tools: T[]): Array<{ family: CapabilityFamily; label: string; tools: T[]; }>; /** Thrown when a `conclusion` tool's response violates the contract. */ export declare class ToolContractViolationError extends Error { readonly toolName: string; readonly violation: string; constructor(toolName: string, violation: string); } /** * Assert that a tool's response satisfies the conclusion-over-graph contract. * * - `explicit-topology` tools are exempt (they may return raw topology). * - An unclassified tool name throws — the contract refuses to silently pass a * tool that has not declared its class. * - A `conclusion` tool's response is rejected when it either: * (a) contains a top-level array of id-reference edge objects longer than * {@link MAX_PROVENANCE_EDGES} (a raw adjacency/edge dump), or * (b) carries both a top-level `nodes[]` and a top-level `edges[]`, so the * answer is only reconstructable by joining the two (a graph dump). * * "Top-level" means the response object's own enumerable values (or the * response itself when it is an array). Bounded provenance under the limit is * fine — a conclusion may cite a few edges to explain *why* it concluded. */ export declare function assertConclusionShape(toolName: string, response: unknown): void; /** Stable governance-finding code emitted when a conclusion tool regresses into a graph dump. */ export declare const CONCLUSION_SHAPE_VIOLATION_CODE = "conclusion-shape-violation"; /** * Whether the conclusion-shape check should be STRICT (throw) rather than advisory. * Strict under the vitest/CI suite so a regressing handler fails the suite; advisory * in production. Overridable via `OPENLORE_CONCLUSION_CONTRACT=strict|advisory` so a * targeted test can exercise either mode deterministically. */ export declare function isStrictConclusionContract(): boolean; /** The governance finding for a conclusion tool that returned a graph-shaped response. */ export declare function conclusionShapeFinding(toolName: string, violation: string): GovernanceFinding; /** * Enforce the conclusion-over-graph contract on a live dispatch result and return * the value to serialize. `explicit-topology` and well-shaped `conclusion` * responses are returned untouched. A violation throws in strict mode, or is logged * and disclosed (result still returned) in advisory mode. Non-contract errors * propagate unchanged. */ export declare function enforceConclusionContract(toolName: string, result: unknown, log?: (message: string) => void): unknown; /** Permanent, deprecated tool-name aliases: prior name → canonical name. */ export declare const TOOL_NAME_ALIASES: Record; /** * Resolve a possibly-aliased tool name to its canonical name. Returns the input * unchanged when it is already canonical or unknown (callers handle unknown names * downstream — this never throws and never invents a name). */ export declare function resolveCanonicalToolName(name: string): string; //# sourceMappingURL=tool-contract.d.ts.map