UNPKG

anon-identity

Version:

Decentralized identity framework with DIDs, Verifiable Credentials, and privacy-preserving selective disclosure

404 lines 14.2 kB
"use strict"; /** * Provider-Agnostic Base Interface for MCP * * Abstract base classes and interfaces for LLM providers */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseProviderFactory = exports.BaseLLMProvider = void 0; const events_1 = require("events"); const types_1 = require("../types"); /** * Abstract base provider class */ class BaseLLMProvider extends events_1.EventEmitter { constructor(config) { super(); this.requestCount = 0; this.errorCount = 0; this.lastRequestTime = null; this.lastErrorTime = null; this.id = config.id; this.name = config.id; this.version = '1.0.0'; this.description = `${config.id} LLM provider`; this.config = config; this.status = types_1.ProviderStatus.UNAVAILABLE; // Default capabilities - subclasses should override this.capabilities = { completion: true, streaming: false, functionCalling: false, embeddings: false, moderation: false, multimodal: false, codeGeneration: false, jsonMode: false }; // Default rate limits - subclasses should override this.rateLimits = config.rateLimits || { requestsPerMinute: 60, tokensPerMinute: 100000, requestsPerDay: 1000, tokensPerDay: 1000000, concurrentRequests: 10 }; // Default models - subclasses should populate this.models = []; } /** * Process request based on type */ async processRequest(request, context) { this.validateRequest(request); this.updateMetrics(); try { let response; switch (request.type) { case types_1.LLMRequestType.COMPLETION: response = await this.completion(request, context); break; case types_1.LLMRequestType.FUNCTION_CALL: response = await this.completion(request, context); break; case types_1.LLMRequestType.EMBEDDING: if (!this.capabilities.embeddings) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.FUNCTION_NOT_FOUND, message: 'Embeddings not supported by this provider', timestamp: new Date(), provider: this.id, retryable: false }); } response = await this.embed(request, context); break; case types_1.LLMRequestType.MODERATION: if (!this.capabilities.moderation) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.FUNCTION_NOT_FOUND, message: 'Moderation not supported by this provider', timestamp: new Date(), provider: this.id, retryable: false }); } response = await this.moderate(request, context); break; case types_1.LLMRequestType.STREAMING: throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_REQUEST, message: 'Use stream() method for streaming requests', timestamp: new Date(), provider: this.id, retryable: false }); default: throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_REQUEST, message: `Unsupported request type: ${request.type}`, timestamp: new Date(), provider: this.id, retryable: false }); } this.emit('request_completed', { request, response, context }); return response; } catch (error) { this.handleError(error, request, context); throw error; } } /** * Process streaming request */ async *processStreamingRequest(request, context) { this.validateRequest(request); this.updateMetrics(); if (!this.capabilities.streaming) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.FUNCTION_NOT_FOUND, message: 'Streaming not supported by this provider', timestamp: new Date(), provider: this.id, retryable: false }); } try { for await (const chunk of this.stream(request, context)) { this.emit('stream_chunk', { request, chunk, context }); yield chunk; } this.emit('stream_completed', { request, context }); } catch (error) { this.handleError(error, request, context); throw error; } } /** * Validate request before processing */ validateRequest(request) { if (!request.id) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_REQUEST, message: 'Request ID is required', timestamp: new Date(), provider: this.id, retryable: false }); } if (!request.prompt && request.type !== types_1.LLMRequestType.EMBEDDING) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_REQUEST, message: 'Prompt is required', timestamp: new Date(), provider: this.id, requestId: request.id, retryable: false }); } if (!request.agentDID) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_REQUEST, message: 'Agent DID is required', timestamp: new Date(), provider: this.id, requestId: request.id, retryable: false }); } // Validate function calling requirements if (request.type === types_1.LLMRequestType.FUNCTION_CALL) { if (!this.capabilities.functionCalling) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.FUNCTION_NOT_FOUND, message: 'Function calling not supported by this provider', timestamp: new Date(), provider: this.id, requestId: request.id, retryable: false }); } if (!request.functions || request.functions.length === 0) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.INVALID_REQUEST, message: 'Functions are required for function calling', timestamp: new Date(), provider: this.id, requestId: request.id, retryable: false }); } } } /** * Create base response structure */ createBaseResponse(request, context) { return { id: `resp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, requestId: request.id, type: request.type, provider: this.id, model: request.parameters?.model || this.config.defaultModel, timestamp: new Date(), status: types_1.ResponseStatus.SUCCESS }; } /** * Create error response */ createErrorResponse(request, context, error) { const baseResponse = this.createBaseResponse(request, context); const mcpError = error instanceof types_1.MCPError ? error : new types_1.MCPError({ code: types_1.MCPErrorCode.PROVIDER_ERROR, message: error.message, timestamp: new Date(), provider: this.id, requestId: request.id, retryable: false }); return { ...baseResponse, status: types_1.ResponseStatus.ERROR, error: mcpError }; } /** * Calculate usage information */ calculateUsage(request, response, model) { // Simplified token calculation - in production this would be more accurate const promptTokens = Math.ceil((request.prompt?.length || 0) / 4); const completionTokens = Math.ceil(response.length / 4); const totalTokens = promptTokens + completionTokens; return { promptTokens, completionTokens, totalTokens, model, provider: this.id, cost: this.calculateCost(promptTokens, completionTokens, model) }; } /** * Calculate cost based on token usage */ calculateCost(promptTokens, completionTokens, model) { const modelInfo = this.models.find(m => m.id === model); if (!modelInfo) return 0; const promptCost = (promptTokens / 1000) * modelInfo.inputCost; const completionCost = (completionTokens / 1000) * modelInfo.outputCost; return promptCost + completionCost; } /** * Handle errors */ handleError(error, request, context) { this.errorCount++; this.lastErrorTime = new Date(); this.emit('request_error', { error, request, context, provider: this.id }); // Update provider status based on error frequency const errorRate = this.errorCount / this.requestCount; if (errorRate > 0.1) { // More than 10% error rate this.status = types_1.ProviderStatus.ERROR; } } /** * Update request metrics */ updateMetrics() { this.requestCount++; this.lastRequestTime = new Date(); // Reset status if it was in error state and enough time has passed if (this.status === types_1.ProviderStatus.ERROR && this.lastErrorTime) { const timeSinceError = Date.now() - this.lastErrorTime.getTime(); if (timeSinceError > 5 * 60 * 1000) { // 5 minutes this.status = types_1.ProviderStatus.AVAILABLE; } } } /** * Convert function definitions to provider-specific format */ convertFunctions(functions) { // Base implementation - subclasses should override for provider-specific formats return functions.map(fn => ({ name: fn.name, description: fn.description, parameters: fn.parameters })); } /** * Extract function calls from provider response */ extractFunctionCalls(response) { // Base implementation - subclasses should override for provider-specific parsing const calls = []; if (response.function_call) { calls.push({ name: response.function_call.name, arguments: JSON.parse(response.function_call.arguments || '{}'), id: `call-${Date.now()}` }); } return calls; } /** * Get provider statistics */ getStats() { return { requestCount: this.requestCount, errorCount: this.errorCount, errorRate: this.requestCount > 0 ? this.errorCount / this.requestCount : 0, lastRequestTime: this.lastRequestTime, lastErrorTime: this.lastErrorTime, status: this.status }; } /** * Reset statistics */ resetStats() { this.requestCount = 0; this.errorCount = 0; this.lastRequestTime = null; this.lastErrorTime = null; this.status = types_1.ProviderStatus.AVAILABLE; } /** * Get supported models */ getSupportedModels() { return [...this.models]; } /** * Check if model is supported */ isModelSupported(modelId) { return this.models.some(model => model.id === modelId); } /** * Get default model for request type */ getDefaultModel(requestType) { // Return configured default or first available model if (this.config.defaultModel && this.isModelSupported(this.config.defaultModel)) { return this.config.defaultModel; } return this.models.length > 0 ? this.models[0].id : ''; } /** * Validate model availability */ validateModel(modelId) { if (modelId && !this.isModelSupported(modelId)) { throw new types_1.MCPError({ code: types_1.MCPErrorCode.MODEL_NOT_FOUND, message: `Model ${modelId} not supported by provider ${this.id}`, timestamp: new Date(), provider: this.id, retryable: false }); } } /** * Shutdown provider */ async shutdown() { this.status = types_1.ProviderStatus.UNAVAILABLE; this.removeAllListeners(); } } exports.BaseLLMProvider = BaseLLMProvider; /** * Abstract provider factory */ class BaseProviderFactory { /** * Validate base configuration requirements */ validateBaseConfig(config) { if (!config.id || typeof config.id !== 'string') return false; if (!config.endpoint || typeof config.endpoint !== 'string') return false; if (config.enabled !== undefined && typeof config.enabled !== 'boolean') return false; return true; } } exports.BaseProviderFactory = BaseProviderFactory; // Export interfaces inline above // export { ProviderRequestContext, ProviderResponseContext }; //# sourceMappingURL=base-provider.js.map