1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! Structural validation of tool-call arguments against declared schemas.
//!
//! Every tool advertises a JSON Schema for its parameters (built-ins in
//! `defs.rs`, Rhai script tools via their compiled `@param` annotations, MCP
//! tools via the server's `inputSchema`). Until issue #155 nothing checked a
//! model's arguments against that schema: handlers did ad-hoc presence checks
//! that could not tell `{"path": 42}` from a missing `path`, and extra or
//! misspelled properties passed through silently. This module is the one
//! validator dispatch consults before a call is executed.
//!
//! Two properties are load-bearing:
//!
//! - **A schema that does not compile skips validation instead of refusing
//! calls.** Garbage schemas are reachable in normal operation - a typo'd
//! Rhai `@param n strng required` compiles to `{"type": "strng"}`, and MCP
//! servers may send fragments this crate cannot interpret. Refusing those
//! calls would break working tools; [`ArgValidation::SchemaUnusable`] lets
//! the caller log and dispatch anyway.
//! - **External `$ref`s never resolve.** The `jsonschema` dependency is built
//! with `default-features = false`, so a server-supplied schema referencing
//! an external URI fails to compile (and is skipped, per the point above)
//! rather than fetching over the network or filesystem at validation time.
use Value;
/// How many individual schema violations a refusal message reports before
/// summarising the rest. The message goes back to the model as a tool result;
/// three concrete violations are enough to self-correct on, and a pathological
/// call (say, a giant object where a string was expected) should not turn into
/// a pathological refusal.
const MAX_REPORTED_ERRORS: usize = 3;
/// Byte cap on each rendered violation. Validator messages embed the offending
/// instance value, which the model already has; a huge argument does not need
/// to be echoed back in full.
const MAX_ERROR_LEN: usize = 256;
/// The outcome of checking one tool call's arguments against its schema.
/// Validate `args` against `schema`, the exact parameter schema advertised to
/// the model for `tool_name`.
///
/// `Value::Null` arguments are treated as `{}`: providers substitute an empty
/// object when a model omits tool input entirely, and a null reaching here
/// means the same "no arguments" - not a JSON null argument object.
/// One violation as the model will read it: the validator's own message,
/// length-capped, prefixed with the offending argument's path when the
/// violation is not at the root.