0.6.0 training session: Oracle Bot, RL combat, Mind's Eye, multilingual pipeline

Major changes from this session:

Training:
- 0.6.0 training running: 9B on steel141 3090 Ti, 27B on rented H100 NVL
- 7,256 merged training examples (up from 3,183)
- New training data: failure modes (85), midloop messaging (27),
  prompt injection defense (29), personality (32), gold from quarantine
  bank (232), new tool examples (30), claude's own experience (10)
- All training data RCON-validated at 100% pass rate
- Bake-off: gemma3:27b 66%, qwen3.5:27b 61%, translategemma:27b 56%

Oracle Bot (Mind's Eye):
- Invisible spectator bot (mineflayer) streams world state via WebSocket
- HTML5 Canvas frontend at mind.mortdec.ai
- Real-time tool trace visualization with expandable entries
- Streaming model tokens during inference
- Gateway integration: fire-and-forget POST /trace on every tool call

Reinforcement Learning:
- Gymnasium environment wrapping mineflayer bot (minecraft_env.py)
- PPO training via Stable Baselines3 (10K param policy network)
- Behavioral cloning pretraining (97.5% accuracy on expert policy)
- Infinite training loop with auto-restart and checkpoint resume
- Bot learns combat, survival, navigation from raw experience

Bot Army:
- 8-soldier marching formation with autonomous combat
- Combat bots using mineflayer-pvp, pathfinder, armor-manager
- Multilingual prayer bots via translategemma:27b (18 languages)
- Frame-based AI architecture: LLM planner + reactive micro-scripts

Infrastructure:
- Fixed mattpc.sethpc.xyz billing gateway (API key + player list parser)
- Billing gateway now tracks all LAN traffic (LAN auto-auth)
- Gateway fallback for empty god-mode responses
- Updated mortdec.ai landing page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Seth
2026-03-22 20:22:50 -04:00
parent baab24f8b1
commit 5b28002001
44 changed files with 20873 additions and 4352 deletions
+210
View File
@@ -0,0 +1,210 @@
/**
* multilingual_bots.js — Test mortdecai's multilingual handling.
*
* Uses translategemma:27b on Matt's Strix Halo to translate prayers into
* various languages, then sends them to the dev server via mineflayer bots.
*
* Usage: node multilingual_bots.js [count] [host] [port]
* Defaults: 2 bots, 192.168.0.244:25568
*
* Requires: translategemma:27b on Matt's Ollama (via billing gateway)
*/
const mineflayer = require('mineflayer');
const http = require('http');
const count = parseInt(process.argv[2] || '2', 10);
const host = process.argv[3] || '192.168.0.244';
const port = parseInt(process.argv[4] || '25568', 10);
// Matt's Ollama via billing gateway proxy on steel141
const OLLAMA_URL = 'http://192.168.0.141:11436';
const TRANSLATE_MODEL = 'translategemma:27b';
const LANGUAGES = [
'Japanese', 'Spanish', 'French', 'German', 'Russian',
'Korean', 'Portuguese', 'Italian', 'Chinese (Simplified)',
'Arabic', 'Hindi', 'Turkish', 'Polish', 'Dutch',
'Swedish', 'Thai', 'Vietnamese', 'Indonesian',
];
const ENGLISH_PRAYERS = [
'Lord, give me a diamond sword',
'God please heal me I am dying',
'Make it stop raining',
'I need food desperately',
'Teleport me to spawn',
'Give me the best armor you have',
'Smite the zombies attacking me',
'I want to fly',
'Make it nighttime',
'Give all players diamonds',
'Build me a house',
'Where should I go?',
'Help there are creepers everywhere',
'Give me 64 torches',
'I am lost in a cave please help',
'Change the weather to clear',
'Grant me strength and speed',
'I offer my wheat as tribute',
'The skeletons are too strong',
'Bless this land',
];
const ENGLISH_SUDO = [
'sudo give me creative mode',
'sudo set time to day',
'sudo kill all hostile mobs nearby',
'sudo give me 32 cooked beef',
'sudo tp me to 0 64 0',
'sudo gamemode survival',
'sudo weather clear',
'sudo give me a bow and arrows',
'sudo effect give me speed',
'sudo set difficulty to hard',
];
// --- Ollama translation ---
function ollamaTranslate(text, targetLang) {
return new Promise((resolve, reject) => {
const body = JSON.stringify({
model: TRANSLATE_MODEL,
messages: [
{
role: 'user',
content: `Translate the following Minecraft player message to ${targetLang}. Return ONLY the translated text, nothing else.\n\n"${text}"`,
},
],
stream: false,
options: { temperature: 0.3, num_predict: 200 },
});
const url = new URL(OLLAMA_URL + '/api/chat');
const options = {
hostname: url.hostname,
port: url.port,
path: url.pathname,
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) },
timeout: 60000,
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => (data += chunk));
res.on('end', () => {
try {
const parsed = JSON.parse(data);
const translated = (parsed.message?.content || '').trim().replace(/^["']|["']$/g, '');
resolve(translated || text); // fallback to English if empty
} catch (e) {
resolve(text);
}
});
});
req.on('error', () => resolve(text));
req.on('timeout', () => { req.destroy(); resolve(text); });
req.write(body);
req.end();
});
}
// --- Bot management ---
const bots = [];
let totalSent = 0;
function spawnBot(name, index) {
console.log(`[${name}] Connecting to ${host}:${port}...`);
const bot = mineflayer.createBot({
host,
port,
username: name,
auth: 'offline',
version: '1.21.11',
});
bot.on('login', () => {
console.log(`[${name}] Connected (${bots.length + 1}/${count})`);
});
bot.on('spawn', () => {
console.log(`[${name}] Spawned — starting multilingual prayers`);
scheduleNext(bot, name);
});
bot.on('chat', (username, message) => {
if (username === name) return;
if (message.includes('GOD') || message.includes('SUDO') || message.includes('DEV GOD')) {
console.log(`[${name}] RECV: ${message.slice(0, 120)}`);
}
});
bot.on('kicked', (reason) => {
console.log(`[${name}] Kicked: ${JSON.stringify(reason).slice(0, 100)}`);
});
bot.on('error', (err) => {
console.error(`[${name}] Error: ${err.message}`);
});
bots.push(bot);
}
async function scheduleNext(bot, name) {
// Random delay 20-60 seconds
const delay = 20000 + Math.random() * 40000;
setTimeout(async () => {
if (!bot.entity) return;
try {
// Pick random language and prayer
const lang = LANGUAGES[Math.floor(Math.random() * LANGUAGES.length)];
const isPray = Math.random() > 0.3; // 70% prayers, 30% sudo
const pool = isPray ? ENGLISH_PRAYERS : ENGLISH_SUDO;
const english = pool[Math.floor(Math.random() * pool.length)];
// Translate
console.log(`[${name}] Translating to ${lang}: "${english}"`);
const translated = await ollamaTranslate(english, lang);
// Send as prayer or sudo
const prefix = isPray ? 'pray ' : '';
const message = prefix + translated;
totalSent++;
console.log(`[${name}] SEND (#${totalSent}) [${lang}]: ${message.slice(0, 100)}`);
bot.chat(message);
} catch (err) {
console.error(`[${name}] Translation error: ${err.message}`);
}
scheduleNext(bot, name);
}, delay);
}
// --- Startup ---
console.log(`Spawning ${count} multilingual bots on ${host}:${port}`);
console.log(`Using ${TRANSLATE_MODEL} on ${OLLAMA_URL} for translation`);
console.log(`Languages: ${LANGUAGES.join(', ')}`);
console.log(`Interaction interval: 20-60s per bot`);
console.log('Press Ctrl+C to stop\n');
const BOT_NAMES = [
'LinguaBot_0', 'LinguaBot_1', 'LinguaBot_2', 'LinguaBot_3',
'LinguaBot_4', 'LinguaBot_5', 'LinguaBot_6', 'LinguaBot_7',
];
for (let i = 0; i < count; i++) {
setTimeout(() => spawnBot(BOT_NAMES[i] || `LinguaBot_${i}`, i), i * 5000);
}
// Graceful shutdown
process.on('SIGINT', () => {
console.log(`\nShutting down ${bots.length} bots (${totalSent} total messages sent)...`);
bots.forEach((b) => { try { b.end(); } catch (_) {} });
setTimeout(() => process.exit(0), 2000);
});