@bevel-software/platform-mcp-core 0.25.2 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/call-guards.d.ts +47 -0
  2. package/dist/call-guards.d.ts.map +1 -0
  3. package/dist/call-guards.js +215 -0
  4. package/dist/call-guards.js.map +1 -0
  5. package/dist/dispatch.d.ts +5 -1
  6. package/dist/dispatch.d.ts.map +1 -1
  7. package/dist/dispatch.js +19 -2
  8. package/dist/dispatch.js.map +1 -1
  9. package/dist/get-has-no-body.d.ts +49 -0
  10. package/dist/get-has-no-body.d.ts.map +1 -0
  11. package/dist/get-has-no-body.js +104 -0
  12. package/dist/get-has-no-body.js.map +1 -0
  13. package/dist/index.d.ts +7 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +7 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/mcp-app.d.ts +118 -0
  18. package/dist/mcp-app.d.ts.map +1 -0
  19. package/dist/mcp-app.js +126 -0
  20. package/dist/mcp-app.js.map +1 -0
  21. package/dist/meta-tools.d.ts +1 -1
  22. package/dist/meta-tools.d.ts.map +1 -1
  23. package/dist/meta-tools.js +28 -6
  24. package/dist/meta-tools.js.map +1 -1
  25. package/dist/proxied-tool.d.ts +33 -3
  26. package/dist/proxied-tool.d.ts.map +1 -1
  27. package/dist/proxied-tool.js +234 -21
  28. package/dist/proxied-tool.js.map +1 -1
  29. package/dist/results.d.ts +20 -1
  30. package/dist/results.d.ts.map +1 -1
  31. package/dist/results.js +117 -3
  32. package/dist/results.js.map +1 -1
  33. package/dist/schema-validity.d.ts +50 -0
  34. package/dist/schema-validity.d.ts.map +1 -0
  35. package/dist/schema-validity.js +254 -0
  36. package/dist/schema-validity.js.map +1 -0
  37. package/dist/tool-interface.d.ts +137 -0
  38. package/dist/tool-interface.d.ts.map +1 -0
  39. package/dist/tool-interface.js +640 -0
  40. package/dist/tool-interface.js.map +1 -0
  41. package/dist/utcp-namespace.d.ts +14 -0
  42. package/dist/utcp-namespace.d.ts.map +1 -1
  43. package/dist/utcp-namespace.js +7 -2
  44. package/dist/utcp-namespace.js.map +1 -1
  45. package/package.json +2 -1
  46. package/src/call-guards.ts +237 -0
  47. package/src/dispatch.ts +18 -1
  48. package/src/get-has-no-body.ts +110 -0
  49. package/src/index.ts +45 -0
  50. package/src/mcp-app.ts +194 -0
  51. package/src/meta-tools.ts +31 -6
  52. package/src/proxied-tool.ts +237 -19
  53. package/src/results.ts +129 -3
  54. package/src/schema-validity.ts +264 -0
  55. package/src/tool-interface.ts +673 -0
  56. package/src/utcp-namespace.ts +7 -2
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Is a connected tool's input schema valid JSON Schema?
3
+ *
4
+ * AI clients ask this question themselves, and when the answer is no they drop
5
+ * the tool WITHOUT SAYING SO: the tool is simply missing for the agent, with
6
+ * nothing in Hexis to look at. So Hexis asks it first, when a server's tools
7
+ * are loaded, and keeps such a tool off every agent surface with a marker the
8
+ * server's owner can read.
9
+ *
10
+ * The check is the JSON Schema META-SCHEMA (2020-12, the draft the MCP
11
+ * specification names), run by `ajv` — the same validator the MCP SDK and the
12
+ * clients use, so a tool is hidden on exactly the violations a client would
13
+ * also refuse, and the reason is quoted in the words the client reports. The
14
+ * three refusals this started from reproduce to the character:
15
+ *
16
+ * /properties/…/socialLinks/items/anyOf must be an array
17
+ * /properties/…/value/anyOf/0/required/0 must be a string
18
+ * /properties/…/value/properties/table/type must be equal to one of the allowed values
19
+ *
20
+ * One thing the meta-schema does not cover is checked beside it: a `pattern`
21
+ * (or a `patternProperties` key) that is not a compilable regular expression.
22
+ * The meta-schema says only that it is a string, while a client COMPILES it and
23
+ * drops the tool when that throws — see {@link regexDefect}.
24
+ *
25
+ * NOT a repair. Nothing here rewrites a schema — the proxy passes a connected
26
+ * server's schema through as sent, and an invalid one is reported, never fixed.
27
+ */
28
+ /** Where a schema is not valid JSON Schema, and why. */
29
+ export interface SchemaDefect {
30
+ /** JSON Pointer into the schema, e.g. `/properties/value/required/0`. */
31
+ path: string;
32
+ /** The violation in the validator's own words, e.g. `must be a string`. */
33
+ reason: string;
34
+ }
35
+ /**
36
+ * The first place `schema` is not valid JSON Schema, or `null` when it is.
37
+ *
38
+ * FAIL-OPEN: a schema the validator itself cannot process (an unknown
39
+ * `$schema` dialect, say) is reported as having no defect. A validator fault
40
+ * is not evidence against the tool, and the cost of being wrong here is one
41
+ * tool hidden from every agent.
42
+ */
43
+ export declare function inputSchemaDefect(schema: unknown): SchemaDefect | null;
44
+ /**
45
+ * The sentence the tool's owner reads, wherever the marker is shown — the tool
46
+ * setup page and `list_tool_setup` say the same thing in the same words,
47
+ * because they are the same finding.
48
+ */
49
+ export declare function schemaDefectMarker(defect: SchemaDefect): string;
50
+ //# sourceMappingURL=schema-validity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-validity.d.ts","sourceRoot":"","sources":["../src/schema-validity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;CAChB;AAsCD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAwBtE;AA8ID;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE/D"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Is a connected tool's input schema valid JSON Schema?
3
+ *
4
+ * AI clients ask this question themselves, and when the answer is no they drop
5
+ * the tool WITHOUT SAYING SO: the tool is simply missing for the agent, with
6
+ * nothing in Hexis to look at. So Hexis asks it first, when a server's tools
7
+ * are loaded, and keeps such a tool off every agent surface with a marker the
8
+ * server's owner can read.
9
+ *
10
+ * The check is the JSON Schema META-SCHEMA (2020-12, the draft the MCP
11
+ * specification names), run by `ajv` — the same validator the MCP SDK and the
12
+ * clients use, so a tool is hidden on exactly the violations a client would
13
+ * also refuse, and the reason is quoted in the words the client reports. The
14
+ * three refusals this started from reproduce to the character:
15
+ *
16
+ * /properties/…/socialLinks/items/anyOf must be an array
17
+ * /properties/…/value/anyOf/0/required/0 must be a string
18
+ * /properties/…/value/properties/table/type must be equal to one of the allowed values
19
+ *
20
+ * One thing the meta-schema does not cover is checked beside it: a `pattern`
21
+ * (or a `patternProperties` key) that is not a compilable regular expression.
22
+ * The meta-schema says only that it is a string, while a client COMPILES it and
23
+ * drops the tool when that throws — see {@link regexDefect}.
24
+ *
25
+ * NOT a repair. Nothing here rewrites a schema — the proxy passes a connected
26
+ * server's schema through as sent, and an invalid one is reported, never fixed.
27
+ */
28
+ import Ajv2020 from 'ajv/dist/2020.js';
29
+ /**
30
+ * One validator for the process. `strict: false` keeps this to the
31
+ * meta-schema: ajv's strict mode objects to things no client refuses (an
32
+ * unknown keyword, a `required` naming an undeclared property), and hiding a
33
+ * tool that works is worse than listing one whose schema is merely unusual.
34
+ *
35
+ * `validateFormats: false` is the same rule applied to the META-schema's own
36
+ * `format` annotations (`$id` and `$ref` as `uri-reference`, `pattern` as
37
+ * `regex`). Switching them on is INERT, which is worth knowing before anyone
38
+ * reaches for it: `validateSchema` does not assert the meta-schema's formats
39
+ * at all, so every schema gets the same verdict with `validateFormats: true`
40
+ * as with it off — including `pattern: "["`, which ajv-formats' own `regex`
41
+ * function rejects when called directly. The switch changes configuration,
42
+ * not behaviour; `__tests__/schema-validity.test.ts` pins that.
43
+ *
44
+ * It would be the wrong thing to want in any case. An AI client never
45
+ * meta-validates the schema document: the MCP SDK's validator runs
46
+ * `{ strict: false, validateFormats: true, validateSchema: false }`
47
+ * (`validation/ajv-provider.js`) — formats on the INSTANCE, the schema
48
+ * document itself never checked against the meta-schema — so a malformed
49
+ * `$id` or `$ref` compiles there without complaint, and flagging one here
50
+ * would hide a tool every client accepts. The one URI-valued construct a
51
+ * client really refuses is a `$ref` it cannot RESOLVE (`can't resolve
52
+ * reference …` out of `compile`), and no format assertion catches that one
53
+ * either; none is ever offered, because `sanitizeInputSchema` replaces an
54
+ * unresolvable or non-local `$ref` with `{}` before the listing goes out.
55
+ * Each half is pinned where it belongs: what this check does NOT flag in
56
+ * `__tests__/schema-validity.test.ts`, and what the proxy offers in place of
57
+ * such a `$ref` in `__tests__/schema-pass-through.test.ts`.
58
+ *
59
+ * So the one format that does decide a client's verdict is `regex` — a client
60
+ * COMPILES a `pattern` — and because the meta-check misses it under either
61
+ * setting, it is checked directly, below.
62
+ */
63
+ const ajv = new Ajv2020({ strict: false, allErrors: false, validateFormats: false });
64
+ /**
65
+ * The first place `schema` is not valid JSON Schema, or `null` when it is.
66
+ *
67
+ * FAIL-OPEN: a schema the validator itself cannot process (an unknown
68
+ * `$schema` dialect, say) is reported as having no defect. A validator fault
69
+ * is not evidence against the tool, and the cost of being wrong here is one
70
+ * tool hidden from every agent.
71
+ */
72
+ export function inputSchemaDefect(schema) {
73
+ // MCP requires an OBJECT input schema. `true`/`false` are legal JSON Schema
74
+ // but not legal here, and an array or a string is neither. Only `undefined`
75
+ // is ABSENT: a server that advertises `"inputSchema": null` has declared one
76
+ // and declared it wrong, which is a thing its owner wants to hear about.
77
+ if (schema === undefined)
78
+ return null; // absent: `toListedTool` supplies `{}`
79
+ if (schema === null || typeof schema !== 'object' || Array.isArray(schema)) {
80
+ return { path: '/', reason: 'must be an object' };
81
+ }
82
+ let valid;
83
+ try {
84
+ valid = ajv.validateSchema(schema);
85
+ }
86
+ catch {
87
+ return null;
88
+ }
89
+ if (!valid) {
90
+ const first = ajv.errors?.[0];
91
+ if (!first)
92
+ return null;
93
+ return {
94
+ path: first.instancePath || '/',
95
+ reason: withArticle(first.message ?? 'is not valid JSON Schema'),
96
+ };
97
+ }
98
+ return regexDefect(schema);
99
+ }
100
+ /** JSON Schema keywords whose value is a schema, or a list of schemas. */
101
+ const SCHEMA_VALUED_KEYWORDS = [
102
+ 'additionalItems',
103
+ 'additionalProperties',
104
+ 'allOf',
105
+ 'anyOf',
106
+ 'contains',
107
+ 'contentSchema',
108
+ 'else',
109
+ 'if',
110
+ 'items',
111
+ 'not',
112
+ 'oneOf',
113
+ 'prefixItems',
114
+ 'propertyNames',
115
+ 'then',
116
+ 'unevaluatedItems',
117
+ 'unevaluatedProperties',
118
+ ];
119
+ /**
120
+ * Keywords whose value is a MAP of schemas: the keys are names, the values
121
+ * schemas. `$defs`/`definitions` are NOT walked as such: an entry there is a
122
+ * schema only once a reference reaches it (ajv compiles nothing else, and the
123
+ * listing the proxy serves drops the block and inlines only what a `$ref`
124
+ * reaches), so the walk follows the references instead — see
125
+ * {@link regexDefect}.
126
+ */
127
+ const SCHEMA_MAP_KEYWORDS = ['dependentSchemas', 'patternProperties', 'properties'];
128
+ /**
129
+ * A bound on the walk below, for a schema whose shape is the sender's choice.
130
+ * It caps the QUEUE, so neither depth nor breadth can make the check cost more
131
+ * than this many entries.
132
+ */
133
+ const MAX_REGEX_CHECK_NODES = 50_000;
134
+ /**
135
+ * The first regex-bearing keyword in `schema` that does not compile, or `null`.
136
+ *
137
+ * The meta-schema does NOT catch these: `{ "type": "string", "pattern": "[" }`
138
+ * is a perfectly well-formed schema document. But a client does not merely read
139
+ * a `pattern` — it COMPILES it (the MCP SDK's own validator is `ajv.compile`),
140
+ * so that schema throws there and the tool is dropped just as silently as one
141
+ * the meta-schema rejects. Hexis has to find it for the same reason it finds
142
+ * the others.
143
+ *
144
+ * Tested with the `u` flag, which is how ajv compiles a `pattern`
145
+ * (`unicodeRegExp`, on by default) — so the verdict matches the validator the
146
+ * clients actually run rather than a looser reading. The walk is iterative and
147
+ * only ever descends through keywords whose value IS a schema, so a tool's own
148
+ * field named `pattern` (or a `pattern` string inside a `const` value) is data
149
+ * and is left alone.
150
+ *
151
+ * A `$defs`/`definitions` entry is reached only through a local `$ref` (or
152
+ * `$dynamicRef`) that names it, and reported at ITS OWN path — the place in
153
+ * the schema the server sent, which is what its owner edits. An entry nothing
154
+ * references is never compiled by a client and never listed by the proxy, so
155
+ * a bad regex in it hides no tool anywhere and is not a defect here: this
156
+ * module's contract is "hidden on exactly what a client would refuse".
157
+ */
158
+ function regexDefect(schema) {
159
+ const queue = [{ node: schema, path: '' }];
160
+ // Each node once, by path: two references to one entry are one schema.
161
+ const seen = new Set(['']);
162
+ // The cap bounds what is ENQUEUED, not only what is dequeued: a wide schema
163
+ // reaches its limit by breadth rather than depth, and a queue entry costs a
164
+ // path string that the node it describes does not. Past the cap the check
165
+ // simply stops looking, which is the fail-open rule this whole file follows.
166
+ const enqueue = (node, path) => {
167
+ if (seen.has(path) || queue.length >= MAX_REGEX_CHECK_NODES)
168
+ return;
169
+ seen.add(path);
170
+ queue.push({ node, path });
171
+ };
172
+ for (let i = 0; i < queue.length; i += 1) {
173
+ const { node, path } = queue[i];
174
+ if (typeof node.pattern === 'string' && !compiles(node.pattern)) {
175
+ return { path: `${path}/pattern`, reason: 'must be a valid regular expression' };
176
+ }
177
+ for (const keyword of ['$ref', '$dynamicRef']) {
178
+ const reference = node[keyword];
179
+ if (typeof reference !== 'string' || !reference.startsWith('#/'))
180
+ continue;
181
+ const target = resolveLocalPointer(schema, reference);
182
+ if (isSchemaObject(target))
183
+ enqueue(target, reference.slice(1));
184
+ }
185
+ for (const keyword of SCHEMA_MAP_KEYWORDS) {
186
+ const map = node[keyword];
187
+ if (!isSchemaObject(map))
188
+ continue;
189
+ for (const [key, value] of Object.entries(map)) {
190
+ if (keyword === 'patternProperties' && !compiles(key)) {
191
+ return { path: `${path}/patternProperties/${pointerPart(key)}`, reason: 'must be a valid regular expression' };
192
+ }
193
+ if (isSchemaObject(value))
194
+ enqueue(value, `${path}/${keyword}/${pointerPart(key)}`);
195
+ }
196
+ }
197
+ for (const keyword of SCHEMA_VALUED_KEYWORDS) {
198
+ const value = node[keyword];
199
+ if (Array.isArray(value)) {
200
+ value.forEach((item, index) => {
201
+ if (isSchemaObject(item))
202
+ enqueue(item, `${path}/${keyword}/${index}`);
203
+ });
204
+ }
205
+ else if (isSchemaObject(value)) {
206
+ enqueue(value, `${path}/${keyword}`);
207
+ }
208
+ }
209
+ }
210
+ return null;
211
+ }
212
+ function isSchemaObject(value) {
213
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
214
+ }
215
+ /** The node a local JSON Pointer (`#/$defs/x`) names in `root`, or undefined. */
216
+ function resolveLocalPointer(root, pointer) {
217
+ let node = root;
218
+ for (const part of pointer.slice(2).split('/')) {
219
+ if (!isSchemaObject(node) && !Array.isArray(node))
220
+ return undefined;
221
+ const key = part.replace(/~1/g, '/').replace(/~0/g, '~');
222
+ // Own members only: `#/__proto__` must name nothing, not `Object.prototype`.
223
+ if (!Object.prototype.hasOwnProperty.call(node, key))
224
+ return undefined;
225
+ node = node[key];
226
+ }
227
+ return node;
228
+ }
229
+ function compiles(pattern) {
230
+ try {
231
+ new RegExp(pattern, 'u');
232
+ return true;
233
+ }
234
+ catch {
235
+ return false;
236
+ }
237
+ }
238
+ /** A JSON Pointer path segment: `~` and `/` in a name have to be escaped. */
239
+ function pointerPart(name) {
240
+ return name.replace(/~/g, '~0').replace(/\//g, '~1');
241
+ }
242
+ /**
243
+ * The sentence the tool's owner reads, wherever the marker is shown — the tool
244
+ * setup page and `list_tool_setup` say the same thing in the same words,
245
+ * because they are the same finding.
246
+ */
247
+ export function schemaDefectMarker(defect) {
248
+ return `Hidden from agents: its schema is invalid at ${defect.path} (${defect.reason}).`;
249
+ }
250
+ /** ajv says `must be string`; a sentence a person reads says `must be a string`. */
251
+ function withArticle(message) {
252
+ return message.replace(/^must be (array|boolean|integer|null|number|object|string)$/, (_full, type) => `must be a${/^[aeiou]/.test(type) ? 'n' : ''} ${type}`);
253
+ }
254
+ //# sourceMappingURL=schema-validity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-validity.js","sourceRoot":"","sources":["../src/schema-validity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * A tool's INTERFACE, in the two forms an agent needs it: the one-line call
3
+ * example that opens every description, and the argument list a refusal shows
4
+ * when a call did not match.
5
+ *
6
+ * Both are derived from the tool's own input schema and nothing else. A
7
+ * hand-written example drifts from the schema the moment either changes, and a
8
+ * connected server's tools would have none at all — so there is one generator
9
+ * here, used by the platform's own tools, by a deployment's, and by every
10
+ * connected server's alike.
11
+ *
12
+ * Pure: no IO, no clock, no client. The surfaces that list tools call
13
+ * {@link withCallExample}; the argument check beside it (`call-guards.ts`)
14
+ * calls {@link argumentsDoNotMatchMessage}.
15
+ */
16
+ /** What every tool description starts with, on a line of its own. */
17
+ export declare const CALL_LINE_PREFIX = "Call: ";
18
+ /** The `kind` an arguments-do-not-match refusal carries, for a client that branches on it. */
19
+ export declare const ARGUMENTS_DO_NOT_MATCH_KIND = "arguments-do-not-match";
20
+ /**
21
+ * The sentence that leads the mismatches when every argument was wrapped in a
22
+ * `body` the tool does not have — the single most common wrong call, because
23
+ * the platform's own tools DO take their arguments that way and a connector
24
+ * tool's arguments are flat.
25
+ */
26
+ export declare const BODY_AT_TOP_LEVEL_LINE = "This tool takes its arguments at the top level, not under \"body\".";
27
+ /**
28
+ * The mirror of {@link BODY_AT_TOP_LEVEL_LINE}: the same mistake the other way
29
+ * round, by an agent that learned the flat shape and used it on a tool whose
30
+ * arguments ride a `body` envelope. The platform's route-hosted tools take that
31
+ * envelope, and the arguments of a flat call reach their route as query
32
+ * parameters instead of a body — which is how the route tells this apart from a
33
+ * call that simply left everything out, and can say which it was.
34
+ */
35
+ export declare const ARGS_UNDER_BODY_LINE = "This tool takes its arguments under \"body\", not at the top level.";
36
+ type Dict = Record<string, unknown>;
37
+ /**
38
+ * The arguments the call example passes: one placeholder per REQUIRED
39
+ * argument, in the order the schema requires them, and nothing else.
40
+ *
41
+ * This is the example as a VALUE, which is what makes the example testable —
42
+ * every tool the platform declares is checked with it against its own schema,
43
+ * so an example an agent copies is one the check accepts.
44
+ */
45
+ export declare function exampleArguments(inputs: unknown, depth?: number): Dict;
46
+ /**
47
+ * The call example for one tool: the namespace this connection exposes, the
48
+ * tool's name, and its required arguments with a placeholder each, in the shape
49
+ * the tool really takes.
50
+ *
51
+ * `utcpName` is the tool's registered UTCP name (`<manual>.<tool>`); the
52
+ * namespace and name come from the same mapping the chain runtime uses, so the
53
+ * example is literally callable inside `call_tool_chain`. Optional arguments
54
+ * are left out — the example is the shortest call that can work, not a catalog.
55
+ */
56
+ export declare function callExample(utcpName: string, inputs: unknown): string;
57
+ /** The `Call:` line as it appears at the top of a description. */
58
+ export declare function callLine(utcpName: string, inputs: unknown): string;
59
+ /**
60
+ * A description with its call example ahead of it. Idempotent: a description
61
+ * that already opens with a `Call:` line keeps the one it has, so a surface
62
+ * that lists the same tool through two layers cannot stack two examples.
63
+ */
64
+ export declare function withCallExample(description: string | undefined, utcpName: string, inputs: unknown): string;
65
+ /**
66
+ * Split a description into its `Call:` line and the rest, so a caller that
67
+ * prepends text of its own (the knowledge-base tools' purpose prefix) can keep
68
+ * the example first — the line only does its job if it is the first thing read.
69
+ */
70
+ export declare function splitCallLine(description: string): {
71
+ call: string | null;
72
+ rest: string;
73
+ };
74
+ /**
75
+ * The tool's interface as lines: every argument with its type, whether it is
76
+ * required, and its description — the top level, then one level below it,
77
+ * indented. This is what an agent needs in order to correct its call, and it
78
+ * is the schema's own content, never prose about it.
79
+ */
80
+ export declare function describeInterface(inputs: unknown, depth?: number, indent?: string): string[];
81
+ /**
82
+ * The whole refusal: one sentence that the arguments do not match, the
83
+ * mismatches one per line, the interface, and the call example last — the order
84
+ * an agent reads it in, ending with the line it can copy.
85
+ */
86
+ export declare function argumentsDoNotMatchMessage(toolName: string, utcpName: string, inputs: unknown, mismatches: string[], options?: {
87
+ /**
88
+ * The schema the CALL EXAMPLE is generated from, when that is not the
89
+ * schema the arguments were checked against. A route-hosted tool is checked
90
+ * against its FLAT arguments — the ones its handler receives, and so the
91
+ * ones the mismatch lines and the interface name — while the example still
92
+ * has to show the `{ body: { … } }` envelope an agent actually types.
93
+ * Default: one schema for both.
94
+ */
95
+ exampleInputs?: unknown;
96
+ }): string;
97
+ /**
98
+ * A compiled check for one input schema: either the rules to check a call
99
+ * against, or the reason this schema cannot be used for checking.
100
+ *
101
+ * Compiled once per distinct schema and kept (see {@link checkFor}), so the
102
+ * check costs a walk of the arguments and nothing else per call.
103
+ */
104
+ export type CompiledCheck = {
105
+ checkable: false;
106
+ reason: string;
107
+ } | {
108
+ checkable: true;
109
+ check: (args: Dict) => string[];
110
+ };
111
+ /**
112
+ * Compile one input schema into a check, or decide it cannot be checked.
113
+ *
114
+ * Deliberately conservative: anything this module cannot reason about with
115
+ * certainty — a combinator, a `$ref`, a schema that is not an object — switches
116
+ * the check OFF rather than guessing. A checker that refuses valid calls would
117
+ * take tools away from every agent at once, so every rule here is one a call
118
+ * cannot satisfy by any reading of the schema.
119
+ */
120
+ export declare function compileCheck(inputs: unknown, depth?: number): CompiledCheck;
121
+ /**
122
+ * Could this pattern backtrack catastrophically? True for a group that repeats
123
+ * (`*`, `+`, `{…}`) and itself contains a quantifier or an
124
+ * alternation — `(a+)+`, `(a|a)*`, `(\w+\s?)*` — and for a backreference.
125
+ *
126
+ * JavaScript's matcher backtracks, so such a pattern, which comes from a
127
+ * schema someone else wrote, could hold the event loop for seconds on one
128
+ * caller's string. The test is a conservative over-approximation (it flags
129
+ * some patterns that would in fact be fast); a flagged pattern is simply not
130
+ * asserted, which is what this module does with any keyword it cannot judge
131
+ * safely.
132
+ */
133
+ export declare function patternMayBacktrack(source: string): boolean;
134
+ /** The compiled check for one input schema, compiled at most once per schema. */
135
+ export declare function checkFor(inputs: unknown): CompiledCheck;
136
+ export {};
137
+ //# sourceMappingURL=tool-interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-interface.d.ts","sourceRoot":"","sources":["../src/tool-interface.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AAEH,qEAAqE;AACrE,eAAO,MAAM,gBAAgB,WAAW,CAAC;AAEzC,8FAA8F;AAC9F,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,wEAAsE,CAAC;AAE1G;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,wEAAsE,CAAC;AAqBxG,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAqGpC;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,SAAI,GAAG,IAAI,CAiBjE;AA4BD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAErE;AAED,kEAAkE;AAClE,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAElE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAI1G;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAKxF;AAYD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,SAAI,EAAE,MAAM,SAAK,GAAG,MAAM,EAAE,CAmBnF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,MAAM,EAAE,EACpB,OAAO,GAAE;IACP;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACpB,GACL,MAAM,CASR;AAED;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,EAAE,CAAA;CAAE,CAAC;AAkBzD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,SAAI,GAAG,aAAa,CAmFtE;AAmHD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CA6C3D;AA+CD,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,aAAa,CAOvD"}