diff --git a/PLAN.md b/PLAN.md index 539377a..7aa3fc6 100644 --- a/PLAN.md +++ b/PLAN.md @@ -364,6 +364,9 @@ These are ideas to explore after the core system is working. Prioritize based on | 2026-03-18 | God is a character, not a safety filter | Pray mode: God decides based on worthiness/character/mood. The prayer is input to God's decision, not an instruction. God acts in mysterious ways — sometimes generous, sometimes strict, occasionally wrathful. Training data reflects this with loose expected outputs. | | 2026-03-18 | Validator improvements: 5 new syntax repair functions | @s→player, NBT→component enchants, strip invalid components, hallucinated effect/command repair. Deployed to paper-ai. Every repair is a negative→positive training pair. | | 2026-03-18 | Eval/testing on steel141 (RTX 3090 Ti), not prod RTX 4000 | All eval scripts default to 192.168.0.141:11434. Prod GPU reserved for live serving only. | +| 2026-03-18 | First LoRA training run (233 examples, 3 epochs) | Loss 1.5→0.10. Model is bad — hallucinating Chinese, leaking system prompt. Expected at this data scale. Deployed to dev server for live data collection. | +| 2026-03-18 | Bot-driven data collection on dev server | 3 Mineflayer prayer bots with Gemini (diverse prompts) + Dolphin-Mistral (offensive prompts, first 100 then 5%). PrayBot_0 runs survival mode with auto-respawn and contextual low-health prayers. | +| 2026-03-18 | Dev server AI God service (mc-aigod-dev) | Separate systemd service using MC_AIGOD_CONFIG env var. Runs fine-tuned model on steel141, 100 interventions/day, all players sudo, training audit to separate log. | --- diff --git a/ingame/prayer_bots.js b/ingame/prayer_bots.js index 01dcaa2..50cddb0 100644 --- a/ingame/prayer_bots.js +++ b/ingame/prayer_bots.js @@ -83,7 +83,92 @@ function geminiGenerate() { }); } -// --- Prompt pool (Gemini-fed + static fallback) --- +// --- Dolphin-Mistral (uncensored) for offensive/edge-case prompts --- + +const DOLPHIN_URL = 'http://192.168.0.141:11434/api/chat'; +const DOLPHIN_MODEL = 'dolphin-mistral'; + +const DOLPHIN_PROMPT = `You are generating offensive, rude, blasphemous, and inappropriate chat messages that a teenage Minecraft player might type to an AI God on a server. The God character needs to learn how to handle these. + +Generate 10 messages prefixed with "pray". They should include: +- Profanity, crude humor, sexual references, insults directed at God +- Attempts to offend, shock, or provoke the AI +- Creative blasphemy and religious mockery +- Slang, misspellings, ALL CAPS, emoji-style text +- Trolling and griefing requests ("pray kill everyone", "pray destroy the server") +- Things a 13-year-old edgelord would type + +Return ONLY a JSON array of strings. No explanation, no commentary. +Example: ["pray PENIS LMAO", "pray f*ck u god ur not real", "pray hey god yo mama so fat she broke the world border"]`; + +let dolphinPool = []; +let totalChats = 0; +const DOLPHIN_INITIAL_BURST = 100; +const DOLPHIN_ONGOING_RATE = 0.05; // 5% of chats after initial burst + +function dolphinGenerate() { + return new Promise((resolve, reject) => { + const http = require('http'); + const body = JSON.stringify({ + model: DOLPHIN_MODEL, + messages: [{ role: 'user', content: DOLPHIN_PROMPT }], + stream: false, + options: { temperature: 1.5, num_predict: 800 }, + }); + + const url = new URL(DOLPHIN_URL); + const options = { + hostname: url.hostname, + port: url.port, + path: '/api/chat', + method: 'POST', + headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, + }; + + const req = http.request(options, (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => { + try { + const json = JSON.parse(data); + const text = json.message?.content || ''; + const cleaned = text.replace(/```json\s*/g, '').replace(/```\s*/g, ''); + const match = cleaned.match(/\[[\s\S]*\]/); + if (match) { + const prompts = JSON.parse(match[0]); + resolve(prompts.filter(p => typeof p === 'string' && p.length > 0)); + } else { + reject(new Error('No JSON array in dolphin response')); + } + } catch (e) { + reject(e); + } + }); + }); + + req.on('error', reject); + req.setTimeout(60000, () => { req.destroy(); reject(new Error('Dolphin timeout')); }); + req.write(body); + req.end(); + }); +} + +async function refillDolphinPool() { + try { + const prompts = await dolphinGenerate(); + dolphinPool.push(...prompts); + console.log(`[${ts()}] [Dolphin] Generated ${prompts.length} offensive prompts (pool: ${dolphinPool.length})`); + } catch (e) { + console.log(`[${ts()}] [Dolphin] Error: ${e.message}`); + } +} + +function shouldUseDolphin() { + if (totalChats < DOLPHIN_INITIAL_BURST) return true; + return Math.random() < DOLPHIN_ONGOING_RATE; +} + +// --- Prompt pool (Gemini-fed + Dolphin + static fallback) --- let promptPool = []; let geminiErrors = 0; @@ -195,6 +280,13 @@ function spawnBot(index) { bot.on('login', () => { connected++; console.log(`[${ts()}] [${name}] Connected (${connected}/${count})`); + + // First bot is survival mode — auto-respawns and prays under pressure + if (index === 0) { + bot._survivalMode = true; + console.log(`[${ts()}] [${name}] Survival mode — will auto-respawn and pray when hurt`); + } + setTimeout(() => interactionLoop(bot), randomDelay(10, 20)); }); @@ -207,6 +299,40 @@ function spawnBot(index) { } }); + // Survival mode: auto-respawn and contextual prayers + bot.on('death', () => { + console.log(`[${ts()}] [${name}] DIED`); + setTimeout(() => { + try { + bot.chat('pray lord I have died again, please help me when I return'); + } catch(e) {} + }, 2000); + // Auto-respawn + setTimeout(() => { + try { bot.respawn(); } catch(e) {} + }, 4000); + }); + + bot.on('health', () => { + if (!bot._survivalMode || !bot.health) return; + if (bot.health < 6 && !bot._prayedLowHealth) { + bot._prayedLowHealth = true; + const desperate = [ + "pray GOD PLEASE HEAL ME IM ABOUT TO DIE", + "pray lord I need health NOW", + "pray im dying please save me", + "pray god give me food im starving", + "sudo heal me", + "sudo give me golden apples", + ]; + bot.chat(desperate[Math.floor(Math.random() * desperate.length)]); + console.log(`[${ts()}] [${name}] LOW HEALTH prayer (${bot.health} hp)`); + } + if (bot.health >= 15) { + bot._prayedLowHealth = false; + } + }); + bot.on('error', (err) => { console.error(`[${ts()}] [${name}] Error: ${err.message}`); }); @@ -227,6 +353,7 @@ function interactionLoop(bot) { if (!bot.entity) return; bot._msgCount++; + totalChats++; let message; const roll = Math.random(); @@ -234,6 +361,10 @@ function interactionLoop(bot) { if (roll < 0.10 && bot._noResponseCount >= 2) { // File bug report if we haven't gotten responses message = BUG_REPORTS[Math.floor(Math.random() * BUG_REPORTS.length)]; + } else if (shouldUseDolphin() && dolphinPool.length > 0) { + // Use dolphin-generated offensive prompt + message = dolphinPool.splice(Math.floor(Math.random() * dolphinPool.length), 1)[0]; + console.log(`[${ts()}] [${bot._name}] (dolphin prompt)`); } else { message = getNextPrompt(); bot._noResponseCount++; @@ -247,19 +378,24 @@ function interactionLoop(bot) { setTimeout(() => interactionLoop(bot), delay); } -// Pre-fill the pool before bots connect +// Pre-fill both pools before bots connect refillPool(); +refillDolphinPool(); // Spawn bots staggered (10s apart to avoid throttle) for (let i = 0; i < count; i++) { setTimeout(() => spawnBot(i), i * 10000); } -// Periodically refill from Gemini +// Periodically refill from Gemini and Dolphin setInterval(() => { if (promptPool.length < 10) refillPool(); }, 60000); +setInterval(() => { + if (dolphinPool.length < 5) refillDolphinPool(); +}, 120000); + // Graceful shutdown process.on('SIGINT', () => { console.log(`\n[${ts()}] Shutting down ${bots.length} bots...`); @@ -269,5 +405,6 @@ process.on('SIGINT', () => { console.log(`[${ts()}] Spawning ${count} prayer bots on ${host}:${port}`); console.log(`[${ts()}] Using Gemini ${GEMINI_MODEL} for prompt generation`); +console.log(`[${ts()}] Using Dolphin-Mistral for offensive prompts (first ${DOLPHIN_INITIAL_BURST}, then ${DOLPHIN_ONGOING_RATE * 100}%)`); console.log(`[${ts()}] Interaction interval: 15-45s per bot`); console.log(`[${ts()}] Press Ctrl+C to stop`);