Merge pull request #407 from kolbytn/lil-changes

Lil changes
This commit is contained in:
Max Robinson 2025-01-10 12:43:49 -06:00 committed by GitHub
commit a95fa33266
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 51 additions and 17 deletions

View file

@ -17,6 +17,14 @@
}, },
"type": "debug" "type": "debug"
}, },
"debug_inventory_restriction": {
"goal": "Place 1 oak plank, then place 1 stone brick",
"initial_inventory": {
"oak_planks": 20
},
"type": "debug",
"restrict_to_inventory": true
},
"construction": { "construction": {
"type": "construction", "type": "construction",
"goal": "Build a house", "goal": "Build a house",

View file

@ -35,7 +35,8 @@ export default
"code_timeout_mins": 10, // minutes code is allowed to run. -1 for no timeout "code_timeout_mins": 10, // minutes code is allowed to run. -1 for no timeout
"max_messages": 15, // max number of messages to keep in context "max_messages": 15, // max number of messages to keep in context
"max_commands": -1, // max number of commands to use in a response. -1 for no limit "num_examples": 2, // number of examples to give to the model
"max_commands": -1, // max number of commands that can be used in consecutive responses. -1 for no limit
"verbose_commands": true, // show full command syntax "verbose_commands": true, // show full command syntax
"narrate_behavior": true, // chat simple automatic actions ('Picking up item!') "narrate_behavior": true, // chat simple automatic actions ('Picking up item!')
"chat_bot_messages": true, // publicly chat messages to other bots "chat_bot_messages": true, // publicly chat messages to other bots

View file

@ -3,7 +3,7 @@ import { Coder } from './coder.js';
import { Prompter } from './prompter.js'; import { Prompter } from './prompter.js';
import { initModes } from './modes.js'; import { initModes } from './modes.js';
import { initBot } from '../utils/mcdata.js'; import { initBot } from '../utils/mcdata.js';
import { containsCommand, commandExists, executeCommand, truncCommandMessage, isAction } from './commands/index.js'; import { containsCommand, commandExists, executeCommand, truncCommandMessage, isAction, blacklistCommands } from './commands/index.js';
import { ActionManager } from './action_manager.js'; import { ActionManager } from './action_manager.js';
import { NPCContoller } from './npc/controller.js'; import { NPCContoller } from './npc/controller.js';
import { MemoryBank } from './memory_bank.js'; import { MemoryBank } from './memory_bank.js';
@ -47,7 +47,8 @@ export class Agent {
await this.prompter.initExamples(); await this.prompter.initExamples();
console.log('Initializing task...'); console.log('Initializing task...');
this.task = new Task(this, task_path, task_id); this.task = new Task(this, task_path, task_id);
this.blocked_actions = this.task.blocked_actions || []; const blocked_actions = this.task.blocked_actions || [];
blacklistCommands(blocked_actions);
serverProxy.connect(this); serverProxy.connect(this);

View file

@ -14,6 +14,18 @@ export function getCommand(name) {
return commandMap[name]; return commandMap[name];
} }
export function blacklistCommands(commands) {
const unblockable = ['!stop', '!stats', '!inventory', '!goal'];
for (let command_name of commands) {
if (unblockable.includes(command_name)){
console.warn(`Command ${command_name} is unblockable`);
continue;
}
delete commandMap[command_name];
delete commandList.find(command => command.name === command_name);
}
}
const commandRegex = /!(\w+)(?:\(((?:-?\d+(?:\.\d+)?|true|false|"[^"]*")(?:\s*,\s*(?:-?\d+(?:\.\d+)?|true|false|"[^"]*"))*)\))?/ const commandRegex = /!(\w+)(?:\(((?:-?\d+(?:\.\d+)?|true|false|"[^"]*")(?:\s*,\s*(?:-?\d+(?:\.\d+)?|true|false|"[^"]*"))*)\))?/
const argRegex = /-?\d+(?:\.\d+)?|true|false|"[^"]*"/g; const argRegex = /-?\d+(?:\.\d+)?|true|false|"[^"]*"/g;
@ -214,7 +226,7 @@ export async function executeCommand(agent, message) {
} }
} }
export function getCommandDocs(blacklist=null) { export function getCommandDocs() {
const typeTranslations = { const typeTranslations = {
//This was added to keep the prompt the same as before type checks were implemented. //This was added to keep the prompt the same as before type checks were implemented.
//If the language model is giving invalid inputs changing this might help. //If the language model is giving invalid inputs changing this might help.
@ -228,9 +240,6 @@ export function getCommandDocs(blacklist=null) {
Use the commands with the syntax: !commandName or !commandName("arg1", 1.2, ...) if the command takes arguments.\n Use the commands with the syntax: !commandName or !commandName("arg1", 1.2, ...) if the command takes arguments.\n
Do not use codeblocks. Use double quotes for strings. Only use one command in each response, trailing commands and comments will be ignored.\n`; Do not use codeblocks. Use double quotes for strings. Only use one command in each response, trailing commands and comments will be ignored.\n`;
for (let command of commandList) { for (let command of commandList) {
if (blacklist && blacklist.includes(command.name)) {
continue;
}
docs += command.name + ': ' + command.description + '\n'; docs += command.name + ': ' + command.description + '\n';
if (command.params) { if (command.params) {
docs += 'Params:\n'; docs += 'Params:\n';

View file

@ -1,5 +1,6 @@
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 { getCommandDocs } from './index.js';
import convoManager from '../conversation.js'; import convoManager from '../conversation.js';
const pad = (str) => { const pad = (str) => {
@ -181,12 +182,7 @@ export const queryList = [
name: '!help', name: '!help',
description: 'Lists all available commands and their descriptions.', description: 'Lists all available commands and their descriptions.',
perform: async function (agent) { perform: async function (agent) {
const commandList = actionsList.map(action => { return getCommandDocs();
return `${action.name.padEnd(15)} - ${action.description}`; // Ensure consistent spacing
}).join('\n');
console.log(commandList);
return `Available Commands:\n${commandList}`;
} }
}, },
]; ];

View file

@ -558,6 +558,14 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont
const target_dest = new Vec3(Math.floor(x), Math.floor(y), Math.floor(z)); const target_dest = new Vec3(Math.floor(x), Math.floor(y), Math.floor(z));
if (bot.modes.isOn('cheat') && !dontCheat) { if (bot.modes.isOn('cheat') && !dontCheat) {
if (bot.restrict_to_inventory) {
let block = bot.inventory.items().find(item => item.name === blockType);
if (!block) {
log(bot, `Cannot place ${blockType}, you are restricted to your current inventory.`);
return false;
}
}
// invert the facing direction // invert the facing direction
let face = placeOn === 'north' ? 'south' : placeOn === 'south' ? 'north' : placeOn === 'east' ? 'west' : 'east'; let face = placeOn === 'north' ? 'south' : placeOn === 'south' ? 'north' : placeOn === 'east' ? 'west' : 'east';
if (blockType.includes('torch') && placeOn !== 'bottom') { if (blockType.includes('torch') && placeOn !== 'bottom') {
@ -599,7 +607,7 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont
if (item_name == "redstone_wire") if (item_name == "redstone_wire")
item_name = "redstone"; item_name = "redstone";
let block = bot.inventory.items().find(item => item.name === item_name); let block = bot.inventory.items().find(item => item.name === item_name);
if (!block && bot.game.gameMode === 'creative') { if (!block && bot.game.gameMode === 'creative' && !bot.restrict_to_inventory) {
await bot.creative.setInventorySlot(36, mc.makeItem(item_name, 1)); // 36 is first hotbar slot await bot.creative.setInventorySlot(36, mc.makeItem(item_name, 1)); // 36 is first hotbar slot
block = bot.inventory.items().find(item => item.name === item_name); block = bot.inventory.items().find(item => item.name === item_name);
} }

View file

@ -404,6 +404,9 @@ export function initModes(agent) {
_agent = agent; _agent = agent;
// the mode controller is added to the bot object so it is accessible from anywhere the bot is used // the mode controller is added to the bot object so it is accessible from anywhere the bot is used
agent.bot.modes = new ModeController(); agent.bot.modes = new ModeController();
if (agent.task) {
agent.bot.restrict_to_inventory = agent.task.restrict_to_inventory;
}
let modes_json = agent.prompter.getInitModes(); let modes_json = agent.prompter.getInitModes();
if (modes_json) { if (modes_json) {
agent.bot.modes.loadJson(modes_json); agent.bot.modes.loadJson(modes_json);

View file

@ -4,6 +4,7 @@ import { getCommandDocs } from './commands/index.js';
import { getSkillDocs } from './library/index.js'; import { getSkillDocs } from './library/index.js';
import { stringifyTurns } from '../utils/text.js'; import { stringifyTurns } from '../utils/text.js';
import { getCommand } from './commands/index.js'; import { getCommand } from './commands/index.js';
import settings from '../../settings.js';
import { Gemini } from '../models/gemini.js'; import { Gemini } from '../models/gemini.js';
import { GPT } from '../models/gpt.js'; import { GPT } from '../models/gpt.js';
@ -155,8 +156,8 @@ export class Prompter {
async initExamples() { async initExamples() {
try { try {
this.convo_examples = new Examples(this.embedding_model); this.convo_examples = new Examples(this.embedding_model, settings.num_examples);
this.coding_examples = new Examples(this.embedding_model); this.coding_examples = new Examples(this.embedding_model, settings.num_examples);
// Wait for both examples to load before proceeding // Wait for both examples to load before proceeding
await Promise.all([ await Promise.all([
@ -186,7 +187,7 @@ export class Prompter {
prompt = prompt.replaceAll('$ACTION', this.agent.actions.currentActionLabel); prompt = prompt.replaceAll('$ACTION', this.agent.actions.currentActionLabel);
} }
if (prompt.includes('$COMMAND_DOCS')) if (prompt.includes('$COMMAND_DOCS'))
prompt = prompt.replaceAll('$COMMAND_DOCS', getCommandDocs(this.agent.blocked_actions)); prompt = prompt.replaceAll('$COMMAND_DOCS', getCommandDocs());
if (prompt.includes('$CODE_DOCS')) if (prompt.includes('$CODE_DOCS'))
prompt = prompt.replaceAll('$CODE_DOCS', getSkillDocs()); prompt = prompt.replaceAll('$CODE_DOCS', getSkillDocs());
if (prompt.includes('$EXAMPLES') && examples !== null) if (prompt.includes('$EXAMPLES') && examples !== null)

View file

@ -51,6 +51,7 @@ export class Task {
this.taskStartTime = Date.now(); this.taskStartTime = Date.now();
this.validator = new TaskValidator(this.data, this.agent); this.validator = new TaskValidator(this.data, this.agent);
this.blocked_actions = this.data.blocked_actions || []; this.blocked_actions = this.data.blocked_actions || [];
this.restrict_to_inventory = !!this.data.restrict_to_inventory;
if (this.data.goal) if (this.data.goal)
this.blocked_actions.push('!endGoal'); this.blocked_actions.push('!endGoal');
if (this.data.conversation) if (this.data.conversation)

View file

@ -33,6 +33,9 @@ export class Examples {
this.examples = examples; this.examples = examples;
if (!this.model) return; // Early return if no embedding model if (!this.model) return; // Early return if no embedding model
if (this.select_num === 0)
return;
try { try {
// Create array of promises first // Create array of promises first
const embeddingPromises = examples.map(example => { const embeddingPromises = examples.map(example => {
@ -52,6 +55,9 @@ export class Examples {
} }
async getRelevant(turns) { async getRelevant(turns) {
if (this.select_num === 0)
return [];
let turn_text = this.turnsToText(turns); let turn_text = this.turnsToText(turns);
if (this.model !== null) { if (this.model !== null) {
let embedding = await this.model.embed(turn_text); let embedding = await this.model.embed(turn_text);