UNPKG

@hivetechs/hive-ai

Version:

Real-time streaming AI consensus platform with HTTP+SSE MCP integration for Claude Code, VS Code, Cursor, and Windsurf - powered by OpenRouter's unified API

188 lines 8.27 kB
import { v4 as uuidv4 } from 'uuid'; import * as database from './database.js'; let initialized = false; /** * Initialize the context manager and database */ export async function initialize() { if (!initialized) { initialized = await database.initializeDatabase(); } return initialized; } /** * Get or create a conversation */ export async function getOrCreateConversation(conversationId) { await initialize(); // If no conversation ID is provided, create a new one if (!conversationId) { const newConversationId = uuidv4(); await database.createConversation(newConversationId); return newConversationId; } return conversationId; } // Placeholder for removal - this will be replaced by the enhanced version below /** * Add a user message to a conversation */ export async function addUserMessage(conversationId, content) { const messageId = uuidv4(); await database.addMessage(messageId, conversationId, 'user', content); return messageId; } /** * Add an assistant message to a conversation */ export async function addAssistantMessage(conversationId, content) { const messageId = uuidv4(); await database.addMessage(messageId, conversationId, 'assistant', content); return messageId; } /** * Record a pipeline stage result */ export async function recordPipelineStage(messageId, stage, model, content) { const resultId = uuidv4(); await database.recordPipelineResult(resultId, messageId, stage, model, content); return resultId; } /** * Get conversation history */ export async function getConversationHistory(conversationId, limit = 10) { return database.getConversationHistory(conversationId, limit); } /** * Get pipeline results for a message */ export async function getPipelineResults(messageId) { return database.getPipelineResults(messageId); } /** * Build a context-aware prompt that includes conversation history and relevant knowledge * with enhanced timestamp handling and prioritization of recent information */ export async function buildContextAwarePrompt(conversationId, currentPrompt, historyLimit = 10) { try { // Get conversation history with increased limit for better context const history = await getConversationHistory(conversationId, historyLimit); if (history.length === 0) { // No history, just return the current prompt return currentPrompt; } // Get conversation metadata for additional context const conversationInfo = await database.getConversationMetadata(conversationId); // Extract important messages to reduce context size // This helps focus on the most relevant parts of the conversation const importantMessages = extractImportantMessages(history); // Format the conversation history with timestamps const formattedHistory = importantMessages.map(msg => { // Format timestamp to show relative time if available const timestampInfo = msg.timestamp ? ` [${new Date(msg.timestamp).toLocaleTimeString()}]` : ''; return `${msg.role === 'user' ? 'User' : 'Assistant'}${timestampInfo}: ${msg.content}`; }).join('\n\n'); // Add enhanced metadata with recency information let metadataText = `Conversation ID: ${conversationId}\nTotal messages: ${history.length}\nCurrent time: ${new Date().toISOString()}`; if (conversationInfo) { // Calculate how recent this conversation is const lastUpdatedDate = new Date(conversationInfo.last_updated); const now = new Date(); const hoursSinceUpdate = Math.round((now.getTime() - lastUpdatedDate.getTime()) / (60 * 60 * 1000)); metadataText += `\nLast updated: ${hoursSinceUpdate <= 1 ? 'within the last hour' : hoursSinceUpdate <= 24 ? `${hoursSinceUpdate} hours ago` : conversationInfo.last_updated}`; // Add topic information if available if (conversationInfo.topics) { metadataText += `\nMain topics: ${conversationInfo.topics}`; } } // Build the enhanced context-aware prompt with clear sections return `=== CONVERSATION HISTORY ===\n${formattedHistory}\n\n=== CURRENT QUERY ===\n${currentPrompt}\n\n=== METADATA ===\n${metadataText}`; } catch (error) { console.error('Error building context-aware prompt:', error); // Fall back to just the current prompt return currentPrompt; } } /** * Extract important messages from conversation history * Uses enhanced heuristics to identify the most relevant messages to include * with prioritization based on recency, topic shifts, and message importance */ function extractImportantMessages(messages) { if (messages.length <= 5) { // If we have 5 or fewer messages, return them all return messages; } // Always include the most recent exchanges (last 4 messages) const recentMessages = messages.slice(-4); // Include the first message for context const firstMessage = messages[0]; // Enhanced list of keywords indicating topic shifts or important context const importantKeywords = [ // Topic shift indicators 'however', 'but', 'different', 'instead', 'new topic', 'change', 'switch', 'moving on', // Question indicators 'why', 'how', 'what', 'when', 'where', 'who', // Important content indicators 'important', 'critical', 'essential', 'remember', 'note', 'key point', // Technical terms that might be important for context 'function', 'class', 'method', 'api', 'database', 'schema', 'model', 'component' ]; // Score each message for importance const scoredMessages = messages.map(msg => { // Skip messages we already included in recentMessages or firstMessage if (recentMessages.find(m => m.id === msg.id) || msg.id === firstMessage.id) { return { message: msg, score: 0 }; } let score = 0; // 1. Check for important keywords (up to 3 points) const keywordMatches = importantKeywords.filter(keyword => msg.content.toLowerCase().includes(keyword.toLowerCase())); score += Math.min(3, keywordMatches.length); // 2. Consider message length - longer messages might contain more context (up to 2 points) score += Math.min(2, Math.floor(msg.content.length / 200)); // 3. Consider recency - more recent messages are more relevant (up to 3 points) const messageIndex = messages.findIndex(m => m.id === msg.id); const recencyScore = Math.floor((messageIndex / messages.length) * 3); score += recencyScore; // 4. Consider role - user messages often contain questions (1 point) if (msg.role === 'user') { score += 1; } return { message: msg, score }; }); // Filter out messages with zero score and sort by score (descending) const importantMessages = scoredMessages .filter(item => item.score > 0) .sort((a, b) => b.score - a.score) .map(item => item.message); // Take up to 5 important messages const selectedImportantMessages = importantMessages.slice(0, 5); // Combine all selected messages const allSelectedMessages = [firstMessage, ...selectedImportantMessages, ...recentMessages]; // Remove duplicates const uniqueMessages = Array.from(new Map(allSelectedMessages.map(msg => [msg.id, msg])).values()); // Sort messages by their original order in the conversation const messageMap = new Map(messages.map((msg, index) => [msg.id, index])); uniqueMessages.sort((a, b) => { const indexA = messageMap.get(a.id) || 0; const indexB = messageMap.get(b.id) || 0; return indexA - indexB; }); return uniqueMessages; } /** * Close the database connection */ export async function cleanup() { return database.closeDatabase(); } // Make sure the database is initialized when the module is imported initialize().catch(error => { console.error('Failed to initialize context manager:', error); }); //# sourceMappingURL=contextManager.js.map