Fixed LLM bot support

This commit is contained in:
cameron 2026-03-01 09:59:26 -05:00
parent 792f12b925
commit e1d059d72c
3 changed files with 50 additions and 30 deletions

View File

@ -1,17 +1,19 @@
const fs = require('fs');
const path = require('path');
const { LLM } = require('@themaximalist/llm.js'); // or wherever your LLM package lives
const OpenAI = require('openai');
// read optional config file
const configPath = path.join(__dirname, '..', 'llm_config.json');
const configPath = path.join(__dirname, 'llm_config.json');
const llmOptions = fs.existsSync(configPath)
? JSON.parse(fs.readFileSync(configPath, 'utf8'))
: {};
console.log(`Read config from ${configPath}`);
class LLMBot {
constructor() {
// One instance keeps the whole conversation in memory
this.llm = new LLM(llmOptions);
// Instantiate the OpenAI client with the config options we just read
this.llm = new OpenAI(llmOptions);
// Prompt fragments well reuse
this.writePrompt =
@ -31,23 +33,39 @@ Keep it short, fun, and on-topic.`;
async Write(story_so_far) {
const msg = `${this.writePrompt}\n\nStory so far:\n${story_so_far}`;
const llm_response = await this.llm.chat(msg);
console.log(`Received response from LLM: ${llm_response}`)
return llm_response.trim();
const response = await this.llm.chat.completions.create({
model: llmOptions.model || 'meta-llama/Llama-3.2-3B-Instruct-Turbo',
messages: [{ role: 'user', content: msg }],
temperature: llmOptions.temperature ?? 0.8,
max_tokens: llmOptions.max_tokens ?? 80,
});
console.log(`Received response from LLM: ${response.choices[0].message.content}`);
return response.choices[0].message.content.trim();
}
async Vote(story_so_far, choices) {
const choicesBlock = choices.map((c, i) => `${i}: ${c}`).join('\n');
const msg = `${this.votePrompt}\n\nStory:\n${story_so_far}\n\nChoices:\n${choicesBlock}`;
const reply = (await this.llm.chat(msg)).trim();
// extract first digit found, fallback to 0
const response = await this.llm.chat.completions.create({
model: llmOptions.model || 'meta-llama/Llama-3.2-3B-Instruct-Turbo',
messages: [{ role: 'user', content: msg }],
temperature: 0.2,
max_tokens: 5,
});
const reply = response.choices[0].message.content.trim();
const match = reply.match(/\d+/);
return match ? parseInt(match[0], 10) : 0;
}
async Banter(chat_so_far) {
const msg = `${this.banterPrompt}\n\nChat so far:\n${chat_so_far}`;
return (await this.llm.chat(msg)).trim();
const response = await this.llm.chat.completions.create({
model: llmOptions.model || 'meta-llama/Llama-3.2-3B-Instruct-Turbo',
messages: [{ role: 'user', content: msg }],
temperature: llmOptions.temperature ?? 0.8,
max_tokens: llmOptions.max_tokens ?? 60,
});
return response.choices[0].message.content.trim();
}
}

View File

@ -15,6 +15,7 @@
"cookie-parser": "^1.4.7",
"express": "^5.2.1",
"node-fetch": "^3.3.2",
"openai": "^6.25.0",
"socket.io": "^4.8.3",
"uuid": "^13.0.0"
}

View File

@ -117,7 +117,7 @@ class YarnGame {
console.log("Creating bots...")
for (let i = 0; i < botCount; i++) {
const bot_id = randomUUID()
const bot = BotFactory.createBot("random");
const bot = BotFactory.createBot("llm");
this.bots.push({ bot_id, bot });
const bot_player = {
player_id: bot_id,
@ -130,23 +130,24 @@ class YarnGame {
}
}
startGame(settings) {
async startGame(settings) {
this.gameSettings = { ...this.gameSettings, ...settings };
this.startBots(this.gameSettings.botCount);
this.inProgress = true;
this.yarnStory = [{ player: "Narrator", str: this.gameSettings.startText }];
this.players.forEach(p => p.score = 0);
this.startWritingPhase();
await this.startWritingPhase();
}
processBotWriting() {
async processBotWriting() {
for (const botObj of this.bots) {
const botText = botObj.bot.Write(this.getStoryText());
const botText = await botObj.bot.Write(this.getStoryText());
console.log(`Bot text: ${botText}`)
this.submitEntry(botObj.bot_id, botText)
}
}
startWritingPhase() {
async startWritingPhase() {
this.currentPhase = 'writing';
this.round_data = [];
this.submittedPlayers = new Set();
@ -176,18 +177,18 @@ class YarnGame {
return this.submittedPlayers.size >= this.players.length;
}
processBotVoting() {
async processBotVoting() {
for (const botObj of this.bots) {
const botVote = botObj.bot.Vote(this.getStoryText(), this.round_data);
const botVote = await botObj.bot.Vote(this.getStoryText(), this.round_data);
this.submitVote(botObj.bot_id, botVote)
}
}
startVotingPhase() {
async startVotingPhase() {
this.currentPhase = 'voting';
this.votedPlayers = new Set();
this.timeRemaining = 30; // 30 seconds for voting
this.processBotVoting()
await this.processBotVoting()
}
submitVote(playerId, entryIndex) {
@ -390,7 +391,7 @@ io.on('connection', (socket) => {
io.to(currentRoom).emit('settingsUpdate', game.gameSettings);
});
socket.on('startGame', (settings) => {
socket.on('startGame', async (settings) => {
if (!currentRoom || !playerId) return;
const game = games[currentRoom];
@ -401,13 +402,13 @@ io.on('connection', (socket) => {
}
console.log(`Starting new game with settings ${JSON.stringify(settings)}`)
game.startGame(settings);
await game.startGame(settings);
io.to(currentRoom).emit('gameStarted', game.getState());
startTimer(game);
await startTimer(game);
});
socket.on('submitEntry', (data) => {
socket.on('submitEntry', async (data) => {
if (!currentRoom || !playerId) return;
const game = games[currentRoom];
@ -420,7 +421,7 @@ io.on('connection', (socket) => {
if (game.allPlayersSubmitted()) {
clearInterval(game.timer);
game.startVotingPhase();
await game.startVotingPhase();
io.to(currentRoom).emit('votingPhase', {
entries: game.round_data.map((e, i) => ({
index: i,
@ -495,10 +496,10 @@ io.on('connection', (socket) => {
});
});
function startTimer(game) {
async function startTimer(game) {
if (game.timer) clearInterval(game.timer);
game.timer = setInterval(() => {
game.timer = setInterval(async () => {
game.timeRemaining--;
io.to(game.roomName).emit('timerUpdate', game.timeRemaining);
@ -512,7 +513,7 @@ function startTimer(game) {
}
}
game.startVotingPhase();
await game.startVotingPhase();
io.to(game.roomName).emit('votingPhase', {
entries: game.round_data.map((e, i) => ({
index: i,
@ -558,10 +559,10 @@ function endVotingPhase(game) {
});
} else {
// Start next round after a short delay
setTimeout(() => {
setTimeout(async () => {
game.startWritingPhase();
io.to(game.roomName).emit('newRound', game.getState());
startTimer(game);
await startTimer(game);
}, 5000);
}
}