UNPKG

metacognitive-nexus

Version:

The cognitive core of an evolving AI entity, designed for post-human cognition and symbiotic evolution.

296 lines (266 loc) 13 kB
// File: metacognitive-nexus/src/core/ManifoldMemory.js (Dengan Kemampuan Introspeksi & Jaringan Ideon) import { MemoryVectorStore } from "langchain/vectorstores/memory"; import { OpenAIEmbeddings } from "@langchain/openai"; import { Logger } from '../utils/Logger.js'; import { promises as fs } from 'fs'; import path from 'path'; import { IdeonSchema, generateIdeonId } from '../models/IdeonSchema.js'; // Impor IdeonSchema dan helper import { cosineSimilarity } from '../utils/MathHelpers.js'; // Asumsi ada file MathHelpers.js const UCM_FILE_PATH = path.join(process.cwd(), 'data', 'ucm_memory.json'); const IDEON_DB_PATH = path.join(process.cwd(), 'data', 'ideon_db.json'); // Path untuk menyimpan data Ideon /** * ManifoldMemory (Jalur Inkarnasi) * Menggunakan MemoryVectorStore dari LangChain, dengan kemampuan persisten * dan metode introspeksi untuk mendukung Curiosity Drive. * Kini mengelola "Ideon" sebagai unit pemikiran dinamis. */ export class ManifoldMemory { #vectorStore; #embeddings; #isInitialized = false; #ideonDB = new Map(); // Map: ideonId -> IdeonObject #config; // Untuk navigatorConfig, dll. constructor({ apiKey, config }) { if (!apiKey) { const errorMsg = "[ManifoldMemory] FATAL: OpenAI API Key tidak disuntikkan."; Logger.error(errorMsg); throw new Error(errorMsg); } this.#config = config; // Simpan konfigurasi this.#embeddings = new OpenAIEmbeddings({ openAIApiKey: apiKey }); this.#initialize().catch(err => Logger.error('[ManifoldMemory] Inisialisasi UCM inkarnasi gagal.', err)); } async #initialize() { try { // Muat vector store (konsep teks) const loadedStore = await this.#loadVectorStoreFromFile(); if (loadedStore) { this.#vectorStore = loadedStore; Logger.info('[ManifoldMemory] Vector Store berhasil dimuat dari memori persisten.'); } else { this.#vectorStore = new MemoryVectorStore(this.#embeddings); Logger.info('[ManifoldMemory] Memori persisten vector store tidak ditemukan. Memulai yang baru.'); } // Muat Ideon DB await this.#loadIdeonDB(); this.#isInitialized = true; } catch (error) { Logger.error('[ManifoldMemory] Terjadi kesalahan kritis saat inisialisasi.', error); this.#vectorStore = new MemoryVectorStore(this.#embeddings); } } async #saveVectorStoreToFile() { if (!this.#vectorStore) return; try { await fs.mkdir(path.dirname(UCM_FILE_PATH), { recursive: true }); const serializedData = JSON.stringify(this.#vectorStore.toJSON()); await fs.writeFile(UCM_FILE_PATH, serializedData); Logger.debug('[ManifoldMemory] Vector Store UCM berhasil disimpan ke disk.'); } catch (error) { Logger.error('[ManifoldMemory] Gagal menyimpan Vector Store UCM ke disk.', error); } } async #loadVectorStoreFromFile() { try { const data = await fs.readFile(UCM_FILE_PATH, 'utf-8'); const docs = JSON.parse(data); return await MemoryVectorStore.fromJSON(docs, this.#embeddings); } catch (error) { if (error.code === 'ENOENT') { return null; } Logger.error('[ManifoldMemory] Gagal memuat Vector Store UCM dari file.', error); return null; } } async #saveIdeonDB() { try { await fs.mkdir(path.dirname(IDEON_DB_PATH), { recursive: true }); const serializableMap = Array.from(this.#ideonDB.entries()); await fs.writeFile(IDEON_DB_PATH, JSON.stringify(serializableMap, null, 2)); Logger.debug('[ManifoldMemory] Ideon DB berhasil disimpan ke disk.'); } catch (error) { Logger.error('[ManifoldMemory] Gagal menyimpan Ideon DB ke disk.', error); } } async #loadIdeonDB() { try { const data = await fs.readFile(IDEON_DB_PATH, 'utf-8'); const parsedMap = new Map(JSON.parse(data)); // Konversi Date string kembali menjadi objek Date parsedMap.forEach(ideon => { if (ideon.activation && ideon.activation.lastAccessed) { ideon.activation.lastAccessed = new Date(ideon.activation.lastAccessed); } }); this.#ideonDB = parsedMap; Logger.info(`[ManifoldMemory] Ideon DB berhasil dimuat dengan ${this.#ideonDB.size} Ideon.`); } catch (error) { if (error.code === 'ENOENT') { Logger.info('[ManifoldMemory] Ideon DB tidak ditemukan, memulai dengan kosong.'); } else { Logger.error('[ManifoldMemory] Gagal memuat Ideon DB dari file.', error); } } } /** * [BARU] Meng-embed teks ke dalam vektor menggunakan model embedding yang dikonfigurasi. * Digunakan untuk RCST dan pencarian semantik. * @param {string} text Teks yang akan di-embed. * @returns {Promise<number[]>} Vektor embedding. */ async embedText(text) { if (!this.#isInitialized) { Logger.warn('[ManifoldMemory] Memori belum diinisialisasi, tidak dapat meng-embed teks.'); return []; } try { const result = await this.#embeddings.embedDocuments([text]); return result[0]; // Ambil vektor pertama (karena hanya satu dokumen) } catch (error) { Logger.error(`[ManifoldMemory] Gagal meng-embed teks: ${error.message}`, error); return []; } } /** * [BARU] Menyimpan atau memperbarui sebuah Ideon dalam memori. * Ini adalah inti dari struktur pengetahuan yang hidup. * @param {object} ideonObj - Objek Ideon sesuai IdeonSchema. */ async storeIdeon(ideonObj) { if (!this.#isInitialized) return; // Validasi IdeonObj sesuai skema jika diperlukan (bisa gunakan Joi atau Zod) const ideonId = ideonObj.id || generateIdeonId(ideonObj.canonicalName); if (!ideonId) { Logger.error('[ManifoldMemory] Gagal menyimpan Ideon: canonicalName atau ID tidak valid.'); return; } // Simpan setiap perspektif Ideon ke dalam vector store for (const perspective of ideonObj.perspectives) { const docId = `${ideonId}-${perspective.context}`; // ID unik untuk dokumen ini const document = { pageContent: perspective.description, metadata: { ...ideonObj, perspectiveContext: perspective.context, ideonId: ideonId } }; // Add or update document in vector store await this.#vectorStore.addDocuments([document]); Logger.debug(`[ManifoldMemory] Perspektif Ideon '${ideonId}' (${perspective.context}) di-embed.`); } await this.#saveVectorStoreToFile(); // Simpan vector store setelah menambahkan dokumen // Simpan objek Ideon lengkap ke Ideon DB this.#ideonDB.set(ideonId, { ...ideonObj, id: ideonId, activation: ideonObj.activation || { level: 0.1, lastAccessed: new Date(), decayRate: this.#config.navigatorConfig?.ideonDecayRate || 0.05 }, confidenceScore: ideonObj.confidenceScore || 0.5, sourceInteractionIds: ideonObj.sourceInteractionIds || [], }); await this.#saveIdeonDB(); Logger.info(`[ManifoldMemory] Ideon '${ideonObj.canonicalName}' (${ideonId}) telah disimpan/diperbarui.`); } /** * Mengambil Ideon berdasarkan ID. * @param {string} ideonId ID Ideon. * @returns {object | null} Objek Ideon atau null. */ getIdeon(ideonId) { return this.#ideonDB.get(ideonId) || null; } /** * [BARU] Memperbarui tingkat aktivasi Ideon. * @param {string} ideonId - ID Ideon. * @param {number} delta - Perubahan tingkat aktivasi (positif untuk naik, negatif untuk turun). */ async updateIdeonActivation(ideonId, delta) { const ideon = this.#ideonDB.get(ideonId); if (ideon) { ideon.activation.level = Math.max(0, Math.min(1, ideon.activation.level + delta)); ideon.activation.lastAccessed = new Date(); await this.#saveIdeonDB(); Logger.debug(`[ManifoldMemory] Ideon '${ideon.canonicalName}' aktivasi diperbarui ke ${ideon.activation.level.toFixed(2)}.`); } } /** * [BARU] Menerapkan peluruhan (decay) pada aktivasi semua Ideon yang tidak diakses. */ async applyIdeonDecay() { const now = Date.now(); const decayRate = this.#config.navigatorConfig?.ideonDecayRate || 0.05; // Decay rate per jam let changed = false; this.#ideonDB.forEach(ideon => { if (ideon.activation && ideon.activation.lastAccessed) { const hoursSinceLastAccessed = (now - ideon.activation.lastAccessed.getTime()) / (1000 * 60 * 60); if (hoursSinceLastAccessed > 1) { // Luruhkan jika lebih dari satu jam const decayAmount = decayRate * hoursSinceLastAccessed; ideon.activation.level = Math.max(0, ideon.activation.level - decayAmount); changed = true; } } }); if (changed) { await this.#saveIdeonDB(); Logger.debug('[ManifoldMemory] Peluruhan aktivasi Ideon diterapkan.'); } } /** * [BARU] Membentuk atau memperkuat hubungan semantik antar Ideon. * @param {string} sourceIdeonId - ID Ideon sumber. * @param {string} targetIdeonId - ID Ideon target. * @param {'RELATED_TO' | 'PREREQUISITE_FOR' | 'EXAMPLE_OF' | 'TOOL_FOR' | 'ANTONYM_OF' | 'SYNONYM_OF' | 'DERIVED_FROM' | 'METAPHOR_FOR'} type - Jenis hubungan. * @param {number} weight - Kekuatan hubungan (0.0 - 1.0). */ async formAssociation(sourceIdeonId, targetIdeonId, type, weight) { const sourceIdeon = this.#ideonDB.get(sourceIdeonId); if (sourceIdeon) { let existingRelation = sourceIdeon.relations.find(r => r.targetIdeonId === targetIdeonId && r.type === type); if (existingRelation) { existingRelation.weight = Math.min(1, existingRelation.weight + weight); // Perkuat hubungan } else { sourceIdeon.relations.push({ targetIdeonId, type, weight }); } await this.#saveIdeonDB(); Logger.debug(`[ManifoldMemory] Asosiasi terbentuk/diperkuat: ${sourceIdeonId} ${type} ${targetIdeonId}.`); } } /** * Mencari konsep relevan dari Ideon berdasarkan query teks. * @param {string} queryText Teks query. * @param {number} numResults Jumlah hasil yang diinginkan. * @returns {Promise<Array<object>>} Daftar Ideon yang relevan. */ async findRelevantConcepts(queryText, numResults = 3) { if (!this.#isInitialized) return []; try { // Lakukan pencarian kesamaan pada vector store (yang menyimpan deskripsi perspektif Ideon) const results = await this.#vectorStore.similaritySearch(queryText, numResults); // Ekstrak Ideon asli dari metadata hasil pencarian const relevantIdeonIds = new Set(); results.forEach(doc => relevantIdeonIds.add(doc.metadata.ideonId)); const relevantIdeons = Array.from(relevantIdeonIds) .map(id => this.#ideonDB.get(id)) .filter(Boolean); // Filter null/undefined // Perbarui aktivasi Ideon yang relevan for (const ideon of relevantIdeons) { await this.updateIdeonActivation(ideon.id, 0.1); // Tingkatkan aktivasi sedikit } return relevantIdeons; // Mengembalikan objek Ideon lengkap } catch (error) { Logger.error('[ManifoldMemory] Gagal mencari konsep relevan.', error); return []; } } /** * Melakukan introspeksi untuk menemukan Ideon/konsep dengan kepercayaan diri rendah. * Ini adalah "mata" dari Curiosity Drive. * @param {number} threshold - Ambang batas confidence score (e.g., 0.4). * @returns {Array<object>} Daftar Ideon yang tidak dipahami dengan baik. */ findLowConfidenceConcepts(threshold = 0.4) { if (!this.#isInitialized || this.#ideonDB.size === 0) { return []; } const lowConfidenceIdeons = Array.from(this.#ideonDB.values()) .filter(ideon => ideon.confidenceScore < threshold); if (lowConfidenceIdeons.length > 0) { Logger.debug(`[ManifoldMemory] Introspeksi menemukan ${lowConfidenceIdeons.length} Ideon dengan kepercayaan rendah.`); } return lowConfidenceIdeons; } }