@stackline/tool-router 1.0.1 → 1.0.3
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.
- package/CHANGELOG.md +7 -0
- package/README.md +191 -94
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index.min.js +1 -1
- package/package.json +10 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.2] - 2026-09-28
|
|
4
|
+
|
|
5
|
+
- Organize package documentation, preserve API and migration examples, and add Stackline community links.
|
|
6
|
+
- Improve package discovery keywords with precise domain terms and `stackline`.
|
|
7
|
+
- Pin GitHub Actions release tooling and require an explicit missing-version response before publication.
|
|
8
|
+
|
|
9
|
+
|
|
3
10
|
All notable changes to this project are documented in this file. The format is
|
|
4
11
|
based on Keep a Changelog and the project follows Semantic Versioning.
|
|
5
12
|
|
package/README.md
CHANGED
|
@@ -1,20 +1,79 @@
|
|
|
1
1
|
# @stackline/tool-router
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/@stackline/tool-router)
|
|
6
|
+
[](https://github.com/alexandroit/stackline-tool-router)
|
|
7
|
+
[](https://github.com/alexandroit/stackline-tool-router)
|
|
8
|
+
[](https://alexandro.net/docs/vanilla/tool-router/)
|
|
9
|
+
[](https://www.reddit.com/r/Stackline/)
|
|
10
|
+
|
|
11
|
+
**[Documentation](https://alexandro.net/docs/vanilla/tool-router/)** | **[npm](https://www.npmjs.com/package/@stackline/tool-router)** | **[Issues](https://github.com/alexandroit/stackline-tool-router/issues)** | **[Repository](https://github.com/alexandroit/stackline-tool-router)**
|
|
12
|
+
|
|
13
|
+
**Current package version:** `1.0.3`
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Why this package?
|
|
8
18
|
|
|
9
19
|
Route a user request to the smallest relevant subset of an AI tool catalog.
|
|
10
20
|
The router is local, deterministic, zero-dependency, and understands MCP,
|
|
11
21
|
OpenAI, Anthropic, Gemini, and provider-neutral definitions.
|
|
12
22
|
|
|
23
|
+
<a id="why-route-tools"></a>
|
|
24
|
+
|
|
25
|
+
### Why route tools
|
|
26
|
+
|
|
27
|
+
Large tool catalogs create three practical problems:
|
|
28
|
+
|
|
29
|
+
- definitions consume context before the task starts;
|
|
30
|
+
- similar tools become harder for a model to distinguish;
|
|
31
|
+
- sending every schema increases request size, latency, and cost.
|
|
32
|
+
|
|
33
|
+
`@stackline/tool-router` builds an in-memory BM25F-style index over names,
|
|
34
|
+
namespaces, aliases, tags, descriptions, and JSON Schema text. It adds bounded
|
|
35
|
+
prefix matching, typo tolerance, uppercase acronym recognition, and a small
|
|
36
|
+
action-synonym layer. Literal name and namespace matches remain stronger than
|
|
37
|
+
synonym matches.
|
|
38
|
+
|
|
39
|
+
The router never calls a model, embedding endpoint, database, or network
|
|
40
|
+
service. The same catalog and query produce the same ordering.
|
|
41
|
+
|
|
42
|
+
## Compatibility
|
|
43
|
+
|
|
44
|
+
| Item | Value |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| Package | `@stackline/tool-router@1.0.3` |
|
|
47
|
+
| Node.js runtime | `>=14.17.0` |
|
|
48
|
+
| CommonJS / primary entry | `./dist/index.cjs` |
|
|
49
|
+
| ES module entry | `./dist/index.js` |
|
|
50
|
+
| Type declarations | `./dist/index.d.ts` |
|
|
51
|
+
|
|
52
|
+
- Node.js 14.17 and newer;
|
|
53
|
+
- ESM and CommonJS;
|
|
54
|
+
- browsers through the `StacklineToolRouter` global build;
|
|
55
|
+
- TypeScript 3.9 through current releases;
|
|
56
|
+
- Deno and Bun through the ESM build;
|
|
57
|
+
- no runtime dependencies.
|
|
58
|
+
|
|
59
|
+
Detailed runtime and declaration guarantees are in
|
|
60
|
+
[docs/COMPATIBILITY.md](https://github.com/alexandroit/stackline-tool-router/blob/main/docs/COMPATIBILITY.md).
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
npm install @stackline/tool-router
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
69
|
+
|
|
13
70
|
```bash
|
|
14
71
|
npm install @stackline/tool-router
|
|
15
72
|
```
|
|
16
73
|
|
|
17
|
-
|
|
74
|
+
<a id="quick-start"></a>
|
|
75
|
+
|
|
76
|
+
### Quick start
|
|
18
77
|
|
|
19
78
|
```js
|
|
20
79
|
import { createToolRouter } from '@stackline/tool-router';
|
|
@@ -65,46 +124,9 @@ const response = await openai.responses.create({
|
|
|
65
124
|
No provider SDK is required by the package. Route first, then pass
|
|
66
125
|
`routed.tools` to the SDK already used by the application.
|
|
67
126
|
|
|
68
|
-
|
|
127
|
+
<a id="search-and-route"></a>
|
|
69
128
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- definitions consume context before the task starts;
|
|
73
|
-
- similar tools become harder for a model to distinguish;
|
|
74
|
-
- sending every schema increases request size, latency, and cost.
|
|
75
|
-
|
|
76
|
-
`@stackline/tool-router` builds an in-memory BM25F-style index over names,
|
|
77
|
-
namespaces, aliases, tags, descriptions, and JSON Schema text. It adds bounded
|
|
78
|
-
prefix matching, typo tolerance, uppercase acronym recognition, and a small
|
|
79
|
-
action-synonym layer. Literal name and namespace matches remain stronger than
|
|
80
|
-
synonym matches.
|
|
81
|
-
|
|
82
|
-
The router never calls a model, embedding endpoint, database, or network
|
|
83
|
-
service. The same catalog and query produce the same ordering.
|
|
84
|
-
|
|
85
|
-
## Supported definitions
|
|
86
|
-
|
|
87
|
-
| Source | Recognized shape | Returned by `route()` |
|
|
88
|
-
| --- | --- | --- |
|
|
89
|
-
| MCP | `{ name, inputSchema }` | original MCP tool |
|
|
90
|
-
| OpenAI Responses | `{ type: 'function', name, parameters }` | original Responses tool |
|
|
91
|
-
| OpenAI Chat | `{ type: 'function', function: { ... } }` | original Chat tool |
|
|
92
|
-
| Anthropic | `{ name, input_schema }` | original Anthropic tool |
|
|
93
|
-
| Gemini | `{ name, parameters }` or `functionDeclarations` | original Gemini declaration |
|
|
94
|
-
| Canonical | `{ name, inputSchema }` or `{ name, schema }` | original object |
|
|
95
|
-
|
|
96
|
-
Provider envelopes are accepted directly:
|
|
97
|
-
|
|
98
|
-
```js
|
|
99
|
-
const openaiRouter = createToolRouter({ tools: openaiTools });
|
|
100
|
-
const geminiRouter = createToolRouter({ functionDeclarations });
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Keep one provider-compatible catalog per outbound request. The package
|
|
104
|
-
normalizes definitions for retrieval; it does not rewrite JSON Schema dialects
|
|
105
|
-
or convert one provider's wire format into another.
|
|
106
|
-
|
|
107
|
-
## Search and route
|
|
129
|
+
### Search and route
|
|
108
130
|
|
|
109
131
|
Use `search` when ranking evidence matters:
|
|
110
132
|
|
|
@@ -151,7 +173,35 @@ Token counts are transparent estimates based on JSON character length divided
|
|
|
151
173
|
by four. They are useful for relative budgets, not a replacement for a
|
|
152
174
|
provider-specific tokenizer.
|
|
153
175
|
|
|
154
|
-
##
|
|
176
|
+
## Features and Integrations
|
|
177
|
+
|
|
178
|
+
<a id="supported-definitions"></a>
|
|
179
|
+
|
|
180
|
+
### Supported definitions
|
|
181
|
+
|
|
182
|
+
| Source | Recognized shape | Returned by `route()` |
|
|
183
|
+
| --- | --- | --- |
|
|
184
|
+
| MCP | `{ name, inputSchema }` | original MCP tool |
|
|
185
|
+
| OpenAI Responses | `{ type: 'function', name, parameters }` | original Responses tool |
|
|
186
|
+
| OpenAI Chat | `{ type: 'function', function: { ... } }` | original Chat tool |
|
|
187
|
+
| Anthropic | `{ name, input_schema }` | original Anthropic tool |
|
|
188
|
+
| Gemini | `{ name, parameters }` or `functionDeclarations` | original Gemini declaration |
|
|
189
|
+
| Canonical | `{ name, inputSchema }` or `{ name, schema }` | original object |
|
|
190
|
+
|
|
191
|
+
Provider envelopes are accepted directly:
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
const openaiRouter = createToolRouter({ tools: openaiTools });
|
|
195
|
+
const geminiRouter = createToolRouter({ functionDeclarations });
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Keep one provider-compatible catalog per outbound request. The package
|
|
199
|
+
normalizes definitions for retrieval; it does not rewrite JSON Schema dialects
|
|
200
|
+
or convert one provider's wire format into another.
|
|
201
|
+
|
|
202
|
+
<a id="dynamic-catalogs"></a>
|
|
203
|
+
|
|
204
|
+
### Dynamic catalogs
|
|
155
205
|
|
|
156
206
|
Updates maintain postings and document frequencies without rebuilding the
|
|
157
207
|
router:
|
|
@@ -169,7 +219,9 @@ router.clear();
|
|
|
169
219
|
By default, duplicate IDs throw `ERR_TOOL_DUPLICATE`. Tool IDs use an explicit
|
|
170
220
|
`id` when present, otherwise `namespace:name`, otherwise `name`.
|
|
171
221
|
|
|
172
|
-
|
|
222
|
+
<a id="byot-discovery-helper"></a>
|
|
223
|
+
|
|
224
|
+
### BYOT discovery helper
|
|
173
225
|
|
|
174
226
|
`createToolSearch` creates a compact search function and an executor for
|
|
175
227
|
bring-your-own-tool discovery loops:
|
|
@@ -192,7 +244,9 @@ Targets are `canonical`, `mcp`, `openai-responses`, `openai-chat`,
|
|
|
192
244
|
schemas. Applications decide how selected tools are admitted into the next
|
|
193
245
|
model request.
|
|
194
246
|
|
|
195
|
-
|
|
247
|
+
<a id="ranking-controls"></a>
|
|
248
|
+
|
|
249
|
+
### Ranking controls
|
|
196
250
|
|
|
197
251
|
Default field weights favor intent-bearing identifiers:
|
|
198
252
|
|
|
@@ -234,7 +288,9 @@ const router = createToolRouter(tools, {
|
|
|
234
288
|
Set `synonyms: false` for literal-only retrieval. Custom tokenizers are also
|
|
235
289
|
supported and receive both indexed text and queries.
|
|
236
290
|
|
|
237
|
-
|
|
291
|
+
<a id="catalog-metadata"></a>
|
|
292
|
+
|
|
293
|
+
### Catalog metadata
|
|
238
294
|
|
|
239
295
|
Canonical metadata improves routing without changing provider payloads:
|
|
240
296
|
|
|
@@ -253,27 +309,9 @@ const tool = {
|
|
|
253
309
|
For provider definitions, metadata can be placed on the outer tool object.
|
|
254
310
|
The original object is returned unchanged and by reference.
|
|
255
311
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
| Export | Purpose |
|
|
259
|
-
| --- | --- |
|
|
260
|
-
| `createToolRouter(tools, options)` | build a mutable in-memory router |
|
|
261
|
-
| `router.search(query, options)` | ranked matches with evidence |
|
|
262
|
-
| `router.select(query, options)` | original tool definitions only |
|
|
263
|
-
| `router.route(query, options)` | selected tools plus budget metrics |
|
|
264
|
-
| `router.add/remove/replace/clear` | update a live catalog |
|
|
265
|
-
| `router.get/list/has/stats` | inspect the normalized catalog |
|
|
266
|
-
| `routeTools(tools, query, options)` | one-shot routing helper |
|
|
267
|
-
| `createToolSearch(router, options)` | provider-shaped discovery function |
|
|
268
|
-
| `normalizeTool/normalizeTools` | inspect canonical retrieval records |
|
|
269
|
-
| `detectToolFormat(tool)` | detect a supported provider shape |
|
|
270
|
-
| `estimateToolTokens(tool)` | bounded provider-neutral size estimate |
|
|
271
|
-
| `tokenize/normalizeText` | use the default text pipeline directly |
|
|
272
|
-
|
|
273
|
-
Every validation error is a `ToolRouterError` with a stable `code` beginning
|
|
274
|
-
with `ERR_TOOL_`.
|
|
312
|
+
<a id="evaluation-and-performance"></a>
|
|
275
313
|
|
|
276
|
-
|
|
314
|
+
### Evaluation and performance
|
|
277
315
|
|
|
278
316
|
The repository includes the complete corpus and benchmark command:
|
|
279
317
|
|
|
@@ -293,7 +331,29 @@ catalog vocabulary, descriptions, aliases, and query distribution materially
|
|
|
293
331
|
change the result. Run the included benchmark with representative tools before
|
|
294
332
|
choosing production limits.
|
|
295
333
|
|
|
296
|
-
|
|
334
|
+
<a id="documentation"></a>
|
|
335
|
+
|
|
336
|
+
### Documentation
|
|
337
|
+
|
|
338
|
+
- [Live routing workbench](https://alexandro.net/docs/vanilla/tool-router/)
|
|
339
|
+
- [OpenAI, Anthropic, Gemini, and MCP integrations](https://github.com/alexandroit/stackline-tool-router/blob/main/docs/INTEGRATIONS.md)
|
|
340
|
+
- [Evaluation and benchmark methodology](https://github.com/alexandroit/stackline-tool-router/blob/main/docs/BENCHMARKS.md)
|
|
341
|
+
- [Executable provider examples](https://github.com/alexandroit/stackline-tool-router/blob/main/examples)
|
|
342
|
+
- [Architecture](https://github.com/alexandroit/stackline-tool-router/blob/main/docs/ARCHITECTURE.md)
|
|
343
|
+
- [Market research](https://github.com/alexandroit/stackline-tool-router/blob/main/docs/MARKET_RESEARCH.md)
|
|
344
|
+
- [Stackline open-source catalog](https://alexandro.net/docs/open-source/)
|
|
345
|
+
- [Changelog](https://github.com/alexandroit/stackline-tool-router/blob/main/CHANGELOG.md)
|
|
346
|
+
- [Contributing](https://github.com/alexandroit/stackline-tool-router/blob/main/CONTRIBUTING.md)
|
|
347
|
+
|
|
348
|
+
Examples are included in the npm tarball and build provider request objects
|
|
349
|
+
without credentials or network calls. This makes format compatibility
|
|
350
|
+
executable before an application connects its own SDK.
|
|
351
|
+
|
|
352
|
+
## Security
|
|
353
|
+
|
|
354
|
+
<a id="security-and-limits"></a>
|
|
355
|
+
|
|
356
|
+
### Security and limits
|
|
297
357
|
|
|
298
358
|
Tool definitions are untrusted input. The implementation:
|
|
299
359
|
|
|
@@ -308,37 +368,74 @@ Tool definitions are untrusted input. The implementation:
|
|
|
308
368
|
- has zero runtime dependencies and performs no network access.
|
|
309
369
|
|
|
310
370
|
Defaults are intended for ordinary provider schemas. Raise limits only for a
|
|
311
|
-
catalog that has already been validated. See [SECURITY.md](SECURITY.md) for
|
|
371
|
+
catalog that has already been validated. See [SECURITY.md](https://github.com/alexandroit/stackline-tool-router/blob/main/SECURITY.md) for
|
|
312
372
|
private vulnerability reporting.
|
|
313
373
|
|
|
314
|
-
##
|
|
374
|
+
## API Surface
|
|
315
375
|
|
|
316
|
-
|
|
317
|
-
- ESM and CommonJS;
|
|
318
|
-
- browsers through the `StacklineToolRouter` global build;
|
|
319
|
-
- TypeScript 3.9 through current releases;
|
|
320
|
-
- Deno and Bun through the ESM build;
|
|
321
|
-
- no runtime dependencies.
|
|
376
|
+
<a id="api"></a>
|
|
322
377
|
|
|
323
|
-
|
|
324
|
-
|
|
378
|
+
### API
|
|
379
|
+
|
|
380
|
+
| Export | Purpose |
|
|
381
|
+
| --- | --- |
|
|
382
|
+
| `createToolRouter(tools, options)` | build a mutable in-memory router |
|
|
383
|
+
| `router.search(query, options)` | ranked matches with evidence |
|
|
384
|
+
| `router.select(query, options)` | original tool definitions only |
|
|
385
|
+
| `router.route(query, options)` | selected tools plus budget metrics |
|
|
386
|
+
| `router.add/remove/replace/clear` | update a live catalog |
|
|
387
|
+
| `router.get/list/has/stats` | inspect the normalized catalog |
|
|
388
|
+
| `routeTools(tools, query, options)` | one-shot routing helper |
|
|
389
|
+
| `createToolSearch(router, options)` | provider-shaped discovery function |
|
|
390
|
+
| `normalizeTool/normalizeTools` | inspect canonical retrieval records |
|
|
391
|
+
| `detectToolFormat(tool)` | detect a supported provider shape |
|
|
392
|
+
| `estimateToolTokens(tool)` | bounded provider-neutral size estimate |
|
|
393
|
+
| `tokenize/normalizeText` | use the default text pipeline directly |
|
|
325
394
|
|
|
326
|
-
|
|
395
|
+
Every validation error is a `ToolRouterError` with a stable `code` beginning
|
|
396
|
+
with `ERR_TOOL_`.
|
|
327
397
|
|
|
328
|
-
|
|
329
|
-
- [OpenAI, Anthropic, Gemini, and MCP integrations](docs/INTEGRATIONS.md)
|
|
330
|
-
- [Evaluation and benchmark methodology](docs/BENCHMARKS.md)
|
|
331
|
-
- [Executable provider examples](examples)
|
|
332
|
-
- [Architecture](docs/ARCHITECTURE.md)
|
|
333
|
-
- [Market research](docs/MARKET_RESEARCH.md)
|
|
334
|
-
- [Stackline open-source catalog](https://alexandro.net/docs/open-source/)
|
|
335
|
-
- [Changelog](CHANGELOG.md)
|
|
336
|
-
- [Contributing](CONTRIBUTING.md)
|
|
398
|
+
## Local Development
|
|
337
399
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
400
|
+
```sh
|
|
401
|
+
git clone https://github.com/alexandroit/stackline-tool-router.git
|
|
402
|
+
cd stackline-tool-router
|
|
403
|
+
npm ci
|
|
404
|
+
npm run test
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Release tooling uses Node.js 24.20.0 and npm 11.19.0. The consumer runtime contract remains the one documented above.
|
|
408
|
+
|
|
409
|
+
## Consumer Smoke Test
|
|
410
|
+
|
|
411
|
+
Run the repository's existing consumer/package check after installing development dependencies:
|
|
412
|
+
|
|
413
|
+
```sh
|
|
414
|
+
npm run test:install
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
## Release Checklist
|
|
418
|
+
|
|
419
|
+
Run `npm run test` and inspect the package contents before release. Publish a new version through the [GitHub Actions publishing workflow](https://github.com/alexandroit/stackline-tool-router/actions/workflows/publish.yml), using the SHA-512 digest of the reviewed tarball. Verify the exact published version, tarball integrity, and npm provenance after the run.
|
|
341
420
|
|
|
342
421
|
## License
|
|
343
422
|
|
|
344
|
-
[MIT](LICENSE)
|
|
423
|
+
[MIT](https://github.com/alexandroit/stackline-tool-router/blob/main/LICENSE)
|
|
424
|
+
|
|
425
|
+
## Credits and original authors
|
|
426
|
+
|
|
427
|
+
- Alexandro Paixao Marques.
|
|
428
|
+
- Copyright (c) 2026 Alexandro Paixao Marques.
|
|
429
|
+
- Stackline maintenance: [Alexandro Paixao Marques](https://www.linkedin.com/in/aleinfo/) and [Stackline contributors](https://github.com/alexandroit).
|
|
430
|
+
|
|
431
|
+
Original copyright, license notices and contributor acknowledgements remain part of this distribution. Stackline maintenance does not replace authorship of the original work.
|
|
432
|
+
|
|
433
|
+
## Community and Links
|
|
434
|
+
|
|
435
|
+
- [Stackline website](https://alexandro.net/)
|
|
436
|
+
- [GitHub projects](https://github.com/alexandroit)
|
|
437
|
+
- [npm packages](https://www.npmjs.com/~alex360qc)
|
|
438
|
+
- [Reddit community — r/Stackline](https://www.reddit.com/r/Stackline/)
|
|
439
|
+
- [Maintainer LinkedIn](https://www.linkedin.com/in/aleinfo/)
|
|
440
|
+
|
|
441
|
+
Use this repository's issue tracker for reproducible bugs and feature requests. Join r/Stackline for examples, usage questions and release discussions.
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
package/dist/index.min.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/*! @stackline/tool-router v1.0.
|
|
1
|
+
/*! @stackline/tool-router v1.0.2 | MIT */
|
|
2
2
|
var StacklineToolRouter=(()=>{var X=Object.defineProperty;var Oe=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var xe=Object.prototype.hasOwnProperty;var be=(t,e)=>{for(var n in e)X(t,n,{get:e[n],enumerable:!0})},Re=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ye(e))!xe.call(t,i)&&i!==n&&X(t,i,{get:()=>e[i],enumerable:!(o=Oe(e,i))||o.enumerable});return t};var Ee=t=>Re(X({},"__esModule",{value:!0}),t);var Qe={};be(Qe,{TOOL_FORMATS:()=>G,ToolRouter:()=>$,ToolRouterError:()=>F,createToolRouter:()=>H,createToolSearch:()=>se,default:()=>Ge,defineTool:()=>ie,detectToolFormat:()=>Q,estimateToolTokens:()=>oe,normalizeIdentifier:()=>S,normalizeText:()=>q,normalizeTool:()=>j,normalizeTools:()=>v,routeTools:()=>ne,tokenize:()=>k});var F=class extends Error{constructor(e,n,o){super(n),this.name="ToolRouterError",this.code=e,o!==void 0&&(this.details=o)}};function f(t,e,n){throw new F(t,e,n)}var Le=new Set(["__proto__","prototype","constructor"]);function Se(t){return typeof t=="string"&&Le.has(t)}function y(t){return t!==null&&typeof t=="object"}function d(t,e){if(!y(t)&&typeof t!="function")return;let n=Object.getOwnPropertyDescriptor(t,e);return n&&Object.prototype.hasOwnProperty.call(n,"value")?n.value:void 0}function P(t){if(!y(t))return[];let e=Object.getOwnPropertyDescriptors(t),n=[];for(let o of Object.keys(e)){let i=e[o];!i.enumerable||!Object.prototype.hasOwnProperty.call(i,"value")||Se(o)||n.push([o,i.value])}return n}function N(t,e=""){return typeof t=="string"?t:e}function w(t,e=256){if(!Array.isArray(t))return[];let n=[];for(let o=0;o<t.length&&n.length<e;o++){let i=d(t,String(o));typeof i=="string"&&i.length>0&&n.push(i)}return n}function b(t,e,n,o){return t===void 0?e:((!Number.isInteger(t)||t<1||t>n)&&f("ERR_TOOL_ROUTER_OPTION",`${o} must be an integer between 1 and ${n}`),t)}function I(t,e,n,o,i){return t===void 0?e:((typeof t!="number"||!Number.isFinite(t)||t<n||t>o)&&f("ERR_TOOL_ROUTER_OPTION",`${i} must be a finite number between ${n} and ${o}`),t)}var G=Object.freeze(["canonical","mcp","openai-chat","openai-responses","anthropic","gemini"]);function Ae(t){if(!(t===void 0||t==="auto"))return G.includes(t)||f("ERR_TOOL_FORMAT",`Unsupported tool format: ${String(t)}`),t}function Q(t){y(t)||f("ERR_TOOL_DEFINITION","Tool definition must be an object");let e=d(t,"type"),n=d(t,"function");if(e==="function"&&y(n))return"openai-chat";if(e==="function"&&typeof d(t,"name")=="string")return"openai-responses";if(d(t,"input_schema")!==void 0)return"anthropic";if(d(t,"inputSchema")!==void 0)return"mcp";if(d(t,"parameters")!==void 0)return"gemini";if(typeof d(t,"name")=="string")return"canonical";f("ERR_TOOL_FORMAT","Unable to detect the tool definition format")}function ze(t,e){if(e==="openai-chat"){let n=d(t,"function");return y(n)||f("ERR_TOOL_DEFINITION","OpenAI Chat tool.function must be an object"),n}return t}function we(t,e){return e==="mcp"||e==="canonical"?d(t,"inputSchema")===void 0?d(t,"schema"):d(t,"inputSchema"):e==="anthropic"?d(t,"input_schema"):d(t,"parameters")}function ke(t,e){if(e==="mcp"||e==="canonical")return d(t,"outputSchema")}function Ne(t){for(let e of["__",".","/"]){let n=t.indexOf(e);if(n>0)return t.slice(0,n)}return""}function j(t,e={}){y(t)||f("ERR_TOOL_DEFINITION","Tool definition must be an object"),y(e)||f("ERR_TOOL_ROUTER_OPTION","Normalization options must be an object");let n=Ae(e.format)||Q(t),o=ze(t,n),i=N(d(o,"name"));i.length===0&&f("ERR_TOOL_NAME","Tool name must be a non-empty string"),i.length>512&&f("ERR_TOOL_NAME","Tool name must not exceed 512 characters");let s=N(d(o,"description")),a=N(d(t,"namespace"))||N(d(o,"namespace"))||Ne(i),l=N(d(t,"id"))||N(d(o,"id"))||(a?`${a}:${i}`:i),m=w(d(t,"tags")).concat(w(d(o,"tags"))),g=w(d(t,"aliases")).concat(w(d(o,"aliases")));return Object.freeze({aliases:Object.freeze(Array.from(new Set(g))),description:s,format:n,id:l,inputSchema:we(o,n),name:i,namespace:a,original:t,outputSchema:ke(o,n),tags:Object.freeze(Array.from(new Set(m)))})}function Ie(t){if(Array.isArray(t))return t;y(t)||f("ERR_TOOL_CATALOG","Tool catalog must be an array or provider envelope");let e=d(t,"tools");if(Array.isArray(e))return e;let n=d(t,"functionDeclarations");if(Array.isArray(n))return n;f("ERR_TOOL_CATALOG","Tool catalog envelope must contain tools or functionDeclarations")}function v(t,e={}){y(e)||f("ERR_TOOL_ROUTER_OPTION","Normalization options must be an object");let n=Ie(t),o=b(e.maxTools,1e5,1e6,"maxTools");n.length>o&&f("ERR_TOOL_CATALOG_SIZE",`Tool catalog exceeds maxTools (${o})`);let i=[];for(let s=0;s<n.length;s++){let c=Object.getOwnPropertyDescriptor(n,String(s));if(!c||!Object.prototype.hasOwnProperty.call(c,"value"))continue;let a=c.value;if(y(a)&&Array.isArray(d(a,"functionDeclarations"))){let r=d(a,"functionDeclarations");r.length>o-i.length&&f("ERR_TOOL_CATALOG_SIZE",`Tool catalog exceeds maxTools (${o})`);for(let l=0;l<r.length;l++){let m=Object.getOwnPropertyDescriptor(r,String(l));m&&Object.prototype.hasOwnProperty.call(m,"value")&&i.push(j(m.value,{format:"gemini"}))}}else i.push(j(a,e))}return i}var je=new Set(["title","description","$comment","format","pattern","const"]),ae=new Set(["enum","examples","required"]);function ce(t,e={}){if(!y(t)&&typeof t!="boolean")return"";let n=e.maxSchemaDepth===void 0?24:e.maxSchemaDepth,o=e.maxSchemaNodes===void 0?1e4:e.maxSchemaNodes,i=e.maxTextLength===void 0?65536:e.maxTextLength,s=new WeakSet,c=[],a=0,r=0;function l(){a+=1,a>o&&f("ERR_TOOL_SCHEMA_SIZE",`Tool schema exceeds maxSchemaNodes (${o})`)}function m(h){if(typeof h!="string"&&typeof h!="number")return;let u=String(h);if(u.length===0||r>=i)return;let T=i-r,_=u.slice(0,T);c.push(_),r+=_.length+1}function g(h,u,T){if(u>n&&f("ERR_TOOL_SCHEMA_DEPTH",`Tool schema exceeds maxSchemaDepth (${n})`),l(),!y(h)||s.has(h))return;if(s.add(h),Array.isArray(h)){h.length>o-a&&f("ERR_TOOL_SCHEMA_SIZE",`Tool schema exceeds maxSchemaNodes (${o})`);for(let p=0;p<h.length;p++){let O=Object.getOwnPropertyDescriptor(h,String(p));!O||!Object.prototype.hasOwnProperty.call(O,"value")||(ae.has(T)?(l(),m(O.value)):g(O.value,u+1,T))}return}let _=P(h);_.length>o-a&&f("ERR_TOOL_SCHEMA_SIZE",`Tool schema exceeds maxSchemaNodes (${o})`);for(let[p,O]of _)(T==="properties"||T==="$defs"||T==="definitions")&&m(p),je.has(p)?(l(),m(O)):(ae.has(p)&&Array.isArray(O),g(O,u+1,p))}return g(t,0,""),c.join(" ")}function ee(t,e={}){let n=e.maxDepth===void 0?64:e.maxDepth,o=e.maxNodes===void 0?1e5:e.maxNodes,i=new WeakSet,s=0;function c(r){return JSON.stringify(r).length}function a(r,l){if(l>n&&f("ERR_TOOL_VALUE_DEPTH",`Tool definition exceeds maxDepth (${n})`),s+=1,s>o&&f("ERR_TOOL_VALUE_SIZE",`Tool definition exceeds maxNodes (${o})`),r===null)return 4;if(typeof r=="string")return c(r);if(typeof r=="number")return Number.isFinite(r)?String(r).length:4;if(typeof r=="boolean")return r?4:5;if(typeof r=="bigint"&&f("ERR_TOOL_VALUE_TYPE","Tool definition cannot contain bigint values"),typeof r=="undefined"||typeof r=="function"||typeof r=="symbol")return 0;i.has(r)&&f("ERR_TOOL_CYCLIC","Tool definition must be JSON-serializable"),i.add(r);let m=2,g=0;if(Array.isArray(r)){r.length>o-s&&f("ERR_TOOL_VALUE_SIZE",`Tool definition exceeds maxNodes (${o})`);for(let h=0;h<r.length;h++){let u=Object.getOwnPropertyDescriptor(r,String(h)),T=u&&Object.prototype.hasOwnProperty.call(u,"value")?u.value:null;m+=a(T,l+1)+(g>0?1:0),g+=1}}else{let h=P(r);h.length>o-s&&f("ERR_TOOL_VALUE_SIZE",`Tool definition exceeds maxNodes (${o})`);for(let[u,T]of h){let _=a(T,l+1);_===0&&(T===void 0||typeof T=="function"||typeof T=="symbol")||(m+=c(u)+1+_+(g>0?1:0),g+=1)}}return i.delete(r),m}return Math.max(1,Math.ceil(a(t,0)/4))}var Me=/[\u0300-\u036f]/g,De=/([\p{Ll}\p{N}])([\p{Lu}])/gu,Fe=/([\p{Lu}]+)([\p{Lu}][\p{Ll}])/gu,$e=/[\p{L}\p{N}]+/gu,fe=/[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uac00-\ud7af]/u;function q(t){if(typeof t!="string")return"";let e=t;return typeof e.normalize=="function"&&(e=e.normalize("NFKD")),e.replace(Me,"").replace(Fe,"$1 $2").replace(De,"$1 $2").toLocaleLowerCase("en-US")}function S(t){return q(t).replace(/[^\p{L}\p{N}]+/gu,"")}function k(t,e={}){let n=e.maxTokenLength===void 0?64:e.maxTokenLength;(!Number.isInteger(n)||n<2||n>256)&&f("ERR_TOOL_ROUTER_OPTION","maxTokenLength must be an integer between 2 and 256");let i=q(t).match($e)||[],s=[];for(let c of i){let a=c.slice(0,n);if((a.length>1||fe.test(a))&&s.push(a),a.length>2&&fe.test(a)){let r=Array.from(a);for(let l=0;l<r.length-1;l++)s.push(`${r[l]}${r[l+1]}`)}}return s}function Z(t){let e=Array.from(` ${t} `),n=[];for(let o=0;o<=e.length-3;o++)n.push(e.slice(o,o+3).join(""));return n}function le(t,e,n){let o=Array.from(t),i=Array.from(e);if(Math.abs(o.length-i.length)>n)return n+1;if(o.length===0)return Math.min(i.length,n+1);if(i.length===0)return Math.min(o.length,n+1);let s=new Array(i.length+1);for(let c=0;c<=i.length;c++)s[c]=c;for(let c=1;c<=o.length;c++){let a=new Array(i.length+1);a[0]=c;let r=a[0];for(let l=1;l<=i.length;l++){let m=s[l-1]+(o[c-1]===i[l-1]?0:1),g=a[l-1]+1,h=s[l]+1;a[l]=Math.min(m,g,h),r=Math.min(r,a[l])}if(r>n)return n+1;s=a}return s[i.length]}var M=Object.freeze(["name","namespace","aliases","tags","description","schema"]),me=Object.freeze({aliases:7,description:2,name:10,namespace:8,schema:1,tags:5}),Ue=Object.freeze([["cancel","close","delete","remove"],["create","add","make","new","open","schedule"],["download","fetch","get","read","retrieve"],["find","discover","look","lookup","query","search"],["list","browse","show"],["send","deliver","post","publish"],["update","change","edit","modify","set"],["available","availability","free"],["conversation","conversations","message","messages"],["document","documents","file","files","page","pages"]]);function Ce(t){let e=Object.create(null);for(let n of M){let o=t&&Object.prototype.hasOwnProperty.call(t,n)?t[n]:me[n];e[n]=I(o,me[n],0,100,`fieldWeights.${n}`)}return Object.freeze(e)}function Pe(t){t!==void 0&&t!==!1&&!y(t)&&f("ERR_TOOL_ROUTER_OPTION","synonyms must be false or an object of string arrays");let e=new Map;function n(i){let s=Array.from(new Set(i.filter(c=>typeof c=="string"&&c.length>1)));for(let c of s){let a=e.get(c);a||(a=new Set,e.set(c,a));for(let r of s)r!==c&&a.add(r)}}if(t!==!1)for(let i of Ue)n(i);if(y(t))for(let[i,s]of P(t)){let c=k(i)[0];if(!c)continue;typeof s!="string"&&!Array.isArray(s)&&f("ERR_TOOL_ROUTER_OPTION",`synonyms.${i} must be a string or array of strings`);let a=[];for(let r of w(typeof s=="string"?[s]:s))a.push(...k(r));n([c,...a])}let o=Object.create(null);for(let[i,s]of e)o[i]=Object.freeze(Array.from(s));return Object.freeze(o)}function ve(t={}){(t===null||typeof t!="object")&&f("ERR_TOOL_ROUTER_OPTION","Router options must be an object");let e=t.tokenizer===void 0?k:t.tokenizer;typeof e!="function"&&f("ERR_TOOL_ROUTER_OPTION","tokenizer must be a function");let n=t.onDuplicate===void 0?"error":t.onDuplicate;return n!=="error"&&n!=="replace"&&f("ERR_TOOL_ROUTER_OPTION","onDuplicate must be error or replace"),Object.freeze({b:I(t.b,.75,0,1,"b"),fieldWeights:Ce(t.fieldWeights),format:t.format,fuzzy:t.fuzzy===void 0?!0:!!t.fuzzy,k1:I(t.k1,1.2,.1,5,"k1"),maxExpansions:b(t.maxExpansions,12,100,"maxExpansions"),maxQueryLength:b(t.maxQueryLength,4096,65536,"maxQueryLength"),maxSchemaDepth:b(t.maxSchemaDepth,24,256,"maxSchemaDepth"),maxSchemaNodes:b(t.maxSchemaNodes,1e4,1e6,"maxSchemaNodes"),maxTextLength:b(t.maxTextLength,65536,1e6,"maxTextLength"),maxTools:b(t.maxTools,1e5,1e6,"maxTools"),minFuzzyLength:b(t.minFuzzyLength,4,32,"minFuzzyLength"),onDuplicate:n,synonyms:Pe(t.synonyms),tokenizer:e})}function de(t){let e=new Map;for(let n of t)e.set(n,(e.get(n)||0)+1);return e}function qe(t){return`${t} ${S(t)}`}function Ze(t){let e=k(t).filter(o=>o.length>0),n=new Set;if(e.length>1){n.add(e.map(o=>Array.from(o)[0]).join(""));for(let o=0;o<e.length-1;o++)for(let i=o+2;i<=Math.min(e.length,o+6);i++)n.add(e.slice(o,i).map(s=>Array.from(s)[0]).join(""))}return n}function Ye(t){let e=[],n=t.match(/\b[A-Z][A-Z0-9]{1,7}\b/g)||[];for(let o of n)e.push(`acr:${o.toLocaleLowerCase("en-US")}`);return e}function V(t){if(t===void 0)return;let e=typeof t=="string"?[t]:t;return Array.isArray(e)||f("ERR_TOOL_ROUTER_OPTION","Search filters must be strings or arrays of strings"),new Set(w(e,1e4))}function ue(t){let e=V(t.ids),n=V(t.namespaces),o=V(t.formats),i=V(t.tags),s=t.filter;return s!==void 0&&typeof s!="function"&&f("ERR_TOOL_ROUTER_OPTION","filter must be a function"),c=>{if(e&&!e.has(c.id)||n&&!n.has(c.namespace)||o&&!o.has(c.format))return!1;if(i){for(let a of i)if(!c.tags.includes(a))return!1}return s===void 0||!!s(c)}}function te(t,e,n,o,i,s=!1){return Object.freeze({estimatedTokens:t.estimatedTokens,id:t.record.id,matchedFields:Object.freeze(Array.from(o).sort()),matchedTerms:Object.freeze(Array.from(n).sort()),name:t.record.name,pinned:s,queryCoverage:i,record:t.record,score:e===null?null:Number(e.toFixed(6)),tool:t.record.original})}var $=class t{constructor(e=[],n={}){this._options=ve(n),this._documents=new Map,this._postings=new Map,this._prefixes=new Map,this._trigrams=new Map,this._fieldTotals=Object.create(null);for(let o of M)this._fieldTotals[o]=0;this._estimatedTokens=0,!(Array.isArray(e)&&e.length===0)&&this.add(e)}get size(){return this._documents.size}get options(){return this._options}add(e,n={}){let o=y(e)&&(Array.isArray(d(e,"tools"))||Array.isArray(d(e,"functionDeclarations")))||Array.isArray(e)?e:[e],s=v(o,{format:n.format===void 0?this._options.format:n.format,maxTools:this._options.maxTools}).map(r=>this._prepare(r)),c=new Set;for(let r of s)c.has(r.record.id)&&f("ERR_TOOL_DUPLICATE",`Duplicate tool id in batch: ${r.record.id}`),c.add(r.record.id),this._documents.has(r.record.id)&&this._options.onDuplicate==="error"&&f("ERR_TOOL_DUPLICATE",`Tool id already exists: ${r.record.id}`);let a=this._documents.size;for(let r of c)this._documents.has(r)||(a+=1);a>this._options.maxTools&&f("ERR_TOOL_CATALOG_SIZE",`Tool catalog exceeds maxTools (${this._options.maxTools})`);for(let r of s)this._documents.has(r.record.id)&&this._removeDocument(r.record.id),this._addDocument(r);return this}remove(e){let n=Array.isArray(e)?e:[e],o=0;for(let i of n){typeof i!="string"&&f("ERR_TOOL_NAME","Tool id must be a string");let s=this._resolveDocument(i);s&&this._removeDocument(s.record.id)&&(o+=1)}return o}replace(e,n={}){let o=new t([],this._options);return o.add(e,n),this._documents=o._documents,this._postings=o._postings,this._prefixes=o._prefixes,this._trigrams=o._trigrams,this._fieldTotals=o._fieldTotals,this._estimatedTokens=o._estimatedTokens,this}clear(){this._documents.clear(),this._postings.clear(),this._prefixes.clear(),this._trigrams.clear();for(let e of M)this._fieldTotals[e]=0;return this._estimatedTokens=0,this}has(e){return!!this._resolveDocument(e)}get(e){let n=this._resolveDocument(e);return n?n.record:void 0}list(){return Array.from(this._documents.values(),e=>e.record)}stats(){return Object.freeze({estimatedTokens:this._estimatedTokens,fields:Object.freeze({...this._fieldTotals}),terms:this._postings.size,tools:this.size})}search(e,n={}){typeof e!="string"&&f("ERR_TOOL_QUERY","Search query must be a string"),e.length>this._options.maxQueryLength&&f("ERR_TOOL_QUERY_SIZE",`Search query exceeds maxQueryLength (${this._options.maxQueryLength})`);let o=b(n.limit,5,1e3,"limit"),i=I(n.minScore,.01,0,Number.MAX_SAFE_INTEGER,"minScore"),s=this._tokenize(e).concat(Ye(e));if(s.length===0||this.size===0)return[];let c=de(s),a=new Map,r=ue(n),l=new Map;for(let[_,p]of c){let O=this._expand(_),x=new Map;for(let[E,A]of O){let R=this._postings.get(E);if(!R)continue;let D=R.size,he=Math.log(1+(this.size-D+.5)/(D+.5));for(let[C,pe]of R){let B=this._documents.get(C);if(!B)continue;let Y=l.get(C);if(Y===void 0&&(Y=r(B.record),l.set(C,Y)),!Y)continue;let W=0,J=[];for(let z of M){let re=pe[z]||0;if(re===0||this._options.fieldWeights[z]===0)continue;let ge=this._fieldTotals[z]/Math.max(1,this.size),Te=1-this._options.b+this._options.b*(B.fieldLengths[z]/ge);W+=this._options.fieldWeights[z]*re/Te,J.push(z)}if(W===0)continue;let _e=W*(this._options.k1+1)/(W+this._options.k1),K=he*_e*A*(1+Math.log(p)),L=x.get(C);if(L||(L={contribution:0,fields:new Set,terms:new Set},x.set(C,L)),K>L.contribution)L.contribution=K,L.fields=new Set(J);else if(K===L.contribution)for(let z of J)L.fields.add(z);L.terms.add(E)}}for(let[E,A]of x){let R=a.get(E);R||(R={fields:new Set,queryTerms:new Set,score:0,terms:new Set},a.set(E,R)),R.score+=A.contribution,R.queryTerms.add(_);for(let D of A.terms)R.terms.add(D);for(let D of A.fields)R.fields.add(D)}}let m=S(e),g=[];for(let[_,p]of a){let O=this._documents.get(_),x=p.score;m&&O.identifiers.has(m)?x+=12:m&&O.identifiersText.includes(m)&&(x+=2);for(let A of c.keys())O.nameTokens.has(A)&&(x+=1.5),O.namespaceTokens.has(A)&&(x+=2);let E=p.queryTerms.size/c.size;x=x*(.65+.35*E)+E,!(x<i)&&g.push({document:O,score:x,state:p,coverage:E})}g.sort((_,p)=>p.score-_.score||_.document.record.name.localeCompare(p.document.record.name)||_.document.record.id.localeCompare(p.document.record.id));let h=[],u=0,T=n.maxEstimatedTokens===void 0?1/0:I(n.maxEstimatedTokens,1/0,1,Number.MAX_SAFE_INTEGER,"maxEstimatedTokens");for(let _ of g){if(h.length>=o)break;u+_.document.estimatedTokens>T||(h.push(te(_.document,_.score,_.state.terms,_.state.fields,Number(_.coverage.toFixed(6)))),u+=_.document.estimatedTokens)}return h}select(e,n={}){return this.search(e,n).map(o=>o.tool)}route(e,n={}){let o=b(n.maxTools,5,1e3,"maxTools"),i=n.maxEstimatedTokens===void 0?1/0:I(n.maxEstimatedTokens,1/0,1,Number.MAX_SAFE_INTEGER,"maxEstimatedTokens"),s=[],c=new Set,a=0,r=!1,l=n.pinned===void 0?[]:typeof n.pinned=="string"?[n.pinned]:n.pinned;Array.isArray(l)||f("ERR_TOOL_ROUTER_OPTION","pinned must be a string or array of strings");for(let u of l){if(s.length>=o)break;let T=this._resolveDocument(u);!T||c.has(T.record.id)||(s.push(te(T,null,new Set,new Set,0,!0)),c.add(T.record.id),a+=T.estimatedTokens,a>i&&(r=!0))}let m=this.search(e,{...n,limit:Math.min(1e3,Math.max(o,o*4)),maxEstimatedTokens:void 0});for(let u of m){if(s.length>=o)break;c.has(u.id)||a+u.estimatedTokens>i||(s.push(u),c.add(u.id),a+=u.estimatedTokens)}let g=n.fallback===void 0?"none":n.fallback;if(["none","first","all"].includes(g)||f("ERR_TOOL_ROUTER_OPTION","fallback must be none, first, or all"),s.length===0&&g!=="none"){let u=ue(n),T=Array.from(this._documents.values()).filter(p=>u(p.record)).sort((p,O)=>p.record.id.localeCompare(O.record.id)),_=g==="first"?1:o;for(let p of T){if(s.length>=_)break;a+p.estimatedTokens>i||(s.push(te(p,null,new Set,new Set,0)),c.add(p.record.id),a+=p.estimatedTokens)}}let h=this._estimatedTokens===0?0:Math.max(0,1-a/this._estimatedTokens);return Object.freeze({budgetExceeded:r,catalogEstimatedTokens:this._estimatedTokens,catalogSize:this.size,estimatedTokens:a,matches:Object.freeze(s),records:Object.freeze(s.map(u=>u.record)),selectedCount:s.length,tokenReduction:Number(h.toFixed(6)),tools:Object.freeze(s.map(u=>u.tool))})}_prepare(e){let n=ce(e.inputSchema,this._options),o={aliases:e.aliases.join(" "),description:e.description,name:qe(e.name),namespace:e.namespace,schema:n,tags:e.tags.join(" ")},i=Object.create(null),s=Object.create(null),c=new Set([S(e.name)]);for(let r of e.aliases)c.add(S(r));e.namespace&&c.add(S(`${e.namespace} ${e.name}`)),c.delete("");let a=0;for(let r of M){a+=o[r].length,(o[r].length>this._options.maxTextLength||a>this._options.maxTextLength*2)&&f("ERR_TOOL_TEXT_SIZE",`Tool ${e.id} exceeds maxTextLength (${this._options.maxTextLength})`);let l=this._tokenize(o[r]);i[r]=de(l),s[r]=l.length}for(let r of Ze(e.name)){let l=`acr:${r}`;i.name.set(l,(i.name.get(l)||0)+1),s.name+=1}return{estimatedTokens:ee(e.original),fieldLengths:s,fieldTokens:i,identifiers:c,identifiersText:Array.from(c).join(" "),nameTokens:new Set(this._tokenize(e.name)),namespaceTokens:new Set(this._tokenize(e.namespace)),record:e}}_tokenize(e){let n=this._options.tokenizer(e);Array.isArray(n)||f("ERR_TOOL_TOKENIZER","tokenizer must return an array of strings");let o=[];for(let i of n)typeof i!="string"&&f("ERR_TOOL_TOKENIZER","tokenizer results must be strings"),i.length>0&&i.length<=256&&o.push(i);return o}_addDocument(e){this._documents.set(e.record.id,e),this._estimatedTokens+=e.estimatedTokens;for(let n of M){this._fieldTotals[n]+=e.fieldLengths[n];for(let[o,i]of e.fieldTokens[n]){let s=this._postings.get(o),c=!s;s||(s=new Map,this._postings.set(o,s));let a=s.get(e.record.id);a||(a=Object.create(null),s.set(e.record.id,a)),a[n]=i,c&&this._addLexiconTerm(o)}}}_removeDocument(e){let n=this._documents.get(e);if(!n)return!1;this._documents.delete(e),this._estimatedTokens-=n.estimatedTokens;for(let o of M){this._fieldTotals[o]-=n.fieldLengths[o];for(let i of n.fieldTokens[o].keys()){let s=this._postings.get(i);s&&(s.delete(e),s.size===0&&(this._postings.delete(i),this._removeLexiconTerm(i)))}}return!0}_addLexiconTerm(e){let n=Math.min(8,e.length);for(let o=2;o<=n;o++){let i=e.slice(0,o),s=this._prefixes.get(i);s||(s=new Set,this._prefixes.set(i,s)),s.add(e)}for(let o of new Set(Z(e))){let i=this._trigrams.get(o);i||(i=new Set,this._trigrams.set(o,i)),i.add(e)}}_removeLexiconTerm(e){let n=Math.min(8,e.length);for(let o=2;o<=n;o++){let i=e.slice(0,o),s=this._prefixes.get(i);s&&(s.delete(e),s.size===0&&this._prefixes.delete(i))}for(let o of new Set(Z(e))){let i=this._trigrams.get(o);i&&(i.delete(e),i.size===0&&this._trigrams.delete(o))}}_expand(e){let n=new Map;this._addLiteralExpansions(n,e,1);let o=this._options.synonyms[e];if(o)for(let r of o)this._addLiteralExpansions(n,r,.72);if(n.size>0||!this._options.fuzzy||e.length<this._options.minFuzzyLength)return new Map(Array.from(n).sort((r,l)=>l[1]-r[1]||r[0].localeCompare(l[0])).slice(0,this._options.maxExpansions));let i=new Set(Z(e)),s=new Map;for(let r of i){let l=this._trigrams.get(r);if(l)for(let m of l)s.set(m,(s.get(m)||0)+1)}let c=[],a=e.length<=5?1:2;for(let[r,l]of s){let m=new Set(Z(r)),g=l/(i.size+m.size-l);if(g<.25)continue;let h=le(e,r,a);if(h>a)continue;let u=1-h/Math.max(e.length,r.length);c.push({term:r,weight:.55+.25*u,similarity:g})}c.sort((r,l)=>l.similarity-r.similarity||l.weight-r.weight||r.term.localeCompare(l.term));for(let r of c.slice(0,this._options.maxExpansions))n.set(r.term,r.weight);return n}_addLiteralExpansions(e,n,o){if(this._postings.has(n)&&e.set(n,Math.max(o,e.get(n)||0)),n.length<3)return;let i=n.slice(0,Math.min(8,n.length)),s=this._prefixes.get(i);if(!s)return;let c=Array.from(s).filter(a=>a.startsWith(n)&&a!==n).sort((a,r)=>Math.abs(a.length-n.length)-Math.abs(r.length-n.length)||a.localeCompare(r));for(let a of c.slice(0,this._options.maxExpansions))e.set(a,Math.max(o*.78,e.get(a)||0))}_resolveDocument(e){if(typeof e!="string")return;let n=this._documents.get(e);if(n)return n;let o;for(let i of this._documents.values())i.record.name===e&&(!o||i.record.id.localeCompare(o.record.id)<0)&&(o=i);return o}};function H(t=[],e={}){return new $(t,e)}function ne(t,e,n={}){let o=n.router||{},i={...n};return delete i.router,H(t,o).route(e,i)}function oe(t){return ee(t)}function ie(t){return j(t).original}var U=Object.freeze({additionalProperties:!1,properties:{limit:{description:"Maximum number of matching tool summaries to return.",maximum:25,minimum:1,type:"integer"},query:{description:"Capability, action, service, or resource needed for the task.",minLength:1,type:"string"}},required:["query"],type:"object"});function We(t,e,n){if(t==="openai-responses")return{type:"function",name:e,description:n,parameters:U};if(t==="openai-chat")return{type:"function",function:{name:e,description:n,parameters:U}};if(t==="anthropic")return{name:e,description:n,input_schema:U};if(t==="gemini")return{name:e,description:n,parameters:U};if(t==="mcp")return{name:e,description:n,inputSchema:U};if(t==="canonical")return{name:e,description:n,inputSchema:U};f("ERR_TOOL_FORMAT",`Unsupported search tool target: ${String(t)}`)}function se(t,e={}){(!t||typeof t.search!="function")&&f("ERR_TOOL_ROUTER","createToolSearch requires a ToolRouter instance");let n=e.target===void 0?"canonical":e.target,o=e.name===void 0?"search_tools":e.name,i=e.description===void 0?"Find the smallest set of available tools relevant to a capability or task.":e.description;(typeof o!="string"||o.length===0)&&f("ERR_TOOL_NAME","Search tool name must be a non-empty string"),typeof i!="string"&&f("ERR_TOOL_DEFINITION","Search tool description must be a string");let s=e.limit===void 0?5:e.limit;(!Number.isInteger(s)||s<1||s>25)&&f("ERR_TOOL_ROUTER_OPTION","Search tool limit must be an integer between 1 and 25");let c=We(n,o,i);return Object.freeze({definition:c,execute(a){(!a||typeof a!="object"||typeof a.query!="string"||a.query.length===0)&&f("ERR_TOOL_QUERY","Search tool input.query must be a non-empty string");let r=a.limit===void 0?s:a.limit;(!Number.isInteger(r)||r<1||r>25)&&f("ERR_TOOL_QUERY","Search tool input.limit must be an integer between 1 and 25");let l=t.search(a.query,{limit:r});return Object.freeze({catalogSize:t.size,query:a.query,tools:Object.freeze(l.map(m=>Object.freeze({description:m.record.description,id:m.id,name:m.name,namespace:m.record.namespace||void 0,score:m.score,tags:m.record.tags})))})}})}var Ge=Object.freeze({TOOL_FORMATS:G,ToolRouter:$,ToolRouterError:F,createToolRouter:H,createToolSearch:se,defineTool:ie,detectToolFormat:Q,estimateToolTokens:oe,normalizeIdentifier:S,normalizeText:q,normalizeTool:j,normalizeTools:v,routeTools:ne,tokenize:k});return Ee(Qe);})();
|
|
3
3
|
//# sourceMappingURL=index.min.js.map
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackline/tool-router",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Zero-dependency AI tool discovery and routing for MCP, OpenAI, Anthropic, and Gemini catalogs",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"stackline",
|
|
7
|
+
"npm-package",
|
|
8
|
+
"tool-router",
|
|
9
|
+
"typescript",
|
|
10
|
+
"nodejs",
|
|
6
11
|
"ai",
|
|
7
12
|
"agents",
|
|
8
13
|
"tool-routing",
|
|
@@ -15,8 +20,9 @@
|
|
|
15
20
|
"anthropic",
|
|
16
21
|
"gemini",
|
|
17
22
|
"bm25",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
23
|
+
"zero-dependency",
|
|
24
|
+
"tool-calling",
|
|
25
|
+
"routing"
|
|
20
26
|
],
|
|
21
27
|
"license": "MIT",
|
|
22
28
|
"author": {
|
|
@@ -97,7 +103,7 @@
|
|
|
97
103
|
"c8": "12.0.0",
|
|
98
104
|
"esbuild": "0.28.2",
|
|
99
105
|
"eslint": "10.8.1",
|
|
100
|
-
"publint": "0.3.
|
|
106
|
+
"publint": "0.3.24",
|
|
101
107
|
"typescript": "7.0.2"
|
|
102
108
|
}
|
|
103
109
|
}
|