@van1s1mys/ai-router 1.1.0 → 1.2.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.
- package/README.md +37 -3
- package/dist/index.cjs +64 -1
- package/dist/index.d.cts +45 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +64 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,6 +32,31 @@ const result = await router.search('how to reach support?');
|
|
|
32
32
|
router.destroy(); // cleanup when done
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
## Progressive model loading
|
|
36
|
+
|
|
37
|
+
Start with a fast model, upgrade to a better one in the background:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const router = new SmartRouter({
|
|
41
|
+
routes,
|
|
42
|
+
model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'],
|
|
43
|
+
onModelUpgrade: (modelId) => console.log(`Upgraded to ${modelId}`),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await router.ready; // first model ready — search works immediately
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Instance caching & preloading
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// Pre-warm at page load
|
|
53
|
+
SmartRouter.preload({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
54
|
+
|
|
55
|
+
// Later — returns cached instance, no re-download
|
|
56
|
+
const router = SmartRouter.create({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
57
|
+
await router.ready; // instant if preload finished
|
|
58
|
+
```
|
|
59
|
+
|
|
35
60
|
## Multilingual support
|
|
36
61
|
|
|
37
62
|
The default model (`Xenova/all-MiniLM-L6-v2`) works best for English. For other languages, use the multilingual model:
|
|
@@ -50,12 +75,21 @@ const router = new SmartRouter({
|
|
|
50
75
|
| Option | Type | Default | Description |
|
|
51
76
|
|---|---|---|---|
|
|
52
77
|
| `routes` | `RouteConfig[]` | required | Routes to index |
|
|
53
|
-
| `model` | `string` | `"Xenova/all-MiniLM-L6-v2"` |
|
|
78
|
+
| `model` | `string \| string[]` | `"Xenova/all-MiniLM-L6-v2"` | Model ID or ordered array for progressive loading |
|
|
54
79
|
| `threshold` | `number` | `0.5` | Minimum similarity score (0-1) |
|
|
80
|
+
| `onModelUpgrade` | `(modelId: string) => void` | — | Called when the router switches to the next model |
|
|
81
|
+
|
|
82
|
+
### `SmartRouter.create(options): SmartRouter`
|
|
83
|
+
|
|
84
|
+
Returns a cached instance for the given model config. Safe to call on every component mount.
|
|
85
|
+
|
|
86
|
+
### `SmartRouter.preload(options): SmartRouter`
|
|
87
|
+
|
|
88
|
+
Same as `create()`, but intended to be called at page load to pre-warm the model.
|
|
55
89
|
|
|
56
90
|
### `router.ready: Promise<void>`
|
|
57
91
|
|
|
58
|
-
Resolves when the model is loaded and routes are indexed. Resolves immediately during SSR.
|
|
92
|
+
Resolves when the first model is loaded and routes are indexed. Resolves immediately during SSR.
|
|
59
93
|
|
|
60
94
|
### `router.search(query): Promise<SearchResult | null>`
|
|
61
95
|
|
|
@@ -63,7 +97,7 @@ Returns `{ path, score }` or `null` if no route meets the threshold. Returns `nu
|
|
|
63
97
|
|
|
64
98
|
### `router.destroy()`
|
|
65
99
|
|
|
66
|
-
Terminates the worker
|
|
100
|
+
Terminates the worker, cleans up resources, and removes from cache. Safe to call multiple times.
|
|
67
101
|
|
|
68
102
|
## SSR
|
|
69
103
|
|
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ function createBlobWorker() {
|
|
|
36
36
|
URL.revokeObjectURL(url);
|
|
37
37
|
return worker;
|
|
38
38
|
}
|
|
39
|
-
var
|
|
39
|
+
var _SmartRouter = class _SmartRouter {
|
|
40
40
|
/**
|
|
41
41
|
* Creates a new SmartRouter instance.
|
|
42
42
|
*
|
|
@@ -52,6 +52,7 @@ var SmartRouter = class {
|
|
|
52
52
|
this.worker = null;
|
|
53
53
|
this.pendingSearches = /* @__PURE__ */ new Map();
|
|
54
54
|
this.destroyed = false;
|
|
55
|
+
this._cacheKey = null;
|
|
55
56
|
this.ssr = !isBrowser;
|
|
56
57
|
this.readyPromise = new Promise((resolve, reject) => {
|
|
57
58
|
this.resolveReady = resolve;
|
|
@@ -64,6 +65,63 @@ var SmartRouter = class {
|
|
|
64
65
|
this.onModelUpgrade = options.onModelUpgrade;
|
|
65
66
|
this.initWorker(options);
|
|
66
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns a cached SmartRouter instance for the given options.
|
|
70
|
+
* If an instance with the same model configuration already exists and
|
|
71
|
+
* hasn't been destroyed, it is returned immediately — no new worker
|
|
72
|
+
* is spawned and no model is re-downloaded.
|
|
73
|
+
*
|
|
74
|
+
* Use this instead of `new SmartRouter()` when the router may be
|
|
75
|
+
* created multiple times (e.g. React component mounts/unmounts).
|
|
76
|
+
*
|
|
77
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* // Safe to call on every mount — returns the same instance
|
|
82
|
+
* const router = SmartRouter.create({ routes, model: 'Xenova/all-MiniLM-L6-v2' });
|
|
83
|
+
* await router.ready;
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
static create(options) {
|
|
87
|
+
const key = _SmartRouter.cacheKey(options);
|
|
88
|
+
const cached = _SmartRouter.cache.get(key);
|
|
89
|
+
if (cached && !cached.destroyed) return cached;
|
|
90
|
+
const instance = new _SmartRouter(options);
|
|
91
|
+
instance._cacheKey = key;
|
|
92
|
+
_SmartRouter.cache.set(key, instance);
|
|
93
|
+
return instance;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Pre-downloads the model(s) and indexes routes in the background
|
|
97
|
+
* so that a later {@link create} call returns an already-ready instance.
|
|
98
|
+
*
|
|
99
|
+
* Safe to call at page load — runs in a Web Worker and does not
|
|
100
|
+
* block the main thread. No-op on the server (SSR).
|
|
101
|
+
* Calling it multiple times with the same options is a no-op.
|
|
102
|
+
*
|
|
103
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
104
|
+
* @returns The pre-warming SmartRouter instance (await `.ready` if needed).
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* // At page load — start downloading the model immediately
|
|
109
|
+
* SmartRouter.preload({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
110
|
+
*
|
|
111
|
+
* // Later, when the user opens search — instant, model is already loaded
|
|
112
|
+
* const router = SmartRouter.create({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
113
|
+
* await router.ready; // resolves immediately if preload finished
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
static preload(options) {
|
|
117
|
+
return _SmartRouter.create(options);
|
|
118
|
+
}
|
|
119
|
+
/** @internal Generates a stable cache key from options. */
|
|
120
|
+
static cacheKey(options) {
|
|
121
|
+
return JSON.stringify(
|
|
122
|
+
Array.isArray(options.model) ? options.model : [options.model || "Xenova/all-MiniLM-L6-v2"]
|
|
123
|
+
);
|
|
124
|
+
}
|
|
67
125
|
/**
|
|
68
126
|
* Promise that resolves when the model is loaded and routes are indexed.
|
|
69
127
|
* Rejects if initialization fails (e.g. network error, invalid model).
|
|
@@ -195,6 +253,9 @@ var SmartRouter = class {
|
|
|
195
253
|
destroy() {
|
|
196
254
|
if (this.destroyed) return;
|
|
197
255
|
this.destroyed = true;
|
|
256
|
+
if (this._cacheKey) {
|
|
257
|
+
_SmartRouter.cache.delete(this._cacheKey);
|
|
258
|
+
}
|
|
198
259
|
this.rejectAllPending(new Error("SmartRouter destroyed"));
|
|
199
260
|
if (this.worker) {
|
|
200
261
|
try {
|
|
@@ -213,6 +274,8 @@ var SmartRouter = class {
|
|
|
213
274
|
this.pendingSearches.clear();
|
|
214
275
|
}
|
|
215
276
|
};
|
|
277
|
+
_SmartRouter.cache = /* @__PURE__ */ new Map();
|
|
278
|
+
var SmartRouter = _SmartRouter;
|
|
216
279
|
// Annotate the CommonJS export names for ESM import in node:
|
|
217
280
|
0 && (module.exports = {
|
|
218
281
|
SmartRouter
|
package/dist/index.d.cts
CHANGED
|
@@ -119,6 +119,7 @@ interface SearchResult {
|
|
|
119
119
|
* ```
|
|
120
120
|
*/
|
|
121
121
|
declare class SmartRouter {
|
|
122
|
+
private static cache;
|
|
122
123
|
private worker;
|
|
123
124
|
private readyPromise;
|
|
124
125
|
private resolveReady;
|
|
@@ -127,6 +128,50 @@ declare class SmartRouter {
|
|
|
127
128
|
private destroyed;
|
|
128
129
|
private readonly ssr;
|
|
129
130
|
private onModelUpgrade?;
|
|
131
|
+
private _cacheKey;
|
|
132
|
+
/**
|
|
133
|
+
* Returns a cached SmartRouter instance for the given options.
|
|
134
|
+
* If an instance with the same model configuration already exists and
|
|
135
|
+
* hasn't been destroyed, it is returned immediately — no new worker
|
|
136
|
+
* is spawned and no model is re-downloaded.
|
|
137
|
+
*
|
|
138
|
+
* Use this instead of `new SmartRouter()` when the router may be
|
|
139
|
+
* created multiple times (e.g. React component mounts/unmounts).
|
|
140
|
+
*
|
|
141
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* // Safe to call on every mount — returns the same instance
|
|
146
|
+
* const router = SmartRouter.create({ routes, model: 'Xenova/all-MiniLM-L6-v2' });
|
|
147
|
+
* await router.ready;
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
static create(options: RouteOptions): SmartRouter;
|
|
151
|
+
/**
|
|
152
|
+
* Pre-downloads the model(s) and indexes routes in the background
|
|
153
|
+
* so that a later {@link create} call returns an already-ready instance.
|
|
154
|
+
*
|
|
155
|
+
* Safe to call at page load — runs in a Web Worker and does not
|
|
156
|
+
* block the main thread. No-op on the server (SSR).
|
|
157
|
+
* Calling it multiple times with the same options is a no-op.
|
|
158
|
+
*
|
|
159
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
160
|
+
* @returns The pre-warming SmartRouter instance (await `.ready` if needed).
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* // At page load — start downloading the model immediately
|
|
165
|
+
* SmartRouter.preload({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
166
|
+
*
|
|
167
|
+
* // Later, when the user opens search — instant, model is already loaded
|
|
168
|
+
* const router = SmartRouter.create({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
169
|
+
* await router.ready; // resolves immediately if preload finished
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
static preload(options: RouteOptions): SmartRouter;
|
|
173
|
+
/** @internal Generates a stable cache key from options. */
|
|
174
|
+
private static cacheKey;
|
|
130
175
|
/**
|
|
131
176
|
* Creates a new SmartRouter instance.
|
|
132
177
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -119,6 +119,7 @@ interface SearchResult {
|
|
|
119
119
|
* ```
|
|
120
120
|
*/
|
|
121
121
|
declare class SmartRouter {
|
|
122
|
+
private static cache;
|
|
122
123
|
private worker;
|
|
123
124
|
private readyPromise;
|
|
124
125
|
private resolveReady;
|
|
@@ -127,6 +128,50 @@ declare class SmartRouter {
|
|
|
127
128
|
private destroyed;
|
|
128
129
|
private readonly ssr;
|
|
129
130
|
private onModelUpgrade?;
|
|
131
|
+
private _cacheKey;
|
|
132
|
+
/**
|
|
133
|
+
* Returns a cached SmartRouter instance for the given options.
|
|
134
|
+
* If an instance with the same model configuration already exists and
|
|
135
|
+
* hasn't been destroyed, it is returned immediately — no new worker
|
|
136
|
+
* is spawned and no model is re-downloaded.
|
|
137
|
+
*
|
|
138
|
+
* Use this instead of `new SmartRouter()` when the router may be
|
|
139
|
+
* created multiple times (e.g. React component mounts/unmounts).
|
|
140
|
+
*
|
|
141
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* // Safe to call on every mount — returns the same instance
|
|
146
|
+
* const router = SmartRouter.create({ routes, model: 'Xenova/all-MiniLM-L6-v2' });
|
|
147
|
+
* await router.ready;
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
static create(options: RouteOptions): SmartRouter;
|
|
151
|
+
/**
|
|
152
|
+
* Pre-downloads the model(s) and indexes routes in the background
|
|
153
|
+
* so that a later {@link create} call returns an already-ready instance.
|
|
154
|
+
*
|
|
155
|
+
* Safe to call at page load — runs in a Web Worker and does not
|
|
156
|
+
* block the main thread. No-op on the server (SSR).
|
|
157
|
+
* Calling it multiple times with the same options is a no-op.
|
|
158
|
+
*
|
|
159
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
160
|
+
* @returns The pre-warming SmartRouter instance (await `.ready` if needed).
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* // At page load — start downloading the model immediately
|
|
165
|
+
* SmartRouter.preload({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
166
|
+
*
|
|
167
|
+
* // Later, when the user opens search — instant, model is already loaded
|
|
168
|
+
* const router = SmartRouter.create({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
169
|
+
* await router.ready; // resolves immediately if preload finished
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
static preload(options: RouteOptions): SmartRouter;
|
|
173
|
+
/** @internal Generates a stable cache key from options. */
|
|
174
|
+
private static cacheKey;
|
|
130
175
|
/**
|
|
131
176
|
* Creates a new SmartRouter instance.
|
|
132
177
|
*
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ function createBlobWorker() {
|
|
|
10
10
|
URL.revokeObjectURL(url);
|
|
11
11
|
return worker;
|
|
12
12
|
}
|
|
13
|
-
var
|
|
13
|
+
var _SmartRouter = class _SmartRouter {
|
|
14
14
|
/**
|
|
15
15
|
* Creates a new SmartRouter instance.
|
|
16
16
|
*
|
|
@@ -26,6 +26,7 @@ var SmartRouter = class {
|
|
|
26
26
|
this.worker = null;
|
|
27
27
|
this.pendingSearches = /* @__PURE__ */ new Map();
|
|
28
28
|
this.destroyed = false;
|
|
29
|
+
this._cacheKey = null;
|
|
29
30
|
this.ssr = !isBrowser;
|
|
30
31
|
this.readyPromise = new Promise((resolve, reject) => {
|
|
31
32
|
this.resolveReady = resolve;
|
|
@@ -38,6 +39,63 @@ var SmartRouter = class {
|
|
|
38
39
|
this.onModelUpgrade = options.onModelUpgrade;
|
|
39
40
|
this.initWorker(options);
|
|
40
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns a cached SmartRouter instance for the given options.
|
|
44
|
+
* If an instance with the same model configuration already exists and
|
|
45
|
+
* hasn't been destroyed, it is returned immediately — no new worker
|
|
46
|
+
* is spawned and no model is re-downloaded.
|
|
47
|
+
*
|
|
48
|
+
* Use this instead of `new SmartRouter()` when the router may be
|
|
49
|
+
* created multiple times (e.g. React component mounts/unmounts).
|
|
50
|
+
*
|
|
51
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* // Safe to call on every mount — returns the same instance
|
|
56
|
+
* const router = SmartRouter.create({ routes, model: 'Xenova/all-MiniLM-L6-v2' });
|
|
57
|
+
* await router.ready;
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
static create(options) {
|
|
61
|
+
const key = _SmartRouter.cacheKey(options);
|
|
62
|
+
const cached = _SmartRouter.cache.get(key);
|
|
63
|
+
if (cached && !cached.destroyed) return cached;
|
|
64
|
+
const instance = new _SmartRouter(options);
|
|
65
|
+
instance._cacheKey = key;
|
|
66
|
+
_SmartRouter.cache.set(key, instance);
|
|
67
|
+
return instance;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Pre-downloads the model(s) and indexes routes in the background
|
|
71
|
+
* so that a later {@link create} call returns an already-ready instance.
|
|
72
|
+
*
|
|
73
|
+
* Safe to call at page load — runs in a Web Worker and does not
|
|
74
|
+
* block the main thread. No-op on the server (SSR).
|
|
75
|
+
* Calling it multiple times with the same options is a no-op.
|
|
76
|
+
*
|
|
77
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
78
|
+
* @returns The pre-warming SmartRouter instance (await `.ready` if needed).
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* // At page load — start downloading the model immediately
|
|
83
|
+
* SmartRouter.preload({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
84
|
+
*
|
|
85
|
+
* // Later, when the user opens search — instant, model is already loaded
|
|
86
|
+
* const router = SmartRouter.create({ routes, model: ['Xenova/all-MiniLM-L6-v2', 'Xenova/multilingual-e5-small'] });
|
|
87
|
+
* await router.ready; // resolves immediately if preload finished
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
static preload(options) {
|
|
91
|
+
return _SmartRouter.create(options);
|
|
92
|
+
}
|
|
93
|
+
/** @internal Generates a stable cache key from options. */
|
|
94
|
+
static cacheKey(options) {
|
|
95
|
+
return JSON.stringify(
|
|
96
|
+
Array.isArray(options.model) ? options.model : [options.model || "Xenova/all-MiniLM-L6-v2"]
|
|
97
|
+
);
|
|
98
|
+
}
|
|
41
99
|
/**
|
|
42
100
|
* Promise that resolves when the model is loaded and routes are indexed.
|
|
43
101
|
* Rejects if initialization fails (e.g. network error, invalid model).
|
|
@@ -169,6 +227,9 @@ var SmartRouter = class {
|
|
|
169
227
|
destroy() {
|
|
170
228
|
if (this.destroyed) return;
|
|
171
229
|
this.destroyed = true;
|
|
230
|
+
if (this._cacheKey) {
|
|
231
|
+
_SmartRouter.cache.delete(this._cacheKey);
|
|
232
|
+
}
|
|
172
233
|
this.rejectAllPending(new Error("SmartRouter destroyed"));
|
|
173
234
|
if (this.worker) {
|
|
174
235
|
try {
|
|
@@ -187,6 +248,8 @@ var SmartRouter = class {
|
|
|
187
248
|
this.pendingSearches.clear();
|
|
188
249
|
}
|
|
189
250
|
};
|
|
251
|
+
_SmartRouter.cache = /* @__PURE__ */ new Map();
|
|
252
|
+
var SmartRouter = _SmartRouter;
|
|
190
253
|
export {
|
|
191
254
|
SmartRouter
|
|
192
255
|
};
|
package/package.json
CHANGED