/** * toolArgsValidation — validate LLM-produced tool args against the tool's * declared `inputSchema` BEFORE dispatch (backlog #9). * * Pattern: pure function module — no events, and no state beyond one compiled- * regex cache (which doubles as the warn-once ledger for `pattern`s * that do not compile); the toolCalls stage owns when to call it and * what to do with the verdict. * Role: The model writes tool args as free-form JSON; nothing guaranteed * they match the schema the tool advertised. Dispatching garbage * surfaced as deep tool stack traces (or worse, silent misbehavior). * Validating at the boundary turns a malformed call into a * MODEL-VISIBLE structured tool result, so the LLM corrects its * args and retries on the next ReAct iteration. * * ── Honest-subset contract ──────────────────────────────────────────────── * This is NOT a full JSON Schema implementation. It enforces the core that * tool schemas in the wild actually use, and IGNORES everything else * (permissive on unknown keywords — a schema using `oneOf`/`$ref` still * validates the supported core, never false-rejects on the rest): * * ENFORCED: `type` (object/array/string/number/integer/boolean/null, * union arrays), `required`, `properties` (recursive), * `items` (single-schema, recursive), `enum` (primitives), * `additionalProperties: false` ONLY when explicitly set, * and the STRING SHAPE keywords `pattern` / `minLength` / * `maxLength`. * IGNORED: format, numeric min/max, oneOf/anyOf/allOf/not, $ref, * const, dependencies, … * * ── Why string SHAPE joined the subset ──────────────────────────────────── * A tool result ended with an offer ("I can also map these ids to volume * names"); the person answered "yes please"; the model bound that sentence as * the IDENTIFIER argument and dispatched. The tool's schema declared the * identifier's shape and this boundary did not read it, so a call that could * never succeed cost a round trip — and the consumer hand-rolled an * affirmative blocklist to do what the declaration already said. A declared * shape a boundary ignores is worse than no declaration: the author believes * it is enforced. * * `pattern` is JSON Schema's own semantics — UNANCHORED, ECMA-262, applied to * strings only. A regex the schema author got wrong must never take dispatch * with it: it is compiled once, and a compile failure degrades to no-pattern * plus one developer warning. * * ── Security: what an issue may echo ────────────────────────────────────── * `type` / `enum` / `required` / `additionalProperties` issues name the PATH, * the EXPECTED shape, and the TYPE of what arrived — never the supplied value. * Enum expectations echo SCHEMA values only (already LLM-visible in the tools * block). * * String-SHAPE issues are the one exception, and it is a narrow one: the * complaint IS the value's shape, so `expected string, got string` teaches * nothing and the correction cannot converge. They carry `value` — a capped * excerpt ({@link MAX_VALUE_CHARS}) of the offending string — plus `hint`, the * parameter's own `description`, which is where an author writes what the * identifier looks like. Neither adds exposure: the value is the model's own * tool-call argument, already verbatim in the history this message is appended * to. The OTel adapter renders `path`/`expected`/`got` only, so third-party * telemetry stays value-free either way. */ /** When to enforce: 'enforce' rejects before dispatch (default), 'warn' * emits the event but executes anyway, 'off' skips validation entirely. */ export type ToolArgValidationMode = 'enforce' | 'warn' | 'off'; /** One schema violation. `got` is a TYPE NAME (optionally with a measured * length), never a value. */ export interface ToolArgIssue { /** Dot/bracket path from the args root, '' for the root itself. */ readonly path: string; readonly expected: string; readonly got: string; /** * A capped excerpt of the offending STRING. Present on string-shape issues * (`pattern` / `minLength` / `maxLength`) and on nothing else — see the * security note in this file's header for why those alone may echo. */ readonly value?: string; /** * The parameter's own `description` from the schema, when it declares one. * Carried on string-shape issues: the description is where an author writes * what the identifier looks like, and that sentence is the correction. */ readonly hint?: string; } export interface ToolArgValidationResult { readonly ok: boolean; readonly issues: readonly ToolArgIssue[]; } /** * Validate tool-call args against the tool's `inputSchema`. * * Total function: a malformed/exotic SCHEMA never throws — anything outside * the honest subset is ignored, so the worst a bad schema can do is * under-validate (never block a legitimate call). */ export declare function validateToolArgs(args: unknown, inputSchema: Readonly> | undefined): ToolArgValidationResult; /** * Render the MODEL-VISIBLE tool result for a rejected call. Names paths and * expectations; reports received TYPES for structural issues and the capped * offending VALUE for string-shape ones, because a shape complaint that will * not say which string it is about cannot be acted on. `JSON.stringify` quotes * and escapes the excerpt, so a multi-line argument stays one line. * * The parameter's own `description` follows on its own line when the schema * declares one: that sentence is usually the whole correction. */ export declare function formatToolArgIssues(toolName: string, issues: readonly ToolArgIssue[]): string;