Merge pull request #370 from kolbytn/multi-chat-patches

Yet more multi agent controls
This commit is contained in:
Max Robinson 2024-12-13 16:31:49 -06:00 committed by GitHub
commit 89c94d9d9b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 89 additions and 30 deletions

View file

@ -32,7 +32,9 @@
{"role": "system", "content": "say hi to john_goodman"}, {"role": "system", "content": "say hi to john_goodman"},
{"role": "assistant", "content": "!startConversation(\"john_goodman\", \"Hey John\"))"}, {"role": "assistant", "content": "!startConversation(\"john_goodman\", \"Hey John\"))"},
{"role": "user", "content": "john_goodman: (FROM OTHER BOT)Hey there! What's up?"}, {"role": "user", "content": "john_goodman: (FROM OTHER BOT)Hey there! What's up?"},
{"role": "assistant", "content": "Hey John, not much. Just saying hi. Bye! !endConversation('john_goodman')"} {"role": "assistant", "content": "Hey John, not much. Just saying hi."},
{"role": "user", "content": "john_goodman: (FROM OTHER BOT)Bye!"},
{"role": "assistant", "content": "Bye! !endConversation('john_goodman')"}
], ],
[ [

View file

@ -1,5 +1,5 @@
{ {
"name": "grok", "name": "Grok",
"model": "grok-beta", "model": "grok-beta",

View file

@ -1,15 +1,13 @@
{ {
"name": "qwen", "name": "qwen",
"cooldown": 5000,
"model": { "model": {
"api": "qwen", "api": "qwen",
"url": "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", "url": "https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/text-generation/generation",
"model": "qwen-max" "model": "qwen-max"
}, },
"embedding": { "embedding": "openai"
"api": "qwen",
"url": "https://dashscope.aliyuncs.com/api/v1/services/embeddings/text-embedding/text-embedding",
"model": "text-embedding-v2"
}
} }

View file

@ -318,6 +318,7 @@ export class Agent {
} }
async routeResponse(to_player, message) { async routeResponse(to_player, message) {
if (this.shut_up) return;
let self_prompt = to_player === 'system' || to_player === this.name; let self_prompt = to_player === 'system' || to_player === this.name;
if (self_prompt && this.last_sender) { if (self_prompt && this.last_sender) {
// this is for when the agent is prompted by system while still in conversation // this is for when the agent is prompted by system while still in conversation
@ -437,22 +438,18 @@ export class Agent {
}, INTERVAL); }, INTERVAL);
this.bot.emit('idle'); this.bot.emit('idle');
// Check for task completion
if (this.task.data) {
setInterval(() => {
let res = this.task.isDone();
if (res) {
// TODO kill other bots
this.cleanKill(res.message, res.code);
}
}, 1000);
}
} }
async update(delta) { async update(delta) {
await this.bot.modes.update(); await this.bot.modes.update();
this.self_prompter.update(delta); this.self_prompter.update(delta);
if (this.task.data) {
let res = this.task.isDone();
if (res) {
console.log('Task finished:', res.message);
this.killAll();
}
}
} }
isIdle() { isIdle() {
@ -465,4 +462,8 @@ export class Agent {
this.history.save(); this.history.save();
process.exit(code); process.exit(code);
} }
killAll() {
serverProxy.shutdown();
}
} }

View file

@ -48,6 +48,10 @@ class AgentServerProxy {
this.socket.emit('login-agent', this.agent.name); this.socket.emit('login-agent', this.agent.name);
} }
shutdown() {
this.socket.emit('shutdown');
}
getSocket() { getSocket() {
return this.socket; return this.socket;
} }

View file

@ -134,7 +134,7 @@ class ConversationManager {
convo.active = true; convo.active = true;
this.activeConversation = convo; this.activeConversation = convo;
this._startMonitor(); this._startMonitor();
this.sendToBot(send_to, message, true); this.sendToBot(send_to, message, true, false);
} }
startConversationFromOtherBot(name) { startConversationFromOtherBot(name) {
@ -144,14 +144,14 @@ class ConversationManager {
this._startMonitor(); this._startMonitor();
} }
sendToBot(send_to, message, start=false) { sendToBot(send_to, message, start=false, open_chat=true) {
if (!this.isOtherAgent(send_to)) { if (!this.isOtherAgent(send_to)) {
agent.bot.whisper(send_to, message); console.warn(`${agent.name} tried to send bot message to non-bot ${send_to}`);
return; return;
} }
const convo = this._getConvo(send_to); const convo = this._getConvo(send_to);
if (settings.chat_bot_messages && !start) if (settings.chat_bot_messages && open_chat)
agent.openChat(`(To ${send_to}) ${message}`); agent.openChat(`(To ${send_to}) ${message}`);
if (convo.ignore_until_start) if (convo.ignore_until_start)
@ -174,7 +174,7 @@ class ConversationManager {
// check if any convo is active besides the sender // check if any convo is active besides the sender
if (Object.values(this.convos).some(c => c.active && c.name !== sender)) { if (Object.values(this.convos).some(c => c.active && c.name !== sender)) {
this.sendToBot(sender, `I'm talking to someone else, try again later. !endConversation("${sender}")`); this.sendToBot(sender, `I'm talking to someone else, try again later. !endConversation("${sender}")`, false, false);
return; return;
} }
@ -240,7 +240,7 @@ class ConversationManager {
endAllConversations() { endAllConversations() {
for (const sender in this.convos) { for (const sender in this.convos) {
this.convos[sender].end(); this.endConversation(sender);
} }
if (self_prompter_paused) { if (self_prompter_paused) {
_resumeSelfPrompter(); _resumeSelfPrompter();

View file

@ -897,10 +897,7 @@ export async function giveToPlayer(bot, itemType, username, num=1) {
} }
// if we are too close, make some distance // if we are too close, make some distance
if (bot.entity.position.distanceTo(player.position) < 2) { if (bot.entity.position.distanceTo(player.position) < 2) {
let goal = new pf.goals.GoalNear(player.position.x, player.position.y, player.position.z, 2); await moveAwayFromEntity(bot, player, 2);
let inverted_goal = new pf.goals.GoalInvert(goal);
bot.pathfinder.setMovements(new pf.Movements(bot));
await bot.pathfinder.goto(inverted_goal);
} }
await bot.lookAt(player.position); await bot.lookAt(player.position);
if (await discard(bot, itemType, num)) { if (await discard(bot, itemType, num)) {
@ -1106,6 +1103,21 @@ export async function moveAway(bot, distance) {
return true; return true;
} }
export async function moveAwayFromEntity(bot, entity, distance=16) {
/**
* Move away from the given entity.
* @param {MinecraftBot} bot, reference to the minecraft bot.
* @param {Entity} entity, the entity to move away from.
* @param {number} distance, the distance to move away.
* @returns {Promise<boolean>} true if the bot moved away, false otherwise.
**/
let goal = new pf.goals.GoalFollow(entity, distance);
let inverted_goal = new pf.goals.GoalInvert(goal);
bot.pathfinder.setMovements(new pf.Movements(bot));
await bot.pathfinder.goto(inverted_goal);
return true;
}
export async function avoidEnemies(bot, distance=16) { export async function avoidEnemies(bot, distance=16) {
/** /**
* Move a given distance away from all nearby enemy mobs. * Move a given distance away from all nearby enemy mobs.

View file

@ -179,7 +179,7 @@ export class Task {
await new Promise((resolve) => setTimeout(resolve, 10000)); await new Promise((resolve) => setTimeout(resolve, 10000));
if (available_agents.length < this.data.agent_count) { if (available_agents.length < this.data.agent_count) {
console.log(`Missing ${this.data.agent_count - available_agents.length} bot(s).`); console.log(`Missing ${this.data.agent_count - available_agents.length} bot(s).`);
this.agent.cleanKill('Not all required players/bots are present in the world. Exiting.', 4); this.agent.killAll();
} }
} }

View file

@ -35,6 +35,16 @@ class MainProxy {
this.socket.on('register-agents-success', () => { this.socket.on('register-agents-success', () => {
console.log('Agents registered'); console.log('Agents registered');
}); });
this.socket.on('shutdown', () => {
console.log('Shutting down');
for (let agentName in this.agent_processes) {
this.agent_processes[agentName].stop();
}
setTimeout(() => {
process.exit(0);
}, 2000);
});
} }
addAgent(agent) { addAgent(agent) {

View file

@ -101,6 +101,19 @@ export function createMindServer(port = 8080) {
} }
}); });
socket.on('stop-all-agents', () => {
console.log('Killing all agents');
stopAllAgents();
});
socket.on('shutdown', () => {
console.log('Shutting down');
for (let manager of Object.values(agentManagers)) {
manager.emit('shutdown');
}
process.exit(0);
});
}); });
server.listen(port, 'localhost', () => { server.listen(port, 'localhost', () => {
@ -121,6 +134,15 @@ function agentsUpdate(socket) {
socket.emit('agents-update', agents); socket.emit('agents-update', agents);
} }
function stopAllAgents() {
for (const agentName in inGameAgents) {
let manager = agentManagers[agentName];
if (manager) {
manager.emit('stop-agent', agentName);
}
}
}
// Optional: export these if you need access to them from other files // Optional: export these if you need access to them from other files
export const getIO = () => io; export const getIO = () => io;
export const getServer = () => server; export const getServer = () => server;

View file

@ -85,6 +85,8 @@
`} `}
</div> </div>
</div> </div>
<button class="stop-btn" onclick="killAllAgents()">Stop All</button>
<button class="stop-btn" onclick="shutdown()">Shutdown</button>
`).join('') : `).join('') :
'<div class="agent">No agents connected</div>'; '<div class="agent">No agents connected</div>';
}); });
@ -100,6 +102,14 @@
function stopAgent(agentName) { function stopAgent(agentName) {
socket.emit('stop-agent', agentName); socket.emit('stop-agent', agentName);
} }
function killAllAgents() {
socket.emit('stop-all-agents');
}
function shutdown() {
socket.emit('shutdown');
}
</script> </script>
</body> </body>
</html> </html>