This commit is contained in:
Ayush Maniar 2025-04-07 20:33:54 -07:00
commit c43dc879d2
11 changed files with 13285 additions and 137 deletions

View file

@ -53,16 +53,19 @@ def analyze_json_file(file_path):
try:
with open(file_path, 'r') as f:
data = json.load(f)
if 'turns' in data and isinstance(data['turns'], list):
for turn in reversed(data['turns']): # Check turns from the end
if turn.get('role') == 'system' and isinstance(turn.get('content'), str):
code = turn["content"].split(":")[-1].strip()
if code in ["2", "1"]: # Check for success codes
return True
elif 0 < float(code) < 1: # Check for other success indicators
return code
if "turns" in data:
for turn in data["turns"]:
if turn.get("role") == "system" and "content" in turn:
if isinstance(turn["content"], str) and "Task ended with score : " in turn["content"]:
score_found = True
if "Task ended with score : 1" in turn["content"]:
return 1
elif "Task ended with score : 0" in turn["content"]:
return 0
else:
return False
score = float(turn["content"].split(":")[-1].strip())
return score
return False
except FileNotFoundError:
print(f"Error: File not found: {file_path}")
@ -82,12 +85,12 @@ def extract_result(folder_path):
if not json_files:
return None
else:
outcome = False
score = None
for json_file in json_files:
outcome = analyze_json_file(json_file)
if outcome:
return True
return False
score = analyze_json_file(json_file)
if score is not None:
return score
return 0
def aggregate_results(local_folders):
"""
@ -110,7 +113,7 @@ def aggregate_results(local_folders):
result = extract_result(folder_path)
if result is not None:
total += 1
successful += float(result)
successful += result
except Exception as e:
print(f"Error processing {folder_name}: {e}")
@ -161,28 +164,6 @@ def update_keys_json():
with open("keys.json", 'w', encoding='utf-8') as file:
json.dump(data, file, indent=4)
def check_task_completion(agents):
"""Check memory.json files of all agents to determine task success/failure."""
for agent in agents:
memory_path = f"bots/{agent}/memory.json"
try:
with open(memory_path, 'r') as f:
memory = json.load(f)
# Check the last system message in turns
for turn in reversed(memory['turns']):
if turn['role'] == 'system' and 'code' in turn['content']:
# Extract completion code
if 'code : 2' in turn['content']:
return True # Task successful
elif 'code : 4' in turn['content']:
return False # Task failed
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"Error reading memory for agent {agent}: {e}")
continue
return False # Default to failure if no conclusive result found
def set_environment_variable_tmux_session(session_name, key, value):
"""Set an environment variable for the current process."""
subprocess.run(["tmux", "send-keys", "-t", session_name, f"export {key}={value}", "C-m"])
@ -202,7 +183,8 @@ def launch_parallel_experiments(task_path,
max_messages=15,
num_examples=2,
no_pruning=False,
block_conversation=False):
block_conversation=False,
run_in_tmux=True):
with open(task_path, 'r', encoding='utf-8') as file:
content = file.read()
@ -211,8 +193,6 @@ def launch_parallel_experiments(task_path,
task_ids = json_data.keys()
task_type = json_data[list(task_ids)[0]]["type"]
# split the task_ids into num_parallel groups
task_ids = list(task_ids)
task_ids_split = [task_ids[i::num_parallel] for i in range(num_parallel)]
@ -224,7 +204,10 @@ def launch_parallel_experiments(task_path,
elif task_type == "construction":
world_name = "Superflat"
if run_in_tmux:
servers = create_server_files("./server_data/", num_parallel, world_name=world_name)
else:
servers = [(f"./server_data_{i}/", 55916 + i) for i in range(num_parallel)]
date_time = datetime.now().strftime("%m-%d_%H-%M")
experiments_folder = f"experiments/{exp_name}_{date_time}"
exp_name = f"{exp_name}_{date_time}"
@ -259,7 +242,8 @@ def launch_parallel_experiments(task_path,
max_messages=max_messages,
num_examples=num_examples,
no_pruning=no_pruning,
block_conversation=block_conversation)
block_conversation=block_conversation,
run_in_tmux=run_in_tmux)
time.sleep(5)
total_num_tasks = len(task_ids)
@ -307,7 +291,8 @@ def launch_server_experiment(task_path,
max_messages=15,
num_examples=2,
no_pruning=False,
block_conversation=False):
block_conversation=False,
run_in_tmux=True):
"""
Launch a Minecraft server and run experiments on it.
@ -360,13 +345,13 @@ def launch_server_experiment(task_path,
agent_profiles_str += f'\"{agent}\", '
agent_profiles_str += f"\"{agent_profiles[-1]}\"]'"
print(agent_profiles_str)
if run_in_tmux:
print("run in tmux is true")
launch_world(server_path, session_name="server_" + session_name, agent_names=agent_names, port=server_port)
subprocess.run(['tmux', 'new-session', '-d', '-s', session_name], check=True)
# set environment variables
if run_in_tmux:
set_environment_variable_tmux_session(session_name, "MINECRAFT_PORT", server_port)
set_environment_variable_tmux_session(session_name, "MINDSERVER_PORT", mindserver_port)
set_environment_variable_tmux_session(session_name, "PROFILES", agent_profiles_str)
@ -376,23 +361,91 @@ def launch_server_experiment(task_path,
if insecure_coding:
set_environment_variable_tmux_session(session_name, "INSECURE_CODING", "true")
make_ops(agent_names, session_name)
else:
agent_profiles_str = "["
for agent in agent_profiles[:-1]:
agent_profiles_str += f"\"{agent}\", "
agent_profiles_str += f"\"{agent_profiles[-1]}\"]"
# print(agent_profiles_str)
os.environ["PROFILES"] = agent_profiles_str
os.environ["MAX_MESSAGES"] = str(max_messages)
os.environ["NUM_EXAMPLES"] = str(num_examples)
os.environ["LOG_ALL"] = "true"
run_script(task_path,
task_ids,
num_exp,
experiments_folder,
agent_names,
server_path,
s3=s3,
s3_path=s3_path,
session_name=session_name,
run_in_tmux=run_in_tmux)
# add the bots as op
# op_script_content = "sleep 5\n\op @p" * 20
# op_script_file = f"./tmp/op_script_{session_name}.sh"
# make_script_file_and_run(op_script_content, "server_" + session_name, op_script_file)
blocked_actions = []
if not no_pruning:
if task_type == "cooking":
blocked_actions = BLOCKED_ACTIONS_COOKING
elif task_type == "techtree":
blocked_actions = BLOCKED_ACTIONS_CRAFTING
elif task_type == "construction":
blocked_actions = BLOCKED_ACTIONS_CONSTRUCTION
if block_conversation:
blocked_actions += ["!endConversation", "!startConversation"]
set_environment_variable_tmux_session(session_name, "BLOCKED_ACTIONS", blocked_actions)
# blocked_actions = []
# if not no_pruning:
# if task_type == "cooking":
# blocked_actions = BLOCKED_ACTIONS_COOKING
# elif task_type == "techtree":
# blocked_actions = BLOCKED_ACTIONS_CRAFTING
# elif task_type == "construction":
# blocked_actions = BLOCKED_ACTIONS_CONSTRUCTION
# if block_conversation:
# blocked_actions += ["!endConversation", "!startConversation"]
# set_environment_variable_tmux_session(session_name, "BLOCKED_ACTIONS", blocked_actions)
# script_content = ""
# for task_id in task_ids:
# # Create a separate folder for each task_id
# task_folder = os.path.join(experiments_folder, str(task_id))
# os.makedirs(task_folder, exist_ok=True)
# assert os.path.exists(task_folder), f"Directory {task_folder} was not created"
# print(f"Created directory: {task_folder}")
# cmd = f"node main.js --task_path \'{task_path}\' --task_id {task_id}"
# cp_cmd = f"cp {agent_names[0]}.json {server_path}bots/{agent_names[0]}/profile.json"
# for _ in range(num_exp):
# script_content += f"{cmd}\n"
# script_content += "sleep 2\n"
# for agent in agent_names:
# agent_file_path = os.path.join(task_folder, f"{agent}_{_}.json")
# script_content += f"echo 'Saving to {agent_file_path}'\n"
# cp_cmd = f"cp bots/{agent}/memory.json {agent_file_path}"
# script_content += f"echo '{cp_cmd}'\n"
# script_content += f"{cp_cmd}\n"
# script_content += "sleep 1\n"
# if s3:
# s3_cmd = f"aws s3 cp {agent_file_path} s3://{s3_path}/{task_id}/{agent}_{_}.json"
# script_content += f"echo 'Uploading {agent_file_path} to S3'\n"
# script_content += f"echo '{s3_cmd}'\n"
# script_content += f"{s3_cmd}\n"
# script_content += "sleep 1\n"
# script_content += f"sleep 10\n"
# if s3:
# for agent in agent_names:
# script_content += f"aws s3 cp bots/{agent} s3://{s3_path}/bots/{agent} --recursive\n"
# # Create a temporary shell script file
# script_file = f"./tmp/experiment_script_{session_name}.sh"
# make_script_file_and_run(script_content, script_file, session_name=session_name, run_in_tmux=True)
def run_script(task_path,
task_ids,
num_exp,
experiments_folder,
agent_names,
server_path,
s3=False,
s3_path="mindcraft-experiments",
session_name="0",
run_in_tmux=True,):
script_content = ""
for task_id in task_ids:
# Create a separate folder for each task_id
@ -426,7 +479,8 @@ def launch_server_experiment(task_path,
# Create a temporary shell script file
script_file = f"./tmp/experiment_script_{session_name}.sh"
make_script_file_and_run(script_content, session_name, script_file)
make_script_file_and_run(script_content, script_file, session_name=session_name, run_in_tmux=run_in_tmux)
def make_ops(agent_names, session_name):
"""Make the agents operators in the Minecraft world."""
@ -458,7 +512,10 @@ def check_agent_ops(agent_names, ops_file="ops.json"):
return False
return True
def make_script_file_and_run(script_content, session_name, file_name):
def make_script_file_and_run(script_content,
file_name,
session_name="0",
run_in_tmux=True):
script_dir = os.path.dirname(file_name)
os.makedirs(script_dir, exist_ok=True)
assert os.path.exists(script_dir), f"Script directory {script_dir} was not created"
@ -472,9 +529,10 @@ def make_script_file_and_run(script_content, session_name, file_name):
script_file_run = "bash " + file_name
# Execute the shell script using subprocess
if run_in_tmux:
subprocess.run(["tmux", "send-keys", "-t", session_name, script_file_run, "C-m"])
# subprocess.run(["tmux", "send-keys", "-t", session_name, f"/op {agent_names[0]}", "C-m"])
else:
subprocess.run(script_file_run.split())
def make_profiles(agent_names, models, apis, template_profile="profiles/collab_profile.json", url="http://127.0.0.1:8000/v1"):
assert len(agent_names) == len(models)
@ -645,6 +703,7 @@ def main():
# edit_server_properties_file("../server_data/", 55917)
parser = argparse.ArgumentParser(description='Run Minecraft AI agent experiments')
parser.add_argument('--no_launch_world', action='store_true', help='Do not launch the Minecraft world')
parser.add_argument('--task_path', default="multiagent_crafting_tasks.json", help='Path to the task file')
parser.add_argument('--num_agents', default=2, type=int, help='Number of agents to run')
parser.add_argument('--num_exp', default=1, type=int, help='Number of experiments to run')
@ -666,13 +725,14 @@ def main():
args = parser.parse_args()
print(args)
if not args.no_launch_world:
try:
subprocess.run(['tmux', 'kill-server'], check=True)
except:
print("No tmux session to kill")
# delete all server files
if not args.no_launch_world:
clean_up_server_files(args.num_parallel)
if args.add_keys:
update_keys_json()
@ -692,7 +752,8 @@ def main():
max_messages=args.max_messages,
num_examples=args.num_examples,
no_pruning=args.no_pruning,
block_conversation=args.block_conversation)
block_conversation=args.block_conversation,
run_in_tmux=not args.no_launch_world)
if __name__ == "__main__":
main()

View file

@ -12,14 +12,12 @@ export class ConstructionTaskValidator {
let valid = false;
let score = 0;
let result = this.blueprint.check(this.agent.bot);
if (result.mismatches.length === 0) {
if (result.mismatches.y_amount === 0) {
valid = true;
console.log('Task is complete');
}
let total_blocks = result.mismatches.length + result.matches.length;
score = (result.matches.length / total_blocks) * 100;
console.log(`Agent name is ${this.agent.name}`);
console.log(`Task is ${score}% complete \n\n`);
let total_blocks = result.mismatches.y_amount + result.matches.y_amount;
score = (result.matches.y_amount / total_blocks) * 100;
return {
"valid": valid,
"score": score
@ -37,10 +35,10 @@ export class ConstructionTaskValidator {
export function resetConstructionWorld(bot, blueprint) {
console.log('Resetting world...');
const starting_position = blueprint.levels[0].coordinates;
const length = blueprint.levels[0].placement.length + 5;
const height = blueprint.levels.length + 5;
const width = blueprint.levels[0].placement[0].length + 5;
const command = `/fill ${starting_position[0]} ${starting_position[1]} ${starting_position[2]} ${starting_position[0] + width} ${starting_position[1] + height} ${starting_position[2] + length} air`;
const y_amount = blueprint.levels[0].placement.y_amount + 5;
const height = blueprint.levels.y_amount + 5;
const width = blueprint.levels[0].placement[0].y_amount + 5;
const command = `/fill ${starting_position[0]} ${starting_position[1]} ${starting_position[2]} ${starting_position[0] + width} ${starting_position[1] + height} ${starting_position[2] + y_amount} air`;
bot.chat(command);
console.log('World reset');
}
@ -50,7 +48,7 @@ export function checkLevelBlueprint(agent, levelNum) {
const bot = agent.bot;
try {
const result = blueprint.checkLevel(bot, levelNum);
if (result.mismatches.length === 0) {
if (result.mismatches.y_amount === 0) {
return `Level ${levelNum} is correct`;
} else {
let explanation = blueprint.explainLevelDifference(bot, levelNum);
@ -69,7 +67,7 @@ export function checkBlueprint(agent) {
const blueprint = agent.task.blueprint;
const bot = agent.bot;
const result = blueprint.check(bot);
if (result.mismatches.length === 0) {
if (result.mismatches.y_amount === 0) {
return "Blueprint is correct";
} else {
let explanation = blueprint.explainBlueprintDifference(bot);
@ -97,11 +95,11 @@ export class Blueprint {
var placement_string = "[\n";
for (let row of placement) {
placement_string += "[";
for (let i = 0; i < row.length - 1; i++) {
for (let i = 0; i < row.y_amount - 1; i++) {
let item = row[i];
placement_string += `${item}, `;
}
let final_item = row[row.length - 1];
let final_item = row[row.y_amount - 1];
placement_string += `${final_item}],\n`;
}
placement_string += "]";
@ -118,7 +116,7 @@ export class Blueprint {
explainBlueprintDifference(bot) {
var explanation = "";
const levels = this.data.levels;
for (let i = 0; i < levels.length; i++) {
for (let i = 0; i < levels.y_amount; i++) {
let level_explanation = this.explainLevelDifference(bot, i);
explanation += level_explanation + "\n";
}
@ -129,7 +127,7 @@ export class Blueprint {
const mismatches = results.mismatches;
const levelData = this.data.levels[levelNum];
if (mismatches.length === 0) {
if (mismatches.y_amount === 0) {
return `Level ${levelData.level} is complete`;
}
var explanation = `Level ${levelData.level} `;
@ -153,7 +151,7 @@ export class Blueprint {
const levels = this.data.levels;
const mismatches = [];
const matches = [];
for (let i = 0; i < levels.length; i++) {
for (let i = 0; i < levels.y_amount; i++) {
const result = this.checkLevel(bot, i);
mismatches.push(...result.mismatches);
matches.push(...result.matches);
@ -173,9 +171,9 @@ export class Blueprint {
const mismatches = [];
const matches = [];
for (let zOffset = 0; zOffset < placement.length; zOffset++) {
for (let zOffset = 0; zOffset < placement.y_amount; zOffset++) {
const row = placement[zOffset];
for (let xOffset = 0; xOffset < row.length; xOffset++) {
for (let xOffset = 0; xOffset < row.y_amount; xOffset++) {
const blockName = row[xOffset];
const x = startCoords[0] + xOffset;
@ -240,15 +238,15 @@ export class Blueprint {
// Update bounds
minX = Math.min(minX, baseX);
maxX = Math.max(maxX, baseX + placement[0].length - 1);
maxX = Math.max(maxX, baseX + placement[0].y_amount - 1);
minY = Math.min(minY, baseY);
maxY = Math.max(maxY, baseY);
minZ = Math.min(minZ, baseZ);
maxZ = Math.max(maxZ, baseZ + placement.length - 1);
maxZ = Math.max(maxZ, baseZ + placement.y_amount - 1);
// Loop through the 2D placement array
for (let z = 0; z < placement.length; z++) {
for (let x = 0; x < placement[z].length; x++) {
for (let z = 0; z < placement.y_amount; z++) {
for (let x = 0; x < placement[z].y_amount; x++) {
const blockType = placement[z][x];
if (blockType) {
const setblockCommand = `/setblock ${baseX + x} ${baseY} ${baseZ + z} ${blockType}`;
@ -289,15 +287,15 @@ export class Blueprint {
// Update bounds
minX = Math.min(minX, baseX) - 30;
maxX = Math.max(maxX, baseX + placement[0].length - 1) + 30;
maxX = Math.max(maxX, baseX + placement[0].y_amount - 1) + 30;
minY = Math.min(minY, baseY);
maxY = Math.max(maxY, baseY);
minZ = Math.min(minZ, baseZ) - 30;
maxZ = Math.max(maxZ, baseZ + placement.length - 1) + 30;
maxZ = Math.max(maxZ, baseZ + placement.y_amount - 1) + 30;
// Loop through the 2D placement array
for (let z = 0; z < placement.length; z++) {
for (let x = 0; x < placement[z].length; x++) {
for (let z = 0; z < placement.y_amount; z++) {
for (let x = 0; x < placement[z].y_amount; x++) {
const blockType = placement[z][x];
if (blockType) {
const setblockCommand = `/setblock ${baseX + x} ${baseY} ${baseZ + z} air`;
@ -350,8 +348,8 @@ export function proceduralGeneration(m = 20,
complexity = 4,
startCoord = [148,-60,-170]) {
// Build 3D space
const matrix = Array.from({length: p}, () =>
Array.from({length: m}, () =>
const matrix = Array.from({y_amount: p}, () =>
Array.from({y_amount: m}, () =>
Array(n).fill('air')
)
);
@ -359,7 +357,7 @@ export function proceduralGeneration(m = 20,
// todo: extrapolate into another param? then have set materials be dynamic?
let roomMaterials = ["stone", "terracotta", "quartz_block", "copper_block", "purpur_block"]
if (complexity < roomMaterials.length) {
if (complexity < roomMaterials.y_amount) {
roomMaterials = roomMaterials.slice(0, complexity + 1);
}
@ -510,9 +508,9 @@ export function proceduralGeneration(m = 20,
// Takes in a room and randomly converts some faces to be windows
function addWindowsAsSquares(matrix, x, y, z, newLength, newWidth, newDepth, material) {
// Matrix dimensions
const matrixDepth = matrix.length;
const matrixLength = matrix[0].length;
const matrixWidth = matrix[0][0].length;
const matrixDepth = matrix.y_amount;
const matrixLength = matrix[0].y_amount;
const matrixWidth = matrix[0][0].y_amount;
const windowX = Math.ceil(minRoomWidth / 2)
const windowY = Math.ceil(minRoomLength / 2)
const windowZ = Math.ceil(minRoomDepth / 2)
@ -593,9 +591,9 @@ export function proceduralGeneration(m = 20,
function addWindowsAsPlane(matrix, x, y, z, newLength, newWidth, newDepth, material) {
// Ensure the new dimensions are within bounds
const maxX = matrix[0].length;
const maxY = matrix[0][0].length;
const maxZ = matrix.length;
const maxX = matrix[0].y_amount;
const maxY = matrix[0][0].y_amount;
const maxZ = matrix.y_amount;
// Each face has a 30% chance of becoming a window
if (Math.random() < 0.8) {
@ -643,21 +641,21 @@ export function proceduralGeneration(m = 20,
//still a little buggy
function addStairs(matrix, x, y, z, length, width, material) {
function addStairs(matrix, x, y, z, y_amount, width, material) {
let currentZ = z;
let currentX = x + 1;
let currentY = y + 1;
let direction = 0;
let stepCount = 0;
const maxSteps = length * width; // Safety limit
const maxSteps = y_amount * width; // Safety limit
while (currentZ >= 0 && currentX < x + length - 1 && currentY < y + width - 1 && stepCount < maxSteps) {
while (currentZ >= 0 && currentX < x + y_amount - 1 && currentY < y + width - 1 && stepCount < maxSteps) {
// Place stair block
matrix[currentZ][currentX][currentY] = material || 'stone';
// Clear 3 blocks above for headroom
for (let i = 1; i <= 3; i++) {
if (currentZ + i < matrix.length) {
if (currentZ + i < matrix.y_amount) {
matrix[currentZ + i][currentX][currentY] = 'air';
}
}
@ -665,8 +663,8 @@ export function proceduralGeneration(m = 20,
// Move to next position based on direction
if (direction === 0) {
currentX++;
if (currentX >= x + length - 1) {
currentX = x + length - 2;
if (currentX >= x + y_amount - 1) {
currentX = x + y_amount - 2;
direction = 1;
} else {
currentZ--;
@ -700,7 +698,7 @@ export function proceduralGeneration(m = 20,
// Consider a random probability of adding a carpet
if (Math.random() < probability) {
// Choose a random color for the carpet
let randomColor = colors[Math.floor(Math.random() * colors.length)];
let randomColor = colors[Math.floor(Math.random() * colors.y_amount)];
// Add carpet one z position above the floor with a random color
matrix[z + 1][x][y] = `${randomColor}_carpet`;
}
@ -773,7 +771,7 @@ export function proceduralGeneration(m = 20,
for (let attempt = 0; attempt < 150; attempt++) {
const material = roomMaterials[Math.floor(Math.random() * roomMaterials.length)];
const material = roomMaterials[Math.floor(Math.random() * roomMaterials.y_amount)];
// dimensions of room
@ -790,7 +788,7 @@ export function proceduralGeneration(m = 20,
newZ = 0; // Ground floor
if (validateAndBuildBorder(matrix, newX, newY, newZ, newLength, newWidth, newDepth, m, n, p, material)) {
lastRoom = {x: newX, y: newY, z: newZ, length: newLength, width: newWidth, depth: newDepth};
lastRoom = {x: newX, y: newY, z: newZ, y_amount: newLength, width: newWidth, depth: newDepth};
roomPlaced = true;
placedRooms++;
@ -820,14 +818,14 @@ export function proceduralGeneration(m = 20,
embellishments(carpetStyle, windowStyle, matrix, newX, newY, newZ, newLength, newWidth, newDepth, material)
// addLadder(matrix, lastRoom.x + Math.floor(lastRoom.length / 2),
// addLadder(matrix, lastRoom.x + Math.floor(lastRoom.y_amount / 2),
// lastRoom.y + Math.floor(lastRoom.width / 2),
// newZ); // Adding the ladder
addStairs(matrix, newX, newY, newZ, newLength, newWidth, material)
lastRoom = {x: newX, y: newY, z: newZ, length: newLength, width: newWidth, depth: newDepth};
lastRoom = {x: newX, y: newY, z: newZ, y_amount: newLength, width: newWidth, depth: newDepth};
roomPlaced = true;
placedRooms++;
break;
@ -847,7 +845,7 @@ export function proceduralGeneration(m = 20,
addDoor(matrix, lastRoom.x, lastRoom.y + Math.floor(lastRoom.width / 2), lastRoom.z, material);
lastRoom = {x: newX, y: newY, z: newZ, length: newLength, width: newWidth, depth: newDepth};
lastRoom = {x: newX, y: newY, z: newZ, y_amount: newLength, width: newWidth, depth: newDepth};
roomPlaced = true;
placedRooms++;
break;
@ -855,7 +853,7 @@ export function proceduralGeneration(m = 20,
break;
case 'right':
newX = lastRoom.x + lastRoom.length - 1;
newX = lastRoom.x + lastRoom.y_amount - 1;
newY = lastRoom.y;
newZ = lastRoom.z;
if (validateAndBuildBorder(matrix, newX, newY, newZ, newLength, newWidth, newDepth, m, n, p, material)) {
@ -863,12 +861,12 @@ export function proceduralGeneration(m = 20,
embellishments(carpetStyle, windowStyle, matrix, newX, newY, newZ, newLength, newWidth, newDepth, material)
addDoor(matrix, lastRoom.x + lastRoom.length - 1,
addDoor(matrix, lastRoom.x + lastRoom.y_amount - 1,
lastRoom.y + Math.floor(lastRoom.width / 2),
lastRoom.z, material);
lastRoom = {x: newX, y: newY, z: newZ, length: newLength, width: newWidth, depth: newDepth};
lastRoom = {x: newX, y: newY, z: newZ, y_amount: newLength, width: newWidth, depth: newDepth};
roomPlaced = true;
placedRooms++;
break;
@ -884,12 +882,12 @@ export function proceduralGeneration(m = 20,
embellishments(carpetStyle, windowStyle, matrix, newX, newY, newZ, newLength, newWidth, newDepth, material)
addDoor(matrix, lastRoom.x + Math.floor(lastRoom.length / 2),
addDoor(matrix, lastRoom.x + Math.floor(lastRoom.y_amount / 2),
lastRoom.y + lastRoom.width - 1,
lastRoom.z, material);
lastRoom = {x: newX, y: newY, z: newZ, length: newLength, width: newWidth, depth: newDepth};
lastRoom = {x: newX, y: newY, z: newZ, y_amount: newLength, width: newWidth, depth: newDepth};
roomPlaced = true;
placedRooms++;
break;
@ -905,12 +903,12 @@ export function proceduralGeneration(m = 20,
embellishments(carpetStyle, windowStyle, matrix, newX, newY, newZ, newLength, newWidth, newDepth, material)
addDoor(matrix, lastRoom.x + Math.floor(lastRoom.length / 2),
addDoor(matrix, lastRoom.x + Math.floor(lastRoom.y_amount / 2),
lastRoom.y,
lastRoom.z, material);
lastRoom = {x: newX, y: newY, z: newZ, length: newLength, width: newWidth, depth: newDepth};
lastRoom = {x: newX, y: newY, z: newZ, y_amount: newLength, width: newWidth, depth: newDepth};
roomPlaced = true;
placedRooms++;
break;
@ -978,7 +976,7 @@ function printMatrix(matrix) {
*/
function matrixToBlueprint(matrix, startCoord) {
// Validate inputs
if (!Array.isArray(matrix) || !Array.isArray(startCoord) || startCoord.length !== 3) {
if (!Array.isArray(matrix) || !Array.isArray(startCoord) || startCoord.y_amount !== 3) {
console.log(matrix)
throw new Error('Invalid input format');
}
@ -1003,6 +1001,85 @@ function matrixToBlueprint(matrix, startCoord) {
};
}
async function getBlockName(bot, coordinate) {
const blockAtLocation = bot.blockAt(new Vec3(coordinate.x, coordinate.y, coordinate.z));
const blockName = blockAtLocation ? bot.registry.blocks[blockAtLocation.type].name : "air";
return blockName;
}
/**
* Converts a world location to a blueprint. takes some time to ensure that the chunks are loaded before conversion.
* @param startCoord - [x,y,z] that signifies the start of the blueprint
* @param y_amount - how many spaces you want to register from the start coordinate in the y dimension
* @param x_amount - how many spaces in the x direction on minecraft
* @param z_amount - how many spaces from the start coordinate in the z direction in minecraft
* @param bot - the mineflayer agent (ex. andy)
* @returns - a Blueprint object of the converted blueprint
*/
export async function worldToBlueprint(startCoord, y_amount, x_amount, z_amount, bot) {
await bot.waitForChunksToLoad();
const materials = {};
const levels = [];
for (let y = 0; y < y_amount; y++) {
const placement = [];
const coordinates = [startCoord.x, startCoord.y + y, startCoord.z];
for (let z = 0; z < z_amount; z++) {
const row = [];
for (let x = 0; x < x_amount; x++) {
const worldCoord = {
x: startCoord.x + x,
y: startCoord.y + y,
z: startCoord.z + z
};
await bot.waitForChunksToLoad(worldCoord);
const blockName = await getBlockName(bot, worldCoord);
row.push(blockName);
if (blockName !== 'air') {
materials[blockName] = (materials[blockName] || 0) + 1;
}
}
placement.push(row);
}
levels.push({
level: y,
coordinates: coordinates,
placement: placement
})
}
console.log(levels);
const blueprint_data = {
materials: materials,
levels: levels
}
return blueprint_data
}
export function blueprintToTask(blueprint_data, num_agents) {
let initialInventory = {}
for (let j = 0; j < num_agents; j++) {
initialInventory[JSON.stringify(j)] = {};
}
let give_agent = 0;
for (const key of Object.keys(blueprint_data.materials)) {
initialInventory[JSON.stringify(give_agent)][key] = blueprint_data.materials[key];
give_agent = (give_agent + 1) % num_agents;
}
const task = {
type: "construction",
goal: "Make a structure with the blueprint below",
conversation: "Let's share materials and make a structure with the blueprint",
agent_count: 2,
blueprint: blueprint_data,
initial_inventory: initialInventory,
};
return task;
}
// testing code

View file

@ -379,7 +379,7 @@ export class Prompter {
let prompt = this.profile.saving_memory;
prompt = await this.replaceStrings(prompt, null, null, to_summarize);
let resp = await this.chat_model.sendRequest([], prompt);
await this._saveLog(prompt, null, resp, 'memSaving');
await this._saveLog(prompt, to_summarize, resp, 'memSaving');
if (resp?.includes('</think>')) {
const [_, afterThink] = resp.split('</think>')
resp = afterThink

BIN
tasks/.DS_Store vendored

Binary file not shown.

View file

@ -0,0 +1,688 @@
{
"pyramid": {
"type": "construction",
"goal": "Make a structure with the blueprint below",
"conversation": "Let's share materials and make a structure with the blueprint",
"agent_count": 2,
"blueprint": {
"materials": {
"polished_granite": 1,
"gold_block": 27,
"stone_bricks": 41,
"polished_andesite": 34,
"quartz_block": 16,
"stone": 23,
"polished_diorite": 21,
"quartz_pillar": 2,
"glowstone": 3
},
"levels": [
{
"level": 0,
"coordinates": [
-60,
-60,
6
],
"placement": [
[
"polished_granite",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"gold_block",
"stone_bricks",
"polished_andesite",
"gold_block",
"quartz_block",
"polished_andesite",
"gold_block",
"stone_bricks",
"gold_block"
],
[
"air",
"stone_bricks",
"polished_andesite",
"stone",
"polished_diorite",
"polished_andesite",
"stone",
"stone_bricks",
"polished_diorite",
"gold_block"
],
[
"air",
"polished_andesite",
"stone",
"polished_diorite",
"polished_andesite",
"stone",
"stone_bricks",
"polished_diorite",
"stone",
"stone_bricks"
],
[
"air",
"gold_block",
"polished_diorite",
"polished_andesite",
"stone",
"stone_bricks",
"polished_diorite",
"stone",
"stone_bricks",
"polished_andesite"
],
[
"air",
"quartz_block",
"polished_andesite",
"stone",
"stone_bricks",
"polished_diorite",
"stone",
"stone_bricks",
"polished_andesite",
"quartz_block"
],
[
"air",
"polished_andesite",
"stone",
"stone_bricks",
"polished_diorite",
"stone",
"stone_bricks",
"polished_andesite",
"polished_diorite",
"stone_bricks"
],
[
"air",
"gold_block",
"stone_bricks",
"polished_diorite",
"stone",
"stone_bricks",
"polished_andesite",
"polished_diorite",
"stone_bricks",
"polished_andesite"
],
[
"air",
"stone_bricks",
"polished_diorite",
"stone",
"stone_bricks",
"polished_andesite",
"polished_diorite",
"stone_bricks",
"polished_andesite",
"gold_block"
],
[
"air",
"gold_block",
"gold_block",
"stone_bricks",
"polished_andesite",
"quartz_block",
"stone_bricks",
"polished_andesite",
"gold_block",
"gold_block"
]
]
},
{
"level": 1,
"coordinates": [
-60,
-60,
6
],
"placement": [
[
"quartz_pillar",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"gold_block",
"stone_bricks",
"polished_andesite",
"quartz_block",
"stone_bricks",
"polished_andesite",
"gold_block",
"air"
],
[
"air",
"air",
"stone_bricks",
"stone",
"polished_diorite",
"polished_andesite",
"stone",
"stone_bricks",
"stone_bricks",
"air"
],
[
"air",
"air",
"polished_andesite",
"polished_diorite",
"polished_andesite",
"stone",
"stone_bricks",
"polished_diorite",
"polished_andesite",
"air"
],
[
"air",
"air",
"quartz_block",
"polished_andesite",
"stone",
"glowstone",
"polished_diorite",
"stone",
"quartz_block",
"air"
],
[
"air",
"air",
"stone_bricks",
"stone",
"stone_bricks",
"polished_diorite",
"stone",
"stone_bricks",
"stone_bricks",
"air"
],
[
"air",
"air",
"polished_andesite",
"stone_bricks",
"polished_diorite",
"stone",
"stone_bricks",
"polished_andesite",
"polished_andesite",
"air"
],
[
"air",
"air",
"gold_block",
"stone_bricks",
"polished_andesite",
"quartz_block",
"stone_bricks",
"polished_andesite",
"gold_block",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
]
]
},
{
"level": 2,
"coordinates": [
-60,
-60,
6
],
"placement": [
[
"quartz_pillar",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"gold_block",
"stone_bricks",
"quartz_block",
"gold_block",
"gold_block",
"air",
"air"
],
[
"air",
"air",
"air",
"stone_bricks",
"polished_diorite",
"polished_andesite",
"stone",
"polished_andesite",
"air",
"air"
],
[
"air",
"air",
"air",
"quartz_block",
"polished_andesite",
"glowstone",
"stone_bricks",
"quartz_block",
"air",
"air"
],
[
"air",
"air",
"air",
"gold_block",
"stone",
"stone_bricks",
"polished_diorite",
"stone_bricks",
"air",
"air"
],
[
"air",
"air",
"air",
"gold_block",
"polished_andesite",
"quartz_block",
"stone_bricks",
"gold_block",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
]
]
},
{
"level": 3,
"coordinates": [
-60,
-60,
6
],
"placement": [
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"gold_block",
"quartz_block",
"gold_block",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"quartz_block",
"glowstone",
"quartz_block",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"gold_block",
"quartz_block",
"gold_block",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
]
]
},
{
"level": 4,
"coordinates": [
-60,
-60,
6
],
"placement": [
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"gold_block",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
],
[
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air",
"air"
]
]
}
]
},
"initial_inventory": {
"0": {
"polished_granite": 1,
"stone_bricks": 41,
"quartz_block": 16,
"polished_diorite": 21,
"glowstone": 3
},
"1": {
"gold_block": 27,
"polished_andesite": 34,
"stone": 23,
"quartz_pillar": 2
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
import mineflayer from 'mineflayer';
import { worldToBlueprint, blueprintToTask } from '../../src/agent/task_types/construction_tasks.js';
import fs from 'fs';
import { start } from 'repl';
const bot = mineflayer.createBot({
host: 'localhost', // Replace with your server IP or hostname
port: 55916, // Replace with your server port
username: 'andy', // Replace with your bot's username
// password: 'your_bot_password' // Only if the server has online-mode=true
});
bot.on('spawn', async () => {
console.log("Bot spawned. Starting blueprint check...");
// set this to be minX, minY, minZ
const startCoord = {
x: -60,
y: 1,
z: 6,
}
bot.chat(`/tp andy ${startCoord.x} ${startCoord.y} ${startCoord.z}`);
const yOffset = 5;
const xOffset = 10;
const zOffset = 10;
const taskFilePath = '/Users/isadorawhite/izzy_mindcraft/mindcraft/tasks/construction_tasks/custom/pyramid.json';
const task_name = "pyramid";
setTimeout(async () => {
let task_blueprint = await worldToBlueprint(startCoord, yOffset, xOffset, zOffset, bot);
for (const level of task_blueprint.levels) {
// Perform operations on each level
console.log("Level coordinates:", level.coordinates);
const new_coordinates = [level.coordinates[0], -60, level.coordinates[2]];
level.coordinates = new_coordinates;
console.log("New coordinates:", level.coordinates);
}
console.log("Blueprint generated:", task_blueprint.levels[0].coordinates);
const task = blueprintToTask(task_blueprint, 2);
const task_collection = {}
task_collection[task_name] = task;
fs.writeFileSync(taskFilePath, JSON.stringify(task_collection, null, 2), (err) => {
if (err) {
console.error('Error writing task to file:', err);
} else {
console.log('Task dumped to file successfully.');
}
});
}, 5000); // Delay of 5 seconds (5000 milliseconds)
});

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff