UNPKG

@nullplatform/llm-gateway

Version:
317 lines 14.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExtensionsLoader = void 0; const logger_1 = require("../utils/logger"); const path_1 = __importDefault(require("path")); const child_process_1 = require("child_process"); const fs_1 = require("fs"); class ExtensionsLoader { plugins = new Map(); adapters = new Map(); providers = new Map(); logger; config; constructor(config, logger) { this.logger = logger || new logger_1.Logger(); this.config = config; } getPluginBuilders() { return this.plugins; } getAdapterBuilders() { return this.adapters; } getProviderBuilders() { return this.providers; } async initializeExtensions() { const availableExtensions = this.config || []; for (const extension of availableExtensions) { let module; if (extension.path) { module = path_1.default.resolve(extension.path); } else if (extension.module) { module = await this.resolveModule(extension.module); } else { throw new Error(`Plugin must have either path or module specified at ${JSON.stringify(extension)}`); } try { const extensionModule = await Promise.resolve(`${module}`).then(s => __importStar(require(s))); const discoveredPlugins = await this.discoverAndRegisterExtensionType("plugin", extensionModule, this.implementsIPlugin.bind(this)); for (const [name, plugin] of discoveredPlugins) { this.plugins.set(name, plugin); } const discoveredProviders = await this.discoverAndRegisterExtensionType("llm-provider", extensionModule, this.implementsIProvider.bind(this)); for (const [name, plugin] of discoveredProviders) { this.providers.set(name, plugin); } const discoveredAdapters = await this.discoverAndRegisterExtensionType("adapter", extensionModule, this.implementsILLMAdapter.bind(this)); for (const [name, plugin] of discoveredAdapters) { this.adapters.set(name, plugin); } } catch (error) { this.logger.error(`Failed to load plugin module ${module}:`, error); throw error; } } } async resolveModule(moduleName) { // First try to resolve as local module try { // Try to resolve locally first const localPath = require.resolve(moduleName); this.logger.info(`Resolved module ${moduleName} locally at: ${localPath}`); return moduleName; // Return the module name for dynamic import } catch (localError) { this.logger.warn(`Failed to resolve module ${moduleName} locally:`, localError.message); // If local resolution fails, try global try { const globalPath = this.getGlobalModulePath(moduleName); if (globalPath && (0, fs_1.existsSync)(globalPath)) { this.logger.info(`Resolved module ${moduleName} globally at: ${globalPath}`); // Try to find the correct entry point for the global module return this.findModuleEntryPoint(globalPath, moduleName); } else { throw new Error(`Global module path not found: ${globalPath}`); } } catch (globalError) { this.logger.error(`Failed to resolve module ${moduleName} globally:`, globalError.message); // As a last resort, try the module name directly (sometimes works with global modules) this.logger.warn(`Attempting to import ${moduleName} directly as fallback`); return moduleName; } } } getGlobalModulePath(moduleName) { try { // Get global node_modules path const globalRoot = (0, child_process_1.execSync)('npm root -g', { encoding: 'utf8' }).trim(); const globalModulePath = path_1.default.join(globalRoot, moduleName); this.logger.debug(`Checking global module path: ${globalModulePath}`); return globalModulePath; } catch (error) { this.logger.error('Failed to get global npm root:', error); // Fallback: try common global paths const commonGlobalPaths = [ '/usr/local/lib/node_modules', '/usr/lib/node_modules', path_1.default.join(process.env.HOME || '', '.npm-global/lib/node_modules'), path_1.default.join(process.env.APPDATA || '', 'npm/node_modules') // Windows ]; for (const globalPath of commonGlobalPaths) { const modulePath = path_1.default.join(globalPath, moduleName); if ((0, fs_1.existsSync)(modulePath)) { this.logger.info(`Found global module at fallback path: ${modulePath}`); return modulePath; } } return null; } } findModuleEntryPoint(modulePath, moduleName) { try { // First, try to read package.json to get the correct entry point const packageJsonPath = path_1.default.join(modulePath, 'package.json'); if ((0, fs_1.existsSync)(packageJsonPath)) { const packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, 'utf8')); this.logger.debug(`Package.json for ${moduleName}:`, { main: packageJson.main, module: packageJson.module, exports: packageJson.exports }); // Check for various entry points in order of preference const entryPoints = [ packageJson.main, packageJson.module, packageJson.exports?.['.']?.import, packageJson.exports?.['.']?.require, packageJson.exports?.['.'], // Common built entry points 'dist/index.js', 'lib/index.js', 'build/index.js', // TypeScript source files (fallback if not built) 'index.ts', 'basic-apikey-auth/index.ts', // CommonJS fallbacks 'index.js', 'index.mjs' ]; for (const entryPoint of entryPoints) { if (entryPoint) { const fullPath = path_1.default.resolve(modulePath, entryPoint); this.logger.debug(`Checking entry point: ${fullPath}`); if ((0, fs_1.existsSync)(fullPath)) { this.logger.info(`Found entry point for ${moduleName}: ${fullPath}`); return fullPath; } } } this.logger.warn(`No valid entry point found in package.json for ${moduleName}`); } // Fallback: try common entry point files const commonEntryPoints = [ 'dist/index.js', // Most likely for your package 'index.js', 'index.ts', // TypeScript source if not built 'basic-apikey-auth/index.ts', // Source file location 'index.mjs', 'lib/index.js', 'build/index.js', 'main.js' ]; this.logger.debug(`Trying fallback entry points for ${moduleName}`); for (const entryPoint of commonEntryPoints) { const fullPath = path_1.default.join(modulePath, entryPoint); this.logger.debug(`Checking fallback: ${fullPath}`); if ((0, fs_1.existsSync)(fullPath)) { this.logger.info(`Found fallback entry point for ${moduleName}: ${fullPath}`); return fullPath; } } // Debug: List what's actually in the directory try { const files = (0, fs_1.readdirSync)(modulePath); this.logger.warn(`Contents of ${modulePath}:`, files); } catch (e) { this.logger.error(`Could not read directory ${modulePath}:`, e); } // If we can't find a specific entry point, return the module path and let Node.js try to resolve it this.logger.warn(`Could not find entry point for ${moduleName}, using module path: ${modulePath}`); return modulePath; } catch (error) { this.logger.error(`Error finding entry point for ${moduleName}:`, error); return modulePath; } } async discoverAndRegisterExtensionType(extensionTypeName = "UnknownType", extensionModule, typeValidator) { // Get all exported values from the module const extensionType = new Map(); const exports = Object.keys(extensionModule).map(key => ({ name: key, value: extensionModule[key] })); for (const exported of exports) { const { name, value } = exported; // Check if it's a class constructor if (this.isConstructor(value)) { // Check if it's not abstract and implements IPlugin if (typeValidator(value) && !this.isAbstractClass(value)) { try { // Get plugin metadata - assuming it's a static property or method const metadata = this.getExtensionMetadata(value); if (metadata && metadata.name) { extensionType.set(metadata.name, value); this.logger.info(`Registered extension of type [${extensionTypeName}] : ${metadata.name}`); } else { this.logger.warn(`Plugin class ${name} doesn't have valid metadata`); } } catch (error) { this.logger.error(`Failed to register plugin ${name}:`, error); } } } } return extensionType; } isConstructor(obj) { return typeof obj === 'function' && obj.prototype && obj.prototype.constructor === obj; } implementsILLMAdapter(constructor) { const prototype = constructor.prototype; const metadata = constructor.metadata || prototype.metadata; return (prototype && metadata && typeof prototype === 'object' && typeof prototype.configure === 'function' && (typeof prototype.transformInput === 'function' && typeof prototype.transformOutput === 'function' && typeof prototype.transformOutputChunk === 'function')); } implementsIProvider(constructor) { const prototype = constructor.prototype; const metadata = constructor.metadata || prototype.metadata; return (prototype && metadata && typeof prototype === 'object' && typeof prototype.configure === 'function' && (typeof prototype.execute === 'function' && typeof prototype.executeStreaming === 'function')); } implementsIPlugin(constructor) { const prototype = constructor.prototype; const metadata = constructor.metadata || prototype.metadata; return (prototype && metadata && typeof prototype === 'object' && typeof prototype.configure === 'function' && (typeof prototype.beforeModel === 'function' || typeof prototype.afterModel === 'function' || typeof prototype.configure === 'function')); } isAbstractClass(constructor) { return constructor.prototype && Object.getOwnPropertyNames(constructor.prototype) .some(prop => constructor.prototype[prop] === undefined); } getExtensionMetadata(constructor) { if (constructor.metadata) { return constructor.metadata; } if (constructor.prototype.metadata) { return constructor.prototype.metadata; } throw new Error(`Plugin class ${constructor.name} does not have metadata defined`); } } exports.ExtensionsLoader = ExtensionsLoader; //# sourceMappingURL=extentionsLoader.js.map