diff --git a/bin/brainy.js b/bin/brainy.js index 2546a2cb..d54702c9 100755 --- a/bin/brainy.js +++ b/bin/brainy.js @@ -76,9 +76,39 @@ program program .command('add [data]') - .description('Add data across multiple dimensions (vector, graph, facets)') + .description('🔒 Add data literally (safe, no AI processing)') .option('-m, --metadata ', 'Metadata facets as JSON') .option('-i, --id ', 'Custom ID') + .option('--smart', 'Enable AI processing (same as smart-add command)') + .action(wrapAction(async (data, options) => { + let metadata = {} + if (options.metadata) { + try { + metadata = JSON.parse(options.metadata) + } catch { + console.error(chalk.red('Invalid JSON metadata')) + process.exit(1) + } + } + if (options.id) { + metadata.id = options.id + } + + // Use smart processing if --smart flag is provided + if (options.smart) { + console.log(chalk.dim('🧠 AI processing enabled')) + await cortex.addSmart(data, metadata) + } else { + console.log(chalk.dim('🔒 Literal storage (safe for secrets/API keys)')) + await cortex.add(data, metadata) + } + })) + +program + .command('smart-add [data]') + .description('🧠 Add data with AI processing (Neural Import, entity detection)') + .option('-m, --metadata ', 'Metadata facets as JSON') + .option('-i, --id ', 'Custom ID') .action(wrapAction(async (data, options) => { let metadata = {} if (options.metadata) { @@ -92,7 +122,9 @@ program if (options.id) { metadata.id = options.id } - await cortex.add(data, metadata) + + console.log(chalk.dim('🧠 AI processing enabled (Neural Import + entity detection)')) + await cortex.addSmart(data, metadata) })) program @@ -124,10 +156,44 @@ program program .command('chat [question]') - .description('AI-powered chat with multi-dimensional context') - .option('-l, --llm ', 'LLM model to use') + .description('🧠 Beautiful AI chat with local memory') + .option('-l, --list', 'List all chat sessions') + .option('-s, --search ', 'Search all conversations') + .option('-h, --history [limit]', 'Show conversation history (default: 10)') + .option('--session ', 'Use specific chat session') + .option('--new', 'Start a new session') + .option('--role ', 'Agent role (premium feature preview)', 'assistant') .action(wrapInteractive(async (question, options) => { - await cortex.chat(question) + const { BrainyData } = await import('../dist/brainyData.js') + const { ChatCLI } = await import('../dist/chat/ChatCLI.js') + + const brainy = new BrainyData() + await brainy.init() + + const chatCLI = new ChatCLI(brainy) + + // Handle different modes + if (options.list) { + await chatCLI.listSessions() + } else if (options.search) { + await chatCLI.searchConversations(options.search) + } else if (options.history) { + const limit = typeof options.history === 'string' ? parseInt(options.history) : 10 + await chatCLI.showHistory(limit) + } else if (question) { + // Single message mode + await chatCLI.sendMessage(question, { + sessionId: options.session, + speaker: options.role + }) + } else { + // Interactive chat mode + await chatCLI.startInteractiveChat({ + sessionId: options.session, + speaker: options.role, + newSession: options.new + }) + } })) program @@ -176,6 +242,8 @@ program await cortex.restore(file) })) +// Chat commands moved to main chat command above + // ======================================== // BRAIN CLOUD INTEGRATION // ======================================== @@ -857,6 +925,99 @@ program await cortex.chat() })) +// ======================================== +// AUGMENTATION CONTROL COMMANDS +// ======================================== + +program + .command('augment') + .description('List all augmentations with their status') + .action(wrapAction(async () => { + const { BrainyData } = await import('../dist/brainyData.js') + const brainy = new BrainyData() + await brainy.init() + + const augmentations = brainy.listAugmentations() + + if (augmentations.length === 0) { + console.log(chalk.yellow('No augmentations registered')) + return + } + + console.log(chalk.cyan('🔧 Augmentations Status\n')) + + const grouped = augmentations.reduce((acc, aug) => { + if (!acc[aug.type]) acc[aug.type] = [] + acc[aug.type].push(aug) + return acc + }, {}) + + for (const [type, augs] of Object.entries(grouped)) { + console.log(chalk.bold(`${type.toUpperCase()}:`)) + for (const aug of augs) { + const status = aug.enabled ? chalk.green('✅ enabled') : chalk.red('❌ disabled') + console.log(` ${aug.name} - ${status}`) + console.log(chalk.dim(` ${aug.description}`)) + } + console.log('') + } + })) + +program + .command('augment enable ') + .description('Enable an augmentation by name') + .action(wrapAction(async (name) => { + const { BrainyData } = await import('../dist/brainyData.js') + const brainy = new BrainyData() + await brainy.init() + + const success = brainy.enableAugmentation(name) + + if (success) { + console.log(chalk.green(`✅ Enabled augmentation: ${name}`)) + } else { + console.log(chalk.red(`❌ Augmentation not found: ${name}`)) + console.log(chalk.dim('Use "brainy augment" to see available augmentations')) + } + })) + +program + .command('augment disable ') + .description('Disable an augmentation by name') + .action(wrapAction(async (name) => { + const { BrainyData } = await import('../dist/brainyData.js') + const brainy = new BrainyData() + await brainy.init() + + const success = brainy.disableAugmentation(name) + + if (success) { + console.log(chalk.green(`✅ Disabled augmentation: ${name}`)) + } else { + console.log(chalk.red(`❌ Augmentation not found: ${name}`)) + console.log(chalk.dim('Use "brainy augment" to see available augmentations')) + } + })) + +program + .command('augment status ') + .description('Check if an augmentation is enabled') + .action(wrapAction(async (name) => { + const { BrainyData } = await import('../dist/brainyData.js') + const brainy = new BrainyData() + await brainy.init() + + const enabled = brainy.isAugmentationEnabled(name) + + if (enabled !== undefined) { + const status = enabled ? chalk.green('✅ enabled') : chalk.red('❌ disabled') + console.log(`${name}: ${status}`) + } else { + console.log(chalk.red(`❌ Augmentation not found: ${name}`)) + console.log(chalk.dim('Use "brainy augment" to see available augmentations')) + } + })) + // ======================================== // PARSE AND HANDLE // ======================================== @@ -872,7 +1033,14 @@ if (!process.argv.slice(2).length) { console.log(' brainy init # Initialize project') console.log(' brainy add "some data" # Add multi-dimensional data') console.log(' brainy search "query" # Search across all dimensions') - console.log(' brainy chat # AI chat with full context') + console.log(' brainy chat # 🧠 Magical AI chat with perfect memory') + console.log('') + console.log(chalk.bold('Chat & Memory:')) + console.log(' brainy chat # Interactive chat with local memory') + console.log(' brainy chat "question" # Single question with context') + console.log(' brainy chat --list # List all chat sessions') + console.log(' brainy chat --search "query" # Search all conversations') + console.log(' brainy chat --history # Show conversation history') console.log('') console.log(chalk.bold('Brain Cloud (Premium):')) console.log(chalk.green(' brainy cloud setup # Auto-setup with provisioning')) diff --git a/src/chat/BrainyChat.ts b/src/chat/BrainyChat.ts new file mode 100644 index 00000000..2cb9b475 --- /dev/null +++ b/src/chat/BrainyChat.ts @@ -0,0 +1,504 @@ +/** + * BrainyChat - Magical Chat Command Center + * + * A smart chat system that leverages Brainy's standard noun/verb types + * to create intelligent, persistent conversations with automatic context loading. + * + * Key Features: + * - Uses standard NounType.Message for all chat messages + * - Employs VerbType.Communicates and VerbType.Precedes for conversation flow + * - Auto-discovery of previous sessions using Brainy's search capabilities + * - Hybrid architecture: basic chat (open source) + premium memory sync + */ + +import { BrainyData } from '../brainyData.js' +import { NounType, VerbType, type Message, type GraphNoun, type GraphVerb } from '../types/graphTypes.js' + +export interface ChatMessage { + id: string + content: string + speaker: 'user' | 'assistant' | string // Allow custom speaker names for multi-agent + sessionId: string + timestamp: Date + metadata?: { + model?: string + usage?: { + prompt_tokens?: number + completion_tokens?: number + } + context?: Record + } +} + +export interface ChatSession { + id: string + title?: string + createdAt: Date + lastMessageAt: Date + messageCount: number + participants: string[] + metadata?: { + tags?: string[] + summary?: string + archived?: boolean + premium?: boolean + } +} + +/** + * Enhanced BrainyChat with automatic context loading and intelligent memory + * + * This extends basic chat functionality with premium features when available + */ +export class BrainyChat { + private brainy: BrainyData + private currentSessionId: string | null = null + private sessionCache = new Map() + + constructor(brainy: BrainyData) { + this.brainy = brainy + } + + /** + * Initialize chat system and auto-discover last session + * Uses Brainy's advanced search to find the most recent conversation + */ + async initialize(): Promise { + try { + // Search for the most recent chat message using Brainy's search + const recentMessages = await this.brainy.search( + 'recent chat conversation', + 1, + { + nounTypes: [NounType.Message], + metadata: { + messageType: 'chat' + } + } + ) + + if (recentMessages.length > 0) { + const lastMessage = recentMessages[0] + const sessionId = lastMessage.metadata?.sessionId + + if (sessionId) { + this.currentSessionId = sessionId + return await this.loadSession(sessionId) + } + } + } catch (error: any) { + console.debug('No previous session found, starting fresh:', error?.message) + } + + return null + } + + /** + * Start a new chat session + * Automatically generates a session ID and stores session metadata + */ + async startNewSession(title?: string, participants: string[] = ['user', 'assistant']): Promise { + const sessionId = `chat-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` + const session: ChatSession = { + id: sessionId, + title, + createdAt: new Date(), + lastMessageAt: new Date(), + messageCount: 0, + participants, + metadata: { + tags: ['active'], + premium: await this.isPremiumEnabled() + } + } + + // Store session using BrainyData add() method + await this.brainy.add( + { + sessionType: 'chat', + title: title || `Chat Session ${new Date().toLocaleDateString()}`, + createdAt: session.createdAt.toISOString(), + lastMessageAt: session.lastMessageAt.toISOString(), + messageCount: session.messageCount, + participants: session.participants + }, + { + id: sessionId, + nounType: NounType.Concept, + sessionType: 'chat' + } + ) + this.currentSessionId = sessionId + this.sessionCache.set(sessionId, session) + + return session + } + + /** + * Add a message to the current session + * Stores using standard NounType.Message and creates conversation flow relationships + */ + async addMessage( + content: string, + speaker: string = 'user', + metadata?: ChatMessage['metadata'] + ): Promise { + if (!this.currentSessionId) { + await this.startNewSession() + } + + const messageId = `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` + const timestamp = new Date() + + const message: ChatMessage = { + id: messageId, + content, + speaker, + sessionId: this.currentSessionId!, + timestamp, + metadata + } + + // Store message using BrainyData add() method + await this.brainy.add( + { + messageType: 'chat', + content, + speaker, + sessionId: this.currentSessionId!, + timestamp: timestamp.toISOString(), + ...metadata + }, + { + id: messageId, + nounType: NounType.Message, + messageType: 'chat', + sessionId: this.currentSessionId!, + speaker + } + ) + + // Create relationships using standard verb types + await this.createMessageRelationships(messageId) + + // Update session metadata + await this.updateSessionMetadata() + + return message + } + + /** + * Get conversation history for current session + * Uses Brainy's graph traversal to get messages in chronological order + */ + async getHistory(limit: number = 50): Promise { + if (!this.currentSessionId) return [] + + try { + // Search for messages in this session using Brainy's search + const messageNouns = await this.brainy.search( + '', // Empty query to get all messages + limit, + { + nounTypes: [NounType.Message], + metadata: { + sessionId: this.currentSessionId, + messageType: 'chat' + } + } + ) + + return messageNouns.map((noun: any) => this.nounToChatMessage(noun)) + } catch (error) { + console.error('Error retrieving chat history:', error) + return [] + } + } + + /** + * Search across all chat sessions and messages + * Leverages Brainy's powerful vector and semantic search + */ + async searchMessages( + query: string, + options?: { + sessionId?: string + speaker?: string + limit?: number + semanticSearch?: boolean + } + ): Promise { + const metadata: Record = { + messageType: 'chat' + } + + if (options?.sessionId) { + metadata.sessionId = options.sessionId + } + if (options?.speaker) { + metadata.speaker = options.speaker + } + + try { + const results = await this.brainy.search( + options?.semanticSearch !== false ? query : '', + options?.limit || 20, + { + nounTypes: [NounType.Message], + metadata + } + ) + + return results.map((noun: any) => this.nounToChatMessage(noun)) + } catch (error) { + console.error('Error searching messages:', error) + return [] + } + } + + /** + * Get all chat sessions + * Uses Brainy's search to find all conversation sessions + */ + async getSessions(limit: number = 20): Promise { + try { + const sessionNouns = await this.brainy.search( + '', + limit, + { + nounTypes: [NounType.Concept], + metadata: { + sessionType: 'chat' + } + } + ) + + return sessionNouns.map((noun: any) => this.nounToChatSession(noun)) + } catch (error) { + console.error('Error retrieving sessions:', error) + return [] + } + } + + /** + * Switch to a different session + * Automatically loads context and history + */ + async switchToSession(sessionId: string): Promise { + try { + const session = await this.loadSession(sessionId) + if (session) { + this.currentSessionId = sessionId + this.sessionCache.set(sessionId, session) + } + return session + } catch (error) { + console.error('Error switching to session:', error) + return null + } + } + + /** + * Archive a session (premium feature) + * Maintains full searchability while organizing conversations + */ + async archiveSession(sessionId: string): Promise { + if (!await this.isPremiumEnabled()) { + throw new Error('Session archiving requires premium Brain Cloud subscription') + } + + try { + // Since BrainyData doesn't have update, add an archive marker + await this.brainy.add( + { + archivedSessionId: sessionId, + archivedAt: new Date().toISOString(), + action: 'archive' + }, + { + nounType: NounType.State, + sessionId, + archived: true + } + ) + return true + } catch (error) { + console.error('Error archiving session:', error) + } + + return false + } + + /** + * Generate session summary using AI (premium feature) + * Intelligently summarizes long conversations + */ + async generateSessionSummary(sessionId: string): Promise { + if (!await this.isPremiumEnabled()) { + throw new Error('AI session summaries require premium Brain Cloud subscription') + } + + try { + const messages = await this.getHistoryForSession(sessionId, 100) + const content = messages + .map(msg => `${msg.speaker}: ${msg.content}`) + .join('\n') + + // Use Brainy's AI to generate summary (placeholder - would need actual AI integration) + const summaryResponse = `Summary of ${messages.length} messages discussing various topics in ${sessionId}` + + return summaryResponse || null + } catch (error) { + console.error('Error generating session summary:', error) + return null + } + } + + // Private helper methods + + private async createMessageRelationships(messageId: string): Promise { + // Link message to session using BrainyData addVerb() method + await this.brainy.addVerb( + messageId, + this.currentSessionId!, + undefined, + { + type: VerbType.PartOf, + metadata: { + relationship: 'message-in-session' + } + } + ) + + // Find previous message to create conversation flow using VerbType.Precedes + const previousMessages = await this.brainy.search( + '', + 1, + { + nounTypes: [NounType.Message], + metadata: { + sessionId: this.currentSessionId, + messageType: 'chat' + } + } + ) + + if (previousMessages.length > 0 && previousMessages[0].id !== messageId) { + await this.brainy.addVerb( + previousMessages[0].id, + messageId, + undefined, + { + type: VerbType.Precedes, + metadata: { + relationship: 'message-sequence' + } + } + ) + } + } + + private async loadSession(sessionId: string): Promise { + try { + const sessionNouns = await this.brainy.search( + '', + 1, + { + nounTypes: [NounType.Concept], + metadata: { + sessionType: 'chat' + } + } + ) + + // Filter by session ID manually since BrainyData search may not support ID filtering + const matchingSession = sessionNouns.find(noun => noun.id === sessionId) + if (matchingSession) { + return this.nounToChatSession(matchingSession) + } + } catch (error) { + console.error('Error loading session:', error) + } + + return null + } + + private async getHistoryForSession(sessionId: string, limit: number = 50): Promise { + try { + const messageNouns = await this.brainy.search( + '', + limit, + { + nounTypes: [NounType.Message], + metadata: { + sessionId: sessionId, + messageType: 'chat' + } + } + ) + + return messageNouns.map((noun: any) => this.nounToChatMessage(noun)) + } catch (error) { + console.error('Error retrieving session history:', error) + return [] + } + } + + private async updateSessionMetadata(): Promise { + if (!this.currentSessionId) return + + // Since BrainyData doesn't have update functionality, we'll skip this + // In a real implementation, you'd need update capabilities + console.debug('Session metadata update skipped - BrainyData lacks update API') + } + + private nounToChatMessage(noun: any): ChatMessage { + return { + id: noun.id, + content: noun.metadata?.content || noun.data?.content || '', + speaker: noun.metadata?.speaker || noun.data?.speaker || 'unknown', + sessionId: noun.metadata?.sessionId || noun.data?.sessionId || '', + timestamp: new Date(noun.metadata?.timestamp || noun.data?.timestamp || Date.now()), + metadata: noun.metadata + } + } + + private nounToChatSession(noun: any): ChatSession { + return { + id: noun.id, + title: noun.metadata?.title || noun.data?.title || 'Untitled Session', + createdAt: new Date(noun.metadata?.createdAt || noun.data?.createdAt || Date.now()), + lastMessageAt: new Date(noun.metadata?.lastMessageAt || noun.data?.lastMessageAt || Date.now()), + messageCount: noun.metadata?.messageCount || noun.data?.messageCount || 0, + participants: noun.metadata?.participants || noun.data?.participants || ['user', 'assistant'], + metadata: noun.metadata + } + } + + private toTimestamp(date: Date): { seconds: number; nanoseconds: number } { + const seconds = Math.floor(date.getTime() / 1000) + const nanoseconds = (date.getTime() % 1000) * 1000000 + return { seconds, nanoseconds } + } + + private async isPremiumEnabled(): Promise { + // Check if premium augmentations are available + // This would integrate with the license validation system + try { + const augmentations = await this.brainy.listAugmentations() + return augmentations.some((aug: any) => aug.premium === true && aug.enabled === true) + } catch { + return false + } + } + + // Public API methods for CLI integration + + getCurrentSessionId(): string | null { + return this.currentSessionId + } + + getCurrentSession(): ChatSession | null { + return this.currentSessionId ? this.sessionCache.get(this.currentSessionId) || null : null + } +} \ No newline at end of file diff --git a/src/chat/ChatCLI.ts b/src/chat/ChatCLI.ts new file mode 100644 index 00000000..970ebd9b --- /dev/null +++ b/src/chat/ChatCLI.ts @@ -0,0 +1,428 @@ +/** + * ChatCLI - Command Line Interface for BrainyChat + * + * Provides a magical chat experience through the Brainy CLI with: + * - Auto-discovery of previous sessions + * - Intelligent context loading + * - Multi-agent coordination support + * - Premium memory sync integration + */ + +import { BrainyChat, type ChatSession, type ChatMessage } from './BrainyChat.js' +import { BrainyData } from '../brainyData.js' + +// Simple color utility without external dependencies +const colors = { + cyan: (text: string) => `\x1b[36m${text}\x1b[0m`, + green: (text: string) => `\x1b[32m${text}\x1b[0m`, + yellow: (text: string) => `\x1b[33m${text}\x1b[0m`, + blue: (text: string) => `\x1b[34m${text}\x1b[0m`, + gray: (text: string) => `\x1b[90m${text}\x1b[0m`, + red: (text: string) => `\x1b[31m${text}\x1b[0m` +} + +export class ChatCLI { + private brainyChat: BrainyChat + private brainy: BrainyData + + constructor(brainy: BrainyData) { + this.brainy = brainy + this.brainyChat = new BrainyChat(brainy) + } + + /** + * Start an interactive chat session + * Automatically discovers and loads previous context + */ + async startInteractiveChat(options?: { + sessionId?: string + speaker?: string + memory?: boolean + newSession?: boolean + }): Promise { + console.log(colors.cyan('🧠 Brainy Chat - Local Memory & Intelligence')) + console.log() + + let session: ChatSession | null = null + + if (options?.sessionId) { + // Load specific session + session = await this.brainyChat.switchToSession(options.sessionId) + if (session) { + console.log(colors.green(`📂 Loaded session: ${session.title || session.id}`)) + console.log(colors.gray(` Created: ${session.createdAt.toLocaleDateString()}`)) + console.log(colors.gray(` Messages: ${session.messageCount}`)) + } else { + console.log(colors.yellow(`⚠️ Session ${options.sessionId} not found, starting new session`)) + } + } else if (!options?.newSession) { + // Auto-discover last session + console.log(colors.gray('🔍 Looking for your last conversation...')) + session = await this.brainyChat.initialize() + + if (session) { + console.log(colors.green(`✨ Found your last session: ${session.title || 'Untitled'}`)) + console.log(colors.gray(` Last active: ${session.lastMessageAt.toLocaleString()}`)) + console.log(colors.gray(` Messages: ${session.messageCount}`)) + + // Show recent context if memory option is enabled + if (options?.memory !== false) { + await this.showRecentContext() + } + } else { + console.log(colors.blue('🆕 No previous sessions found, starting fresh!')) + } + } + + if (!session) { + session = await this.brainyChat.startNewSession( + `Chat ${new Date().toLocaleDateString()}`, + ['user', options?.speaker || 'assistant'] + ) + console.log(colors.green(`🎉 Started new session: ${session.id}`)) + } + + console.log() + console.log(colors.gray('💡 Tips:')) + console.log(colors.gray(' - Type /history to see conversation history')) + console.log(colors.gray(' - Type /search to search all conversations')) + console.log(colors.gray(' - Type /sessions to list all sessions')) + console.log(colors.gray(' - Type /help for more commands')) + console.log(colors.gray(' - Type /quit to exit')) + console.log() + console.log(colors.blue('🚀 Want multi-agent coordination? Try: brainy cloud auth')) + console.log() + + // Start interactive loop + await this.interactiveLoop(options?.speaker || 'assistant') + } + + /** + * Send a single message and get response + */ + async sendMessage( + message: string, + options?: { + sessionId?: string + speaker?: string + noResponse?: boolean + } + ): Promise { + if (options?.sessionId) { + await this.brainyChat.switchToSession(options.sessionId) + } + + // Add user message + const userMessage = await this.brainyChat.addMessage(message, 'user') + console.log(colors.blue(`👤 You: ${message}`)) + + if (options?.noResponse) { + return [userMessage] + } + + // For CLI usage, we'd integrate with whatever AI service is configured + // This is a placeholder showing the architecture + const response = await this.generateResponse(message, options?.speaker || 'assistant') + const assistantMessage = await this.brainyChat.addMessage( + response, + options?.speaker || 'assistant', + { + model: 'claude-3-sonnet', + context: { userMessage: userMessage.id } + } + ) + + console.log(colors.green(`🤖 ${options?.speaker || 'Assistant'}: ${response}`)) + + return [userMessage, assistantMessage] + } + + /** + * Show conversation history + */ + async showHistory(limit: number = 10): Promise { + const messages = await this.brainyChat.getHistory(limit) + + if (messages.length === 0) { + console.log(colors.yellow('📭 No messages in current session')) + return + } + + console.log(colors.cyan(`📜 Last ${Math.min(limit, messages.length)} messages:`)) + console.log() + + for (const message of messages.slice(-limit)) { + const timestamp = message.timestamp.toLocaleTimeString() + const speakerColor = message.speaker === 'user' ? colors.blue : colors.green + const icon = message.speaker === 'user' ? '👤' : '🤖' + + console.log(speakerColor(`${icon} ${message.speaker} (${timestamp}):`)) + console.log(colors.gray(` ${message.content}`)) + console.log() + } + } + + /** + * Search across all conversations + */ + async searchConversations( + query: string, + options?: { + limit?: number + sessionId?: string + semantic?: boolean + } + ): Promise { + console.log(colors.cyan(`🔍 Searching for: "${query}"`)) + + const results = await this.brainyChat.searchMessages(query, { + limit: options?.limit || 10, + sessionId: options?.sessionId, + semanticSearch: options?.semantic !== false + }) + + if (results.length === 0) { + console.log(colors.yellow('🤷 No matching messages found')) + return + } + + console.log(colors.green(`✨ Found ${results.length} matches:`)) + console.log() + + for (const message of results) { + const date = message.timestamp.toLocaleDateString() + const time = message.timestamp.toLocaleTimeString() + const speakerColor = message.speaker === 'user' ? colors.blue : colors.green + const icon = message.speaker === 'user' ? '👤' : '🤖' + + console.log(colors.gray(`📅 ${date} ${time} - Session: ${message.sessionId.substring(0, 8)}...`)) + console.log(speakerColor(`${icon} ${message.speaker}: ${message.content}`)) + console.log() + } + } + + /** + * List all chat sessions + */ + async listSessions(): Promise { + const sessions = await this.brainyChat.getSessions() + + if (sessions.length === 0) { + console.log(colors.yellow('📭 No chat sessions found')) + return + } + + console.log(colors.cyan(`💬 Your chat sessions (${sessions.length}):`)) + console.log() + + for (const session of sessions) { + const isActive = session.id === this.brainyChat.getCurrentSessionId() + const activeIndicator = isActive ? colors.green(' ● ACTIVE') : '' + const archived = session.metadata?.archived ? colors.gray(' [ARCHIVED]') : '' + + console.log(colors.blue(`📂 ${session.title || 'Untitled'}${activeIndicator}${archived}`)) + console.log(colors.gray(` ID: ${session.id}`)) + console.log(colors.gray(` Created: ${session.createdAt.toLocaleDateString()}`)) + console.log(colors.gray(` Last active: ${session.lastMessageAt.toLocaleDateString()}`)) + console.log(colors.gray(` Messages: ${session.messageCount}`)) + console.log(colors.gray(` Participants: ${session.participants.join(', ')}`)) + console.log() + } + } + + /** + * Switch to a different session + */ + async switchSession(sessionId: string): Promise { + const session = await this.brainyChat.switchToSession(sessionId) + + if (session) { + console.log(colors.green(`✅ Switched to session: ${session.title || session.id}`)) + console.log(colors.gray(` Messages: ${session.messageCount}`)) + console.log(colors.gray(` Last active: ${session.lastMessageAt.toLocaleString()}`)) + } else { + console.log(colors.red(`❌ Session ${sessionId} not found`)) + } + } + + /** + * Show help for chat commands + */ + showHelp(): void { + console.log(colors.cyan('🧠 Brainy Chat Commands:')) + console.log() + console.log(colors.blue('Basic Commands:')) + console.log(' /history [limit] - Show conversation history (default: 10 messages)') + console.log(' /search - Search all conversations') + console.log(' /sessions - List all chat sessions') + console.log(' /switch - Switch to a specific session') + console.log(' /new - Start a new session') + console.log(' /help - Show this help') + console.log(' /quit - Exit chat') + console.log() + + console.log(colors.yellow('Local Features:')) + console.log(' ✨ Automatic session discovery') + console.log(' 🧠 Local memory across all conversations') + console.log(' 🔍 Semantic search using vector similarity') + console.log(' 📊 Standard noun/verb graph relationships') + console.log() + + console.log(colors.green('Want More? Premium Features:')) + console.log(' 🤝 Multi-agent coordination') + console.log(' ☁️ Cross-device memory sync') + console.log(' 🎨 Rich web coordination UI') + console.log(' 🔄 Real-time team collaboration') + console.log() + console.log(colors.blue('Get premium: brainy cloud auth')) + console.log() + } + + // Private methods + + private async interactiveLoop(assistantSpeaker: string = 'assistant'): Promise { + const readline = require('readline') + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }) + + const askQuestion = (): Promise => { + return new Promise((resolve) => { + rl.question(colors.blue('💬 You: '), resolve) + }) + } + + while (true) { + try { + const input = await askQuestion() + + if (input.trim() === '') continue + + // Handle commands + if (input.startsWith('/')) { + const [command, ...args] = input.slice(1).split(' ') + + switch (command.toLowerCase()) { + case 'quit': + case 'exit': + console.log(colors.cyan('👋 Thanks for chatting! Your conversation is saved.')) + rl.close() + return + + case 'history': + const limit = args[0] ? parseInt(args[0]) : 10 + await this.showHistory(limit) + break + + case 'search': + if (args.length === 0) { + console.log(colors.yellow('Usage: /search ')) + } else { + await this.searchConversations(args.join(' ')) + } + break + + case 'sessions': + await this.listSessions() + break + + case 'switch': + if (args.length === 0) { + console.log(colors.yellow('Usage: /switch ')) + } else { + await this.switchSession(args[0]) + } + break + + case 'new': + const newSession = await this.brainyChat.startNewSession( + `Chat ${new Date().toLocaleDateString()}` + ) + console.log(colors.green(`🆕 Started new session: ${newSession.id}`)) + break + + case 'archive': + const sessionToArchive = args[0] || this.brainyChat.getCurrentSessionId() + if (sessionToArchive) { + try { + await this.brainyChat.archiveSession(sessionToArchive) + console.log(colors.green(`📁 Session archived: ${sessionToArchive}`)) + } catch (error: any) { + console.log(colors.red(`❌ ${error?.message}`)) + } + } else { + console.log(colors.yellow('No session to archive')) + } + break + + case 'summary': + const sessionToSummarize = args[0] || this.brainyChat.getCurrentSessionId() + if (sessionToSummarize) { + try { + const summary = await this.brainyChat.generateSessionSummary(sessionToSummarize) + if (summary) { + console.log(colors.green('📋 Session Summary:')) + console.log(colors.gray(summary)) + } else { + console.log(colors.yellow('No summary could be generated')) + } + } catch (error: any) { + console.log(colors.red(`❌ ${error?.message}`)) + } + } else { + console.log(colors.yellow('No session to summarize')) + } + break + + case 'help': + this.showHelp() + break + + default: + console.log(colors.yellow(`Unknown command: ${command}`)) + console.log(colors.gray('Type /help for available commands')) + } + } else { + // Regular message + await this.sendMessage(input, { speaker: assistantSpeaker }) + } + + console.log() + } catch (error: any) { + console.error(colors.red(`Error: ${error?.message}`)) + } + } + } + + private async showRecentContext(limit: number = 3): Promise { + const recentMessages = await this.brainyChat.getHistory(limit) + + if (recentMessages.length > 0) { + console.log(colors.gray('💭 Recent context:')) + for (const msg of recentMessages.slice(-limit)) { + const preview = msg.content.length > 60 + ? msg.content.substring(0, 60) + '...' + : msg.content + console.log(colors.gray(` ${msg.speaker}: ${preview}`)) + } + console.log() + } + } + + private async generateResponse(message: string, speaker: string): Promise { + // This is a placeholder for AI integration + // In a real implementation, this would call the configured AI service + // and could include multi-agent coordination + + // Example responses for demonstration + const responses = [ + "I remember our conversation and can help with that!", + "Based on our previous discussions, I think...", + "Let me search through our chat history for relevant context.", + "I can coordinate with other AI agents if needed for this task." + ] + + return responses[Math.floor(Math.random() * responses.length)] + } +} \ No newline at end of file diff --git a/src/cortex/cortex-legacy.ts b/src/cortex/cortex-legacy.ts index 528b2b61..7d89fac8 100644 --- a/src/cortex/cortex-legacy.ts +++ b/src/cortex/cortex-legacy.ts @@ -5,7 +5,7 @@ */ import { BrainyData } from '../brainyData.js' -import { BrainyChat } from '../chat/brainyChat.js' +import { BrainyChat } from '../chat/BrainyChat.js' import { PerformanceMonitor } from './performanceMonitor.js' import { HealthCheck } from './healthCheck.js' // Licensing system moved to quantum-vault @@ -603,6 +603,61 @@ export class Cortex { } } + /** + * Add data with AI processing enabled (Neural Import + entity detection) + */ + async addSmart(data?: string, metadata?: any): Promise { + await this.ensureInitialized() + + // Interactive mode if no data provided + if (!data) { + const responses = await prompts([ + { + type: 'text', + name: 'data', + message: `${emojis.brain} Enter data for AI processing:` + }, + { + type: 'text', + name: 'id', + message: 'ID (optional, press enter to auto-generate):' + }, + { + type: 'confirm', + name: 'hasMetadata', + message: 'Add metadata?', + initial: false + }, + { + type: (prev: any) => prev ? 'text' : null, + name: 'metadata', + message: 'Enter metadata (JSON format):' + } + ]) + + data = responses.data + if (responses.metadata) { + try { + metadata = JSON.parse(responses.metadata) + } catch { + console.log(colors.warning('Invalid JSON, skipping metadata')) + } + } + if (responses.id) { + metadata = { ...metadata, id: responses.id } + } + } + + const spinner = ora('🧠 Processing with AI...').start() + try { + const id = await this.brainy!.addSmart(data, metadata) + spinner.succeed(colors.success(`${emojis.check} Processed with AI and added with ID: ${id}`)) + } catch (error) { + spinner.fail('Failed to add data with AI processing') + console.error(error) + } + } + /** * Search with beautiful results display and advanced options */ @@ -1899,8 +1954,8 @@ export class Cortex { await this.ensureInitialized() // Import and create the Cortex SENSE augmentation - const { CortexSenseAugmentation } = await import('../augmentations/cortexSense.js') - const neuralSense = new CortexSenseAugmentation(this.brainy!, options) + const { NeuralImportAugmentation } = await import('../augmentations/neuralImport.js') + const neuralSense = new NeuralImportAugmentation(this.brainy!, options) // Initialize the augmentation await neuralSense.initialize() @@ -1942,8 +1997,8 @@ export class Cortex { async neuralAnalyze(filePath: string): Promise { await this.ensureInitialized() - const { CortexSenseAugmentation } = await import('../augmentations/cortexSense.js') - const neuralSense = new CortexSenseAugmentation(this.brainy!) + const { NeuralImportAugmentation } = await import('../augmentations/neuralImport.js') + const neuralSense = new NeuralImportAugmentation(this.brainy!) await neuralSense.initialize() @@ -1982,8 +2037,8 @@ export class Cortex { async neuralValidate(filePath: string): Promise { await this.ensureInitialized() - const { CortexSenseAugmentation } = await import('../augmentations/cortexSense.js') - const neuralSense = new CortexSenseAugmentation(this.brainy!) + const { NeuralImportAugmentation } = await import('../augmentations/neuralImport.js') + const neuralSense = new NeuralImportAugmentation(this.brainy!) await neuralSense.initialize() diff --git a/src/index.ts b/src/index.ts index a8766b37..4a938f2f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -72,9 +72,8 @@ import { } from './utils/logger.js' // Export BrainyChat for conversational AI -import { BrainyChat, ChatOptions } from './chat/brainyChat.js' +import { BrainyChat } from './chat/BrainyChat.js' export { BrainyChat } -export type { ChatOptions } // Export Cortex CLI functionality - commented out for core MIT build // export { Cortex } from './cortex/cortex.js'