UNPKG

lanonasis-memory

Version:

Memory as a Service integration - AI-powered memory management with semantic search (Compatible with CLI v3.0.6+)

431 lines 17.2 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; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.EnhancedMemoryService = void 0; const vscode = __importStar(require("vscode")); let cachedMemoryClientModule; let attemptedMemoryClientLoad = false; function getMemoryClientModule() { if (!attemptedMemoryClientLoad) { attemptedMemoryClientLoad = true; try { // eslint-disable-next-line @typescript-eslint/no-require-imports cachedMemoryClientModule = require('@lanonasis/memory-client'); } catch (error) { console.warn('[EnhancedMemoryService] @lanonasis/memory-client not available. Falling back to basic service.', error); cachedMemoryClientModule = undefined; } } return cachedMemoryClientModule; } class EnhancedMemoryService { constructor(secureApiKeyService) { this.client = null; this.cliCapabilities = null; const sdkModule = getMemoryClientModule(); if (!sdkModule) { throw new Error('@lanonasis/memory-client module not available'); } this.sdk = sdkModule; this.secureApiKeyService = secureApiKeyService; this.config = vscode.workspace.getConfiguration('lanonasis'); this.showPerformanceFeedback = this.config.get('showPerformanceFeedback', false); // Create status bar item to show CLI/MCP status this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100); this.statusBarItem.command = 'lanonasis.showConnectionInfo'; this.initializeClient(); } async initializeClient() { const { Environment, EnhancedMemoryClient } = this.sdk; const credential = await this.secureApiKeyService.getStoredCredentials(); if (!credential) { this.client = null; this.updateStatusBar(false, 'No API Key'); return; } try { // Use IDE extension preset for optimized configuration const clientConfig = this.buildClientConfigFromCredential(credential); // Override with VSCode-specific settings const apiUrl = this.config.get('apiUrl', 'https://mcp.lanonasis.com'); const useGateway = this.config.get('useGateway', true); clientConfig.apiUrl = useGateway ? this.config.get('gatewayUrl', 'https://mcp.lanonasis.com') : apiUrl; // Enable CLI detection with shorter timeout for responsive UX clientConfig.preferCLI = Environment.supportsCLI; clientConfig.cliDetectionTimeout = 2000; clientConfig.verbose = this.config.get('verboseLogging', false); // Performance warning: verbose logging in production if (clientConfig.verbose && process.env.NODE_ENV === 'production') { vscode.window.showWarningMessage('Verbose logging is enabled in production. This may impact performance and expose sensitive information in logs.'); console.warn('[EnhancedMemoryService] Warning: Verbose logging is enabled in production. This may impact performance and expose sensitive information in logs.'); } this.client = new EnhancedMemoryClient(clientConfig); // Initialize and detect CLI capabilities await this.client.initialize(); this.cliCapabilities = await this.detectCapabilities(); this.updateStatusBar(true, this.getConnectionStatus()); } catch (error) { console.warn('Enhanced Memory Service initialization failed:', error); this.client = null; this.updateStatusBar(false, 'Initialization Failed'); throw error; } } async detectCapabilities() { if (!this.client) { return { cliAvailable: false, mcpSupport: false, authenticated: false, goldenContract: false }; } try { // Test if CLI integration is working const testRequest = this.toSDKSearchRequest({ query: 'test connection', limit: 1, status: 'active', threshold: 0.1 }); const testResult = await this.client.searchMemories(testRequest); return { cliAvailable: testResult.source === 'cli', mcpSupport: testResult.mcpUsed || false, authenticated: testResult.error === undefined, goldenContract: testResult.source === 'cli' // CLI available implies Golden Contract v1.5.2+ }; } catch { return { cliAvailable: false, mcpSupport: false, authenticated: false, goldenContract: false }; } } getConnectionStatus() { if (!this.cliCapabilities) return 'Unknown'; if (this.cliCapabilities.cliAvailable) { const parts = ['CLI']; if (this.cliCapabilities.mcpSupport) parts.push('MCP'); if (this.cliCapabilities.goldenContract) parts.push('Golden'); return parts.join('+'); } return 'API'; } updateStatusBar(connected, status) { if (connected) { this.statusBarItem.text = `$(database) ${status}`; this.statusBarItem.backgroundColor = undefined; this.statusBarItem.tooltip = `Lanonasis Memory: Connected via ${status}`; } else { this.statusBarItem.text = `$(alert) ${status}`; this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.errorBackground'); this.statusBarItem.tooltip = `Lanonasis Memory: ${status}`; } this.statusBarItem.show(); } async refreshClient() { this.config = vscode.workspace.getConfiguration('lanonasis'); await this.initializeClient(); } async refreshConfig() { await this.refreshClient(); } isAuthenticated() { return this.client !== null; } getCapabilities() { return this.cliCapabilities; } async testConnection(apiKey) { const { EnhancedMemoryClient } = this.sdk; let testClient = this.client; if (apiKey) { const config = this.buildClientConfigFromCredential({ type: 'apiKey', token: apiKey }); testClient = new EnhancedMemoryClient(config); await testClient.initialize(); } if (!testClient) { const credential = await this.secureApiKeyService.getStoredCredentials(); if (!credential) { throw new Error('No API key configured'); } const config = this.buildClientConfigFromCredential(credential); testClient = new EnhancedMemoryClient(config); await testClient.initialize(); } // Test with enhanced client - this will try CLI first, then fallback to API const testRequest = this.toSDKSearchRequest({ query: 'connection test', limit: 1, status: 'active', threshold: 0.1 }); const result = await testClient.searchMemories(testRequest); if (result.error) { throw new Error(result.error); } // Update capabilities after successful test if (!apiKey) { this.cliCapabilities = await this.detectCapabilities(); this.updateStatusBar(true, this.getConnectionStatus()); } } async createMemory(memory) { if (!this.client) { throw new Error('Not authenticated. Please configure your API key.'); } const sdkMemory = this.toSDKCreateRequest(memory); const result = await this.client.createMemory(sdkMemory); if (result.error || !result.data) { throw new Error(result.error || 'Failed to create memory'); } this.showOperationFeedback('create', result); return this.convertSDKMemoryEntry(result.data); } async searchMemories(query, options = {}) { if (!this.client) { throw new Error('Not authenticated. Please configure your API key.'); } const searchRequest = { query, limit: 20, threshold: 0.7, status: 'active', ...options }; const sdkSearchRequest = this.toSDKSearchRequest(searchRequest); const result = await this.client.searchMemories(sdkSearchRequest); if (result.error || !result.data) { throw new Error(result.error || 'Search failed'); } // Show search performance info in verbose mode if (this.config.get('verboseLogging', false)) { this.showOperationFeedback('search', result); } return this.convertSDKSearchResults(result.data.results); } async getMemory(id) { if (!this.client) { throw new Error('Not authenticated. Please configure your API key.'); } const result = await this.client.getMemory(id); if (result.error || !result.data) { throw new Error(result.error || 'Memory not found'); } return this.convertSDKMemoryEntry(result.data); } async listMemories(limit = 50) { if (!this.client) { throw new Error('Not authenticated. Please configure your API key.'); } // Type validation for limit parameter if (typeof limit !== 'number' || limit < 0) { throw new Error('limit must be a non-negative number'); } // Ensure limit is within reasonable bounds const validatedLimit = Math.min(Math.max(1, Math.floor(limit)), 1000); const result = await this.client.listMemories({ limit: validatedLimit, sort: 'updated_at', order: 'desc' }); if (result.error || !result.data) { throw new Error(result.error || 'Failed to fetch memories'); } return result.data.data.map(entry => this.convertSDKMemoryEntry(entry)); } async deleteMemory(id) { if (!this.client) { throw new Error('Not authenticated. Please configure your API key.'); } const result = await this.client.deleteMemory(id); if (result.error) { throw new Error(result.error); } this.showOperationFeedback('delete', result); } async getMemoryStats() { if (!this.client) { throw new Error('Not authenticated. Please configure your API key.'); } const result = await this.client.getMemoryStats(); if (result.error || !result.data) { throw new Error(result.error || 'Failed to fetch stats'); } return this.convertSDKUserMemoryStats(result.data); } showOperationFeedback(operation, result) { if (!this.showPerformanceFeedback) return; const source = result.source === 'cli' ? (result.mcpUsed ? 'CLI+MCP' : 'CLI') : 'API'; const message = `${operation} completed via ${source}`; // Show brief status message vscode.window.setStatusBarMessage(`$(check) ${message}`, 2000); } async showConnectionInfo() { const caps = this.cliCapabilities; if (!caps) { vscode.window.showInformationMessage('Connection status: Unknown'); return; } const details = [ `CLI Available: ${caps.cliAvailable ? '✅' : '❌'}`, `MCP Support: ${caps.mcpSupport ? '✅' : '❌'}`, `Authenticated: ${caps.authenticated ? '✅' : '❌'}`, `Golden Contract: ${caps.goldenContract ? '✅' : '❌'}` ]; const message = `Lanonasis Memory Connection Status:\n\n${details.join('\n')}`; if (caps.cliAvailable && caps.goldenContract) { vscode.window.showInformationMessage(`${message}\n\nEnhanced performance with CLI v1.5.2+ integration!`); } else if (caps.authenticated) { vscode.window.showInformationMessage(`${message}\n\nInstall @lanonasis/cli v1.5.2+ for enhanced performance.`); } else { vscode.window.showWarningMessage(message); } } toSDKCreateRequest(memory) { const { memory_type, ...rest } = memory; return { ...rest, memory_type: this.mapMemoryType(memory_type) }; } toSDKSearchRequest(request) { const { memory_types, ...rest } = request; const sdkTypes = memory_types?.map(type => this.mapMemoryType(type)); const sdkRequest = { ...rest, ...(sdkTypes ? { memory_types: sdkTypes } : {}) }; return sdkRequest; } mapMemoryType(vscodeType) { const typeMap = { conversation: 'context', knowledge: 'knowledge', project: 'project', context: 'context', reference: 'reference', personal: 'personal', workflow: 'workflow' }; return typeMap[vscodeType] ?? 'context'; } mapMemoryTypeFromSDK(sdkType) { const typeMap = { context: 'context', project: 'project', knowledge: 'knowledge', reference: 'reference', personal: 'personal', workflow: 'workflow', conversation: 'conversation' }; return typeMap[sdkType] ?? 'context'; } convertSDKMemoryEntry(sdkEntry) { return { ...sdkEntry, memory_type: this.mapMemoryTypeFromSDK(sdkEntry.memory_type) }; } buildClientConfigFromCredential(credential) { const { ConfigPresets } = this.sdk; const config = ConfigPresets.ideExtension(credential.type === 'apiKey' ? credential.token : undefined); if (credential.type === 'oauth') { config.apiKey = undefined; config.authToken = credential.token; } return config; } convertSDKSearchResults(sdkResults) { return sdkResults.map(result => ({ ...result, memory_type: this.mapMemoryTypeFromSDK(result.memory_type) })); } convertSDKUserMemoryStats(stats) { const initial = { conversation: 0, knowledge: 0, project: 0, context: 0, reference: 0, personal: 0, workflow: 0 }; const memoriesByType = { ...initial }; for (const [key, value] of Object.entries(stats.memories_by_type)) { const mappedKey = this.mapMemoryTypeFromSDK(key); memoriesByType[mappedKey] = value; } return { ...stats, memories_by_type: memoriesByType }; } dispose() { this.statusBarItem.dispose(); } // Migration helper for existing MemoryService users static async migrateFromBasicService(secureApiKeyService) { const enhanced = new EnhancedMemoryService(secureApiKeyService); // Show migration message vscode.window.showInformationMessage('🚀 Upgraded to Enhanced Memory Service with CLI integration!', 'Learn More').then(selection => { if (selection === 'Learn More') { vscode.env.openExternal(vscode.Uri.parse('https://docs.lanonasis.com/cli/integration')); } }); return enhanced; } } exports.EnhancedMemoryService = EnhancedMemoryService; //# sourceMappingURL=EnhancedMemoryService.js.map