Batch of LLM-assisted fixes/feature updates

This commit is contained in:
Cam Spry committed 2026-10-30 23:02:45 -04:00
1 parent 7c6453160a
commit 05aaf394df
16 files changed
+5597 -912

No files matched your search

+58 -17
View File
@@ -1,37 +1,78 @@
const RandomBot = require('./RandomBot');
const LLMBot = require('./LLMBot');
'use strict';
const fs = require('fs');
const path = require('path');
const RandomBot = require('./RandomBot');
const LLMBot = require('./LLMBot');
const NAMES_PATH = path.join(__dirname, 'bot_names.txt');
const FALLBACK_NAMES = ['DefaultBot', 'BackupBot', 'SpareBot', 'ExtraBot'];
function readNames() {
try {
const names = fs
.readFileSync(NAMES_PATH, 'utf8')
.split('\n')
.map((name) => name.trim())
.filter((name) => name.length > 0);
return names.length ? names : FALLBACK_NAMES;
} catch (err) {
console.warn(`[BotFactory] Could not read ${NAMES_PATH}: ${err.message}`);
return FALLBACK_NAMES;
}
}
class BotFactory {
static createBot(type) {
switch (type.toLowerCase()) {
/**
* Create a bot instance. LLM bots fall back to RandomBot when the LLM
* client cannot be constructed (missing API key/config) so a game can
* always start.
*/
static createBot(type = 'llm') {
switch (String(type).toLowerCase()) {
case 'random':
return new RandomBot();
case 'llm':
return new LLMBot();
try {
return new LLMBot();
} catch (err) {
console.warn(
`[BotFactory] LLM bot unavailable (${err.message}); using RandomBot instead.`
);
return new RandomBot();
}
default:
throw new Error(`Unknown bot type: ${type}`);
}
}
static generateBotName() {
const names = fs.readFileSync(path.join(__dirname, 'bot_names.txt'), 'utf8')
.split('\n')
.map(name => name.trim())
.filter(name => name.length > 0);
/**
* Pick a random bot name, avoiding names already used in the room.
*/
static generateBotName(exclude = []) {
const names = readNames();
const taken = new Set(
(Array.isArray(exclude) ? exclude : [exclude])
.filter(Boolean)
.map((name) => String(name).toLowerCase())
);
if (names.length === 0) {
return 'DefaultBot'; // Fallback if no names are found
}
const available = names.filter((name) => !taken.has(name.toLowerCase()));
const pool = available.length ? available : names;
const pick = pool[Math.floor(Math.random() * pool.length)] || FALLBACK_NAMES[0];
const randomIndex = Math.floor(Math.random() * names.length);
return names[randomIndex];
// If every themed name is taken, disambiguate with a number.
if (taken.has(pick.toLowerCase())) {
let suffix = 2;
while (taken.has(`${pick}${suffix}`.toLowerCase())) suffix += 1;
return `${pick}${suffix}`;
}
return pick;
}
static getAvailableBotTypes() {
return ['random'];
return ['llm', 'random'];
}
}
module.exports = BotFactory;
module.exports = BotFactory;