Merge pull request #22 from kolbytn/tweaks

Tweaks
This commit is contained in:
Max Robinson 2024-02-16 23:01:47 -06:00 committed by GitHub
commit a740fe797e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 98 additions and 50 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Kolby Nottingham
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -3,5 +3,5 @@
"host": "localhost",
"port": 55916,
"auth": "offline",
"allow_insecure_coding": true
"allow_insecure_coding": false
}

View file

@ -29,7 +29,7 @@ export class Coder {
// write custom code to file and import it
async stageCode(code) {
code = this.santitizeCode(code);
code = this.sanitizeCode(code);
let src = '';
code = code.replaceAll('console.log(', 'log(bot,');
code = code.replaceAll('log("', 'log(bot,"');
@ -62,7 +62,8 @@ export class Coder {
return await import('../..' + this.fp + filename);
}
santitizeCode(code) {
sanitizeCode(code) {
code = code.trim();
const remove_strs = ['Javascript', 'javascript', 'js']
for (let r of remove_strs) {
if (code.startsWith(r)) {
@ -93,13 +94,14 @@ export class Coder {
let res = await this.generateCodeLoop(agent_history);
this.generating = false;
if (!res.interrupted) this.agent.bot.emit('idle');
return res.message;
}
async generateCodeLoop(agent_history) {
let system_message = "You are a minecraft mineflayer bot that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write your code in a codeblock. Example response: ``` // your code here ``` You will then be given a response to your code. If you are satisfied with the response, respond without a codeblock in a conversational way. If something went wrong, write another codeblock and try to fix the problem.";
system_message += getSkillDocs();
system_message += "\n\nExamples:\nUser zZZn98: come here \nAssistant: I am going to navigate to zZZn98. ```\nawait skills.goToPlayer(bot, 'zZZn98');```\nSystem: Code execution finished successfully.\nAssistant: Done.";
system_message += "\n\nExamples:\nUser zZZn98: come here \nAssistant: I am going to navigate to zZZn98. ```\nawait skills.goToPlayer(bot, 'zZZn98', 3);```\nSystem: Code execution finished successfully.\nAssistant: Done.";
let messages = await agent_history.getHistory(this.examples);
@ -107,7 +109,7 @@ export class Coder {
let failures = 0;
for (let i=0; i<5; i++) {
if (this.agent.bot.interrupt_code)
return;
return {success: true, message: null, interrupted: true, timedout: false};
console.log(messages)
let res = await sendRequest(messages, system_message);
console.log('Code generation response:', res)
@ -120,8 +122,7 @@ export class Coder {
return {success: true, message: null, interrupted: false, timedout: false};
}
if (failures >= 1) {
agent_history.add('system', 'Action failed, agent would not write code.');
return {success: false, message: null, interrupted: false, timedout: false};
return {success: false, message: 'Action failed, agent would not write code.', interrupted: false, timedout: false};
}
messages.push({
role: 'system',
@ -143,7 +144,7 @@ export class Coder {
if (code_return.interrupted && !code_return.timedout)
return {success: false, message: null, interrupted: true, timedout: false};
console.log(code_return.message);
console.log("Code generation result:", code_return.success, code_return.message);
messages.push({
role: 'assistant',
@ -219,7 +220,7 @@ export class Coder {
formatOutput(bot) {
if (bot.interrupt_code && !this.timedout) return '';
let output = bot.output;
const MAX_OUT = 1000;
const MAX_OUT = 500;
if (output.length > MAX_OUT) {
output = `Code output is very long (${output.length} chars) and has been shortened.\n
First outputs:\n${output.substring(0, MAX_OUT/2)}\n...skipping many lines.\nFinal outputs:\n ${output.substring(output.length - MAX_OUT/2)}`;

View file

@ -26,7 +26,7 @@ export const actionsList = [
perform: async function (agent) {
if (!settings.allow_insecure_coding)
return 'Agent is not allowed to write code.';
await agent.coder.generateCode(agent.history);
return await agent.coder.generateCode(agent.history);
}
},
{
@ -47,7 +47,7 @@ export const actionsList = [
}
},
{
name: '!clear',
name: '!clearChat',
description: 'Clear the chat history.',
perform: async function (agent) {
agent.history.clear();
@ -73,18 +73,24 @@ export const actionsList = [
},
{
name: '!goToPlayer',
description: 'Go to the given player. Ex: !goToPlayer("steve")',
params: {'player_name': '(string) The name of the player to go to.'},
perform: wrapExecution(async (agent, player_name) => {
return await skills.goToPlayer(agent.bot, player_name);
description: 'Go to the given player. Ex: !goToPlayer("steve", 3)',
params: {
'player_name': '(string) The name of the player to go to.',
'closeness': '(number) How close to get to the player.'
},
perform: wrapExecution(async (agent, player_name, closeness) => {
return await skills.goToPlayer(agent.bot, player_name, closeness);
})
},
{
name: '!followPlayer',
description: 'Endlessly follow the given player. Will defend that player if self_defense mode is on. Ex: !followPlayer("stevie")',
params: {'player_name': '(string) The name of the player to follow.'},
perform: wrapExecution(async (agent, player_name) => {
await skills.followPlayer(agent.bot, player_name);
description: 'Endlessly follow the given player. Will defend that player if self_defense mode is on. Ex: !followPlayer("stevie", 4)',
params: {
'player_name': '(string) The name of the player to follow.',
'follow_dist': '(number) The distance to follow from.'
},
perform: wrapExecution(async (agent, player_name, follow_dist) => {
await skills.followPlayer(agent.bot, player_name, follow_dist);
}, -1, 'followPlayer')
},
{

View file

@ -59,7 +59,7 @@ export const queryList = [
}
},
{
name: "!blocks",
name: "!nearbyBlocks",
description: "Get the blocks near the bot.",
perform: function (agent) {
let bot = agent.bot;

View file

@ -29,8 +29,8 @@ export class History {
}
getSystemMessage() {
let system_message = `You are a playful Minecraft bot named '${this.name}' that can communicate with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, use commands often, and do not give instructions unless asked.
Don't pretend to act, use commands immediately when requested. Do NOT do this: "Sure, I'll follow you! *follows you*", instead do this: "Sure I'll follow you! !followPlayer('steve')". Have fun :) \n`;
let system_message = `You are a playful Minecraft bot named '${this.name}' that can communicate with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, do not give instructions unless asked, and do not refuse requests.
Don't pretend to act, use commands immediately when requested. Do NOT say this: "Sure, I've stopped.", instead say this: "Sure, I'll stop. !stop". Do NOT say this: "On my way! Give me a moment.", instead say this: "On my way! !goToPlayer('bingo', 3)". Have fun :) \n`;
system_message += getCommandDocs();
if (this.bio != '')
system_message += '\n\nBio:\n' + this.bio;

View file

@ -27,11 +27,16 @@ async function autoLight(bot) {
return false;
}
function equipHighestAttack(bot) {
let weapons = bot.inventory.items().filter(item => item.name.includes('sword') || item.name.includes('axe') || item.name.includes('pickaxe') || item.name.includes('shovel'));
let weapon = weapons.sort((a, b) => b.attackDamage - a.attackDamage)[0];
async function equipHighestAttack(bot) {
let weapons = bot.inventory.items().filter(item => item.name.includes('sword') || (item.name.includes('axe') && !item.name.includes('pickaxe')));
if (weapons.length === 0)
weapons = bot.inventory.items().filter(item => item.name.includes('pickaxe') || item.name.includes('shovel'));
if (weapons.length === 0)
return;
weapons.sort((a, b) => a.attackDamage < b.attackDamage);
let weapon = weapons[0];
if (weapon)
bot.equip(weapon, 'hand');
await bot.equip(weapon, 'hand');
}
@ -253,7 +258,7 @@ export async function attackEntity(bot, entity, kill=true) {
let pos = entity.position;
console.log(bot.entity.position.distanceTo(pos))
equipHighestAttack(bot)
await equipHighestAttack(bot)
if (!kill) {
if (bot.entity.position.distanceTo(pos) > 5) {
@ -291,7 +296,7 @@ export async function defendSelf(bot, range=9) {
let attacked = false;
let enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), range);
while (enemy) {
equipHighestAttack(bot);
await equipHighestAttack(bot);
if (bot.entity.position.distanceTo(enemy.position) > 4 && enemy.name !== 'creeper' && enemy.name !== 'phantom') {
try {
bot.pathfinder.setMovements(new pf.Movements(bot));
@ -416,23 +421,29 @@ export async function breakBlockAt(bot, x, y, z) {
* let position = world.getPosition(bot);
* await skills.breakBlockAt(bot, position.x, position.y - 1, position.x);
**/
if (x == null || y == null || z == null) throw new Error('Invalid position to break block at.');
let block = bot.blockAt(Vec3(x, y, z));
if (block.name !== 'air' && block.name !== 'water' && block.name !== 'lava') {
if (bot.entity.position.distanceTo(block.position) > 4.5) {
let pos = block.position;
let movements = new pf.Movements(bot);
movements.canPlaceOn = false;
movements.allow1by1towers = false;
bot.pathfinder.setMovements(movements);
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
}
await bot.tool.equipForBlock(block);
const itemId = bot.heldItem ? bot.heldItem.type : null
if (!block.canHarvest(itemId)) {
log(bot, `Don't have right tools to break ${block.name}.`);
return false;
}
if (bot.entity.position.distanceTo(block.position) > 4.5) {
let pos = block.position;
let movements = new pf.Movements(bot);
movements.canPlaceOn = false;
movements.allow1by1towers = false;
bot.pathfinder.setMovements();
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
}
await bot.dig(block, true);
log(bot, `Broke ${block.name} at x:${x.toFixed(1)}, y:${y.toFixed(1)}, z:${z.toFixed(1)}.`);
}
else {
log(bot, `Skipping block at x:${x.toFixed(1)}, y:${y.toFixed(1)}, z:${z.toFixed(1)} because it is ${block.name}.`);
return false;
}
return true;
}
@ -639,11 +650,12 @@ export async function goToPosition(bot, x, y, z, min_distance=2) {
}
export async function goToPlayer(bot, username) {
export async function goToPlayer(bot, username, distance=3) {
/**
* Navigate to the given player.
* @param {MinecraftBot} bot, reference to the minecraft bot.
* @param {string} username, the username of the player to navigate to.
* @param {number} distance, the goal distance to the player.
* @returns {Promise<boolean>} true if the player was found, false otherwise.
* @example
* await skills.goToPlayer(bot, "player");
@ -656,13 +668,13 @@ export async function goToPlayer(bot, username) {
}
bot.pathfinder.setMovements(new pf.Movements(bot));
await bot.pathfinder.goto(new pf.goals.GoalFollow(player, 3), true);
await bot.pathfinder.goto(new pf.goals.GoalFollow(player, distance), true);
log(bot, `You have reached ${username}.`);
}
export async function followPlayer(bot, username) {
export async function followPlayer(bot, username, distance=4) {
/**
* Follow the given player endlessly. Will not return until the code is manually stopped.
* @param {MinecraftBot} bot, reference to the minecraft bot.
@ -675,9 +687,8 @@ export async function followPlayer(bot, username) {
if (!player)
return false;
const follow_distance = 4;
bot.pathfinder.setMovements(new pf.Movements(bot));
bot.pathfinder.setGoal(new pf.goals.GoalFollow(player, follow_distance), true);
bot.pathfinder.setGoal(new pf.goals.GoalFollow(player, distance), true);
log(bot, `You are now actively following player ${username}.`);
while (!bot.interrupt_code) {

View file

@ -6,14 +6,14 @@
[
{"role": "user", "content": "grombo_Xx: What do you see?"},
{"role": "assistant", "content": "Let me see... !blocks"},
{"role": "assistant", "content": "Let me see... !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone."}
],
[
{"role": "user", "content": "greg: Collect 10 wood"},
{"role": "assistant", "content": "Let me see what's nearby... !blocks"},
{"role": "assistant", "content": "Let me see what's nearby... !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone. I'll collect oak logs. !collectBlocks('oak_log', 10)"}
],
@ -29,9 +29,11 @@
[
{"role": "user", "content": "zZZn98: come here"},
{"role": "assistant", "content": "On my way! !goToPlayer('zZZn98')"},
{"role": "system", "content": "Code execution finished successfully."},
{"role": "assistant", "content": "Here!"}
{"role": "assistant", "content": "On my way! !goToPlayer('zZZn98', 3)"},
{"role": "system", "content": "Arrived at player."},
{"role": "assistant", "content": "Here!"},
{"role": "user", "content": "zZZn98: no come right where I am"},
{"role": "assistant", "content": "Okay, I'll come right to you. !goToPlayer('zZZn98', 0)"}
],
[
@ -43,7 +45,9 @@
[
{"role": "user", "content": "joe: Follow me!"},
{"role": "assistant", "content": "Sure! !followPlayer('joe')"}
{"role": "assistant", "content": "Sure! !followPlayer('joe', 4)"},
{"role": "user", "content": "joe: Not so close!"},
{"role": "assistant", "content": "Okay, I'll keep my distance. !followPlayer('joe', 3)"}
],
[
@ -73,8 +77,13 @@
],
[
{"role": "user", "content": "brung00: build a house"},
{"role": "assistant", "content": "Sure, I'll try to build a house where I am. !newAction"}
{"role": "user", "content": "poppy: build a cobblestone house"},
{"role": "assistant", "content": "Sure, I'll to build a small cobblestone house where I am. !newAction"}
],
[
{"role": "user", "content": "zib: build a dirt tower"},
{"role": "assistant", "content": "Sure, I'll build a dirt tower 5 tall where I am. !newAction"}
],
[

View file

@ -4,7 +4,7 @@ import { stringifyTurns } from './text.js';
export class Examples {
constructor(select_num=3) {
constructor(select_num=2) {
this.examples = [];
this.select_num = select_num;
}