@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
JavaScript
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