@microfox/ai-router 2.1.1 → 2.1.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 +12 -0
- package/dist/index.d.mts +15 -5
- package/dist/index.d.ts +15 -5
- package/dist/index.js +139 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +139 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @microfox/ai-router
|
|
2
2
|
|
|
3
|
+
## 2.1.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4d3a677: Triggered by issue #46: release @microfox/ai-router patch
|
|
8
|
+
|
|
9
|
+
## 2.1.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 56b7b6e: Changes from PR #36: middlewar-changes-before-after
|
|
14
|
+
|
|
3
15
|
## 2.1.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -130,6 +130,7 @@ type Layer<METADATA extends Record<string, any> = Record<string, any>, ContextSt
|
|
|
130
130
|
path: string | RegExp;
|
|
131
131
|
handler: AiMiddleware<METADATA, ContextState, PARAMS, PARTS, TOOLS>;
|
|
132
132
|
isAgent: boolean;
|
|
133
|
+
timing?: 'before' | 'after';
|
|
133
134
|
hasDynamicParams?: boolean;
|
|
134
135
|
paramNames?: string[];
|
|
135
136
|
};
|
|
@@ -212,13 +213,21 @@ declare class AiRouter<KIT_METADATA extends Record<string, any> = Record<string,
|
|
|
212
213
|
*/
|
|
213
214
|
agent<const TAgents extends (AiMiddleware<any, any, any, any, any> | AiRouter<any, any, any, any, any, any>)[]>(agentPath: string | RegExp | AiMiddleware<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS>, ...agents: TAgents): AiRouter<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS, REGISTERED_TOOLS & (TAgents[number] extends AiRouter<any, any, any, any, any, infer R> ? R : {})>;
|
|
214
215
|
/**
|
|
215
|
-
*
|
|
216
|
-
*
|
|
216
|
+
* Registers middleware that runs BEFORE agent execution for a specific path prefix, regex pattern, or wildcard.
|
|
217
|
+
* The middleware can modify the context and must call `next()` to pass control to the next handler.
|
|
217
218
|
*
|
|
218
|
-
* @param
|
|
219
|
+
* @param mountPathArg The path prefix, regex pattern, or "*" for wildcard matching.
|
|
219
220
|
* @param handler The middleware function or AiAgentKit router instance to mount.
|
|
220
221
|
*/
|
|
221
|
-
|
|
222
|
+
before<THandler extends AiMiddleware<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS> | AiRouter<any, any, any, any, any, any>>(mountPathArg: string | RegExp, handler: THandler): AiRouter<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS, REGISTERED_TOOLS & (THandler extends AiRouter<any, any, any, any, any, infer R> ? R : {})>;
|
|
223
|
+
/**
|
|
224
|
+
* Registers middleware that runs AFTER agent execution for a specific path prefix, regex pattern, or wildcard.
|
|
225
|
+
* The middleware can modify the context and must call `next()` to pass control to the next handler.
|
|
226
|
+
*
|
|
227
|
+
* @param mountPathArg The path prefix, regex pattern, or "*" for wildcard matching.
|
|
228
|
+
* @param handler The middleware function or AiAgentKit router instance to mount.
|
|
229
|
+
*/
|
|
230
|
+
after<THandler extends AiMiddleware<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS> | AiRouter<any, any, any, any, any, any>>(mountPathArg: string | RegExp, handler: THandler): AiRouter<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS, REGISTERED_TOOLS & (THandler extends AiRouter<any, any, any, any, any, infer R> ? R : {})>;
|
|
222
231
|
/**
|
|
223
232
|
* Pre-defines the schema and description for an agent when it is used as a tool by an LLM.
|
|
224
233
|
* This allows `next.agentAsTool()` to create a valid `Tool` object without needing the definition at call time.
|
|
@@ -242,8 +251,9 @@ declare class AiRouter<KIT_METADATA extends Record<string, any> = Record<string,
|
|
|
242
251
|
*/
|
|
243
252
|
registry(): {
|
|
244
253
|
map: Record<string, {
|
|
245
|
-
|
|
254
|
+
before: any[];
|
|
246
255
|
agents: any[];
|
|
256
|
+
after: any[];
|
|
247
257
|
}>;
|
|
248
258
|
tools: REGISTERED_TOOLS;
|
|
249
259
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -130,6 +130,7 @@ type Layer<METADATA extends Record<string, any> = Record<string, any>, ContextSt
|
|
|
130
130
|
path: string | RegExp;
|
|
131
131
|
handler: AiMiddleware<METADATA, ContextState, PARAMS, PARTS, TOOLS>;
|
|
132
132
|
isAgent: boolean;
|
|
133
|
+
timing?: 'before' | 'after';
|
|
133
134
|
hasDynamicParams?: boolean;
|
|
134
135
|
paramNames?: string[];
|
|
135
136
|
};
|
|
@@ -212,13 +213,21 @@ declare class AiRouter<KIT_METADATA extends Record<string, any> = Record<string,
|
|
|
212
213
|
*/
|
|
213
214
|
agent<const TAgents extends (AiMiddleware<any, any, any, any, any> | AiRouter<any, any, any, any, any, any>)[]>(agentPath: string | RegExp | AiMiddleware<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS>, ...agents: TAgents): AiRouter<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS, REGISTERED_TOOLS & (TAgents[number] extends AiRouter<any, any, any, any, any, infer R> ? R : {})>;
|
|
214
215
|
/**
|
|
215
|
-
*
|
|
216
|
-
*
|
|
216
|
+
* Registers middleware that runs BEFORE agent execution for a specific path prefix, regex pattern, or wildcard.
|
|
217
|
+
* The middleware can modify the context and must call `next()` to pass control to the next handler.
|
|
217
218
|
*
|
|
218
|
-
* @param
|
|
219
|
+
* @param mountPathArg The path prefix, regex pattern, or "*" for wildcard matching.
|
|
219
220
|
* @param handler The middleware function or AiAgentKit router instance to mount.
|
|
220
221
|
*/
|
|
221
|
-
|
|
222
|
+
before<THandler extends AiMiddleware<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS> | AiRouter<any, any, any, any, any, any>>(mountPathArg: string | RegExp, handler: THandler): AiRouter<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS, REGISTERED_TOOLS & (THandler extends AiRouter<any, any, any, any, any, infer R> ? R : {})>;
|
|
223
|
+
/**
|
|
224
|
+
* Registers middleware that runs AFTER agent execution for a specific path prefix, regex pattern, or wildcard.
|
|
225
|
+
* The middleware can modify the context and must call `next()` to pass control to the next handler.
|
|
226
|
+
*
|
|
227
|
+
* @param mountPathArg The path prefix, regex pattern, or "*" for wildcard matching.
|
|
228
|
+
* @param handler The middleware function or AiAgentKit router instance to mount.
|
|
229
|
+
*/
|
|
230
|
+
after<THandler extends AiMiddleware<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS> | AiRouter<any, any, any, any, any, any>>(mountPathArg: string | RegExp, handler: THandler): AiRouter<KIT_METADATA, ContextState, PARAMS, PARTS, TOOLS, REGISTERED_TOOLS & (THandler extends AiRouter<any, any, any, any, any, infer R> ? R : {})>;
|
|
222
231
|
/**
|
|
223
232
|
* Pre-defines the schema and description for an agent when it is used as a tool by an LLM.
|
|
224
233
|
* This allows `next.agentAsTool()` to create a valid `Tool` object without needing the definition at call time.
|
|
@@ -242,8 +251,9 @@ declare class AiRouter<KIT_METADATA extends Record<string, any> = Record<string,
|
|
|
242
251
|
*/
|
|
243
252
|
registry(): {
|
|
244
253
|
map: Record<string, {
|
|
245
|
-
|
|
254
|
+
before: any[];
|
|
246
255
|
agents: any[];
|
|
256
|
+
after: any[];
|
|
247
257
|
}>;
|
|
248
258
|
tools: REGISTERED_TOOLS;
|
|
249
259
|
};
|
package/dist/index.js
CHANGED
|
@@ -329,6 +329,9 @@ function extractPathParams(pattern, path2) {
|
|
|
329
329
|
});
|
|
330
330
|
return params;
|
|
331
331
|
}
|
|
332
|
+
function hasDynamicParams(pattern) {
|
|
333
|
+
return /\/:[^\/]+/.test(pattern);
|
|
334
|
+
}
|
|
332
335
|
var AiRouter = class _AiRouter {
|
|
333
336
|
/**
|
|
334
337
|
* Constructs a new AiAgentKit router.
|
|
@@ -389,28 +392,45 @@ var AiRouter = class _AiRouter {
|
|
|
389
392
|
for (const handler of agents) {
|
|
390
393
|
if (typeof handler !== "function") {
|
|
391
394
|
if (handler instanceof _AiRouter && typeof prefix === "string") {
|
|
392
|
-
|
|
395
|
+
const router = handler;
|
|
396
|
+
const mountPath = prefix.toString().replace(/\/$/, "");
|
|
397
|
+
router.stack.forEach((layer) => {
|
|
398
|
+
const layerPath = layer.path.toString();
|
|
399
|
+
const relativeLayerPath = layerPath.startsWith("/") ? layerPath.substring(1) : layerPath;
|
|
400
|
+
const newPath = import_path.default.posix.join(mountPath, relativeLayerPath);
|
|
401
|
+
this.stack.push({ ...layer, path: newPath });
|
|
402
|
+
});
|
|
403
|
+
router.actAsToolDefinitions.forEach((value, key) => {
|
|
404
|
+
const keyPath = key.toString();
|
|
405
|
+
const relativeKeyPath = keyPath.startsWith("/") ? keyPath.substring(1) : keyPath;
|
|
406
|
+
const newKey = import_path.default.posix.join(mountPath, relativeKeyPath);
|
|
407
|
+
this.actAsToolDefinitions.set(newKey, value);
|
|
408
|
+
});
|
|
393
409
|
}
|
|
394
410
|
continue;
|
|
395
411
|
}
|
|
412
|
+
const hasDynamic = typeof prefix === "string" ? hasDynamicParams(prefix) : false;
|
|
413
|
+
const paramNames = typeof prefix === "string" && hasDynamic ? parsePathPattern(prefix).paramNames : void 0;
|
|
396
414
|
this.stack.push({
|
|
397
415
|
path: prefix,
|
|
398
416
|
handler,
|
|
399
|
-
isAgent: true
|
|
417
|
+
isAgent: true,
|
|
400
418
|
// Mark as an agent
|
|
419
|
+
hasDynamicParams: hasDynamic,
|
|
420
|
+
paramNames
|
|
401
421
|
});
|
|
402
422
|
this.logger?.log(`Agent registered: path=${prefix}`);
|
|
403
423
|
}
|
|
404
424
|
return this;
|
|
405
425
|
}
|
|
406
426
|
/**
|
|
407
|
-
*
|
|
408
|
-
*
|
|
427
|
+
* Registers middleware that runs BEFORE agent execution for a specific path prefix, regex pattern, or wildcard.
|
|
428
|
+
* The middleware can modify the context and must call `next()` to pass control to the next handler.
|
|
409
429
|
*
|
|
410
|
-
* @param
|
|
430
|
+
* @param mountPathArg The path prefix, regex pattern, or "*" for wildcard matching.
|
|
411
431
|
* @param handler The middleware function or AiAgentKit router instance to mount.
|
|
412
432
|
*/
|
|
413
|
-
|
|
433
|
+
before(mountPathArg, handler) {
|
|
414
434
|
if (mountPathArg instanceof RegExp && handler instanceof _AiRouter) {
|
|
415
435
|
throw new AiKitError(
|
|
416
436
|
"[AiAgentKit] Mounting a router on a RegExp path is not supported."
|
|
@@ -435,8 +455,50 @@ var AiRouter = class _AiRouter {
|
|
|
435
455
|
this.stack.push({
|
|
436
456
|
path: mountPathArg,
|
|
437
457
|
handler,
|
|
438
|
-
isAgent: false
|
|
458
|
+
isAgent: false,
|
|
439
459
|
// Middleware is not a terminal agent
|
|
460
|
+
timing: "before"
|
|
461
|
+
// Mark as before middleware
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
return this;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Registers middleware that runs AFTER agent execution for a specific path prefix, regex pattern, or wildcard.
|
|
468
|
+
* The middleware can modify the context and must call `next()` to pass control to the next handler.
|
|
469
|
+
*
|
|
470
|
+
* @param mountPathArg The path prefix, regex pattern, or "*" for wildcard matching.
|
|
471
|
+
* @param handler The middleware function or AiAgentKit router instance to mount.
|
|
472
|
+
*/
|
|
473
|
+
after(mountPathArg, handler) {
|
|
474
|
+
if (mountPathArg instanceof RegExp && handler instanceof _AiRouter) {
|
|
475
|
+
throw new AiKitError(
|
|
476
|
+
"[AiAgentKit] Mounting a router on a RegExp path is not supported."
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
if (handler instanceof _AiRouter) {
|
|
480
|
+
const router = handler;
|
|
481
|
+
const mountPath = mountPathArg.toString().replace(/\/$/, "");
|
|
482
|
+
router.stack.forEach((layer) => {
|
|
483
|
+
const layerPath = layer.path.toString();
|
|
484
|
+
const relativeLayerPath = layerPath.startsWith("/") ? layerPath.substring(1) : layerPath;
|
|
485
|
+
const newPath = import_path.default.posix.join(mountPath, relativeLayerPath);
|
|
486
|
+
this.stack.push({ ...layer, path: newPath });
|
|
487
|
+
});
|
|
488
|
+
router.actAsToolDefinitions.forEach((value, key) => {
|
|
489
|
+
const keyPath = key.toString();
|
|
490
|
+
const relativeKeyPath = keyPath.startsWith("/") ? keyPath.substring(1) : keyPath;
|
|
491
|
+
const newKey = import_path.default.posix.join(mountPath, relativeKeyPath);
|
|
492
|
+
this.actAsToolDefinitions.set(newKey, value);
|
|
493
|
+
});
|
|
494
|
+
} else {
|
|
495
|
+
this.stack.push({
|
|
496
|
+
path: mountPathArg,
|
|
497
|
+
handler,
|
|
498
|
+
isAgent: false,
|
|
499
|
+
// Middleware is not a terminal agent
|
|
500
|
+
timing: "after"
|
|
501
|
+
// Mark as after middleware
|
|
440
502
|
});
|
|
441
503
|
}
|
|
442
504
|
return this;
|
|
@@ -502,7 +564,7 @@ var AiRouter = class _AiRouter {
|
|
|
502
564
|
for (const layer of this.stack) {
|
|
503
565
|
const pathKey = layer.path.toString();
|
|
504
566
|
if (!registryMap[pathKey]) {
|
|
505
|
-
registryMap[pathKey] = {
|
|
567
|
+
registryMap[pathKey] = { before: [], agents: [], after: [] };
|
|
506
568
|
}
|
|
507
569
|
if (layer.isAgent) {
|
|
508
570
|
const agentInfo = {
|
|
@@ -516,9 +578,17 @@ var AiRouter = class _AiRouter {
|
|
|
516
578
|
}
|
|
517
579
|
registryMap[pathKey].agents.push(agentInfo);
|
|
518
580
|
} else {
|
|
519
|
-
|
|
520
|
-
handler: layer.handler.name || "anonymous"
|
|
521
|
-
|
|
581
|
+
const middlewareInfo = {
|
|
582
|
+
handler: layer.handler.name || "anonymous",
|
|
583
|
+
timing: layer.timing || "middleware"
|
|
584
|
+
};
|
|
585
|
+
if (layer.timing === "before") {
|
|
586
|
+
registryMap[pathKey].before.push(middlewareInfo);
|
|
587
|
+
} else if (layer.timing === "after") {
|
|
588
|
+
registryMap[pathKey].after.push(middlewareInfo);
|
|
589
|
+
} else {
|
|
590
|
+
registryMap[pathKey].before.push(middlewareInfo);
|
|
591
|
+
}
|
|
522
592
|
}
|
|
523
593
|
}
|
|
524
594
|
return {
|
|
@@ -654,7 +724,17 @@ var AiRouter = class _AiRouter {
|
|
|
654
724
|
}
|
|
655
725
|
const normalizedLayerPath = layerPath.length > 1 && layerPath.endsWith("/") ? layerPath.slice(0, -1) : layerPath;
|
|
656
726
|
const isExactMatch = normalizedPath === normalizedLayerPath;
|
|
657
|
-
|
|
727
|
+
const hasDynamic = hasDynamicParams(normalizedLayerPath);
|
|
728
|
+
if (hasDynamic) {
|
|
729
|
+
const extractedParams = extractPathParams(normalizedLayerPath, normalizedPath);
|
|
730
|
+
if (extractedParams !== null) {
|
|
731
|
+
shouldRun = true;
|
|
732
|
+
ctx.request.params = {
|
|
733
|
+
...ctx.request.params,
|
|
734
|
+
...extractedParams
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
} else if (isInternalCall) {
|
|
658
738
|
shouldRun = isExactMatch;
|
|
659
739
|
} else {
|
|
660
740
|
if (layer.isAgent) {
|
|
@@ -671,31 +751,45 @@ var AiRouter = class _AiRouter {
|
|
|
671
751
|
}
|
|
672
752
|
return shouldRun;
|
|
673
753
|
});
|
|
674
|
-
layersToRun.
|
|
754
|
+
const beforeLayers = layersToRun.filter(
|
|
755
|
+
(l) => !l.isAgent && l.timing === "before"
|
|
756
|
+
);
|
|
757
|
+
const agentLayers = layersToRun.filter((l) => l.isAgent);
|
|
758
|
+
const afterLayers = layersToRun.filter(
|
|
759
|
+
(l) => !l.isAgent && l.timing === "after"
|
|
760
|
+
);
|
|
761
|
+
beforeLayers.sort(
|
|
762
|
+
(a, b) => this._getSpecificityScore(a) - this._getSpecificityScore(b)
|
|
763
|
+
);
|
|
764
|
+
agentLayers.sort(
|
|
675
765
|
(a, b) => this._getSpecificityScore(a) - this._getSpecificityScore(b)
|
|
676
766
|
);
|
|
677
|
-
|
|
678
|
-
(
|
|
767
|
+
afterLayers.sort(
|
|
768
|
+
(a, b) => this._getSpecificityScore(a) - this._getSpecificityScore(b)
|
|
679
769
|
);
|
|
770
|
+
const orderedLayers = [...beforeLayers, ...agentLayers, ...afterLayers];
|
|
771
|
+
const layerDescriptions = orderedLayers.map((l) => {
|
|
772
|
+
const type = l.isAgent ? "agent" : l.timing === "before" ? "before" : l.timing === "after" ? "after" : "middleware";
|
|
773
|
+
return `${l.path.toString()} (${type})`;
|
|
774
|
+
});
|
|
680
775
|
ctx.logger.log(
|
|
681
|
-
`Found ${
|
|
776
|
+
`Found ${orderedLayers.length} layers to run: [${layerDescriptions.join(
|
|
682
777
|
", "
|
|
683
778
|
)}]`
|
|
684
779
|
);
|
|
685
|
-
|
|
686
|
-
if (!layersToRun.length) {
|
|
780
|
+
if (!agentLayers.length && !beforeLayers.length && !afterLayers.length) {
|
|
687
781
|
const errorMsg = `No agent or tool found for path: ${normalizedPath}`;
|
|
688
782
|
ctx.logger.error(errorMsg);
|
|
689
783
|
throw new AgentNotFoundError(normalizedPath);
|
|
690
784
|
}
|
|
691
785
|
const dispatch = async (index) => {
|
|
692
|
-
const layer =
|
|
786
|
+
const layer = orderedLayers[index];
|
|
693
787
|
if (!layer) {
|
|
694
788
|
return;
|
|
695
789
|
}
|
|
696
790
|
const next = () => dispatch(index + 1);
|
|
697
791
|
const layerPath = typeof layer.path === "string" ? layer.path : layer.path.toString();
|
|
698
|
-
const layerType = layer.isAgent ? "agent" : "middleware";
|
|
792
|
+
const layerType = layer.isAgent ? "agent" : layer.timing === "before" ? "before" : layer.timing === "after" ? "after" : "middleware";
|
|
699
793
|
ctx.logger.log(`-> Running ${layerType}: ${layerPath}`);
|
|
700
794
|
try {
|
|
701
795
|
if (ctx._onExecutionStart) {
|
|
@@ -1066,6 +1160,31 @@ var NextHandler = class {
|
|
|
1066
1160
|
}
|
|
1067
1161
|
};
|
|
1068
1162
|
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Deprecated execute style for L1402
|
|
1165
|
+
* execute: (params: any, options: any) => {
|
|
1166
|
+
const finalParams = { ...params, ...fixedParams };
|
|
1167
|
+
|
|
1168
|
+
const executeInternal = async () => {
|
|
1169
|
+
const result = await this.callAgent(
|
|
1170
|
+
agentPath,
|
|
1171
|
+
finalParams,
|
|
1172
|
+
options
|
|
1173
|
+
);
|
|
1174
|
+
if (!result.ok) {
|
|
1175
|
+
throw result.error;
|
|
1176
|
+
}
|
|
1177
|
+
return result.data;
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
const newPromise = this.router.toolExecutionPromise.then(
|
|
1181
|
+
executeInternal,
|
|
1182
|
+
executeInternal
|
|
1183
|
+
);
|
|
1184
|
+
this.router.toolExecutionPromise = newPromise;
|
|
1185
|
+
return newPromise;
|
|
1186
|
+
*
|
|
1187
|
+
*/
|
|
1069
1188
|
};
|
|
1070
1189
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1071
1190
|
0 && (module.exports = {
|