mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-08-09 08:45:33 +02:00
better conversation monitor timers, examples, bot detection
This commit is contained in:
parent
5649cec439
commit
c2dab95061
8 changed files with 106 additions and 39 deletions
|
@ -12,7 +12,7 @@
|
||||||
"modes": {
|
"modes": {
|
||||||
"self_preservation": true,
|
"self_preservation": true,
|
||||||
"unstuck": true,
|
"unstuck": true,
|
||||||
"cowardice": true,
|
"cowardice": false,
|
||||||
"self_defense": true,
|
"self_defense": true,
|
||||||
"hunting": true,
|
"hunting": true,
|
||||||
"item_collecting": true,
|
"item_collecting": true,
|
||||||
|
@ -35,6 +35,13 @@
|
||||||
{"role": "assistant", "content": "Hey John, not much. Just saying hi. Bye! !endConversation('john_goodman')"}
|
{"role": "assistant", "content": "Hey John, not much. Just saying hi. Bye! !endConversation('john_goodman')"}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
{"role": "system", "content": "work together with the other bot"},
|
||||||
|
{"role": "assistant", "content": "!startConversation(\"terrance\", \"Hey gpt! Let's work together on this.\"))"},
|
||||||
|
{"role": "user", "content": "terrance: (FROM OTHER BOT)Sounds good, what should we do first?"},
|
||||||
|
{"role": "assistant", "content": "I'll start by collecting some resources. !collectBlocks('stone', 10)"}
|
||||||
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
{"role": "system", "content": "trade something with zorro_34"},
|
{"role": "system", "content": "trade something with zorro_34"},
|
||||||
{"role": "assistant", "content": "!startConversation(\"zorro_34\", \"Hey let's trade. What do you have?\")"},
|
{"role": "assistant", "content": "!startConversation(\"zorro_34\", \"Hey let's trade. What do you have?\")"},
|
||||||
|
@ -126,6 +133,11 @@
|
||||||
{"role": "assistant", "content": "I'll have to search a wider area. !searchForBlock(\"oak_log\", 100)"}
|
{"role": "assistant", "content": "I'll have to search a wider area. !searchForBlock(\"oak_log\", 100)"}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
{"role": "system", "content": "Code output: Placed oak_planks at (-154, 96, -228)."},
|
||||||
|
{"role": "assistant", "content": "I've placed an oak plank for the house. Wait, I should use newAction to build complicated structures! !newAction(\"Build a house with oak planks\")"}
|
||||||
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
{"role": "user", "content": "trixy88: craft some sticks"},
|
{"role": "user", "content": "trixy88: craft some sticks"},
|
||||||
{"role": "assistant", "content": "!craftRecipe(\"stick\", 4)"},
|
{"role": "assistant", "content": "!craftRecipe(\"stick\", 4)"},
|
||||||
|
|
|
@ -108,10 +108,16 @@ export class ActionManager {
|
||||||
this.currentActionFn = null;
|
this.currentActionFn = null;
|
||||||
clearTimeout(TIMEOUT);
|
clearTimeout(TIMEOUT);
|
||||||
this.cancelResume();
|
this.cancelResume();
|
||||||
console.error("Code execution triggered catch: " + err);
|
console.error("Code execution triggered catch:", err);
|
||||||
|
// Log the full stack trace
|
||||||
|
console.error(err.stack);
|
||||||
await this.stop();
|
await this.stop();
|
||||||
|
|
||||||
let message = this._getBotOutputSummary() + '!!Code threw exception!! Error: ' + err;
|
let message = this._getBotOutputSummary() +
|
||||||
|
'!!Code threw exception!!\n' +
|
||||||
|
'Error: ' + err + '\n' +
|
||||||
|
'Stack trace:\n' + err.stack;
|
||||||
|
|
||||||
let interrupted = this.agent.bot.interrupt_code;
|
let interrupted = this.agent.bot.interrupt_code;
|
||||||
this.agent.clearBotLogs();
|
this.agent.clearBotLogs();
|
||||||
if (!interrupted && !this.agent.coder.generating) {
|
if (!interrupted && !this.agent.coder.generating) {
|
||||||
|
|
|
@ -224,7 +224,7 @@ export class Agent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self_prompt)
|
if (from_other_bot)
|
||||||
this.last_sender = source;
|
this.last_sender = source;
|
||||||
|
|
||||||
// Now translate the message
|
// Now translate the message
|
||||||
|
@ -311,7 +311,7 @@ export class Agent {
|
||||||
|
|
||||||
async routeResponse(to_player, message) {
|
async routeResponse(to_player, message) {
|
||||||
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 && !this.self_prompter.on) {
|
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
|
||||||
// so it can respond to events like death but be routed back to the last sender
|
// so it can respond to events like death but be routed back to the last sender
|
||||||
to_player = this.last_sender;
|
to_player = this.last_sender;
|
||||||
|
@ -320,7 +320,6 @@ export class Agent {
|
||||||
if (convoManager.isOtherAgent(to_player) && convoManager.inConversation(to_player)) {
|
if (convoManager.isOtherAgent(to_player) && convoManager.inConversation(to_player)) {
|
||||||
// if we're in an ongoing conversation with the other bot, send the response to it
|
// if we're in an ongoing conversation with the other bot, send the response to it
|
||||||
convoManager.sendToBot(to_player, message);
|
convoManager.sendToBot(to_player, message);
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// otherwise, use open chat
|
// otherwise, use open chat
|
||||||
|
|
|
@ -116,7 +116,7 @@ export const actionsList = [
|
||||||
description: 'Find and go to the nearest block of a given type in a given range.',
|
description: 'Find and go to the nearest block of a given type in a given range.',
|
||||||
params: {
|
params: {
|
||||||
'type': { type: 'BlockName', description: 'The block type to go to.' },
|
'type': { type: 'BlockName', description: 'The block type to go to.' },
|
||||||
'search_range': { type: 'float', description: 'The range to search for the block.', domain: [0, 512] }
|
'search_range': { type: 'float', description: 'The range to search for the block.', domain: [32, 512] }
|
||||||
},
|
},
|
||||||
perform: runAsAction(async (agent, block_type, range) => {
|
perform: runAsAction(async (agent, block_type, range) => {
|
||||||
await skills.goToNearestBlock(agent.bot, block_type, 4, range);
|
await skills.goToNearestBlock(agent.bot, block_type, 4, range);
|
||||||
|
@ -127,7 +127,7 @@ export const actionsList = [
|
||||||
description: 'Find and go to the nearest entity of a given type in a given range.',
|
description: 'Find and go to the nearest entity of a given type in a given range.',
|
||||||
params: {
|
params: {
|
||||||
'type': { type: 'string', description: 'The type of entity to go to.' },
|
'type': { type: 'string', description: 'The type of entity to go to.' },
|
||||||
'search_range': { type: 'float', description: 'The range to search for the entity.', domain: [0, 512] }
|
'search_range': { type: 'float', description: 'The range to search for the entity.', domain: [32, 512] }
|
||||||
},
|
},
|
||||||
perform: runAsAction(async (agent, entity_type, range) => {
|
perform: runAsAction(async (agent, entity_type, range) => {
|
||||||
await skills.goToNearestEntity(agent.bot, entity_type, 4, range);
|
await skills.goToNearestEntity(agent.bot, entity_type, 4, range);
|
||||||
|
@ -386,10 +386,12 @@ export const actionsList = [
|
||||||
'message': { type: 'string', description: 'The message to send.' },
|
'message': { type: 'string', description: 'The message to send.' },
|
||||||
},
|
},
|
||||||
perform: async function (agent, player_name, message) {
|
perform: async function (agent, player_name, message) {
|
||||||
if (convoManager.inConversation())
|
if (convoManager.inConversation() && !convoManager.inConversation(player_name))
|
||||||
return 'You are already in conversation';
|
return 'You are already in conversation with other bot.';
|
||||||
if (!convoManager.isOtherAgent(player_name))
|
if (!convoManager.isOtherAgent(player_name))
|
||||||
return player_name + ' is not a bot, cannot start conversation.';
|
return player_name + ' is not a bot, cannot start conversation.';
|
||||||
|
if (convoManager.inConversation(player_name))
|
||||||
|
agent.history.add('system', 'You are already in conversation with ' + player_name + ' Don\'t use this command to talk to them.');
|
||||||
convoManager.startConversation(player_name, message);
|
convoManager.startConversation(player_name, message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -48,15 +48,11 @@ export const queryList = [
|
||||||
|
|
||||||
|
|
||||||
let players = world.getNearbyPlayerNames(bot);
|
let players = world.getNearbyPlayerNames(bot);
|
||||||
let bots = [];
|
let bots = convoManager.getInGameAgents().filter(b => b !== agent.name);
|
||||||
for (const player of players) {
|
players = players.filter(p => !bots.includes(p));
|
||||||
if (convoManager.isOtherAgent(player))
|
|
||||||
bots.push(player);
|
|
||||||
}
|
|
||||||
players = players.filter(p => !convoManager.isOtherAgent(p));
|
|
||||||
|
|
||||||
res += '\n- Nearby Human Players: ' + players.join(', ');
|
res += '\n- Nearby Human Players: ' + (players.length > 0 ? players.join(', ') : 'None.');
|
||||||
res += '\n- Nearby Bot Players: ' + bots.join(', ');
|
res += '\n- Nearby Bot Players: ' + (bots.length > 0 ? bots.join(', ') : 'None.');
|
||||||
|
|
||||||
res += '\n' + agent.bot.modes.getMiniDocs() + '\n';
|
res += '\n' + agent.bot.modes.getMiniDocs() + '\n';
|
||||||
return pad(res);
|
return pad(res);
|
||||||
|
@ -137,12 +133,8 @@ export const queryList = [
|
||||||
let bot = agent.bot;
|
let bot = agent.bot;
|
||||||
let res = 'NEARBY_ENTITIES';
|
let res = 'NEARBY_ENTITIES';
|
||||||
let players = world.getNearbyPlayerNames(bot);
|
let players = world.getNearbyPlayerNames(bot);
|
||||||
let bots = [];
|
let bots = convoManager.getInGameAgents().filter(b => b !== agent.name);
|
||||||
for (const player of players) {
|
players = players.filter(p => !bots.includes(p));
|
||||||
if (convoManager.isOtherAgent(player))
|
|
||||||
bots.push(player);
|
|
||||||
}
|
|
||||||
players = players.filter(p => !convoManager.isOtherAgent(p));
|
|
||||||
|
|
||||||
for (const player of players) {
|
for (const player of players) {
|
||||||
res += `\n- Human player: ${player}`;
|
res += `\n- Human player: ${player}`;
|
||||||
|
|
|
@ -44,11 +44,14 @@ class Conversation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const WAIT_TIME_START = 30000;
|
||||||
class ConversationManager {
|
class ConversationManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.convos = {};
|
this.convos = {};
|
||||||
this.activeConversation = null;
|
this.activeConversation = null;
|
||||||
|
this.awaiting_response = false;
|
||||||
|
this.connection_timeout = null;
|
||||||
|
this.wait_time_limit = WAIT_TIME_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
initAgent(a) {
|
initAgent(a) {
|
||||||
|
@ -63,22 +66,59 @@ class ConversationManager {
|
||||||
|
|
||||||
_startMonitor() {
|
_startMonitor() {
|
||||||
clearInterval(this.connection_monitor);
|
clearInterval(this.connection_monitor);
|
||||||
|
let wait_time = 0;
|
||||||
|
let last_time = Date.now();
|
||||||
this.connection_monitor = setInterval(() => {
|
this.connection_monitor = setInterval(() => {
|
||||||
if (!this.activeConversation) {
|
if (!this.activeConversation) {
|
||||||
clearInterval(this.connection_monitor);
|
this._stopMonitor();
|
||||||
return; // will clean itself up
|
return; // will clean itself up
|
||||||
}
|
}
|
||||||
let cur_name = this.activeConversation.name;
|
|
||||||
if (!this.otherAgentInGame(cur_name)) {
|
let delta = Date.now() - last_time;
|
||||||
if (!self_prompter_paused) {
|
last_time = Date.now();
|
||||||
this.endConversation(cur_name);
|
let convo_partner = this.activeConversation.name;
|
||||||
agent.handleMessage('system', `${cur_name} disconnected, conversation has ended.`);
|
|
||||||
}
|
if (this.awaiting_response && agent.isIdle()) {
|
||||||
else {
|
wait_time += delta;
|
||||||
this.endConversation(cur_name);
|
if (wait_time > this.wait_time_limit) {
|
||||||
|
agent.handleMessage('system', `${convo_partner} hasn't responded in ${this.wait_time_limit/1000} seconds, respond with a message to them or your own action.`);
|
||||||
|
wait_time = 0;
|
||||||
|
this.wait_time_limit*=2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 10000);
|
else if (!this.awaiting_response){
|
||||||
|
this.wait_time_limit = WAIT_TIME_START;
|
||||||
|
wait_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.otherAgentInGame(convo_partner) && !this.connection_timeout) {
|
||||||
|
this.connection_timeout = setTimeout(() => {
|
||||||
|
if (this.otherAgentInGame(convo_partner)){
|
||||||
|
this._clearMonitorTimeouts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!self_prompter_paused) {
|
||||||
|
this.endConversation(convo_partner);
|
||||||
|
agent.handleMessage('system', `${convo_partner} disconnected, conversation has ended.`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.endConversation(convo_partner);
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
_stopMonitor() {
|
||||||
|
clearInterval(this.connection_monitor);
|
||||||
|
this.connection_monitor = null;
|
||||||
|
this._clearMonitorTimeouts();
|
||||||
|
}
|
||||||
|
|
||||||
|
_clearMonitorTimeouts() {
|
||||||
|
this.awaiting_response = false;
|
||||||
|
clearTimeout(this.connection_timeout);
|
||||||
|
this.connection_timeout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async startConversation(send_to, message) {
|
async startConversation(send_to, message) {
|
||||||
|
@ -97,6 +137,13 @@ class ConversationManager {
|
||||||
this.sendToBot(send_to, message, true);
|
this.sendToBot(send_to, message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startConversationFromOtherBot(name) {
|
||||||
|
const convo = this._getConvo(name);
|
||||||
|
convo.active = true;
|
||||||
|
this.activeConversation = convo;
|
||||||
|
this._startMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
sendToBot(send_to, message, start=false) {
|
sendToBot(send_to, message, start=false) {
|
||||||
if (!this.isOtherAgent(send_to)) {
|
if (!this.isOtherAgent(send_to)) {
|
||||||
agent.bot.whisper(send_to, message);
|
agent.bot.whisper(send_to, message);
|
||||||
|
@ -118,6 +165,7 @@ class ConversationManager {
|
||||||
end,
|
end,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.awaiting_response = true;
|
||||||
sendBotChatToServer(send_to, json);
|
sendBotChatToServer(send_to, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,10 +180,12 @@ class ConversationManager {
|
||||||
|
|
||||||
if (recieved.start) {
|
if (recieved.start) {
|
||||||
convo.reset();
|
convo.reset();
|
||||||
|
this.startConversationFromOtherBot(sender);
|
||||||
}
|
}
|
||||||
if (convo.ignore_until_start)
|
if (convo.ignore_until_start)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this._clearMonitorTimeouts();
|
||||||
convo.queue(recieved);
|
convo.queue(recieved);
|
||||||
|
|
||||||
// responding to conversation takes priority over self prompting
|
// responding to conversation takes priority over self prompting
|
||||||
|
@ -167,6 +217,10 @@ class ConversationManager {
|
||||||
agents_in_game = agents.filter(a => a.in_game).map(a => a.name);
|
agents_in_game = agents.filter(a => a.in_game).map(a => a.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getInGameAgents() {
|
||||||
|
return agents_in_game;
|
||||||
|
}
|
||||||
|
|
||||||
inConversation(other_agent=null) {
|
inConversation(other_agent=null) {
|
||||||
if (other_agent)
|
if (other_agent)
|
||||||
return this.convos[other_agent]?.active;
|
return this.convos[other_agent]?.active;
|
||||||
|
@ -176,6 +230,7 @@ class ConversationManager {
|
||||||
endConversation(sender) {
|
endConversation(sender) {
|
||||||
if (this.convos[sender]) {
|
if (this.convos[sender]) {
|
||||||
this.convos[sender].end();
|
this.convos[sender].end();
|
||||||
|
this._stopMonitor();
|
||||||
this.activeConversation = null;
|
this.activeConversation = null;
|
||||||
if (self_prompter_paused && !this.inConversation()) {
|
if (self_prompter_paused && !this.inConversation()) {
|
||||||
_resumeSelfPrompter();
|
_resumeSelfPrompter();
|
||||||
|
@ -276,7 +331,7 @@ function _handleFullInMessage(sender, recieved) {
|
||||||
|
|
||||||
let message = _tagMessage(recieved.message);
|
let message = _tagMessage(recieved.message);
|
||||||
if (recieved.end) {
|
if (recieved.end) {
|
||||||
convo.end();
|
convoManager.endConversation(sender);
|
||||||
sender = 'system'; // bot will respond to system instead of the other bot
|
sender = 'system'; // bot will respond to system instead of the other bot
|
||||||
message = `Conversation with ${sender} ended with message: "${message}"`;
|
message = `Conversation with ${sender} ended with message: "${message}"`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ export function getNearbyPlayerNames(bot) {
|
||||||
* @example
|
* @example
|
||||||
* let players = world.getNearbyPlayerNames(bot);
|
* let players = world.getNearbyPlayerNames(bot);
|
||||||
**/
|
**/
|
||||||
let players = getNearbyPlayers(bot, 16);
|
let players = getNearbyPlayers(bot, 64);
|
||||||
let found = [];
|
let found = [];
|
||||||
for (let i = 0; i < players.length; i++) {
|
for (let i = 0; i < players.length; i++) {
|
||||||
if (!found.includes(players[i].username) && players[i].username != bot.username) {
|
if (!found.includes(players[i].username) && players[i].username != bot.username) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as skills from './library/skills.js';
|
||||||
import * as world from './library/world.js';
|
import * as world from './library/world.js';
|
||||||
import * as mc from '../utils/mcdata.js';
|
import * as mc from '../utils/mcdata.js';
|
||||||
import settings from '../../settings.js'
|
import settings from '../../settings.js'
|
||||||
|
import convoManager from './conversation.js';
|
||||||
|
|
||||||
async function say(agent, message) {
|
async function say(agent, message) {
|
||||||
agent.bot.modes.behavior_log += message + '\n';
|
agent.bot.modes.behavior_log += message + '\n';
|
||||||
|
@ -294,7 +295,7 @@ async function execute(mode, agent, func, timeout=-1) {
|
||||||
|
|
||||||
if (should_reprompt) {
|
if (should_reprompt) {
|
||||||
// auto prompt to respond to the interruption
|
// auto prompt to respond to the interruption
|
||||||
let role = agent.last_sender ? agent.last_sender : 'system';
|
let role = convoManager.inConversation() ? agent.last_sender : 'system';
|
||||||
let logs = agent.bot.modes.flushBehaviorLog();
|
let logs = agent.bot.modes.flushBehaviorLog();
|
||||||
agent.handleMessage(role, `(AUTO MESSAGE)Your previous action '${interrupted_action}' was interrupted by ${mode.name}.
|
agent.handleMessage(role, `(AUTO MESSAGE)Your previous action '${interrupted_action}' was interrupted by ${mode.name}.
|
||||||
Your behavior log: ${logs}\nRespond accordingly.`);
|
Your behavior log: ${logs}\nRespond accordingly.`);
|
||||||
|
|
Loading…
Add table
Reference in a new issue