diff --git a/example_tasks.json b/example_tasks.json index 6d33a6f..28b9e36 100644 --- a/example_tasks.json +++ b/example_tasks.json @@ -58,7 +58,7 @@ "blueprint": { "materials": { "plank": { - "id": "oak_plank", + "id": "oak_planks", "number": 40 }, "door": { @@ -72,10 +72,10 @@ "coordinates": [142, -60, -179], "placement": [ - ["plank", "plank", "door", "plank", "plank"], - ["plank", "air", "air", "air", "plank"], - ["plank", "air", "air", "air", "plank"], - ["plank", "plank", "plank", "plank", "plank"] + ["oak_planks", "oak_planks", "oak_door", "oak_planks", "oak_planks"], + ["oak_planks", "air", "air", "air", "oak_planks"], + ["oak_planks", "air", "air", "air", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"] ] }, { @@ -83,10 +83,10 @@ "coordinates": [142, -59, -179], "placement": [ - ["plank", "plank", "air", "plank", "plank"], - ["plank", "air", "air", "air", "plank"], - ["plank", "air", "air", "air", "plank"], - ["plank", "plank", "plank", "plank", "plank"] + ["oak_planks", "oak_planks", "oak_door", "oak_planks", "oak_planks"], + ["oak_planks", "air", "air", "air", "oak_planks"], + ["oak_planks", "air", "air", "air", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"] ] }, { @@ -94,10 +94,10 @@ "coordinates": [142, -58, -179], "placement": [ - ["plank", "plank", "plank", "plank", "plank"], - ["plank", "plank", "plank", "plank", "plank"], - ["plank", "plank", "plank", "plank", "plank"], - ["plank", "plank", "plank", "plank", "plank"] + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"] ] } ] @@ -129,7 +129,7 @@ "coordinates": [142, -60, -179], "placement": [ - ["stone", "stone", "door", "stone", "stone"], + ["stone", "stone", "oak_door", "stone", "stone"], ["stone", "air", "air", "air", "stone"], ["stone", "air", "air", "air", "stone"], ["stone", "stone", "stone", "stone", "stone"] @@ -140,7 +140,7 @@ "coordinates": [142, -59, -179], "placement": [ - ["stone", "stone", "air", "stone", "stone"], + ["stone", "stone", "oak_door", "stone", "stone"], ["stone", "air", "air", "air", "stone"], ["stone", "air", "air", "air", "stone"], ["stone", "stone", "stone", "stone", "stone"] @@ -151,10 +151,10 @@ "coordinates": [142, -58, -179], "placement": [ - ["plank", "plank", "plank", "plank", "plank"], - ["plank", "plank", "plank", "plank", "plank"], - ["plank", "plank", "plank", "plank", "plank"], - ["plank", "plank", "plank", "plank", "plank"] + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"] ] } ] diff --git a/settings.js b/settings.js index a9cc87e..d28e03d 100644 --- a/settings.js +++ b/settings.js @@ -12,7 +12,7 @@ export default "profiles": [ "./andy.json", - "./jill.json", + // "./jill.json", // "./profiles/gpt.json", // "./profiles/claude.json", // "./profiles/gemini.json", diff --git a/src/agent/commands/actions.js b/src/agent/commands/actions.js index bce7af9..b684b77 100644 --- a/src/agent/commands/actions.js +++ b/src/agent/commands/actions.js @@ -1,7 +1,7 @@ import * as skills from '../library/skills.js'; import settings from '../../../settings.js'; import convoManager from '../conversation.js'; -import { checkLevelBlueprint, checkBlueprint } from '../tasks.js'; + function runAsAction (actionFn, resume = false, timeout = -1) { let actionLabel = null; // Will be set on first use @@ -412,32 +412,15 @@ export const actionsList = [ { name: '!checkLevelComplete', description: 'Check if the level is complete and what blocks still need to be placed for the blueprint', + params: { + 'levelNum': { type: 'int', description: 'The level number to check.', domain: [0, Number.MAX_SAFE_INTEGER] } + }, perform: runAsAction(async (agent, levelNum) => { - return await checkLevelBlueprint(agent, levelNum); - //todo: if not complete, explain what still needs to be done + const result = await checkLevelBlueprint(agent, levelNum); + console.log(result); + return result; }) }, - { - name: '!checkBlueprint', - description: 'Check what blocks still need to be placed for the blueprint', - perform: runAsAction(async (agent) => { - return await checkBlueprint(agent); - }) - }, - { - name: '!getBlueprint', - description: 'Get the blueprint for the building', - perform: runAsAction(async (agent) => { - return await agent.task.blueprint.explain(); - }) - }, - { - name: '!getBlueprintLevel', - description: 'Get the blueprint for the building', - perform: runAsAction(async (agent, levelNum) => { - return await agent.task.blueprint.explainLevel(levelNum); - }) - } // { // commented for now, causes confusion with goal command // name: '!npcGoal', // description: 'Set a simple goal for an item or building to automatically work towards. Do not use for complex goals.', diff --git a/src/agent/commands/queries.js b/src/agent/commands/queries.js index 3419d0f..0219d90 100644 --- a/src/agent/commands/queries.js +++ b/src/agent/commands/queries.js @@ -1,6 +1,7 @@ import * as world from '../library/world.js'; import * as mc from '../../utils/mcdata.js'; import convoManager from '../conversation.js'; +import { checkLevelBlueprint, checkBlueprint } from '../tasks.js'; const pad = (str) => { return '\n' + str + '\n'; @@ -167,5 +168,45 @@ export const queryList = [ perform: async function (agent) { return "Saved place names: " + agent.memory_bank.getKeys(); } + }, + { + name: '!checkLevelComplete', + description: 'Check if the level is complete and what blocks still need to be placed for the blueprint', + params: { + 'levelNum': { type: 'int', description: 'The level number to check.', domain: [0, Number.MAX_SAFE_INTEGER] } + }, + perform: function (agent, levelNum) { + let res = checkLevelBlueprint(agent, levelNum); + console.log(res); + return pad(res); + } + }, + { + name: '!checkBlueprint', + description: 'Check what blocks still need to be placed for the blueprint', + perform: function (agent) { + let res = checkBlueprint(agent); + return pad(res); + } + }, + { + name: '!getBlueprint', + description: 'Get the blueprint for the building', + perform: function (agent) { + let res = agent.task.blueprint.explain(); + return pad(res); + } + }, + { + name: '!getBlueprintLevel', + description: 'Get the blueprint for the building', + params: { + 'levelNum': { type: 'int', description: 'The level number to check.', domain: [0, Number.MAX_SAFE_INTEGER] } + }, + perform: function (agent, levelNum) { + let res = agent.task.blueprint.explainLevel(levelNum); + console.log(res); + return pad(res); + } } ]; diff --git a/src/agent/tasks.js b/src/agent/tasks.js index 0ab51bf..392965e 100644 --- a/src/agent/tasks.js +++ b/src/agent/tasks.js @@ -4,6 +4,8 @@ import { getPosition } from './library/world.js' import settings from '../../settings.js'; import { Vec3 } from 'vec3'; +//todo: modify validator code to return an object with valid and score -> do more testing hahah +//todo: figure out how to log these things to the same place as bots/histories export class CraftTaskValidator { constructor(data, agent) { this.target = data.target; @@ -44,9 +46,10 @@ export class ConstructionTaskValidator { validate() { try { //todo: somehow make this more of a percentage or something + console.log('Validating task...'); let valid = false; let score = 0; - this.blueprint.checkBluepint(this.agent.bot).then((result) => { + this.blueprint.check(this.agent.bot).then((result) => { if (result.mismatches.length === 0) { valid = true; console.log('Task is complete'); @@ -63,17 +66,30 @@ export class ConstructionTaskValidator { } } -export async function checkLevelBlueprint(agent, levelNum) { - const blueprint = agent.task.blueprint.data; +export function checkLevelBlueprint(agent, levelNum) { + const blueprint = agent.task.blueprint; const bot = agent.bot; - //todo: in addition to checking the level, explain the differences - return blueprint.checkLevel(bot, levelNum); + const result = blueprint.checkLevel(bot, levelNum); + if (result.mismatches.length === 0) { + return `Level ${levelNum} is correct`; + } else { + let explanation = blueprint.explainLevelDifference(bot, levelNum); + return explanation; + } } -export async function checkBlueprint(agent) { - const blueprint = agent.task.blueprint.data; +export function checkBlueprint(agent) { + console.log('Checking blueprint...'); + console.log(agent); + const blueprint = agent.task.blueprint; const bot = agent.bot; - return blueprint.check(bot); + const result = blueprint.check(bot); + if (result.mismatches.length === 0) { + return "Blueprint is correct"; + } else { + let explanation = blueprint.explainBlueprintDifference(bot); + return explanation; + } } export class Blueprint { constructor(blueprint) { @@ -112,17 +128,17 @@ export class Blueprint { explanation += `\n${placement_string}\n`; return explanation; } - async explainBlueprintDifference(bot) { + explainBlueprintDifference(bot) { var explanation = ""; const levels = this.data.levels; for (let i = 0; i < levels.length; i++) { - let level_explanation = await this.explainLevelDifference(bot, i); + let level_explanation = this.explainLevelDifference(bot, i); explanation += level_explanation + "\n"; } return explanation; } - async explainLevelDifference(bot, levelNum) { - const results = await this.checkLevel(bot, levelNum); + explainLevelDifference(bot, levelNum) { + const results = this.checkLevel(bot, levelNum); const mismatches = results.mismatches; const levelData = this.data.levels[levelNum]; @@ -138,12 +154,12 @@ export class Blueprint { } return explanation; } - async check(bot) { + check(bot) { const levels = this.data.levels; const mismatches = []; const matches = []; for (let i = 0; i < levels.length; i++) { - const result = await this.checkLevel(bot, i); + const result = this.checkLevel(bot, i); mismatches.push(...result.mismatches); matches.push(...result.matches); } @@ -152,7 +168,7 @@ export class Blueprint { "matches": matches }; } - async checkLevel(bot, levelNum) { + checkLevel(bot, levelNum) { const levelData = this.data.levels[levelNum]; const startCoords = levelData.coordinates; const placement = levelData.placement; @@ -169,7 +185,7 @@ export class Blueprint { const z = startCoords[2] + zOffset; try { - const blockAtLocation = await bot.blockAt(new Vec3(x, y, z)); + const blockAtLocation = bot.blockAt(new Vec3(x, y, z)); if (!blockAtLocation || blockAtLocation.name !== blockName) { mismatches.push({ level: levelData.level, diff --git a/test/test_agent_check_blocks.js b/test/test_agent_check_blocks.js new file mode 100644 index 0000000..d085af9 --- /dev/null +++ b/test/test_agent_check_blocks.js @@ -0,0 +1,69 @@ +import mineflayer from 'mineflayer'; +import { Vec3 } from 'vec3'; +import { ConstructionTaskValidator, Blueprint, checkBlueprint, checkLevelBlueprint } from '../src/agent/tasks.js'; +import { Agent } from '../src/agent/agent.js'; + +try { + const agent = new Agent("../andy.json", + false, + null, + 0, + "../example_tasks.json", + "construction_house"); + await new Promise((resolve) => setTimeout(resolve, 10000)); + let result = await checkBlueprint(agent); + // console.log(result); + // const levelResult = await checkLevelBlueprint(agent, 0); + // console.log(levelResult); +} catch (error) { + console.error('An error occurred:', error); + process.exit(1); +} + + + + +// const validator = new ConstructionTaskValidator(); + +const blueprintData = { + "materials": { + "oak_planks": 20, + "oak_door": 1, + "stone": 26, + }, + "levels": [ + { + "level": 0, + "coordinates": [142, -60, -179], + "placement": + [ + ["stone", "stone", "oak_door", "stone", "stone"], + ["stone", "air", "air", "air", "stone"], + ["stone", "air", "air", "air", "stone"], + ["stone", "stone", "stone", "stone", "stone"] + ] + }, + { + "level": 1, + "coordinates": [142, -59, -179], + "placement": + [ + ["stone", "stone", "oak_door", "stone", "stone"], + ["stone", "air", "air", "air", "stone"], + ["stone", "air", "air", "air", "stone"], + ["stone", "stone", "stone", "stone", "stone"] + ] + }, + { + "level": 2, + "coordinates": [142, -58, -179], + "placement": + [ + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"], + ["oak_planks", "oak_planks", "oak_planks", "oak_planks", "oak_planks"] + ] + } + ] +}; \ No newline at end of file