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:
@@ -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);
|
||||
});
|
||||
Reference in New Issue
Block a user