sensai
Version:
Because even AI needs a master
180 lines (179 loc) • 6.74 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, /**
* Create a resource based router where route are grouped by verbs/methods
* and versions.
*
* @param rootDir directory used to create absolute path for route filepath
*/ "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _nodepath = require("node:path");
const _metadata = /*#__PURE__*/ _interop_require_default(require("./metadata"));
const _trie = /*#__PURE__*/ _interop_require_default(require("./trie"));
const _middlewares = /*#__PURE__*/ _interop_require_default(require("./middlewares"));
const _orchestrator = /*#__PURE__*/ _interop_require_default(require("./orchestrator"));
const _constants = require("../../constants");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const _default = async (rootDir = "")=>{
const resources = new Map();
const middlewares = (0, _middlewares.default)();
const orchestrator = (0, _orchestrator.default)();
const routes = (0, _trie.default)();
/**
* Add route with its optional middleware in the router/resource resolution.
*/ const addRoute = (routePath, type)=>{
const { pathname, method, version } = (0, _metadata.default)(routePath);
//const relativePath = relative(rootDir, pathname) || '/'
const relativePath = pathname;
const endpoint = resources.get(relativePath) || {};
resources.set(relativePath, {
...endpoint,
[method]: {
...endpoint[method],
[version]: {
// TODO the join rootDIr should be donei walker
// middlewares: middlewarePaths.map((path) => join(rootDir, path)),
route: (0, _nodepath.join)(rootDir, routePath),
type
}
}
});
routes.add(relativePath);
};
const addTool = (toolPath)=>{
const filename = (0, _nodepath.basename)(toolPath); // TODO merge with get metadata
const chunks = filename.split(".");
if (chunks.length === 3) {
const dirPath = (0, _nodepath.dirname)(toolPath);
const resource = resources.get(dirPath) || {};
resources.set(dirPath, {
...resource,
tool: [
{
name: chunks[1],
path: toolPath
},
...resource.tool || []
]
});
}
};
return {
add (filePath) {
const prefix = getPrefix(filePath);
switch(prefix){
case _constants.FILE_TYPE.MIDDLEWARE:
case _constants.FILE_TYPE.AUTHORIZER:
middlewares.add(filePath);
break;
case _constants.FILE_TYPE.ROUTE:
case _constants.FILE_TYPE.MOCK:
case _constants.FILE_TYPE.PROMPT:
case _constants.FILE_TYPE.ORCHESTRATOR:
addRoute(filePath, prefix);
// a prompt can easily be switched into an orchestrator
orchestrator.add(filePath);
break;
case _constants.FILE_TYPE.TOOL:
addTool(filePath);
break;
}
},
/**
* An orchestrator can use agents as tools to create multi-agent
* orchetration.
*/ getAgents (folderPath) {
return orchestrator.get(folderPath);
},
/**
* Tools apply to a resource (i.e collection of routes under a URL segment).
*/ getTools (folderPath) {
const resource = resources.get(folderPath.substring(rootDir.length));
return resource?.tool || [];
},
/**
* Lookup a path in the router Map.
*/ lookup (urlPath) {
// TODO only use sanitizedUrl if we don't find anything int he static cache
//const sanitizedUrl = sanitize(urlPath)
//return resources.get(urlPath)
const route = routes.lookup(urlPath);
if (route) {
const resource = resources.get(route.path);
if (resource) {
return {
...route,
resource,
// TODO we should move middlewares to build time (i.e NOT when fetching route)
// TODO map/join is not efficient
middlewares: middlewares.get(route.path + "/tmp.ts").map((path)=>(0, _nodepath.join)(rootDir, path))
};
}
}
},
/**
* Remove a file from the router.
*/ remove (filePath) {
const prefix = getPrefix(filePath);
switch(prefix){
case _constants.FILE_TYPE.MIDDLEWARE:
case _constants.FILE_TYPE.AUTHORIZER:
{
middlewares.remove(filePath);
return true;
}
case _constants.FILE_TYPE.ORCHESTRATOR:
{
orchestrator.remove(filePath);
// no return statement as we want to move on to the next case
}
case _constants.FILE_TYPE.ROUTE:
case _constants.FILE_TYPE.MOCK:
case _constants.FILE_TYPE.PROMPT:
case _constants.FILE_TYPE.ORCHESTRATOR:
{
const { pathname, method } = (0, _metadata.default)(filePath); // TODO we should look at version
const endpoint = resources.get(pathname);
delete endpoint[method];
if (Object.keys(endpoint).length < 1) {
routes.remove(pathname);
resources.delete(pathname);
}
return true;
}
}
return false;
},
/**
* // TODO remove if not needed
* Remove all files in a folder
*/ prune (folderPath) {
resources.delete(folderPath);
return routes.remove(folderPath, true);
}
};
};
/**
* Return file prefix.
*
* @examples
*
* getPrefix('route.get.ts')
* // => 'route'
* getPrefix('route.ts')
* // => 'route'
* getPrefix('prompt.name.world.md')
* // => 'prompt'
*/ const getPrefix = (filePath)=>{
return (0, _nodepath.basename)(filePath).split(".")[0];
};