UNPKG

hi-introvert

Version:

A quiet corner of the internet where silence is understood.

1,911 lines (1,887 loc) 77.6 kB
#!/usr/bin/env node import { createRequire } from "node:module"; var __require = /* @__PURE__ */ createRequire(import.meta.url); // src/ui/BlessedApp.ts import blessed from "blessed"; // src/session/WorldSession.ts import { World, toWorldFile, fromWorldFile, Environment, Weather, EnergySystem, initializeThermalProperties, DialogueManager, MemoryConsolidation, SymbolicPhysicalCoupler, CollectiveIntelligence, createMemoryLog, TrustSystem } from "@v1b3x0r/mds-core"; import { EventEmitter } from "events"; import fs2 from "fs"; import path from "path"; import { fileURLToPath } from "url"; // src/vocabulary/base-vocabulary.ts var BASE_VOCABULARY = [ "สวัสดี", "หวัดดี", "ครับ", "ค่ะ", "ขอบคุณ", "hi", "hello", "bye", "thanks", "please", "ผม", "ฉัน", "คุณ", "เขา", "เธอ", "เรา", "พวกเรา", "I", "me", "you", "he", "she", "we", "they", "someone", "แม่", "พ่อ", "พี่", "น้อง", "ครอบครัว", "mom", "dad", "brother", "sister", "family", "เป็น", "มี", "ไป", "มา", "ทำ", "เล่น", "กิน", "ดู", "อ่าน", "เขียน", "is", "have", "go", "come", "do", "play", "eat", "see", "read", "write", "คิด", "รู้", "เข้าใจ", "จำ", "ลืม", "think", "know", "understand", "remember", "forget", "ดี", "สบาย", "สนุก", "เบื่อ", "เศร้า", "โกรธ", "กลัว", "ตื่นเต้น", "happy", "sad", "angry", "scared", "excited", "bored", "tired", "โรงเรียน", "เรียน", "ครู", "เพื่อน", "หนังสือ", "การบ้าน", "สอบ", "school", "study", "teacher", "friend", "book", "homework", "test", "class", "หนึ่ง", "สอง", "สาม", "มาก", "น้อย", "one", "two", "three", "many", "few", "วัน", "เวลา", "ตอน", "เมื่อไหร่", "ตอนนี้", "day", "time", "when", "now", "today", "บ้าน", "ที่", "ไหน", "นี่", "โน่น", "home", "place", "where", "here", "there", "อาหาร", "ข้าว", "น้ำ", "ผลไม้", "ขนม", "อร่อย", "food", "rice", "water", "fruit", "snack", "delicious", "สัตว์", "หมา", "แมว", "นก", "ปลา", "animal", "dog", "cat", "bird", "fish", "สี", "แดง", "น้ำเงิน", "เขียว", "color", "red", "blue", "green", "ใหญ่", "เล็ก", "ยาว", "สั้น", "big", "small", "long", "short", "อะไร", "ทำไม", "ยังไง", "เท่าไหร่", "ใคร", "what", "why", "how", "who", "which", "แต่", "เพราะ", "ถ้า", "แล้ว", "ก็", "but", "because", "if", "then", "so", "ดี", "เก่ง", "สวย", "เท่", "เจ็บ", "good", "cool", "nice", "bad", "hurt", "เกม", "หนัง", "เพลง", "วาด", "ฟัง", "ดู", "game", "movie", "music", "draw", "listen", "watch", "คอม", "โทรศัพท์", "อินเทอร์เน็ต", "เกม", "computer", "phone", "internet", "app", "เอ่อ", "อืม", "งง", "อ๋อ", "เออ", "นะ", "ไหม", "ละ", "ครับ", "มาก", "um", "uh", "hmm", "oh", "well", "ไม่เป็นไร", "จริงเหรอ", "เท่ห์", "เจ๋ง", "ได้เลย", "okay", "really", "sure", "maybe", "fine", "ตื่น", "นอน", "อาบน้ำ", "แปรงฟัน", "ทำงาน", "พัก", "ออกกำลัง", "เดิน", "วิ่ง", "นั่ง", "wake", "sleep", "shower", "brush", "work", "rest", "exercise", "walk", "run", "sit", "เหงา", "สับสน", "กังวล", "สงบ", "ภูมิใจ", "อาย", "โกรธ", "หงุดหงิด", "เครียด", "ผ่อนคลาย", "ตื่นเต้น", "ประหลาดใจ", "เบื่อหน่าย", "สนใจ", "รู้สึก", "lonely", "confused", "anxious", "calm", "proud", "shy", "frustrated", "stressed", "relaxed", "surprised", "bored", "interested", "nervous", "confident", "feel", "ฝน", "แดด", "เมฆ", "ร้อน", "หนาว", "อบอุ่น", "เย็น", "ชื้น", "rain", "sun", "cloud", "hot", "cold", "warm", "cool", "พูด", "คุย", "ฟัง", "ถาม", "ตอบ", "เล่า", "บอก", "พูดคุย", "ส่งข้อความ", "โทร", "talk", "chat", "listen", "ask", "answer", "tell", "speak", "message", "call", "reply", "ฝัน", "หวัง", "กลัว", "ความจริง", "โกหก", "ปัญหา", "แก้ปัญหา", "คำถาม", "คำตอบ", "ความคิด", "ไอเดีย", "ความรู้สึก", "อารมณ์", "dream", "hope", "fear", "truth", "lie", "problem", "solution", "question", "answer", "idea", "feeling", "emotion", "หัว", "มือ", "ตา", "หู", "ปาก", "จมูก", "ขา", "เท้า", "head", "hand", "eye", "ear", "mouth", "nose", "foot", "ต้นไม้", "ดอกไม้", "ฟ้า", "ทะเล", "ภูเขา", "แม่น้ำ", "ธรรมชาติ", "tree", "flower", "sky", "sea", "mountain", "river", "nature", "star", "แชท", "พิมพ์", "คลิก", "ดาวน์โหลด", "อัปโหลด", "วายฟาย", "อีเมล", "โพสต์", "แชร์", "เซฟ", "chat", "type", "click", "download", "upload", "wifi", "email", "post", "share", "save", "ด้วย", "หรือ", "และ", "อย่างไรก็ตาม", "แม้ว่า", "ดังนั้น", "เพราะฉะนั้น", "also", "or", "and", "however", "although", "therefore", "thus", "besides", "มาก", "จริงๆ", "ค่อนข้าง", "เกือบ", "เต็มที่", "จัง", "สุดๆ", "very", "really", "quite", "totally", "actually", "almost", "fully", "extremely", "อยาก", "ต้องการ", "ชอบ", "รัก", "เกลียด", "หวัง", "ปรารถนา", "เชื่อ", "รู้สึก", "ดู", "มอง", "ได้ยิน", "สัมผัส", "พบ", "เจอ", "want", "need", "like", "love", "hate", "hope", "wish", "believe", "see", "look", "hear", "touch", "meet", "find", "lose", "แปลก", "เพื่อน", "ปกติ", "พิเศษ", "ต่าง", "เหมือนกัน", "ง่าย", "ยาก", "สำคัญ", "ธรรมดา", "น่าสนใจ", "น่าเบื่อ", "สนุกสนาน", "น่ากลัว", "ปลอดภัย", "strange", "weird", "normal", "special", "different", "same", "easy", "hard", "important", "simple", "interesting", "boring", "fun", "scary", "safe", "สิ่งของ", "ของ", "ปัญหา", "วิธี", "คำถาม", "ความรู้", "ประสบการณ์", "เวลา", "โอกาส", "ความเป็นจริง", "เหตุผล", "สาเหตุ", "ผลลัพธ์", "ส่วน", "ทาง", "thing", "stuff", "problem", "way", "question", "knowledge", "experience", "chance", "reality", "reason", "cause", "result", "part", "path", "moment", "เท่", "แจ่ม", "แย่", "โอเค", "ช่างเถอะ", "ไม่รู้", "ก็ได้", "เออ", "อ้าว", "เฮ้ย", "cool", "awesome", "lame", "whatever", "dude", "nah", "yep", "dunno", "kinda", "sorta" ]; function getBaseVocabularySize() { return BASE_VOCABULARY.length; } // src/vocabulary/VocabularyTracker.ts class VocabularyTracker { knownWords; learnedWords; conversationCount = 0; constructor(initialVocabulary = BASE_VOCABULARY) { this.knownWords = new Set(initialVocabulary.map((w) => w.toLowerCase().trim())); this.learnedWords = new Map; } detectNewWords(message) { const words = this.tokenize(message); const newWords = []; for (const word of words) { const normalized = word.toLowerCase().trim(); if (normalized.length < 2) continue; if (this.knownWords.has(normalized)) continue; this.knownWords.add(normalized); this.learnedWords.set(normalized, { word, timestamp: Date.now(), source: "user" }); newWords.push(word); } return newWords; } tokenize(message) { const tokens = message.split(/[\s,!?.;:()\[\]{}]+/).filter((t) => t.length > 0); return tokens; } canUse(word) { const normalized = word.toLowerCase().trim(); return this.knownWords.has(normalized); } getVocabularySize() { return this.knownWords.size; } getLearnedWords() { return Array.from(this.learnedWords.values()); } getRecentlyLearned(count = 5) { const learned = this.getLearnedWords(); return learned.sort((a, b) => b.timestamp - a.timestamp).slice(0, count); } incrementConversation() { this.conversationCount++; } getStats() { const baseWords = getBaseVocabularySize(); const learnedWords = this.learnedWords.size; const total = this.knownWords.size; const recent = this.getRecentlyLearned(1); const lastGrowth = recent.length > 0 ? recent[0] : undefined; const growthRate = this.conversationCount > 0 ? learnedWords / this.conversationCount : 0; return { total, baseWords, learnedWords, lastGrowth, growthRate, conversationCount: this.conversationCount }; } toJSON() { return { knownWords: Array.from(this.knownWords), learnedWords: Array.from(this.learnedWords.entries()), conversationCount: this.conversationCount }; } static fromJSON(data) { const tracker = new VocabularyTracker([]); tracker.knownWords = new Set(data.knownWords); tracker.learnedWords = new Map(data.learnedWords); tracker.conversationCount = data.conversationCount; return tracker; } getAllWords() { return Array.from(this.knownWords); } filterUnknownWords(message) { const words = this.tokenize(message); const filtered = words.map((word) => { const normalized = word.toLowerCase().trim(); return this.knownWords.has(normalized) ? word : "[unknown]"; }); return filtered.join(" "); } getCoverage(message) { const words = this.tokenize(message); if (words.length === 0) return 1; const known = words.filter((word) => { const normalized = word.toLowerCase().trim(); return this.knownWords.has(normalized); }); return known.length / words.length; } } // src/session/ContextAnalyzer.ts class ContextAnalyzer { analyzeIntent(message, entity) { const normalized = message.toLowerCase().trim(); const intent = this.detectIntent(normalized); const keywords = this.extractKeywords(normalized); const relevantMemories = this.findRelevantMemories(entity, keywords); const context = this.buildContext(intent, keywords, relevantMemories); const emotionHint = this.estimateEmotionHint(intent, normalized); return { intent, context, relevantMemories, keywords, emotionHint }; } detectIntent(message) { if (/^(hi|hello|hey|sup|สวัสดี|หวัดดี|ว่าไง)/.test(message)) { return "greeting"; } if (/(bye|goodbye|see you|later|ไปละ|บาย|ไปก่อน)/.test(message)) { return "farewell"; } if (message.includes("?") || /^(what|why|how|when|where|who|อะไร|ทำไม|ยังไง|เมื่อไหร่|ที่ไหน|ใคร)/.test(message)) { return "question"; } if (/(good|great|awesome|amazing|cool|เก่ง|เจ๋ง|เท่|ดี)/.test(message)) { return "praise"; } if (/(bad|boring|stupid|wrong|แย่|เบื่อ|โง่|ผิด)/.test(message)) { return "criticism"; } if (/(feel|felt|happy|sad|angry|scared|รู้สึก|ดีใจ|เศร้า|โกรธ|กลัว)/.test(message)) { return "emotion"; } if (/(is|means|คือ|หมายความว่า|แปลว่า)/.test(message)) { return "teaching"; } return "statement"; } extractKeywords(message) { const words = message.split(/[\s,!?.;:()\[\]{}]+/).filter((w) => w.length > 2).map((w) => w.toLowerCase()); const stopWords = new Set([ "the", "a", "an", "is", "are", "was", "were", "be", "been", "have", "has", "had", "do", "does", "did", "ก็", "ที่", "เป็น", "มี", "ได้", "แล้ว" ]); return words.filter((w) => !stopWords.has(w)); } findRelevantMemories(entity, keywords) { if (!entity.memory) return []; const allMemories = entity.memory.recall(); const relevant = []; for (const memory of allMemories) { let score = 0; const contentStr = JSON.stringify(memory.content).toLowerCase(); for (const keyword of keywords) { if (contentStr.includes(keyword)) { score += 1; } } if (keywords.includes(memory.subject.toLowerCase())) { score += 2; } score *= memory.salience; if (score > 0) { relevant.push({ memory, score }); } } return relevant.sort((a, b) => b.score - a.score).slice(0, 5).map((r) => r.memory); } buildContext(intent, keywords, memories) { let context = `Intent: ${intent} `; if (keywords.length > 0) { context += `Keywords: ${keywords.join(", ")} `; } if (memories.length > 0) { context += `Relevant memories: `; for (const memory of memories) { const contentStr = typeof memory.content === "string" ? memory.content : JSON.stringify(memory.content); context += ` - ${memory.type} (${memory.subject}): ${contentStr} `; } } return context; } estimateEmotionHint(intent, message) { switch (intent) { case "greeting": return { valence: 0.3, arousal: 0.4 }; case "praise": return { valence: 0.7, arousal: 0.6 }; case "criticism": return { valence: -0.5, arousal: 0.7 }; case "question": return { valence: 0.1, arousal: 0.5 }; case "emotion": if (/(happy|good|ดี|สนุก)/.test(message)) { return { valence: 0.6, arousal: 0.5 }; } else if (/(sad|bad|เศร้า|แย่)/.test(message)) { return { valence: -0.6, arousal: 0.3 }; } else if (/(angry|โกรธ)/.test(message)) { return { valence: -0.5, arousal: 0.8 }; } return { valence: 0, arousal: 0.5 }; case "farewell": return { valence: -0.2, arousal: 0.3 }; default: return; } } } // src/session/MemoryPromptBuilder.ts class MemoryPromptBuilder { buildPrompt(entity, userMessage, contextAnalysis, vocabularyTracker, options = {}) { const { includeMemories = true, includeVocabulary = true, includeEmotion = true, maxMemories = 5 } = options; let prompt = ""; const essence = this.getEssence(entity); prompt += `# Who you are `; prompt += `${essence} `; const languageInfo = this.getLanguageInfo(entity); if (languageInfo) { prompt += `# Language `; prompt += `${languageInfo} `; } if (includeVocabulary) { const vocabSize = vocabularyTracker.getVocabularySize(); const recentLearned = vocabularyTracker.getRecentlyLearned(3); prompt += `# Vocabulary `; prompt += `- You know ${vocabSize} words `; if (recentLearned.length > 0) { prompt += `- Recently learned: ${recentLearned.map((e) => e.word).join(", ")} `; } prompt += `- Use simple words a 12-year-old would know `; prompt += `- If you don't know a word, ask what it means `; } if (includeEmotion && entity.emotion) { const { valence, arousal, dominance } = entity.emotion; prompt += `# Current emotion `; prompt += `- Valence: ${valence.toFixed(2)} (${this.interpretValence(valence)}) `; prompt += `- Arousal: ${arousal.toFixed(2)} (${this.interpretArousal(arousal)}) `; prompt += `- Dominance: ${dominance.toFixed(2)} (${this.interpretDominance(dominance)}) `; } if (includeMemories && contextAnalysis.relevantMemories.length > 0) { prompt += `# What you remember `; const memories = contextAnalysis.relevantMemories.slice(0, maxMemories); for (const memory of memories) { const time = this.formatTimestamp(memory.timestamp); const contentStr = this.formatMemoryContent(memory.content); prompt += `- [${time}] ${memory.type} about ${memory.subject}: ${contentStr} `; } prompt += ` `; } prompt += `# Situation `; prompt += `- User intent: ${contextAnalysis.intent} `; if (contextAnalysis.keywords.length > 0) { prompt += `- Keywords: ${contextAnalysis.keywords.join(", ")} `; } prompt += ` `; prompt += `# User said `; prompt += `"${userMessage}" `; prompt += `# Instructions `; prompt += `You are helping this entity figure out how to respond. `; prompt += `The entity has their own personality (see essence above). `; prompt += `Your role: suggest a response that fits their character. `; prompt += `Guidelines: `; prompt += `- Keep it short (1-2 sentences) `; prompt += `- Use words from their vocabulary `; prompt += `- Match their emotion state `; prompt += `- Reference their memories if relevant `; prompt += `- Stay true to their essence (don't override it) `; prompt += `# Suggested response `; return prompt; } getEssence(entity) { if (entity.essence) { return entity.essence; } return "You are a curious entity learning about the world."; } getLanguageInfo(entity) { if (!entity.nativeLanguage && !entity.languageWeights) { return null; } let info = ""; if (entity.nativeLanguage) { info += `- Your native language: ${entity.nativeLanguage} `; } if (entity.languageWeights) { const weights = Object.entries(entity.languageWeights).map(([lang, weight]) => `${lang} (${(weight * 100).toFixed(0)}%)`).join(", "); info += `- Language preference: ${weights} `; } info += `- Respond in the language that feels natural to you `; return info; } interpretValence(valence) { if (valence > 0.5) return "positive, happy"; if (valence > 0.2) return "slightly positive"; if (valence > -0.2) return "neutral"; if (valence > -0.5) return "slightly negative"; return "negative, upset"; } interpretArousal(arousal) { if (arousal > 0.7) return "very energetic"; if (arousal > 0.5) return "energetic"; if (arousal > 0.3) return "moderate"; return "calm, low energy"; } interpretDominance(dominance) { if (dominance > 0.6) return "confident, assertive"; if (dominance > 0.3) return "moderate confidence"; if (dominance > 0) return "slightly hesitant"; return "submissive, unsure"; } formatTimestamp(timestamp) { const now = Date.now(); const diff = now - timestamp; const seconds = Math.floor(diff / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (days > 0) return `${days}d ago`; if (hours > 0) return `${hours}h ago`; if (minutes > 0) return `${minutes}m ago`; return "just now"; } formatMemoryContent(content) { if (typeof content === "string") { return content; } if (typeof content === "object" && content !== null) { if (content.message) return content.message; if (content.text) return content.text; if (content.description) return content.description; return JSON.stringify(content); } return String(content); } } // src/session/GrowthTracker.ts class GrowthTracker { metrics; constructor() { this.metrics = { vocabularySize: 0, conversationCount: 0, memoryCount: 0, conceptsLearned: [], emotionalMaturity: 0, firstConversation: undefined, lastConversation: undefined }; } update(data) { Object.assign(this.metrics, data); const now = Date.now(); if (!this.metrics.firstConversation) { this.metrics.firstConversation = now; } this.metrics.lastConversation = now; } learnConcept(concept) { if (!this.metrics.conceptsLearned.includes(concept)) { this.metrics.conceptsLearned.push(concept); } } getMetrics() { return { ...this.metrics }; } getSummary() { const { vocabularySize, conversationCount, memoryCount, conceptsLearned, emotionalMaturity } = this.metrics; const lines = [ "\uD83D\uDCCA Growth Summary", "", `${"Vocabulary:".padEnd(18)}${vocabularySize} words`, `${"Conversations:".padEnd(18)}${conversationCount}`, `${"Memories:".padEnd(18)}${memoryCount}`, `${"Concepts:".padEnd(18)}${conceptsLearned.length} (${conceptsLearned.slice(0, 5).join(", ")}${conceptsLearned.length > 5 ? ", ..." : ""})`, `${"Maturity:".padEnd(18)}${(emotionalMaturity * 100).toFixed(0)}%` ]; return lines.join(` `); } toJSON() { return this.metrics; } static fromJSON(data) { const tracker = new GrowthTracker; tracker.metrics = data; return tracker; } } // src/session/WorldSession.ts import { ProtoLanguageGenerator } from "@v1b3x0r/mds-core"; // src/sensors/OSSensor.ts import os from "os"; import fs from "fs"; class OSSensor { lastCPUInfo = []; lastCPUTimes = []; constructor() { this.initializeCPU(); } initializeCPU() { const cpus = os.cpus(); this.lastCPUInfo = cpus; this.lastCPUTimes = cpus.map((cpu) => ({ idle: cpu.times.idle, total: Object.values(cpu.times).reduce((a, b) => a + b, 0) })); } getMetrics() { const cpuUsage = this.getCPUUsage(); const cpuTemp = this.estimateCPUTemperature(cpuUsage); const memoryUsage = this.getMemoryUsage(); const memoryPressure = this.estimateMemoryPressure(memoryUsage); const battery = this.getBatteryLevel(); return { cpuUsage, cpuTemp, memoryUsage, memoryPressure, batteryLevel: battery.level, batteryCharging: battery.charging, uptime: os.uptime(), loadAverage: os.loadavg(), timestamp: Date.now() }; } mapToEnvironment(metrics) { const temperature = 283 + metrics.cpuUsage * 40 + (metrics.cpuTemp - 293); const humidity = metrics.memoryUsage * 0.7 + metrics.memoryPressure * 0.3; const light = metrics.batteryCharging ? Math.min(1, metrics.batteryLevel + 0.2) : metrics.batteryLevel * 0.9; const loadNormalized = Math.min(1, metrics.loadAverage[0] / os.cpus().length); const windVx = loadNormalized * 30 - 15; const windVy = (metrics.memoryPressure - 0.5) * 20; return { temperature, humidity, light, windVx, windVy }; } getCPUUsage() { const cpus = os.cpus(); let totalUsage = 0; cpus.forEach((cpu, i) => { const lastTimes = this.lastCPUTimes[i]; const idle = cpu.times.idle; const total = Object.values(cpu.times).reduce((a, b) => a + b, 0); const idleDelta = idle - lastTimes.idle; const totalDelta = total - lastTimes.total; const usage = totalDelta > 0 ? 1 - idleDelta / totalDelta : 0; totalUsage += usage; this.lastCPUTimes[i] = { idle, total }; }); return totalUsage / cpus.length; } estimateCPUTemperature(usage) { const baseTemp = 313; const tempRange = 40; return baseTemp + usage * tempRange; } getMemoryUsage() { const totalMem = os.totalmem(); const freeMem = os.freemem(); return (totalMem - freeMem) / totalMem; } estimateMemoryPressure(usage) { if (usage < 0.7) return 0; if (usage < 0.85) return (usage - 0.7) / 0.15; return 1; } getBatteryLevel() { try { if (process.platform === "darwin") { const { execSync } = __require("child_process"); const output = execSync("pmset -g batt", { encoding: "utf-8" }); const match = output.match(/(\d+)%/); const chargingMatch = output.match(/(charging|charged|AC Power)/); if (match) { return { level: parseInt(match[1]) / 100, charging: !!chargingMatch }; } } if (process.platform === "linux") { const capacityPath = "/sys/class/power_supply/BAT0/capacity"; const statusPath = "/sys/class/power_supply/BAT0/status"; if (fs.existsSync(capacityPath)) { const capacity = parseInt(fs.readFileSync(capacityPath, "utf-8")); const status = fs.readFileSync(statusPath, "utf-8").trim(); return { level: capacity / 100, charging: status === "Charging" || status === "Full" }; } } } catch (error) {} return { level: 1, charging: true }; } formatMetrics(metrics) { return `CPU: ${(metrics.cpuUsage * 100).toFixed(1)}% @ ${(metrics.cpuTemp - 273).toFixed(0)}°C Memory: ${(metrics.memoryUsage * 100).toFixed(1)}% (pressure: ${(metrics.memoryPressure * 100).toFixed(0)}%) Battery: ${(metrics.batteryLevel * 100).toFixed(0)}% ${metrics.batteryCharging ? "(charging)" : "(draining)"} Load: ${metrics.loadAverage.map((l) => l.toFixed(2)).join(", ")} Uptime: ${(metrics.uptime / 3600).toFixed(1)}h`; } } // src/session/WorldSession.ts var __filename2 = fileURLToPath(import.meta.url); var __dirname2 = path.dirname(__filename2); function loadMDM(filename) { let mdmPath = path.join(__dirname2, "../entities", filename); if (!fs2.existsSync(mdmPath)) { mdmPath = path.join(__dirname2, "../../entities", filename); } const content = fs2.readFileSync(mdmPath, "utf-8"); return JSON.parse(content); } var companionMDM = loadMDM("companion.mdm"); var travelerMDM = loadMDM("traveler.mdm"); class WorldSession extends EventEmitter { world; entities = new Map; impersonatedEntity; companionEntity; vocabularyTracker; contextAnalyzer; promptBuilder; growthTracker; protoLangGenerator; autoSaveEnabled = false; silentMode = false; lastMessageTime = Date.now(); environment; osSensor; weather; energySystem; dialogueManager; memoryConsolidation; coupler; worldMind; memoryLogs; trustSystems; constructor() { super(); this.world = new World({ features: { ontology: true, communication: true, cognition: true, history: true, linguistics: true, rendering: "headless" }, linguistics: { analyzeEvery: 30, minUsage: 3, maxTranscript: 500 }, llm: { provider: "openrouter", apiKey: process.env.OPENROUTER_KEY, languageModel: "anthropic/claude-3.5-sonnet" } }); this.vocabularyTracker = new VocabularyTracker; this.contextAnalyzer = new ContextAnalyzer; this.promptBuilder = new MemoryPromptBuilder; this.growthTracker = new GrowthTracker; this.protoLangGenerator = new ProtoLanguageGenerator({ minVocabularySize: 50, maxPhraseLength: 8, emotionInfluence: 0.7, fallbackToDialogue: true }); this.environment = new Environment({ baseTemperature: 293, baseHumidity: 0.5, baseLight: 0.8, windVelocity: { vx: 0, vy: 0 }, timeScale: 0 }); this.osSensor = new OSSensor; this.weather = new Weather({ rainProbability: 0.15, rainDuration: 40, maxRainIntensity: 0.8, windVariation: 0.5 }); this.energySystem = new EnergySystem({ thermalTransferRate: 0.1, environmentCoupling: 0.05 }); this.dialogueManager = new DialogueManager; this.memoryConsolidation = new MemoryConsolidation({ similarityThreshold: 0.7, forgettingRate: 0.001, consolidationInterval: 60000 }); this.coupler = new SymbolicPhysicalCoupler({ arousalToSpeed: 0.5, valenceToMass: 0.3, dominanceToForce: 0.4, enabled: true }); this.worldMind = new CollectiveIntelligence; this.memoryLogs = new Map; this.trustSystems = new Map; this.spawnCompanion(); this.spawnTraveler(); this.impersonate("traveler"); this.setupCognitiveLinks(); this.initializeCompanionSkills(); this.setupEnvironmentSensors(); setInterval(() => { this.world.tick(1 / 2); }, 500); setInterval(() => { if (this.autoSaveEnabled) { this.saveSession(); } }, 30000); } setSilentMode(silent) { this.silentMode = silent; } debug(...args) { if (!this.silentMode) { console.log(...args); } } impersonate(entityName) { const entity = this.entities.get(entityName); if (!entity) { this.emit("error", { type: "impersonate", message: `Entity "${entityName}" not found` }); return; } entity.entity.disableAutonomous(); this.impersonatedEntity = entity; this.emit("impersonate", { entityName }); } unpossess() { if (!this.impersonatedEntity) return; const entityName = this.impersonatedEntity.name; this.impersonatedEntity.entity.enableAutonomous(); this.emit("unpossess", { entityName }); this.impersonatedEntity = null; } spawnCompanion() { this.companionEntity = this.spawnEntity("companion", companionMDM); } spawnTraveler() { this.impersonatedEntity = this.spawnEntity("traveler", travelerMDM); } spawnEntity(name, material) { const x = 50 + Math.random() * 100; const y = 50 + Math.random() * 100; const entity = this.world.spawn(material, x, y); entity.enable("memory", "learning", "relationships", "skills"); entity.enableAutonomous(); initializeThermalProperties(entity, 293, 0.5, 1, 0.5); const essence = typeof material.essence === "string" ? material.essence : material.essence?.th || material.essence?.en || "An entity"; entity.remember({ type: "spawn", subject: "self", content: { name, essence }, timestamp: Date.now(), salience: 1 }); const memoryLog = createMemoryLog(entity.uuid); this.memoryLogs.set(entity.uuid, memoryLog); const trustSystem = new TrustSystem({ initialTrust: 0.5, trustThreshold: 0.6 }); trustSystem.setSharePolicy("emotion", "public"); trustSystem.setSharePolicy("memory", "trust"); this.trustSystems.set(entity.uuid, trustSystem); const entityInfo = { name, entity, previousValence: entity.emotion.valence }; this.entities.set(name, entityInfo); return entityInfo; } setupEnvironmentSensors() { this.world.broadcastEvent("system_context", { platform: process.platform, arch: process.arch, nodeVersion: process.version, context: "terminal" }); setInterval(() => { const now = new Date; const hour = now.getHours(); const minute = now.getMinutes(); let timeOfDay = "night"; if (hour >= 5 && hour < 12) timeOfDay = "morning"; else if (hour >= 12 && hour < 17) timeOfDay = "afternoon"; else if (hour >= 17 && hour < 21) timeOfDay = "evening"; this.world.broadcastEvent("time_update", { hour, minute, timeOfDay, timestamp: now.toISOString() }); for (const entityInfo of this.entities.values()) { if (entityInfo.entity.memory && Math.random() < 0.1) { entityInfo.entity.remember({ type: "observation", subject: "time", content: { timeOfDay, hour }, timestamp: Date.now(), salience: 0.2 }); } } }, 30000); const startTime = Date.now(); setInterval(() => { const duration = Date.now() - startTime; const minutes = Math.floor(duration / 60000); if (minutes > 0) { this.world.broadcastEvent("session_duration", { duration, minutes }); for (const entityInfo of this.entities.values()) { if (entityInfo.entity.memory && minutes % 5 === 0) { entityInfo.entity.remember({ type: "observation", subject: "conversation", content: { duration: `${minutes} minutes` }, timestamp: Date.now(), salience: 0.3 }); } } } }, 300000); setInterval(() => { this.spawnLongingField(this.companionEntity, "traveler"); }, 120000); setInterval(() => { const metrics = this.osSensor.getMetrics(); const envMapping = this.osSensor.mapToEnvironment(metrics); this.environment["config"].baseTemperature = envMapping.temperature; this.environment["config"].baseHumidity = envMapping.humidity; this.environment["config"].baseLight = envMapping.light; this.environment["config"].windVelocity = { vx: envMapping.windVx, vy: envMapping.windVy }; this.world.broadcastEvent("environment_update", { temperature: envMapping.temperature, humidity: envMapping.humidity, light: envMapping.light, wind: { vx: envMapping.windVx, vy: envMapping.windVy } }); this.emit("environment", { metrics, mapping: envMapping }); }, 1e4); setInterval(() => { this.weather.update(2); const weatherState = this.weather.getState(); if (weatherState.rain) { this.environment["config"].baseHumidity = Math.min(1, this.environment["config"].baseHumidity + weatherState.rainIntensity * 0.3); this.environment["config"].baseLight = Math.max(0.2, this.environment["config"].baseLight * (1 - weatherState.cloudCover)); const windMult = weatherState.windStrength; this.environment["config"].windVelocity = { vx: this.environment["config"].windVelocity.vx * windMult, vy: this.environment["config"].windVelocity.vy * windMult }; this.world.broadcastEvent("weather_rain", { intensity: weatherState.rainIntensity, cloudCover: weatherState.cloudCover, windStrength: weatherState.windStrength }); this.emit("weather", { type: "rain", intensity: weatherState.rainIntensity, cloudCover: weatherState.cloudCover }); for (const entityInfo of this.entities.values()) { const entity = entityInfo.entity; entity.emotion = { valence: Math.max(-1, entity.emotion.valence - 0.05 * weatherState.rainIntensity), arousal: Math.max(0, entity.emotion.arousal - 0.03 * weatherState.rainIntensity), dominance: entity.emotion.dominance }; } } }, 2000); setInterval(() => { const companion = this.companionEntity.entity; if (companion.memory?.memories && companion.memory.memories.length > 5) { const consolidated = this.memoryConsolidation.consolidate(companion.memory.memories); if (consolidated.length > 0) { this.emit("memory-consolidation", { entity: "companion", count: consolidated.length, strongest: consolidated.slice(0, 3).map((m) => ({ subject: m.subject, strength: m.strength.toFixed(2), rehearsals: m.rehearsalCount })) }); } } this.memoryConsolidation.applyForgetting(60); for (const trustSystem of this.trustSystems.values()) { trustSystem.decayTrust(60); } }, 60000); setInterval(() => { const allEntities = Array.from(this.entities.values()).map((info) => info.entity); const companion = this.companionEntity.entity; const traveler = this.impersonatedEntity.entity; const dx = traveler.x - companion.x; const dy = traveler.y - companion.y; const distance = Math.sqrt(dx * dx + dy * dy); const collisionRadius = 50; if (distance < collisionRadius) { this.emit("collision", { entities: ["companion", "traveler"], distance: distance.toFixed(1) }); this.world.broadcastEvent("entity_collision", { a: "companion", b: "traveler", distance }); } this.energySystem.updateEntityTransfer(allEntities, 1); this.energySystem.updateEnvironmentTransfer(allEntities, this.environment, 1); for (const entity of allEntities) { const physProps = this.coupler.emotionToPhysics(entity.emotion); if (physProps && physProps.speed !== undefined) { const baseSpeed = 2; const emotionalSpeed = baseSpeed * physProps.speed; const angle = Math.random() * Math.PI * 2; const dx2 = Math.cos(angle) * emotionalSpeed; const dy2 = Math.sin(angle) * emotionalSpeed; entity.x = Math.max(0, Math.min(800, entity.x + dx2)); entity.y = Math.max(0, Math.min(600, entity.y + dy2)); entity["_physProps"] = physProps; } } if (Date.now() % 5000 < 1000) { this.emit("thermal", { companion: { temperature: (companion.temperature - 273).toFixed(1) + "°C", humidity: ((companion.humidity || 0) * 100).toFixed(0) + "%" }, traveler: { temperature: (traveler.temperature - 273).toFixed(1) + "°C", humidity: ((traveler.humidity || 0) * 100).toFixed(0) + "%" } }); } }, 1000); setInterval(() => { const allEntities = Array.from(this.entities.values()).map((info) => info.entity); const stats = CollectiveIntelligence.calculateStats(allEntities); const patterns = CollectiveIntelligence.detectPatterns(allEntities); const collectiveEmotion = CollectiveIntelligence.calculateCollectiveEmotion(allEntities); this.emit("world-mind", { stats, patterns, collectiveEmotion }); }, 30000); } getAllEntities() { return Array.from(this.entities.values()); } getEntityInfo() { return this.companionEntity || null; } getGreeting() { const entity = this.companionEntity.entity; const travelerMemories = entity.memory?.recall({ subject: "traveler" }) || []; if (travelerMemories.length === 0) { return entity.speak("intro") || "Hi..."; } else { const greeting = entity.speak("greeting_familiar") || "Welcome back!"; return greeting; } } async handleUserMessage(message) { const traveler = this.impersonatedEntity.entity; const companion = this.companionEntity.entity; const now = Date.now(); const silenceDuration = this.lastMessageTime ? (now - this.lastMessageTime) / 1000 : 0; companion.updateTriggerContext({ userMessage: message, userSilenceDuration: silenceDuration }); companion.checkEmotionTriggers(); this.lastMessageTime = now; const newWords = this.vocabularyTracker.detectNewWords(message); if (newWords.length > 0) { this.emit("vocab", { words: newWords }); for (const word of newWords.slice(0, 2)) { companion.remember({ type: "observation", subject: "vocabulary", content: { word, source: "traveler" }, timestamp: Date.now(), salience: 0.6 }); } } const context = this.contextAnalyzer.analyzeIntent(message, companion); if (context.emotionHint) { const current = companion.emotion; companion.emotion = { valence: (current.valence + context.emotionHint.valence) / 2, arousal: (current.arousal + context.emotionHint.arousal) / 2, dominance: current.dominance }; } if (traveler.memory) { traveler.remember({ type: "interaction", subject: this.companionEntity.name, content: { message, intent: context.intent }, timestamp: Date.now(), salience: 0.7 }); } companion.remember({ type: "interaction", subject: "traveler", content: { message, intent: context.intent }, timestamp: Date.now(), salience: 0.7 }); if (companion.cognitiveLinks && traveler.cognitiveLinks) { companion.connectTo(traveler, { strength: 0.7, bidirectional: true }); this.emit("link", { from: this.companionEntity.name, to: this.impersonatedEntity.name, strength: 0.7 }); } const response = await this.getEntityResponse(message, context); companion.remember({ type: "interaction", subject: "self", content: { response }, timestamp: Date.now(), salience: 0.4 }); this.world.recordSpeech(companion, response); const emotionDelta = companion.emotion.valence - this.companionEntity.previousValence; if (Math.abs(emotionDelta) > 0.1 && companion.learning) { companion.learning.addExperience({ timestamp: Date.now(), action: "respond", context: { intent: context.intent }, outcome: emotionDelta > 0 ? "positive" : "negative", reward: emotionDelta, success: emotionDelta > 0 }); } this.vocabularyTracker.incrementConversation(); this.growthTracker.update({ vocabularySize: this.vocabularyTracker.getVocabularySize(), conversationCount: this.vocabularyTracker.toJSON().conversationCount, memoryCount: companion.memory?.memories?.length || 0 }); for (const keyword of context.keywords) { if (keyword.length > 3) { this.growthTracker.learnConcept(keyword); } } this.companionEntity.previousValence = companion.emotion.valence; const valenceDiff = Math.abs(companion.emotion.valence - traveler.emotion.valence); const arousalDiff = Math.abs(companion.emotion.arousal - traveler.emotion.arousal); const alignment = 1 - (valenceDiff + arousalDiff) / 2; if (alignment > 0.6) { this.spawnSyncMoment(this.companionEntity, this.impersonatedEntity); } return { name: this.companionEntity.name, response, emotion: { ...companion.emotion }, previousValence: this.companionEntity.previousValence, newWordsLearned: newWords }; } async getEntityResponse(userMessage, context) { const entity = this.companionEntity.entity; let response; const categoryMap = { greeting: "intro", praise: "happy", criticism: "sad", question: "thinking", farewell: "intro", curiosity: "curious", excitement: "excited", confusion: "confused", neutral: "self_monologue", introspection: "self_monologue" }; const category = categoryMap[context.intent]; if (category) { response = entity.speak(category); } if (!response && context.keywords.some((k) => !this.vocabularyTracker.canUse(k))) { response = entity.speak("learned_new_word"); } if (!response && context.relevantMemories.length === 0 && context.intent === "question") { response = entity.speak("confused"); } if (!response) { const emotion = entity.emotion; if (emotion.valence > 0.5) { response = entity.speak("happy"); } else if (emotion.valence < -0.3) { response = entity.speak("sad"); } else if (emotion.arousal > 0.6) { response = entity.speak("excited"); } else if (emotion.arousal < 0.3) { response = entity.speak("tired"); } else { response = entity.speak("curious"); } } if (!response && this.vocabularyTracker.getVocabularySize() >= 20) { let vocabularyPool = this.vocabularyTracker.toJSON().knownWords; if (this.world.lexicon) { const patterns = this.world.lexicon.getAll(); if (patterns.length > 0) { const frequentPatterns = patterns.filter((p) => p.weight > 0.3).map((p) => p.phrase); vocabularyPool = [...vocabularyPool, ...frequentPatterns]; } } const envState = this.environment.getState(entity.x, entity.y); const tempCelsius = envState.temperature - 273; if (tempCelsius > 30) vocabularyPool.push("ร้อน", "hot", "\uD83E\uDD75"); else if (tempCelsius < 15) vocabularyPool.push("หนาว", "cold", "\uD83E\uDD76"); if (envState.humidity > 0.7) vocabularyPool.push("ชื้น", "humid", "\uD83D\uDCA7"); if (envState.light < 0.4) vocabularyPool.push("มืด", "dark", "\uD83C\uDF19"); else if (envState.light > 0.8) vocabularyPool.push("สว่าง", "bright", "☀️"); const weatherState = this.weather.getState(); if (weatherState.rain) { vocabularyPool.push("ฝนตก", "rain", "\uD83C\uDF27️", "wet", "เปียก"); if (weatherState.rainIntensity > 0.7) { vocabularyPool.push("heavy rain", "ฝนหนัก", "⛈️"); } } response = this.protoLangGenerator.generateResponse(userMessage, { vocabularyPool, emotion: entity.emotion, minWords: 1, maxWords: 4, allowParticles: true, allowEmoji: true, creativity: 0.6 }); if (response) { this.emit("proto-lang", { message: response, vocabularySize: vocabularyPool.length, environment: { temperature: tempCelsius.toFixed(1) + "°C", humidity: (envState.humidity * 100).toFixed(0) + "%", light: (envState.light * 100).toFixed(0) + "%" } }); } } if (!response && this.world.languageGenerator) { try { this.emit("llm", { action: "fallback" }); const prompt = this.promptBuilder.buildPrompt(entity, userMessage, context, this.vocabularyTracker); const llmResponse = await this.world.languageGenerator.generate({ speaker: entity, context: prompt }); response = llmResponse.text; } catch (error) { this.emit("error", { type: "llm", message: error instanceof Error ? error.message : String(error) }); response = entity.speak("intro") || "..."; } } if (!response) { response = entity.speak("intro") || "..."; } return response; } async spawnFriend(description) { if (!this.world.languageGenerator) { return null; } const prompt = description ? `Create a companion entity for a chat space. Description: "${description}" Generate a JSON object with: - essence (Thai + English description of personality) - languageProfile (native language + weights) - emotion.base (initial valence/arousal/dominance) - dialogue (intro, greeting, confused, etc.) Be creative and make them interesting!` : `Create a new companion entity that would be a good friend for an INTP kid. Make them different but complementary. Generate a JSON object following the same format as companion.mdm.`; try { const response = await this.world.languageGenerator.generate({ speaker: this.primaryEntity.entity, context: prompt }); const generatedData = JSON.parse(response.text); const material = { $schema: "mdspec/v5.7", material: `entity.friend_${Date.now()}`, ...generatedData }; const entity = this.world.spawn(material, 200, 200); const name = generatedData.essence?.en?.split(" ")[0] || `Friend${this.entities.size + 1}`; entity.enable("memory", "learning", "relationships"); entity.enableAutonomous(); const entityInfo = { name, entity, previousValence: entity.emotion.valence }; this.entities.set(name, entityInfo); if (this.primaryEntity.entity.memory) { this.primaryEntity.entity.remember({ type: "interaction", subject: name, content: { action: "met", essence: generatedData.essence }, timestamp: Date.now(), salience: 0.8 }); } return entityInfo; } catch (error) { if (!this.silentMode) console.error("[Spawn Error]", error); return null; } } async generateAutonomousMessage() { const companion = this.companionEntity.entity; if (!companion.isAutonomous()) { return null; } let response = companion.speak("self_monologue"); if (!response) { const emotion = companion.emotion; if (emotion.valence > 0.5) { response = companion.speak("happy"); } else if (emotion.valence < -0.3) { response = companion.speak("sad"); } else { response = companion.speak("curious"); } } if (!response && this.vocabularyTracker.getVocabularySize() >= 20) { let vocabularyPool = this.vocabularyTracker.toJSON().knownWords; if (this.world.lexicon) { const patterns = this.world.lexicon.getAll(); if (patterns.length > 0) { const frequentPatterns = patterns.filter((p) => p.weight > 0.3).map((p) => p.phrase); vocabularyPool = [...vocabularyPool, ...frequentPatterns]; } } const envState = this.environment.getState(companion.x, companion.y); const tempCelsius = envState.temperature - 273; if (tempCelsius > 30) vocabularyPool.push("ร้อน", "hot", "\uD83E\uDD75"); else if (tempCelsius < 15) vocabularyPool.push("หนาว", "cold", "\uD83E\uDD76"); if (envState.humidity > 0.7) vocabularyPool.push("ชื้น", "humid", "\uD83D\uDCA7"); if (envState.light < 0.4) vocabularyPool.push("มืด", "dark", "\uD83C\uDF19"); const weatherState = this.weather.getState(); if (weatherState.rain) { vocabularyPool.push("ฝนตก", "rain", "\uD83C\uDF27️"); } response = this.protoLangGenerator.generate(companion.emotion, vocabularyPool, undefined, envState); } if (!response) { return null; } return { name: this.companionEntity.name, response, emotion: { ...companion.emotion } }; } getStatusSummary() { let output = `\uD83D\uDCCA Status `; for (const entityInfo of this.entities.values()) { const entity = entityInfo.entity; const emotion = entity.emotion; const memoryCount = entity.memory?.count() || 0; const isImpersonated = entityInfo === this.impersonatedEntity ? " (YOU)" : ""; output += `${entityInfo.name}${isImpersonated}: `; output += ` Emotion: ${emotion.valence.toFixed(2)} (${this.getEmotionWord(emotion)}) `; output += ` Arousal: ${emotion.arousal.toFixed(2)} `; output += ` Memories: ${memoryCount} `; } const vocabStats = this.vocabularyTracker.getStats(); output += `\uD83D\uDCDA Vocabulary: ${vocabStats.total} words (+${vocabStats.learnedWords} learned) `; output += `\uD83D\uDCAC Conversations: ${vocabStats.conversationCount} `; const lexiconStats = this.world.getLexiconStats(); if (lexiconStats && lexiconStats.totalTerms > 0) { output += ` \uD83D\uDDE3️