/** * Real AgentDB Integration * * Full-featured AgentDB integration with: * - Vector similarity search for expert retrieval * - Causal reasoning for decision tracking * - Reflexion memory for self-improvement * - Skill library for learned capabilities * - Episodic memory for experience tracking * * @module agentdb-integration * @version 1.0.0 */ import { AgentDBSingleton } from './agentdb-singleton' /** * Expert embedding for semantic search */ export interface ExpertEmbedding { expertId: string name: string signature: string embedding: number[] performance: number metadata: Record } /** * Causal decision record for tracking reasoning chains */ export interface CausalDecision { id: string timestamp: Date expertId: string input: Record output: any reasoning: string[] causality: { causes: string[] effects: string[] confidence: number } outcome?: { success: boolean metrics: Record } } /** * Reflexion entry for self-improvement */ export interface ReflexionEntry { id: string timestamp: Date experience: string reflection: string insights: string[] actionItems: string[] relatedDecisions: string[] } /** * Learned skill in the skill library */ export interface LearnedSkill { id: string name: string description: string implementation: string prerequisites: string[] performance: { successRate: number avgLatency: number usageCount: number } examples: Array<{ input: any output: any context?: string }> } /** * Configuration for AgentDB integration */ export interface AgentDBConfig { dbPath?: string enableCausalReasoning?: boolean enableReflexion?: boolean enableSkillLibrary?: boolean vectorDimension?: number similarityThreshold?: number } /** * AgentDB Manager for learning and memory */ export class AgentDBManager { private db: any | null = null private config: Required constructor(config: AgentDBConfig = {}) { this.config = { dbPath: config.dbPath || ':memory:', enableCausalReasoning: config.enableCausalReasoning ?? true, enableReflexion: config.enableReflexion ?? true, enableSkillLibrary: config.enableSkillLibrary ?? true, vectorDimension: config.vectorDimension ?? 1536, // OpenAI ada-002 dimension similarityThreshold: config.similarityThreshold ?? 0.75 } // Initialize database asynchronously (methods have null guards) this.initializeAgentDb() } /** * Initialize AgentDB using singleton pattern */ private initializeAgentDb(): Promise { return (async () => { try { this.db = await AgentDBSingleton.getInstance(this.config.dbPath) this.initializeTables() } catch (error) { console.warn('⚠ AgentDBManager: Database initialization failed (sql.js compatibility issue):', error) this.db = null } })() } /** * Initialize database tables for learning features */ private initializeTables(): void { if (!this.db) return try { // Expert embeddings table with vector search this.db.exec(` CREATE TABLE IF NOT EXISTS expert_embeddings ( expert_id TEXT PRIMARY KEY, name TEXT NOT NULL, signature TEXT NOT NULL, embedding BLOB NOT NULL, performance REAL DEFAULT 0.0, metadata TEXT, created_at INTEGER DEFAULT (strftime('%s', 'now')) ) `) // Causal decisions table if (this.config.enableCausalReasoning) { this.db.exec(` CREATE TABLE IF NOT EXISTS causal_decisions ( id TEXT PRIMARY KEY, timestamp INTEGER NOT NULL, expert_id TEXT NOT NULL, input TEXT NOT NULL, output TEXT NOT NULL, reasoning TEXT NOT NULL, causality TEXT NOT NULL, outcome TEXT, FOREIGN KEY (expert_id) REFERENCES expert_embeddings(expert_id) ) `) } // Reflexion entries table if (this.config.enableReflexion) { this.db.exec(` CREATE TABLE IF NOT EXISTS reflexion_entries ( id TEXT PRIMARY KEY, timestamp INTEGER NOT NULL, experience TEXT NOT NULL, reflection TEXT NOT NULL, insights TEXT NOT NULL, action_items TEXT NOT NULL, related_decisions TEXT NOT NULL ) `) } // Skill library table if (this.config.enableSkillLibrary) { this.db.exec(` CREATE TABLE IF NOT EXISTS skill_library ( id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, description TEXT NOT NULL, implementation TEXT NOT NULL, prerequisites TEXT NOT NULL, performance TEXT NOT NULL, examples TEXT NOT NULL, created_at INTEGER DEFAULT (strftime('%s', 'now')), updated_at INTEGER DEFAULT (strftime('%s', 'now')) ) `) } } catch (error) { console.warn('⚠ AgentDBManager: Table initialization failed (sql.js compatibility issue):', error) this.db = null } } // ============================================================================ // Expert Embeddings & Vector Search // ============================================================================ /** * Store expert embedding for semantic search */ async storeExpertEmbedding(expert: ExpertEmbedding): Promise { if (!this.db) return const stmt = this.db.prepare(` INSERT OR REPLACE INTO expert_embeddings (expert_id, name, signature, embedding, performance, metadata) VALUES (?, ?, ?, ?, ?, ?) `) const embeddingBuffer = Buffer.from(new Float32Array(expert.embedding).buffer) stmt.run( expert.expertId, expert.name, expert.signature, embeddingBuffer, expert.performance, JSON.stringify(expert.metadata) ) } /** * Find similar experts using vector similarity search */ async findSimilarExperts( queryEmbedding: number[], topK: number = 5 ): Promise { if (!this.db) return [] const results = this.db.vectorSearch({ table: 'expert_embeddings', column: 'embedding', queryVector: queryEmbedding, limit: topK, threshold: this.config.similarityThreshold }) return results.map((row: any) => ({ expertId: row.expert_id, name: row.name, signature: row.signature, embedding: Array.from(new Float32Array(row.embedding.buffer)), performance: row.performance, metadata: JSON.parse(row.metadata || '{}') })) } /** * Get expert by ID */ async getExpert(expertId: string): Promise { if (!this.db) return null const stmt = this.db.prepare(` SELECT * FROM expert_embeddings WHERE expert_id = ? `) const row = stmt.get(expertId) as any if (!row) return null return { expertId: row.expert_id, name: row.name, signature: row.signature, embedding: Array.from(new Float32Array(row.embedding.buffer)), performance: row.performance, metadata: JSON.parse(row.metadata || '{}') } } // ============================================================================ // Causal Reasoning // ============================================================================ /** * Record a causal decision */ async recordCausalDecision(decision: CausalDecision): Promise { if (!this.db) return if (!this.config.enableCausalReasoning) return const stmt = this.db.prepare(` INSERT INTO causal_decisions (id, timestamp, expert_id, input, output, reasoning, causality, outcome) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `) stmt.run( decision.id, decision.timestamp.getTime(), decision.expertId, JSON.stringify(decision.input), JSON.stringify(decision.output), JSON.stringify(decision.reasoning), JSON.stringify(decision.causality), decision.outcome ? JSON.stringify(decision.outcome) : null ) } /** * Get causal chain for a decision */ async getCausalChain(decisionId: string, depth: number = 3): Promise { if (!this.db) return [] const chain: CausalDecision[] = [] const visited = new Set() const getDecision = (id: string): CausalDecision | null => { const stmt = this.db.prepare(` SELECT * FROM causal_decisions WHERE id = ? `) const row = stmt.get(id) as any if (!row) return null return { id: row.id, timestamp: new Date(row.timestamp), expertId: row.expert_id, input: JSON.parse(row.input), output: JSON.parse(row.output), reasoning: JSON.parse(row.reasoning), causality: JSON.parse(row.causality), outcome: row.outcome ? JSON.parse(row.outcome) : undefined } } const traverse = (id: string, currentDepth: number) => { if (currentDepth >= depth || visited.has(id)) return visited.add(id) const decision = getDecision(id) if (!decision) return chain.push(decision) // Traverse causes for (const causeId of decision.causality.causes) { traverse(causeId, currentDepth + 1) } } traverse(decisionId, 0) return chain } // ============================================================================ // Reflexion Memory // ============================================================================ /** * Add reflexion entry for self-improvement */ async addReflexion(entry: ReflexionEntry): Promise { if (!this.db) return if (!this.config.enableReflexion) return const stmt = this.db.prepare(` INSERT INTO reflexion_entries (id, timestamp, experience, reflection, insights, action_items, related_decisions) VALUES (?, ?, ?, ?, ?, ?, ?) `) stmt.run( entry.id, entry.timestamp.getTime(), entry.experience, entry.reflection, JSON.stringify(entry.insights), JSON.stringify(entry.actionItems), JSON.stringify(entry.relatedDecisions) ) } /** * Get recent reflexions */ async getRecentReflexions(limit: number = 10): Promise { if (!this.db) return [] const stmt = this.db.prepare(` SELECT * FROM reflexion_entries ORDER BY timestamp DESC LIMIT ? `) const rows = stmt.all(limit) as any[] return rows.map(row => ({ id: row.id, timestamp: new Date(row.timestamp), experience: row.experience, reflection: row.reflection, insights: JSON.parse(row.insights), actionItems: JSON.parse(row.action_items), relatedDecisions: JSON.parse(row.related_decisions) })) } // ============================================================================ // Skill Library // ============================================================================ /** * Add skill to library */ async addSkill(skill: LearnedSkill): Promise { if (!this.db) return if (!this.config.enableSkillLibrary) return const stmt = this.db.prepare(` INSERT OR REPLACE INTO skill_library (id, name, description, implementation, prerequisites, performance, examples, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, strftime('%s', 'now')) `) stmt.run( skill.id, skill.name, skill.description, skill.implementation, JSON.stringify(skill.prerequisites), JSON.stringify(skill.performance), JSON.stringify(skill.examples) ) } /** * Get skill by name */ async getSkill(name: string): Promise { if (!this.db) return null const stmt = this.db.prepare(` SELECT * FROM skill_library WHERE name = ? `) const row = stmt.get(name) as any if (!row) return null return { id: row.id, name: row.name, description: row.description, implementation: row.implementation, prerequisites: JSON.parse(row.prerequisites), performance: JSON.parse(row.performance), examples: JSON.parse(row.examples) } } /** * List all skills */ async listSkills(): Promise { if (!this.db) return [] const stmt = this.db.prepare(` SELECT * FROM skill_library ORDER BY updated_at DESC `) const rows = stmt.all() as any[] return rows.map(row => ({ id: row.id, name: row.name, description: row.description, implementation: row.implementation, prerequisites: JSON.parse(row.prerequisites), performance: JSON.parse(row.performance), examples: JSON.parse(row.examples) })) } /** * Update skill performance metrics */ async updateSkillPerformance( skillName: string, metrics: { successRate?: number; avgLatency?: number; usageCount?: number } ): Promise { if (!this.db) return const skill = await this.getSkill(skillName) if (!skill) return const updatedPerformance = { ...skill.performance, ...metrics } const stmt = this.db.prepare(` UPDATE skill_library SET performance = ?, updated_at = strftime('%s', 'now') WHERE name = ? `) stmt.run(JSON.stringify(updatedPerformance), skillName) } // ============================================================================ // Cleanup & Utilities // ============================================================================ // ============================================================================ // Cross-Project Features // ============================================================================ /** * Find experts across all projects by role */ async findExpertsByRole(role: string, topK: number = 10): Promise { if (!this.db) return [] const stmt = this.db.prepare(` SELECT * FROM expert_embeddings WHERE name LIKE ? OR expert_id LIKE ? ORDER BY performance DESC LIMIT ? `) const rows = stmt.all(`%${role}%`, `%${role}%`, topK) as any[] return rows.map(row => ({ expertId: row.expert_id, name: row.name, signature: row.signature, embedding: Array.from(new Float32Array(row.embedding.buffer)), performance: row.performance, metadata: JSON.parse(row.metadata || '{}') })) } /** * Compare expert performance across projects */ async compareExpertsAcrossProjects(expertRole: string): Promise<{ expertRole: string totalExperts: number avgPerformance: number bestExpert: { expertId: string; project: string; performance: number } | null projectPerformance: Array<{ project: string; avgPerformance: number; count: number }> }> { const experts = await this.findExpertsByRole(expertRole, 100) if (experts.length === 0) { return { expertRole, totalExperts: 0, avgPerformance: 0, bestExpert: null, projectPerformance: [] } } // Calculate overall stats const avgPerformance = experts.reduce((sum, e) => sum + e.performance, 0) / experts.length // Find best expert const bestExpert = experts.reduce((best, e) => e.performance > best.performance ? e : best ) // Group by project const projectMap = new Map() for (const expert of experts) { const project = expert.metadata.project || 'unknown' if (!projectMap.has(project)) { projectMap.set(project, { sum: 0, count: 0 }) } const stats = projectMap.get(project)! stats.sum += expert.performance stats.count++ } const projectPerformance = Array.from(projectMap.entries()).map(([project, stats]) => ({ project, avgPerformance: stats.sum / stats.count, count: stats.count })) return { expertRole, totalExperts: experts.length, avgPerformance, bestExpert: { expertId: bestExpert.expertId, project: bestExpert.metadata.project || 'unknown', performance: bestExpert.performance }, projectPerformance: projectPerformance.sort((a, b) => b.avgPerformance - a.avgPerformance) } } /** * Export expert knowledge for cross-project sharing */ async exportExpertKnowledge(expertId: string): Promise<{ expert: ExpertEmbedding skills: LearnedSkill[] reflexions: ReflexionEntry[] decisions: CausalDecision[] } | null> { if (!this.db) return null const expert = await this.getExpert(expertId) if (!expert) return null // Get all related data const skills = await this.listSkills() const reflexions = await this.getRecentReflexions(100) // Get recent decisions const decisionStmt = this.db.prepare(` SELECT * FROM causal_decisions WHERE expert_id = ? ORDER BY timestamp DESC LIMIT 50 `) const decisionRows = decisionStmt.all(expertId) as any[] const decisions = decisionRows.map(row => ({ id: row.id, timestamp: new Date(row.timestamp), expertId: row.expert_id, input: JSON.parse(row.input), output: JSON.parse(row.output), reasoning: JSON.parse(row.reasoning), causality: JSON.parse(row.causality), outcome: row.outcome ? JSON.parse(row.outcome) : undefined })) return { expert, skills, reflexions, decisions } } /** * Import expert knowledge from another project */ async importExpertKnowledge( knowledge: { expert: ExpertEmbedding skills: LearnedSkill[] reflexions: ReflexionEntry[] decisions: CausalDecision[] }, targetProject: string ): Promise { // Create new expert ID for target project const newExpertId = `${knowledge.expert.expertId}-${targetProject}-${Date.now()}` // Store expert with new ID await this.storeExpertEmbedding({ ...knowledge.expert, expertId: newExpertId, metadata: { ...knowledge.expert.metadata, project: targetProject, importedFrom: knowledge.expert.metadata.project, originalExpertId: knowledge.expert.expertId } }) // Import skills for (const skill of knowledge.skills) { await this.addSkill({ ...skill, id: `${skill.id}-${targetProject}`, name: `${skill.name}_${targetProject}` }) } return newExpertId } /** * Close database connection */ close(): void { if (this.db) { try { this.db.close() } catch (error) { console.warn('⚠ AgentDBManager: Failed to close database:', error) } finally { this.db = null } } } /** * Get database statistics */ async getStats(): Promise<{ expertCount: number decisionCount: number reflexionCount: number skillCount: number }> { if (!this.db) { return { expertCount: 0, decisionCount: 0, reflexionCount: 0, skillCount: 0 } } const getCount = (table: string) => { const stmt = this.db.prepare(`SELECT COUNT(*) as count FROM ${table}`) return (stmt.get() as any).count } return { expertCount: getCount('expert_embeddings'), decisionCount: this.config.enableCausalReasoning ? getCount('causal_decisions') : 0, reflexionCount: this.config.enableReflexion ? getCount('reflexion_entries') : 0, skillCount: this.config.enableSkillLibrary ? getCount('skill_library') : 0 } } } /** * Create AgentDB manager with default configuration */ export function createAgentDB(config?: AgentDBConfig): AgentDBManager { return new AgentDBManager(config) }