@stackline/tool-router 1.0.3 → 1.0.5
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 +6 -0
- package/README.md +3 -3
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index.min.js +1 -1
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.5 - 2026-11-04
|
|
4
|
+
|
|
5
|
+
- Update development dependency constraints and CI runtimes for reviewed security advisories.
|
|
6
|
+
- Preserve the public runtime API; validate the packed package with the existing consumer tests.
|
|
7
|
+
|
|
8
|
+
|
|
3
9
|
## [1.0.2] - 2026-09-28
|
|
4
10
|
|
|
5
11
|
- Organize package documentation, preserve API and migration examples, and add Stackline community links.
|
package/README.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@stackline/tool-router)
|
|
6
6
|
[](https://github.com/alexandroit/stackline-tool-router)
|
|
7
|
-
[](https://github.com/alexandroit/stackline-tool-router)
|
|
8
8
|
[](https://alexandro.net/docs/vanilla/tool-router/)
|
|
9
9
|
[](https://www.reddit.com/r/Stackline/)
|
|
10
10
|
|
|
11
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
12
|
|
|
13
|
-
**Current package version:** `1.0.
|
|
13
|
+
**Current package version:** `1.0.5`
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -43,7 +43,7 @@ service. The same catalog and query produce the same ordering.
|
|
|
43
43
|
|
|
44
44
|
| Item | Value |
|
|
45
45
|
| --- | --- |
|
|
46
|
-
| Package | `@stackline/tool-router@1.0.
|
|
46
|
+
| Package | `@stackline/tool-router@1.0.5` |
|
|
47
47
|
| Node.js runtime | `>=14.17.0` |
|
|
48
48
|
| CommonJS / primary entry | `./dist/index.cjs` |
|
|
49
49
|
| ES module entry | `./dist/index.js` |
|
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.5 | 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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackline/tool-router",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Zero-dependency AI tool discovery and routing for MCP, OpenAI, Anthropic, and Gemini catalogs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"stackline",
|
|
@@ -105,5 +105,9 @@
|
|
|
105
105
|
"eslint": "10.8.1",
|
|
106
106
|
"publint": "0.3.24",
|
|
107
107
|
"typescript": "7.0.2"
|
|
108
|
+
},
|
|
109
|
+
"overrides": {
|
|
110
|
+
"glob@>=9 <14.0.3": "14.0.3",
|
|
111
|
+
"minimatch@>=7 <11.0.4": "11.0.4"
|
|
108
112
|
}
|
|
109
113
|
}
|