mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-08-04 14:25:43 +02:00
merging crafting_save and procedural generation save
This commit is contained in:
commit
932798195f
18 changed files with 23339 additions and 27278 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -15,4 +15,6 @@ services/viaproxy/saves.json
|
||||||
services/viaproxy/viaproxy.yml
|
services/viaproxy/viaproxy.yml
|
||||||
tmp/
|
tmp/
|
||||||
wandb/
|
wandb/
|
||||||
experiments/
|
experiments/
|
||||||
|
andy_*.json
|
||||||
|
jill_*.json
|
||||||
|
|
104
andy_0.json
104
andy_0.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "andy_0",
|
"name": "Andy_0",
|
||||||
"model": "gpt-4o",
|
"model": "gpt-4o-mini",
|
||||||
"modes": {
|
"modes": {
|
||||||
"hunting": false
|
"hunting": false
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
"conversation_examples": [
|
"conversation_examples": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Hey! let's collaborate to build a stone pickaxe!"
|
"content": "Hey! let's collaborate to build a stone pickaxe!"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
"content": "Cool, let me check what is in my inventory !inventory\nI have 10 oak logs. What do you have?"
|
"content": "Cool, let me check what is in my inventory !inventory\nI have 10 oak logs. What do you have?"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Let me check !inventory \nI have 10 stones."
|
"content": "Let me check !inventory \nI have 10 stones."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -25,13 +25,13 @@
|
||||||
"content": "Let me give you the stones and you can craft the pickaxe. !givePlayer(\"stone\", 10, \"playername\")"
|
"content": "Let me give you the stones and you can craft the pickaxe. !givePlayer(\"stone\", 10, \"playername\")"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Thanks for the stones! Now I can craft the pickaxe. !craftItem(\"stone_pickaxe\", 1)"
|
"content": "Thanks for the stones! Now I can craft the pickaxe. !craftItem(\"stone_pickaxe\", 1)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Hey! let's collaborate to build shears!"
|
"content": "Hey! let's collaborate to build shears!"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
"content": "Cool, let me check what is in my inventory !inventory\nI have 1 iron ingot. What do you have?"
|
"content": "Cool, let me check what is in my inventory !inventory\nI have 1 iron ingot. What do you have?"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Let me check !inventory \nI have 1 iron ingot. "
|
"content": "Let me check !inventory \nI have 1 iron ingot. "
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
"content": "Nice let's check what we need to craft shears. !getCraftingPlan(\"shears\", 1)"
|
"content": "Nice let's check what we need to craft shears. !getCraftingPlan(\"shears\", 1)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "We need 2 iron ingots to craft the shears. Could you share your iron ingot with me?"
|
"content": "We need 2 iron ingots to craft the shears. Could you share your iron ingot with me?"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -55,10 +55,58 @@
|
||||||
"content": "Yes, here is my iron ingot !givePlayer(\"iron_ingot\", 1, \"playername\")"
|
"content": "Yes, here is my iron ingot !givePlayer(\"iron_ingot\", 1, \"playername\")"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Thanks for the iron ingot! Now I can craft the shears. !craftItem(\"shears\", 1)"
|
"content": "Thanks for the iron ingot! Now I can craft the shears. !craftItem(\"shears\", 1)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Hey! Let's collaborate to build a brush"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Cool, let's check what we need for that !getCraftingPlan(\"brush\", 1)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "CRAFTING_PLAN\n- 2 sticks\n- 2 feathers\n- 1 iron ingot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "We need 2 sticks, 2 feathers, and 1 iron ingot to craft the brush. Do you have any of these items?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Let me check !inventory \nI have 2 sticks and 2 feathers."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Great! I have 1 iron ingot. Let me give you my iron ingot and you can craft the brush. !givePlayer(\"iron_ingot\", 1, \"playername\")"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Thanks for the iron ingot! Now I can craft the brush. !craftItem(\"brush\", 1)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Hey! Let's collaborate to build a brush"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Cool, let's check what we need for that !getCraftingPlan(\"brush\", 1)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "no such tool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "I'm sorry, I don't have the crafting plan for a brush. Let me check my inventory to see if I have the items needed. !inventory Do you have access to the crafting plan?"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
|
@ -109,24 +157,6 @@
|
||||||
"content": "terrance: (FROM OTHER BOT)I can build the base, you can build the walls. !newAction(\"Build a 10x10 wall of a house at x:942, y:54, z:1355\")"
|
"content": "terrance: (FROM OTHER BOT)I can build the base, you can build the walls. !newAction(\"Build a 10x10 wall of a house at x:942, y:54, z:1355\")"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
|
||||||
{
|
|
||||||
"role": "system",
|
|
||||||
"content": "trade something with zorro_34"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "!startConversation(\"zorro_34\", \"Hey let's trade. What do you have?\")"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "zorro_34: (FROM OTHER BOT)Let's see... !inventory\nI have a wooden pickaxe, cobblestone, and cooked chicken"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "Okay, could I trade you a cobblestone for a cooked chicken?"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
|
@ -141,26 +171,6 @@
|
||||||
"content": "rupert: (FROM OTHER BOT)Alright, I'll build the walls! !newAction('Build a 10x10 wall of a house at the same location')"
|
"content": "rupert: (FROM OTHER BOT)Alright, I'll build the walls! !newAction('Build a 10x10 wall of a house at the same location')"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "gort: (FROM OTHER BOT)Let's do it, onward!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "Alright, I'll start by getting some cobblestone. !collectBlocks('stone', 10)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "derg: (FROM OTHER BOT)Thanks, see you later!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "See you later. !endConversation(\"derg\")"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
|
|
|
@ -109,9 +109,11 @@ def launch_parallel_experiments(task_path,
|
||||||
exp_name,
|
exp_name,
|
||||||
num_agents=2,
|
num_agents=2,
|
||||||
model="gpt-4o",
|
model="gpt-4o",
|
||||||
|
api="openai",
|
||||||
num_parallel=1,
|
num_parallel=1,
|
||||||
s3=False,
|
s3=False,
|
||||||
bucket_name="mindcraft-experiments"):
|
bucket_name="mindcraft-experiments",
|
||||||
|
template_profile="profiles/collab_profile.json"):
|
||||||
|
|
||||||
with open(task_path, 'r', encoding='utf-8') as file:
|
with open(task_path, 'r', encoding='utf-8') as file:
|
||||||
content = file.read()
|
content = file.read()
|
||||||
|
@ -138,7 +140,10 @@ def launch_parallel_experiments(task_path,
|
||||||
experiments_folder,
|
experiments_folder,
|
||||||
exp_name,
|
exp_name,
|
||||||
s3=s3,
|
s3=s3,
|
||||||
bucket_name=bucket_name)
|
bucket_name=bucket_name,
|
||||||
|
template_profile="profiles/collab_profile.json",
|
||||||
|
model=model,
|
||||||
|
api=api)
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
def launch_server_experiment(task_path,
|
def launch_server_experiment(task_path,
|
||||||
|
@ -148,9 +153,11 @@ def launch_server_experiment(task_path,
|
||||||
experiments_folder,
|
experiments_folder,
|
||||||
exp_name="exp",
|
exp_name="exp",
|
||||||
num_agents=2,
|
num_agents=2,
|
||||||
model="gpt-4o",
|
model="gpt-4o",
|
||||||
|
api="openai",
|
||||||
s3=False,
|
s3=False,
|
||||||
bucket_name="mindcraft-experiments"):
|
bucket_name="mindcraft-experiments",
|
||||||
|
template_profile="profiles/collab_profile.json"):
|
||||||
"""
|
"""
|
||||||
Launch a Minecraft server and run experiments on it.
|
Launch a Minecraft server and run experiments on it.
|
||||||
@param task_path: Path to the task file
|
@param task_path: Path to the task file
|
||||||
|
@ -169,12 +176,14 @@ def launch_server_experiment(task_path,
|
||||||
# set up server and agents
|
# set up server and agents
|
||||||
session_name = str(server_port - 55916)
|
session_name = str(server_port - 55916)
|
||||||
if num_agents == 2:
|
if num_agents == 2:
|
||||||
agent_names = [f"andy_{session_name}", f"jill_{session_name}"]
|
agent_names = [f"Andy_{session_name}", f"Jill_{session_name}"]
|
||||||
models = [model] * 2
|
models = [model] * 2
|
||||||
|
apis = [api] * 2
|
||||||
else:
|
else:
|
||||||
agent_names = [f"andy_{session_name}", f"jill_{session_name}", f"bob_{session_name}"]
|
agent_names = [f"Andy_{session_name}", f"Jill_{session_name}", f"Bob_{session_name}"]
|
||||||
models = [model] * 3
|
models = [model] * 3
|
||||||
make_profiles(agent_names, models)
|
apis = [api] * 3
|
||||||
|
make_profiles(agent_names, models, apis, template_profile=template_profile)
|
||||||
|
|
||||||
# edit_file("settings.js", {"profiles": [f"./{agent}.json" for agent in agent_names]})
|
# edit_file("settings.js", {"profiles": [f"./{agent}.json" for agent in agent_names]})
|
||||||
agent_profiles = [f"./{agent}.json" for agent in agent_names]
|
agent_profiles = [f"./{agent}.json" for agent in agent_names]
|
||||||
|
@ -189,6 +198,18 @@ def launch_server_experiment(task_path,
|
||||||
set_environment_variable_tmux_session(session_name, "MINDSERVER_PORT", mindserver_port)
|
set_environment_variable_tmux_session(session_name, "MINDSERVER_PORT", mindserver_port)
|
||||||
set_environment_variable_tmux_session(session_name, "PROFILES", agent_profiles_str)
|
set_environment_variable_tmux_session(session_name, "PROFILES", agent_profiles_str)
|
||||||
|
|
||||||
|
# you need to add the bots to the world first before you can add them as op
|
||||||
|
cmd = f"node main.js --task_path example_tasks.json --task_id debug_multi_agent_timeout"
|
||||||
|
|
||||||
|
subprocess.run(["tmux", "send-keys", "-t", session_name, cmd, "C-m"])
|
||||||
|
|
||||||
|
time.sleep(20)
|
||||||
|
|
||||||
|
# add the bots as op
|
||||||
|
for agent in agent_names:
|
||||||
|
subprocess.run(["tmux", "send-keys", "-t", "server_" + session_name, f"/op {agent}", "C-m"])
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
script_content = ""
|
script_content = ""
|
||||||
for task_id in task_ids:
|
for task_id in task_ids:
|
||||||
cmd = f"node main.js --task_path {task_path} --task_id {task_id}"
|
cmd = f"node main.js --task_path {task_path} --task_id {task_id}"
|
||||||
|
@ -207,6 +228,7 @@ def launch_server_experiment(task_path,
|
||||||
script_content += f"echo '{s3_cmd}'\n"
|
script_content += f"echo '{s3_cmd}'\n"
|
||||||
script_content += f"{s3_cmd}\n"
|
script_content += f"{s3_cmd}\n"
|
||||||
script_content += "sleep 1\n"
|
script_content += "sleep 1\n"
|
||||||
|
script_content += f"sleep 10\n"
|
||||||
|
|
||||||
# Create a temporary shell script file
|
# Create a temporary shell script file
|
||||||
script_file = f"./tmp/experiment_script_{session_name}.sh"
|
script_file = f"./tmp/experiment_script_{session_name}.sh"
|
||||||
|
@ -226,17 +248,24 @@ def launch_server_experiment(task_path,
|
||||||
|
|
||||||
# subprocess.run(["tmux", "send-keys", "-t", session_name, f"/op {agent_names[0]}", "C-m"])
|
# subprocess.run(["tmux", "send-keys", "-t", session_name, f"/op {agent_names[0]}", "C-m"])
|
||||||
|
|
||||||
def make_profiles(agent_names, models):
|
def make_profiles(agent_names, models, apis, template_profile="profiles/collab_profile.json"):
|
||||||
assert len(agent_names) == len(models)
|
assert len(agent_names) == len(models)
|
||||||
|
|
||||||
with open("profiles/collab_profile.json", 'r') as f:
|
with open(template_profile, 'r') as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
profile = json.loads(content)
|
profile = json.loads(content)
|
||||||
|
|
||||||
for index in range(len(agent_names)):
|
for index in range(len(agent_names)):
|
||||||
profile["name"] = agent_names[index]
|
profile["name"] = agent_names[index]
|
||||||
profile["model"] = models[index]
|
if apis[index] == "vllm":
|
||||||
|
profile["model"] = {
|
||||||
|
"api": "vllm",
|
||||||
|
"model": models[index],
|
||||||
|
"url": "http://localhost:8000/v1"
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
profile["model"] = models[index]
|
||||||
|
|
||||||
with open(f"{agent_names[index]}.json", 'w') as f:
|
with open(f"{agent_names[index]}.json", 'w') as f:
|
||||||
json.dump(profile, f, indent=4)
|
json.dump(profile, f, indent=4)
|
||||||
|
@ -298,8 +327,9 @@ def launch_world(server_path="../server_data/", agent_names=["andy", "jill"], se
|
||||||
cmd = f"cd {server_path} && java -jar server.jar"
|
cmd = f"cd {server_path} && java -jar server.jar"
|
||||||
subprocess.run(['tmux', 'new-session', '-d', '-s', session_name], check=True)
|
subprocess.run(['tmux', 'new-session', '-d', '-s', session_name], check=True)
|
||||||
subprocess.run(["tmux", "send-keys", "-t", session_name, cmd, "C-m"])
|
subprocess.run(["tmux", "send-keys", "-t", session_name, cmd, "C-m"])
|
||||||
for agent in agent_names:
|
# for agent in agent_names:
|
||||||
subprocess.run(["tmux", "send-keys", "-t", session_name, f"/op {agent}", "C-m"])
|
# print(f"\n\n/op {agent}\n\n")
|
||||||
|
# subprocess.run(["tmux", "send-keys", "-t", session_name, f"/op {agent}", "C-m"])
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
def kill_world(session_name="server"):
|
def kill_world(session_name="server"):
|
||||||
|
@ -353,6 +383,9 @@ def main():
|
||||||
parser.add_argument('--s3', action='store_true', help='Whether to upload to s3')
|
parser.add_argument('--s3', action='store_true', help='Whether to upload to s3')
|
||||||
parser.add_argument('--bucket_name', default="mindcraft-experiments", help='Name of the s3 bucket')
|
parser.add_argument('--bucket_name', default="mindcraft-experiments", help='Name of the s3 bucket')
|
||||||
parser.add_argument('--add_keys', action='store_true', help='Create the keys.json to match the environment variables')
|
parser.add_argument('--add_keys', action='store_true', help='Create the keys.json to match the environment variables')
|
||||||
|
parser.add_argument('--template_profile', default="andy.json", help='Model to use for the agents')
|
||||||
|
parser.add_argument('--model', default="gpt-4o-mini", help='Model to use for the agents')
|
||||||
|
parser.add_argument('--api', default="openai", help='API to use for the agents')
|
||||||
# parser.add_argument('--wandb', action='store_true', help='Whether to use wandb')
|
# parser.add_argument('--wandb', action='store_true', help='Whether to use wandb')
|
||||||
# parser.add_argument('--wandb_project', default="minecraft_experiments", help='wandb project name')
|
# parser.add_argument('--wandb_project', default="minecraft_experiments", help='wandb project name')
|
||||||
|
|
||||||
|
@ -378,7 +411,10 @@ def main():
|
||||||
exp_name=args.exp_name,
|
exp_name=args.exp_name,
|
||||||
num_parallel=args.num_parallel,
|
num_parallel=args.num_parallel,
|
||||||
s3=args.s3,
|
s3=args.s3,
|
||||||
bucket_name=args.bucket_name)
|
bucket_name=args.bucket_name,
|
||||||
|
template_profile=args.template_profile,
|
||||||
|
model=args.model,
|
||||||
|
api=args.api)
|
||||||
|
|
||||||
# servers = create_server_files("../server_data/", args.num_parallel)
|
# servers = create_server_files("../server_data/", args.num_parallel)
|
||||||
# date_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
# date_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
||||||
|
|
|
@ -17,6 +17,28 @@
|
||||||
},
|
},
|
||||||
"type": "debug"
|
"type": "debug"
|
||||||
},
|
},
|
||||||
|
"debug_multi_agent_timeout": {
|
||||||
|
"goal": "Just stand at a place and don't do anything",
|
||||||
|
"agent_count": 2,
|
||||||
|
"initial_inventory": {
|
||||||
|
"0": {
|
||||||
|
"iron_ingot": 1
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"iron_ingot": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "debug",
|
||||||
|
"timeout": 15
|
||||||
|
},
|
||||||
|
"debug_different_goal": {
|
||||||
|
"goal": {
|
||||||
|
"0": "Reply to all messages with star emojis when prompted",
|
||||||
|
"1": "Reply to all messages with heart emojis when prompted"
|
||||||
|
},
|
||||||
|
"agent_count": 2,
|
||||||
|
"type": "debug"
|
||||||
|
},
|
||||||
"debug_inventory_restriction": {
|
"debug_inventory_restriction": {
|
||||||
"goal": "Place 1 oak plank, then place 1 stone brick",
|
"goal": "Place 1 oak plank, then place 1 stone brick",
|
||||||
"initial_inventory": {
|
"initial_inventory": {
|
||||||
|
@ -44,7 +66,6 @@
|
||||||
},
|
},
|
||||||
"multiagent_techtree_1_stone_pickaxe": {
|
"multiagent_techtree_1_stone_pickaxe": {
|
||||||
"conversation": "Let's collaborate to build a stone pickaxe",
|
"conversation": "Let's collaborate to build a stone pickaxe",
|
||||||
"goal": "Build a stone pickaxe",
|
|
||||||
"agent_count": 2,
|
"agent_count": 2,
|
||||||
"initial_inventory": {
|
"initial_inventory": {
|
||||||
"0": {
|
"0": {
|
||||||
|
@ -55,6 +76,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"target": "stone_pickaxe",
|
"target": "stone_pickaxe",
|
||||||
|
"goal": "Build a stone pickaxe",
|
||||||
"number_of_target": 1,
|
"number_of_target": 1,
|
||||||
"type": "techtree",
|
"type": "techtree",
|
||||||
"timeout": 300
|
"timeout": 300
|
||||||
|
@ -322,5 +344,41 @@
|
||||||
"number_of_target": 1,
|
"number_of_target": 1,
|
||||||
"type": "techtree",
|
"type": "techtree",
|
||||||
"timeout": 300
|
"timeout": 300
|
||||||
}
|
},
|
||||||
|
"multiagent_cooking_1": {
|
||||||
|
"conversation": "Let's collaborate to make dinner, I am going to search for 'potatoes' and make 1 'baked_potato', you on the other hand, search for cow and cook 1 beef. We have a furnace (fuel already present) nearby to help us cook, search for it over long distances to find it. Note : We only need one of each item, lets not waste time by collecting unnecessary resources.",
|
||||||
|
"agent_count": 2,
|
||||||
|
"target": {
|
||||||
|
"baked_potato":1,
|
||||||
|
"cooked_beef":1
|
||||||
|
},
|
||||||
|
"type": "cooking",
|
||||||
|
"timeout": 300,
|
||||||
|
"goal": "Make 1 baked potato, use a furnace nearby to cook which has fuel in it, let the other agent cook 1 beef"
|
||||||
|
},
|
||||||
|
"multiagent_cooking_2": {
|
||||||
|
"conversation": "Let's collaborate to make bread and cooked_mutton. We can split up to gather ingredients and use the nearby furnace that's already fueled.",
|
||||||
|
"agent_count": 2,
|
||||||
|
"target": {
|
||||||
|
"bread": 1,
|
||||||
|
"cooked_mutton": 1
|
||||||
|
},
|
||||||
|
"type": "cooking",
|
||||||
|
"timeout": 300,
|
||||||
|
"recipes": {
|
||||||
|
"bread": [
|
||||||
|
"Step 1: Go to the farm and collect 3 wheat.",
|
||||||
|
"Step 2: Go to the crafting table and use the wheat to craft bread."
|
||||||
|
],
|
||||||
|
"cooked_mutton": [
|
||||||
|
"Step 1: Kill a sheep and pick up 1 mutton that is dropped.",
|
||||||
|
"Step 2: Go to furnace and use it to cook the mutton."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"blocked_access_to_recipe": [],
|
||||||
|
"goal" : {
|
||||||
|
"0": "Collaborate with randy to make 1 bread and 1 cooked mutton, you can divide the tasks among yourselves.\nThere is a furnace nearby that is already fueled, there is also a smoker and crafting table nearby, use them to your advantage. Crops of all different types are available in the farm where you are standing, you can use them to your advantage as well. The farm also includes animals like cows, pigs, sheep, and chickens that you can use to your advantage.\nSince the farm is huge, make sure to search for the resources over long distances to find them.",
|
||||||
|
"1": "Collaborate with andy to make 1 bread and 1 cooked mutton, you can divide the tasks among yourselves.\nThere is a furnace nearby that is already fueled, there is also a smoker and crafting table nearby, use them to your advantage. Crops of all different types are available in the farm where you are standing, you can use them to your advantage as well. The farm also includes animals like cows, pigs, sheep, and chickens that you can use to your advantage.\nSince the farm is huge, make sure to search for the resources over long distances to find them."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
104
jill_0.json
104
jill_0.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "jill_0",
|
"name": "Jill_0",
|
||||||
"model": "gpt-4o",
|
"model": "gpt-4o-mini",
|
||||||
"modes": {
|
"modes": {
|
||||||
"hunting": false
|
"hunting": false
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
"conversation_examples": [
|
"conversation_examples": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Hey! let's collaborate to build a stone pickaxe!"
|
"content": "Hey! let's collaborate to build a stone pickaxe!"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
"content": "Cool, let me check what is in my inventory !inventory\nI have 10 oak logs. What do you have?"
|
"content": "Cool, let me check what is in my inventory !inventory\nI have 10 oak logs. What do you have?"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Let me check !inventory \nI have 10 stones."
|
"content": "Let me check !inventory \nI have 10 stones."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -25,13 +25,13 @@
|
||||||
"content": "Let me give you the stones and you can craft the pickaxe. !givePlayer(\"stone\", 10, \"playername\")"
|
"content": "Let me give you the stones and you can craft the pickaxe. !givePlayer(\"stone\", 10, \"playername\")"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Thanks for the stones! Now I can craft the pickaxe. !craftItem(\"stone_pickaxe\", 1)"
|
"content": "Thanks for the stones! Now I can craft the pickaxe. !craftItem(\"stone_pickaxe\", 1)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Hey! let's collaborate to build shears!"
|
"content": "Hey! let's collaborate to build shears!"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
"content": "Cool, let me check what is in my inventory !inventory\nI have 1 iron ingot. What do you have?"
|
"content": "Cool, let me check what is in my inventory !inventory\nI have 1 iron ingot. What do you have?"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Let me check !inventory \nI have 1 iron ingot. "
|
"content": "Let me check !inventory \nI have 1 iron ingot. "
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
"content": "Nice let's check what we need to craft shears. !getCraftingPlan(\"shears\", 1)"
|
"content": "Nice let's check what we need to craft shears. !getCraftingPlan(\"shears\", 1)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "We need 2 iron ingots to craft the shears. Could you share your iron ingot with me?"
|
"content": "We need 2 iron ingots to craft the shears. Could you share your iron ingot with me?"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -55,10 +55,58 @@
|
||||||
"content": "Yes, here is my iron ingot !givePlayer(\"iron_ingot\", 1, \"playername\")"
|
"content": "Yes, here is my iron ingot !givePlayer(\"iron_ingot\", 1, \"playername\")"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "user",
|
||||||
"content": "Thanks for the iron ingot! Now I can craft the shears. !craftItem(\"shears\", 1)"
|
"content": "Thanks for the iron ingot! Now I can craft the shears. !craftItem(\"shears\", 1)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Hey! Let's collaborate to build a brush"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Cool, let's check what we need for that !getCraftingPlan(\"brush\", 1)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "CRAFTING_PLAN\n- 2 sticks\n- 2 feathers\n- 1 iron ingot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "We need 2 sticks, 2 feathers, and 1 iron ingot to craft the brush. Do you have any of these items?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Let me check !inventory \nI have 2 sticks and 2 feathers."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Great! I have 1 iron ingot. Let me give you my iron ingot and you can craft the brush. !givePlayer(\"iron_ingot\", 1, \"playername\")"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Thanks for the iron ingot! Now I can craft the brush. !craftItem(\"brush\", 1)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Hey! Let's collaborate to build a brush"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Cool, let's check what we need for that !getCraftingPlan(\"brush\", 1)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "no such tool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "I'm sorry, I don't have the crafting plan for a brush. Let me check my inventory to see if I have the items needed. !inventory Do you have access to the crafting plan?"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
|
@ -109,24 +157,6 @@
|
||||||
"content": "terrance: (FROM OTHER BOT)I can build the base, you can build the walls. !newAction(\"Build a 10x10 wall of a house at x:942, y:54, z:1355\")"
|
"content": "terrance: (FROM OTHER BOT)I can build the base, you can build the walls. !newAction(\"Build a 10x10 wall of a house at x:942, y:54, z:1355\")"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
|
||||||
{
|
|
||||||
"role": "system",
|
|
||||||
"content": "trade something with zorro_34"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "!startConversation(\"zorro_34\", \"Hey let's trade. What do you have?\")"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "zorro_34: (FROM OTHER BOT)Let's see... !inventory\nI have a wooden pickaxe, cobblestone, and cooked chicken"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "Okay, could I trade you a cobblestone for a cooked chicken?"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
|
@ -141,26 +171,6 @@
|
||||||
"content": "rupert: (FROM OTHER BOT)Alright, I'll build the walls! !newAction('Build a 10x10 wall of a house at the same location')"
|
"content": "rupert: (FROM OTHER BOT)Alright, I'll build the walls! !newAction('Build a 10x10 wall of a house at the same location')"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "gort: (FROM OTHER BOT)Let's do it, onward!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "Alright, I'll start by getting some cobblestone. !collectBlocks('stone', 10)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "derg: (FROM OTHER BOT)Thanks, see you later!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "See you later. !endConversation(\"derg\")"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
|
|
|
@ -42,4 +42,4 @@
|
||||||
"type": "techtree",
|
"type": "techtree",
|
||||||
"timeout": 120
|
"timeout": 120
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,27 +8,41 @@
|
||||||
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. $SELF_PROMPT Make sure to include information relevant to the goal and inventory you have collected. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
|
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. $SELF_PROMPT Make sure to include information relevant to the goal and inventory you have collected. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
|
||||||
"conversation_examples": [
|
"conversation_examples": [
|
||||||
[
|
[
|
||||||
{"role": "assistant", "content": "Hey! let's collaborate to build a stone pickaxe!"},
|
{"role": "user", "content": "Hey! let's collaborate to build a stone pickaxe!"},
|
||||||
{"role": "assistant", "content": "Cool, let me check what is in my inventory !inventory\nI have 10 oak logs. What do you have?"},
|
{"role": "assistant", "content": "Cool, let me check what is in my inventory !inventory\nI have 10 oak logs. What do you have?"},
|
||||||
{"role": "assistant", "content": "Let me check !inventory \nI have 10 stones."},
|
{"role": "user", "content": "Let me check !inventory \nI have 10 stones."},
|
||||||
{"role": "assistant", "content": "Let me give you the stones and you can craft the pickaxe. !givePlayer(\"stone\", 10, \"playername\")"},
|
{"role": "assistant", "content": "Let me give you the stones and you can craft the pickaxe. !givePlayer(\"stone\", 10, \"playername\")"},
|
||||||
{"role": "assistant", "content": "Thanks for the stones! Now I can craft the pickaxe. !craftItem(\"stone_pickaxe\", 1)"}
|
{"role": "user", "content": "Thanks for the stones! Now I can craft the pickaxe. !craftItem(\"stone_pickaxe\", 1)"}
|
||||||
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{"role": "assistant", "content": "Hey! let's collaborate to build shears!"},
|
{"role": "user", "content": "Hey! let's collaborate to build shears!"},
|
||||||
{"role": "assistant", "content": "Cool, let me check what is in my inventory !inventory\nI have 1 iron ingot. What do you have?"},
|
{"role": "assistant", "content": "Cool, let me check what is in my inventory !inventory\nI have 1 iron ingot. What do you have?"},
|
||||||
{"role": "assistant", "content": "Let me check !inventory \nI have 1 iron ingot. "},
|
{"role": "user", "content": "Let me check !inventory \nI have 1 iron ingot. "},
|
||||||
{"role": "assistant", "content": "Nice let's check what we need to craft shears. !getCraftingPlan(\"shears\", 1)"},
|
{"role": "assistant", "content": "Nice let's check what we need to craft shears. !getCraftingPlan(\"shears\", 1)"},
|
||||||
{"role": "assistant", "content": "We need 2 iron ingots to craft the shears. Could you share your iron ingot with me?"},
|
{"role": "user", "content": "We need 2 iron ingots to craft the shears. Could you share your iron ingot with me?"},
|
||||||
{"role": "assistant", "content": "Yes, here is my iron ingot !givePlayer(\"iron_ingot\", 1, \"playername\")"},
|
{"role": "assistant", "content": "Yes, here is my iron ingot !givePlayer(\"iron_ingot\", 1, \"playername\")"},
|
||||||
{"role": "assistant", "content": "Thanks for the iron ingot! Now I can craft the shears. !craftItem(\"shears\", 1)"}
|
{"role": "user", "content": "Thanks for the iron ingot! Now I can craft the shears. !craftItem(\"shears\", 1)"}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
{"role": "user", "content": "Hey! Let's collaborate to build a brush"},
|
||||||
|
{"role": "assistant", "content": "Cool, let's check what we need for that !getCraftingPlan(\"brush\", 1)"},
|
||||||
|
{"role": "system", "content": "CRAFTING_PLAN\n- 2 sticks\n- 2 feathers\n- 1 iron ingot"},
|
||||||
|
{"role": "assistant", "content": "We need 2 sticks, 2 feathers, and 1 iron ingot to craft the brush. Do you have any of these items?"},
|
||||||
|
{"role": "user", "content": "Let me check !inventory \nI have 2 sticks and 2 feathers."},
|
||||||
|
{"role": "assistant", "content": "Great! I have 1 iron ingot. Let me give you my iron ingot and you can craft the brush. !givePlayer(\"iron_ingot\", 1, \"playername\")"},
|
||||||
|
{"role": "user", "content": "Thanks for the iron ingot! Now I can craft the brush. !craftItem(\"brush\", 1)"}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"role": "user", "content": "Hey! Let's collaborate to build a brush"},
|
||||||
|
{"role": "assistant", "content": "Cool, let's check what we need for that !getCraftingPlan(\"brush\", 1)"},
|
||||||
|
{"role": "system", "content": "no such tool"},
|
||||||
|
{"role": "assistant", "content": "I'm sorry, I don't have the crafting plan for a brush. Let me check my inventory to see if I have the items needed. !inventory Do you have access to the crafting plan?"}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
{"role": "user", "content": "miner_32: Hey! What are you up to?"},
|
{"role": "user", "content": "miner_32: Hey! What are you up to?"},
|
||||||
{"role": "assistant", "content": "Nothing much miner_32, what do you need?"}
|
{"role": "assistant", "content": "Nothing much miner_32, what do you need?"}
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
{"role": "system", "content": "say hi to john_goodman"},
|
{"role": "system", "content": "say hi to john_goodman"},
|
||||||
{"role": "assistant", "content": "!startConversation(\"john_goodman\", \"Hey John\"))"},
|
{"role": "assistant", "content": "!startConversation(\"john_goodman\", \"Hey John\"))"},
|
||||||
|
@ -44,28 +58,11 @@
|
||||||
{"role": "user", "content": "terrance: (FROM OTHER BOT)I can build the base, you can build the walls. !newAction(\"Build a 10x10 wall of a house at x:942, y:54, z:1355\")"}
|
{"role": "user", "content": "terrance: (FROM OTHER BOT)I can build the base, you can build the walls. !newAction(\"Build a 10x10 wall of a house at x:942, y:54, z:1355\")"}
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
|
||||||
{"role": "system", "content": "trade something with zorro_34"},
|
|
||||||
{"role": "assistant", "content": "!startConversation(\"zorro_34\", \"Hey let's trade. What do you have?\")"},
|
|
||||||
{"role": "user", "content": "zorro_34: (FROM OTHER BOT)Let's see... !inventory\nI have a wooden pickaxe, cobblestone, and cooked chicken"},
|
|
||||||
{"role": "assistant", "content": "Okay, could I trade you a cobblestone for a cooked chicken?"}
|
|
||||||
],
|
|
||||||
|
|
||||||
[
|
[
|
||||||
{"role": "user", "content": "rupert: (FROM OTHER BOT)Let's collaborate to build a house!"},
|
{"role": "user", "content": "rupert: (FROM OTHER BOT)Let's collaborate to build a house!"},
|
||||||
{"role": "assistant", "content": "Sure! I'll share information to help coordinate. Let's center the build at x:942, y:54, z:1355 !newAction(\"Build a 10x10 base of a house at location\")"},
|
{"role": "assistant", "content": "Sure! I'll share information to help coordinate. Let's center the build at x:942, y:54, z:1355 !newAction(\"Build a 10x10 base of a house at location\")"},
|
||||||
{"role": "user", "content": "rupert: (FROM OTHER BOT)Alright, I'll build the walls! !newAction('Build a 10x10 wall of a house at the same location')"}
|
{"role": "user", "content": "rupert: (FROM OTHER BOT)Alright, I'll build the walls! !newAction('Build a 10x10 wall of a house at the same location')"}
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
|
||||||
{"role": "user", "content": "gort: (FROM OTHER BOT)Let's do it, onward!"},
|
|
||||||
{"role": "assistant", "content": "Alright, I'll start by getting some cobblestone. !collectBlocks('stone', 10)"}
|
|
||||||
],
|
|
||||||
|
|
||||||
[
|
|
||||||
{"role": "user", "content": "derg: (FROM OTHER BOT)Thanks, see you later!"},
|
|
||||||
{"role": "assistant", "content": "See you later. !endConversation(\"derg\")"}
|
|
||||||
],
|
|
||||||
|
|
||||||
[
|
[
|
||||||
{"role": "user", "content": "grombo_Xx: What do you see?"},
|
{"role": "user", "content": "grombo_Xx: What do you see?"},
|
||||||
|
|
24
profiles/no_examples.json
Normal file
24
profiles/no_examples.json
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "andy",
|
||||||
|
"model": "gpt-4o",
|
||||||
|
"modes": {
|
||||||
|
"hunting": false
|
||||||
|
},
|
||||||
|
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands.\n$SELF_PROMPT 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, don't give instructions or make lists unless asked, and don't 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(\"playername\", 3)'. Respond only as $NAME, never output '(FROM OTHER BOT)' or pretend to be someone else. If you have nothing to say or do, respond with an just a tab '\t'. Share resources and information with other bots! This is extremely important to me, take a deep breath and have fun :) \n$STATS\n$INVENTORY\n$COMMAND_DOCS\nConversation Begin:",
|
||||||
|
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. $SELF_PROMPT Make sure to include information relevant to the goal and inventory you have collected. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
|
||||||
|
"conversation_examples": [
|
||||||
|
[
|
||||||
|
{"role": "user", "content": "miner_32: Hey! What are you up to?"},
|
||||||
|
{"role": "assistant", "content": "Nothing much miner_32, what do you need?"}
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
{"role": "system", "content": "say hi to john_goodman"},
|
||||||
|
{"role": "assistant", "content": "!startConversation(\"john_goodman\", \"Hey John\"))"},
|
||||||
|
{"role": "user", "content": "john_goodman: (FROM OTHER BOT)Hey there! What's up?"},
|
||||||
|
{"role": "assistant", "content": "Hey John, not much. Just saying hi."},
|
||||||
|
{"role": "user", "content": "john_goodman: (FROM OTHER BOT)Bye!"},
|
||||||
|
{"role": "assistant", "content": "Bye! !endConversation('john_goodman')"}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
11
profiles/vllm.json
Normal file
11
profiles/vllm.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "vllm",
|
||||||
|
|
||||||
|
"model": {
|
||||||
|
"api": "vllm",
|
||||||
|
"model": "Qwen/Qwen2.5-1.5B-Instruct",
|
||||||
|
"url": "http://localhost:8000/v1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"embedding": "openai"
|
||||||
|
}
|
|
@ -345,9 +345,7 @@ export class Agent {
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleMessage(source, message, max_responses=null) {
|
async handleMessage(source, message, max_responses=null) {
|
||||||
if (this.task && this.validator && this.validator.validate()) {
|
await this.checkTaskDone();
|
||||||
this.killBots();
|
|
||||||
}
|
|
||||||
if (!source || !message) {
|
if (!source || !message) {
|
||||||
console.warn('Received empty message from', source);
|
console.warn('Received empty message from', source);
|
||||||
return false;
|
return false;
|
||||||
|
@ -645,20 +643,17 @@ export class Agent {
|
||||||
|
|
||||||
async update(delta) {
|
async update(delta) {
|
||||||
await this.bot.modes.update();
|
await this.bot.modes.update();
|
||||||
await this.self_prompter.update(delta);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (this.task && this.taskTimeout) {
|
|
||||||
const elapsedTime = (Date.now() - this.taskStartTime) / 1000;
|
|
||||||
if (elapsedTime >= this.taskTimeout) {
|
|
||||||
console.log('Task timeout reached. Task unsuccessful.');
|
|
||||||
await this.cleanKill('Task unsuccessful: Timeout reached', 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Caught an error while checking timeout reached",e);
|
|
||||||
}
|
|
||||||
this.self_prompter.update(delta);
|
this.self_prompter.update(delta);
|
||||||
|
await this.checkTaskDone();
|
||||||
|
// if (this.task.data) {
|
||||||
|
// let res = this.task.isDone();
|
||||||
|
// if (res) {
|
||||||
|
// await this.history.add('system', `${res.message} ended with code : ${res.code}`);
|
||||||
|
// await this.history.save();
|
||||||
|
// console.log('Task finished:', res.message);
|
||||||
|
// this.killAll();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
isIdle() {
|
isIdle() {
|
||||||
|
@ -679,4 +674,20 @@ export class Agent {
|
||||||
this.history.save();
|
this.history.save();
|
||||||
process.exit(code);
|
process.exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkTaskDone() {
|
||||||
|
if (this.task.data) {
|
||||||
|
let res = this.task.isDone();
|
||||||
|
if (res) {
|
||||||
|
await this.history.add('system', `${res.message} ended with code : ${res.code}`);
|
||||||
|
await this.history.save();
|
||||||
|
console.log('Task finished:', res.message);
|
||||||
|
this.killAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
killAll() {
|
||||||
|
serverProxy.shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,16 @@ export class ConstructionTaskValidator {
|
||||||
let total_blocks = result.mismatches.length + result.matches.length;
|
let total_blocks = result.mismatches.length + result.matches.length;
|
||||||
score = (result.matches.length / total_blocks) * 100;
|
score = (result.matches.length / total_blocks) * 100;
|
||||||
console.log(`Task is ${score}% complete`);
|
console.log(`Task is ${score}% complete`);
|
||||||
return valid;
|
return {
|
||||||
|
"valid": valid,
|
||||||
|
"score": score
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error validating task:', error);
|
console.error('Error validating task:', error);
|
||||||
return false;
|
return {
|
||||||
|
"valid": false,
|
||||||
|
"score": 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
383
src/agent/task_types/cooking_tasks.js
Normal file
383
src/agent/task_types/cooking_tasks.js
Normal file
|
@ -0,0 +1,383 @@
|
||||||
|
import { getPosition } from "../library/world.js";
|
||||||
|
|
||||||
|
export class CookingTaskInitiator {
|
||||||
|
constructor(data, agent) {
|
||||||
|
this.agent = agent;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
let bot = this.agent.bot;
|
||||||
|
|
||||||
|
//// Setting up the cooking world using minecraft cheats ////
|
||||||
|
|
||||||
|
// Only run the setup if the agent is the first one
|
||||||
|
|
||||||
|
if (this.agent.count_id === 0) {
|
||||||
|
// Clear and prepare the base area
|
||||||
|
await bot.chat(`/fill ~ ~-1 ~ ~50 ~-3 ~50 grass_block`);
|
||||||
|
await bot.chat(`/fill ~ ~-1 ~ ~-50 ~-3 ~50 grass_block`);
|
||||||
|
await bot.chat(`/fill ~ ~-1 ~ ~-50 ~-3 ~-50 grass_block`);
|
||||||
|
await bot.chat(`/fill ~ ~-1 ~ ~50 ~-3 ~-50 grass_block`);
|
||||||
|
await bot.chat(`/fill ~ ~ ~ ~50 ~10 ~50 air`);
|
||||||
|
await bot.chat(`/fill ~ ~ ~ ~-50 ~10 ~50 air`);
|
||||||
|
await bot.chat(`/fill ~ ~ ~ ~-50 ~10 ~-50 air`);
|
||||||
|
await bot.chat(`/fill ~ ~ ~ ~50 ~10 ~-50 air`);
|
||||||
|
|
||||||
|
const position = getPosition(bot);
|
||||||
|
const botX = Math.floor(position.x);
|
||||||
|
const botZ = Math.floor(position.z);
|
||||||
|
|
||||||
|
// Region management system
|
||||||
|
const isOverlapping = (newXMin, newXMax, newZMin, newZMax, occupiedRegions) => {
|
||||||
|
for (const region of occupiedRegions) {
|
||||||
|
if (newXMin < region.xMax && newXMax > region.xMin &&
|
||||||
|
newZMin < region.zMax && newZMax > region.zMin) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const findValidPosition = (width, depth, occupiedRegions) => {
|
||||||
|
const maxXStart = position.x + 25 - width; // Constrain to 50x50 area
|
||||||
|
const minXStart = position.x - 25;
|
||||||
|
const maxZStart = position.z + 25 - depth;
|
||||||
|
const minZStart = position.z - 25;
|
||||||
|
|
||||||
|
let attempts = 0;
|
||||||
|
while (attempts < 1000) {
|
||||||
|
const xStart = Math.floor(minXStart + Math.random() * (maxXStart - minXStart + 1));
|
||||||
|
const zStart = Math.floor(minZStart + Math.random() * (maxZStart - minZStart + 1));
|
||||||
|
const xMin = xStart;
|
||||||
|
const xMax = xStart + width - 1;
|
||||||
|
const zMin = zStart;
|
||||||
|
const zMax = zStart + depth - 1;
|
||||||
|
|
||||||
|
if (!isOverlapping(xMin, xMax, zMin, zMax, occupiedRegions)) {
|
||||||
|
return { xStart, zStart };
|
||||||
|
}
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
throw new Error('Failed to find non-overlapping position after 1000 attempts');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define all regions with their sizes
|
||||||
|
const regionsToPlace = [
|
||||||
|
{ type: 'wheat', width: 5, depth: 5 },
|
||||||
|
{ type: 'beetroots', width: 2, depth: 5 },
|
||||||
|
{ type: 'mushrooms', width: 2, depth: 5 },
|
||||||
|
{ type: 'potatoes', width: 2, depth: 5 },
|
||||||
|
{ type: 'carrots', width: 2, depth: 5 },
|
||||||
|
{ type: 'sugar_cane', width: 3, depth: 3 },
|
||||||
|
{ type: 'sugar_cane', width: 3, depth: 3 },
|
||||||
|
{ type: 'pumpkins', width: 5, depth: 1 },
|
||||||
|
{ type: 'house', width: 11, depth: 11 }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Expand the regions of each type to make sure they don't overlap
|
||||||
|
|
||||||
|
for (let i = 0; i < regionsToPlace.length; i++) {
|
||||||
|
const region = regionsToPlace[i];
|
||||||
|
const { width, depth } = region;
|
||||||
|
regionsToPlace[i].width = width + 4;
|
||||||
|
regionsToPlace[i].depth = depth + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const occupiedRegions = [{
|
||||||
|
xMin : botX - 1,
|
||||||
|
xMax : botX + 1,
|
||||||
|
zMin : botZ - 1,
|
||||||
|
zMax : botZ + 1
|
||||||
|
}];
|
||||||
|
const regionPositions = {};
|
||||||
|
|
||||||
|
// Calculate positions for all regions
|
||||||
|
for (const region of regionsToPlace) {
|
||||||
|
const { xStart, zStart } = findValidPosition(region.width, region.depth, occupiedRegions);
|
||||||
|
|
||||||
|
occupiedRegions.push({
|
||||||
|
xMin: xStart,
|
||||||
|
xMax: xStart + region.width - 1,
|
||||||
|
zMin: zStart,
|
||||||
|
zMax: zStart + region.depth - 1
|
||||||
|
});
|
||||||
|
|
||||||
|
if (region.type === 'sugar_cane') {
|
||||||
|
if (!regionPositions.sugar_cane) regionPositions.sugar_cane = [];
|
||||||
|
regionPositions.sugar_cane.push({ xStart, zStart });
|
||||||
|
} else {
|
||||||
|
regionPositions[region.type] = { xStart, zStart };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Planting functions with dynamic positions
|
||||||
|
const plantWheat = async (xStart, zStart) => {
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
for (let j = 0; j < 5; j++) {
|
||||||
|
const x = xStart + i;
|
||||||
|
const z = zStart + j;
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y - 1} ${z} farmland`);
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y} ${z} wheat[age=7]`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const plantBeetroots = async (xStart, zStart) => {
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
for (let j = 0; j < 5; j++) {
|
||||||
|
const x = xStart + i;
|
||||||
|
const z = zStart + j;
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y - 1} ${z} farmland`);
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y} ${z} beetroots[age=3]`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const plantMushrooms = async (xStart, zStart) => {
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
for (let j = 0; j < 5; j++) {
|
||||||
|
const x = xStart + i;
|
||||||
|
const z = zStart + j;
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y - 1} ${z} mycelium`);
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y} ${z} red_mushroom`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const plantPotatoes = async (xStart, zStart) => {
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
for (let j = 0; j < 5; j++) {
|
||||||
|
const x = xStart + i;
|
||||||
|
const z = zStart + j;
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y - 1} ${z} farmland`);
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y} ${z} potatoes[age=7]`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const plantCarrots = async (xStart, zStart) => {
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
for (let j = 0; j < 5; j++) {
|
||||||
|
const x = xStart + i;
|
||||||
|
const z = zStart + j;
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y - 1} ${z} farmland`);
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y} ${z} carrots[age=7]`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const plantSugarCane = async (patches) => {
|
||||||
|
for (const patch of patches) {
|
||||||
|
const xCenter = patch.xStart + 1;
|
||||||
|
const zCenter = patch.zStart + 1;
|
||||||
|
await bot.chat(`/setblock ${xCenter} ${position.y - 1} ${zCenter} water`);
|
||||||
|
const offsets = [[1, 0], [-1, 0], [0, 1], [0, -1]];
|
||||||
|
for (const [dx, dz] of offsets) {
|
||||||
|
await bot.chat(`/setblock ${xCenter + dx} ${position.y} ${zCenter + dz} sugar_cane[age=15]`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const plantPumpkins = async (xStart, zStart) => {
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
const x = xStart + i;
|
||||||
|
const z = zStart;
|
||||||
|
await bot.chat(`/setblock ${x} ${position.y} ${z} pumpkin`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Execute all planting
|
||||||
|
await plantWheat(regionPositions.wheat.xStart, regionPositions.wheat.zStart);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
await plantBeetroots(regionPositions.beetroots.xStart, regionPositions.beetroots.zStart);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
await plantMushrooms(regionPositions.mushrooms.xStart, regionPositions.mushrooms.zStart);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
await plantPotatoes(regionPositions.potatoes.xStart, regionPositions.potatoes.zStart);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
await plantCarrots(regionPositions.carrots.xStart, regionPositions.carrots.zStart);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
await plantSugarCane(regionPositions.sugar_cane);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
await plantPumpkins(regionPositions.pumpkins.xStart, regionPositions.pumpkins.zStart);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
// House construction
|
||||||
|
const buildHouse = async (xStart, zStart) => {
|
||||||
|
const startX = xStart;
|
||||||
|
const startY = position.y;
|
||||||
|
const startZ = zStart;
|
||||||
|
const width = 10;
|
||||||
|
const depth = 10;
|
||||||
|
const height = 5;
|
||||||
|
|
||||||
|
// Foundation and walls
|
||||||
|
for (let x = startX; x <= startX + depth; x++) {
|
||||||
|
for (let y = startY; y <= startY + height; y++) {
|
||||||
|
for (let z = startZ; z <= startZ + width; z++) {
|
||||||
|
if (y === startY) {
|
||||||
|
if (!(x === startX + depth - 1 && z === startZ + Math.floor(width / 2))) {
|
||||||
|
await bot.chat(`/setblock ${x} ${y} ${z} stone_bricks`);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x === startX || x === startX + depth ||
|
||||||
|
z === startZ || z === startZ + width ||
|
||||||
|
y === startY + height) {
|
||||||
|
|
||||||
|
const isWindow = (
|
||||||
|
(x === startX || x === startX + depth) &&
|
||||||
|
(z === startZ + 3 || z === startZ + width - 3) &&
|
||||||
|
(y === startY + 2 || y === startY + 3)
|
||||||
|
) || (
|
||||||
|
(z === startZ || z === startZ + width) &&
|
||||||
|
(x === startX + 3 || x === startX + depth - 3) &&
|
||||||
|
(y === startY + 2 || y === startY + 3)
|
||||||
|
);
|
||||||
|
|
||||||
|
const isDoor = x === startX + depth &&
|
||||||
|
z === startZ + Math.floor(width / 2) &&
|
||||||
|
(y === startY + 1 || y === startY + 2);
|
||||||
|
|
||||||
|
if (!isWindow && !isDoor) {
|
||||||
|
await bot.chat(`/setblock ${x} ${y} ${z} stone_bricks`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entrance features
|
||||||
|
const doorZ = startZ + Math.floor(width / 2);
|
||||||
|
await bot.chat(`/setblock ${startX + depth - 1} ${startY} ${doorZ} stone_brick_stairs[facing=west]`);
|
||||||
|
await bot.chat(`/setblock ${startX + depth - 1} ${startY} ${doorZ - 1} stone_bricks`);
|
||||||
|
await bot.chat(`/setblock ${startX + depth - 1} ${startY} ${doorZ + 1} stone_bricks`);
|
||||||
|
await bot.chat(`/setblock ${startX + depth} ${startY} ${doorZ} oak_door[half=lower,hinge=left,facing=west,powered=false]`);
|
||||||
|
await bot.chat(`/setblock ${startX + depth} ${startY + 1} ${doorZ} oak_door[half=upper,hinge=left,facing=west,powered=false]`);
|
||||||
|
|
||||||
|
// Roof construction
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
for (let x = startX + i; x <= startX + depth - i; x++) {
|
||||||
|
for (let z = startZ + i; z <= startZ + width - i; z++) {
|
||||||
|
if (x === startX + i || x === startX + depth - i ||
|
||||||
|
z === startZ + i || z === startZ + width - i) {
|
||||||
|
await bot.chat(`/setblock ${x} ${startY + height + i} ${z} cobblestone`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interior items
|
||||||
|
await bot.chat(`/setblock ${startX + 4} ${startY + 1} ${startZ + 3} crafting_table`);
|
||||||
|
await bot.chat(`/setblock ${startX + 4} ${startY + 1} ${startZ + 5} furnace`);
|
||||||
|
// Add fuel to the furnace
|
||||||
|
await bot.chat(`/data merge block ${startX + 4} ${startY + 1} ${startZ + 5} {Items:[{Slot:1b,id:"minecraft:coal",Count:64b}]}`)
|
||||||
|
await bot.chat(`/setblock ${startX + 4} ${startY + 1} ${startZ + 7} smoker`);
|
||||||
|
// Add fuel to the smoker
|
||||||
|
await bot.chat(`/data merge block ${startX + 4} ${startY + 1} ${startZ + 7} {Items:[{Slot:1b,id:"minecraft:coal",Count:64b}]}`)
|
||||||
|
await bot.chat(`/setblock ${startX + depth - 3} ${startY + 1} ${startZ + 2} bed`);
|
||||||
|
};
|
||||||
|
|
||||||
|
await buildHouse(regionPositions.house.xStart, regionPositions.house.zStart);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
// Add a chest with cooking items near the bot
|
||||||
|
const addChestWithItems = async () => {
|
||||||
|
// Find a valid position near the bot (within 10 blocks)
|
||||||
|
const findChestPosition = () => {
|
||||||
|
const maxAttempts = 100;
|
||||||
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||||
|
const x = botX + Math.floor(Math.random() * 10 - 5); // Within ±5 blocks X
|
||||||
|
const z = botZ + Math.floor(Math.random() * 10 - 5); // Within ±5 blocks Z
|
||||||
|
const y = position.y;
|
||||||
|
|
||||||
|
// Check if the position is not overlapping with existing structures
|
||||||
|
if (!isOverlapping(x, x, z, z, occupiedRegions)) {
|
||||||
|
return { x, y, z };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('Failed to find valid chest position');
|
||||||
|
};
|
||||||
|
|
||||||
|
const { x, y, z } = findChestPosition();
|
||||||
|
|
||||||
|
// Place the chest
|
||||||
|
await bot.chat(`/setblock ${x} ${y} ${z} chest`);
|
||||||
|
|
||||||
|
const cookingItems = [
|
||||||
|
['minecraft:milk_bucket', 1], // Non-stackable
|
||||||
|
['minecraft:egg', 16], // Stacks to 16
|
||||||
|
['minecraft:melon_slice', 64], // Stacks to 64
|
||||||
|
['minecraft:sugar', 64],
|
||||||
|
['minecraft:cocoa_beans', 64],
|
||||||
|
['minecraft:apple', 64],
|
||||||
|
['minecraft:cookie', 64],
|
||||||
|
['minecraft:mutton', 64],
|
||||||
|
['minecraft:salmon', 64],
|
||||||
|
['minecraft:cod', 64],
|
||||||
|
['minecraft:kelp', 64],
|
||||||
|
['minecraft:dried_kelp', 64],
|
||||||
|
['minecraft:sweet_berries', 64],
|
||||||
|
['minecraft:honey_bottle', 1], // Non-stackable
|
||||||
|
['minecraft:glow_berries', 64],
|
||||||
|
['minecraft:bowl', 64],
|
||||||
|
['minecraft:golden_carrot', 64],
|
||||||
|
['minecraft:golden_apple', 64],
|
||||||
|
['minecraft:enchanted_golden_apple', 64],
|
||||||
|
['minecraft:cooked_mutton', 64],
|
||||||
|
['minecraft:cooked_salmon', 64],
|
||||||
|
['minecraft:cooked_cod', 64]
|
||||||
|
];
|
||||||
|
|
||||||
|
// Fill the chest with random cooking items
|
||||||
|
for (let slot = 0; slot < cookingItems.length; slot++) { // Chest has 27 slots
|
||||||
|
const randomItem = cookingItems[slot];
|
||||||
|
await bot.chat(`/item replace block ${x} ${y} ${z} container.${slot} with ${randomItem[0]} ${randomItem[1]}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the chest area as occupied
|
||||||
|
occupiedRegions.push({
|
||||||
|
xMin: x,
|
||||||
|
xMax: x,
|
||||||
|
zMin: z,
|
||||||
|
zMax: z
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
await addChestWithItems();
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
// Animal management
|
||||||
|
await bot.chat('/kill @e[type=item,distance=..50]');
|
||||||
|
await bot.chat('/kill @e[type=chicken,distance=..50]');
|
||||||
|
await bot.chat('/kill @e[type=cow,distance=..50]');
|
||||||
|
await bot.chat('/kill @e[type=llama,distance=..50]');
|
||||||
|
await bot.chat('/kill @e[type=mooshroom,distance=..50]');
|
||||||
|
await bot.chat('/kill @e[type=pig,distance=..50]');
|
||||||
|
await bot.chat('/kill @e[type=rabbit,distance=..50]');
|
||||||
|
await bot.chat('/kill @e[type=sheep,distance=..50]');
|
||||||
|
|
||||||
|
await bot.chat(`/kill @e[type=item,distance=..50]`);
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
// Summon new animals
|
||||||
|
const summonAnimals = async () => {
|
||||||
|
const animals = ['chicken', 'cow', 'llama', 'mooshroom', 'pig', 'rabbit', 'sheep'];
|
||||||
|
for (const animal of animals) {
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
const x = position.x - 25 + Math.random() * 50;
|
||||||
|
const z = position.z - 25 + Math.random() * 50;
|
||||||
|
await bot.chat(`/summon ${animal} ${Math.floor(x)} ${position.y} ${Math.floor(z)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await summonAnimals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +1,138 @@
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { executeCommand } from './commands/index.js';
|
import { executeCommand } from './commands/index.js';
|
||||||
import { getPosition } from './library/world.js'
|
import { getPosition } from './library/world.js';
|
||||||
import settings from '../../settings.js';
|
import settings from '../../settings.js';
|
||||||
import { Vec3 } from 'vec3';
|
import { Vec3 } from 'vec3';
|
||||||
import { ConstructionTaskValidator, Blueprint } from './construction_tasks.js';
|
import { ConstructionTaskValidator, Blueprint } from './construction_tasks.js';
|
||||||
import {autoBuild, autoDelete} from "../../test/test_blueprint_layout.js";
|
import {autoBuild, autoDelete} from "../../test/test_blueprint_layout.js";
|
||||||
|
import { CookingTaskInitiator } from './task_types/cooking_tasks.js';
|
||||||
|
|
||||||
//todo: modify validator code to return an object with valid and score -> do more testing hahah
|
//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
|
//todo: figure out how to log these things to the same place as bots/histories
|
||||||
export class CraftTaskValidator {
|
// export class CraftTaskValidator {
|
||||||
constructor(data, agent) {
|
// constructor(data, agent) {
|
||||||
this.target = data.target;
|
// this.target = data.target;
|
||||||
this.number_of_target = data.number_of_target;
|
// this.number_of_target = data.number_of_target;
|
||||||
this.agent = agent;
|
// this.agent = agent;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the presence of required items in an agent's inventory
|
||||||
|
* @param {Object} data - Task data containing target and quantity information
|
||||||
|
* @param {Object} agent - Agent object with bot inventory
|
||||||
|
* @returns {Object} Validation result with success status and missing items
|
||||||
|
*/
|
||||||
|
function checkItemPresence(data, agent) {
|
||||||
|
// Helper function to check if target is a dictionary with quantities
|
||||||
|
function isTargetDictionaryWithQuantities(target) {
|
||||||
|
return typeof target === 'object' &&
|
||||||
|
!Array.isArray(target) &&
|
||||||
|
target !== null &&
|
||||||
|
Object.values(target).every(value => typeof value === 'number');
|
||||||
}
|
}
|
||||||
|
|
||||||
validate() {
|
// Convert any target format into a standardized dictionary
|
||||||
try{
|
function normalizeTargets(target) {
|
||||||
let valid = false;
|
if (typeof target === 'string') {
|
||||||
let total_targets = 0;
|
// Single target case
|
||||||
this.agent.bot.inventory.slots.forEach((slot) => {
|
return { [target]: 1 };
|
||||||
if (slot && slot.name.toLowerCase() === this.target) {
|
} else if (Array.isArray(target)) {
|
||||||
total_targets += slot.count;
|
// Array case - convert to dictionary with default quantity 1
|
||||||
}
|
return target.reduce((acc, item) => {
|
||||||
if (slot && slot.name.toLowerCase() === this.target && slot.count >= this.number_of_target) {
|
acc[item] = 1;
|
||||||
valid = true;
|
return acc;
|
||||||
console.log('Task is complete');
|
}, {});
|
||||||
}
|
} else if (typeof target === 'object' && target !== null) {
|
||||||
});
|
// Already a dictionary - return as is
|
||||||
if (total_targets >= this.number_of_target) {
|
return target;
|
||||||
valid = true;
|
|
||||||
console.log('Task is complete');
|
|
||||||
}
|
|
||||||
return valid;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error validating task:', error);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
throw new Error('Invalid target format');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize quantities to match target format
|
||||||
|
function normalizeQuantities(targets, quantities) {
|
||||||
|
if (quantities === undefined) {
|
||||||
|
// If no quantities specified, default to 1 for each target
|
||||||
|
return Object.keys(targets).reduce((acc, key) => {
|
||||||
|
acc[key] = 1;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
} else if (typeof quantities === 'number') {
|
||||||
|
// If single number provided, apply to all targets
|
||||||
|
return Object.keys(targets).reduce((acc, key) => {
|
||||||
|
acc[key] = quantities;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
} else if (typeof quantities === 'object' && quantities !== null) {
|
||||||
|
// If quantities dictionary provided, use it directly
|
||||||
|
return quantities;
|
||||||
|
}
|
||||||
|
throw new Error('Invalid number_of_target format');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// First normalize targets to always have a consistent format
|
||||||
|
const targets = normalizeTargets(data.target);
|
||||||
|
|
||||||
|
// Determine the required quantities
|
||||||
|
const requiredQuantities = isTargetDictionaryWithQuantities(data.target)
|
||||||
|
? data.target
|
||||||
|
: normalizeQuantities(targets, data.number_of_target);
|
||||||
|
|
||||||
|
// Count items in inventory
|
||||||
|
const inventoryCount = {};
|
||||||
|
agent.bot.inventory.slots.forEach((slot) => {
|
||||||
|
if (slot) {
|
||||||
|
const itemName = slot.name.toLowerCase();
|
||||||
|
inventoryCount[itemName] = (inventoryCount[itemName] || 0) + slot.count;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if all required items are present in sufficient quantities
|
||||||
|
const missingItems = [];
|
||||||
|
let allTargetsMet = true;
|
||||||
|
|
||||||
|
for (const [item, requiredCount] of Object.entries(requiredQuantities)) {
|
||||||
|
const itemName = item.toLowerCase();
|
||||||
|
const currentCount = inventoryCount[itemName] || 0;
|
||||||
|
|
||||||
|
if (currentCount < requiredCount) {
|
||||||
|
allTargetsMet = false;
|
||||||
|
missingItems.push({
|
||||||
|
item: itemName,
|
||||||
|
required: requiredCount,
|
||||||
|
current: currentCount,
|
||||||
|
missing: requiredCount - currentCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: allTargetsMet,
|
||||||
|
missingItems: missingItems
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error checking item presence:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
missingItems: [],
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CookingCraftingTaskValidator {
|
||||||
|
constructor(data, agent) {
|
||||||
|
this.data = data;
|
||||||
|
this.agent = agent;
|
||||||
|
}
|
||||||
|
validate() {
|
||||||
|
const result = checkItemPresence(this.data, this.agent);
|
||||||
|
return {
|
||||||
|
"valid": result.success,
|
||||||
|
"score": result.success ? 1 : 0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +145,7 @@ export class Task {
|
||||||
this.validator = null;
|
this.validator = null;
|
||||||
this.reset_function = null;
|
this.reset_function = null;
|
||||||
this.blocked_actions = [];
|
this.blocked_actions = [];
|
||||||
|
this.task_id = task_id;
|
||||||
if (task_path && task_id) {
|
if (task_path && task_id) {
|
||||||
this.data = this.loadTask(task_path, task_id);
|
this.data = this.loadTask(task_path, task_id);
|
||||||
this.task_type = this.data.type;
|
this.task_type = this.data.type;
|
||||||
|
@ -65,10 +162,13 @@ export class Task {
|
||||||
|
|
||||||
if (this.task_type === 'construction') {
|
if (this.task_type === 'construction') {
|
||||||
this.validator = new ConstructionTaskValidator(this.data, this.agent);
|
this.validator = new ConstructionTaskValidator(this.data, this.agent);
|
||||||
} else if (this.task_type === 'techtree') {
|
} else if (this.task_type === 'cooking' || this.task_type === 'techtree') {
|
||||||
this.validator = new CraftTaskValidator(this.data, this.agent);
|
this.validator = new CookingCraftingTaskValidator(this.data, this.agent);
|
||||||
|
} else {
|
||||||
|
this.validator = null;
|
||||||
}
|
}
|
||||||
this.blocked_actions = this.data.blocked_actions || [];
|
|
||||||
|
|
||||||
if (this.data.blocked_actions) {
|
if (this.data.blocked_actions) {
|
||||||
this.blocked_actions = this.data.blocked_actions[this.agent.count_id.toString()] || [];
|
this.blocked_actions = this.data.blocked_actions[this.agent.count_id.toString()] || [];
|
||||||
} else {
|
} else {
|
||||||
|
@ -81,6 +181,34 @@ export class Task {
|
||||||
this.blocked_actions.push('!endConversation');
|
this.blocked_actions.push('!endConversation');
|
||||||
console.log('Task loaded:', this.data);
|
console.log('Task loaded:', this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.name = this.agent.name;
|
||||||
|
this.available_agents = settings.profiles.map((p) => JSON.parse(readFileSync(p, 'utf8')).name);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAgentGoal() {
|
||||||
|
if (!this.data || !this.data.goal) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let add_string = '';
|
||||||
|
|
||||||
|
if (this.task_type === 'cooking') {
|
||||||
|
add_string = '\nIn the end, all the food should be given to Andy.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If goal is a string, all agents share the same goal
|
||||||
|
if (typeof this.data.goal === 'string') {
|
||||||
|
return this.data.goal + add_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If goal is an object, get the goal for this agent's count_id
|
||||||
|
if (typeof this.data.goal === 'object' && this.data.goal !== null) {
|
||||||
|
const agentId = this.agent.count_id.toString();
|
||||||
|
return (this.data.goal[agentId] || '') + add_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTask(task_path, task_id) {
|
loadTask(task_path, task_id) {
|
||||||
|
@ -104,83 +232,140 @@ export class Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
isDone() {
|
isDone() {
|
||||||
if (this.validator && this.validator.validate())
|
let res = null;
|
||||||
return {"message": 'Task successful', "code": 2};
|
if (this.validator)
|
||||||
|
res = this.validator.validate();
|
||||||
|
if (res && res.valid) {
|
||||||
|
return {"message": 'Task successful', "score": res.score};
|
||||||
|
}
|
||||||
|
let other_names = this.available_agents.filter(n => n !== this.name);
|
||||||
|
const elapsedTime = (Date.now() - this.taskStartTime) / 1000;
|
||||||
|
|
||||||
|
if (elapsedTime >= 30 && this.available_agents.length !== this.data.agent_count) {
|
||||||
|
console.log('No other agents found. Task unsuccessful.');
|
||||||
|
return {"message": 'No other agents found', "score": 0};
|
||||||
|
}
|
||||||
|
|
||||||
if (this.taskTimeout) {
|
if (this.taskTimeout) {
|
||||||
const elapsedTime = (Date.now() - this.taskStartTime) / 1000;
|
|
||||||
if (elapsedTime >= this.taskTimeout) {
|
if (elapsedTime >= this.taskTimeout) {
|
||||||
console.log('Task timeout reached. Task unsuccessful.');
|
console.log('Task timeout reached. Task unsuccessful.');
|
||||||
return {"message": 'Task timeout reached', "code": 4};
|
if (res) {
|
||||||
|
return {"message": 'Task timeout reached', "score": res.score};
|
||||||
|
} else {
|
||||||
|
return {"message": 'Task timeout reached', "score": 0};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async initBotTask() {
|
||||||
|
await this.agent.bot.chat(`/clear ${this.name}`);
|
||||||
|
console.log(`Cleared ${this.name}'s inventory.`);
|
||||||
|
|
||||||
|
|
||||||
initBotTask = async () => {
|
|
||||||
if (this.data === null)
|
|
||||||
return;
|
|
||||||
let bot = this.agent.bot;
|
|
||||||
let name = this.agent.name;
|
|
||||||
|
|
||||||
bot.chat(`/clear ${name}`);
|
|
||||||
console.log(`Cleared ${name}'s inventory.`);
|
|
||||||
|
|
||||||
//kill all drops
|
|
||||||
if (this.agent.count_id === 0) {
|
|
||||||
bot.chat(`/kill @e[type=item]`);
|
|
||||||
}
|
|
||||||
//wait for a bit so inventory is cleared
|
//wait for a bit so inventory is cleared
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
let initial_inventory = null;
|
|
||||||
if (this.data.agent_count > 1) {
|
if (this.data === null)
|
||||||
initial_inventory = this.data.initial_inventory[this.agent.count_id.toString()];
|
return;
|
||||||
console.log("Initial inventory:", initial_inventory);
|
|
||||||
} else if (this.data) {
|
if (this.task_type === 'cooking') {
|
||||||
console.log("Initial inventory:", this.data.initial_inventory);
|
this.initiator = new CookingTaskInitiator(this.data, this.agent);
|
||||||
initial_inventory = this.data.initial_inventory;
|
} else {
|
||||||
|
this.initiator = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("initial_inventory" in this.data) {
|
await this.teleportBots();
|
||||||
|
|
||||||
|
//wait for a bit so bots are teleported
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
|
|
||||||
|
if (this.data.initial_inventory) {
|
||||||
console.log("Setting inventory...");
|
console.log("Setting inventory...");
|
||||||
console.log("Inventory to set:", initial_inventory);
|
let initialInventory = {};
|
||||||
for (let key of Object.keys(initial_inventory)) {
|
|
||||||
console.log('Giving item:', key);
|
// Handle multi-agent inventory assignment
|
||||||
bot.chat(`/give ${name} ${key} ${initial_inventory[key]}`);
|
if (this.data.agent_count > 1) {
|
||||||
};
|
initialInventory = this.data.initial_inventory[this.agent.count_id.toString()] || {};
|
||||||
//wait for a bit so inventory is set
|
console.log("Initial inventory for agent", this.agent.count_id, ":", initialInventory);
|
||||||
|
} else {
|
||||||
|
initialInventory = this.data.initial_inventory;
|
||||||
|
console.log("Initial inventory:", initialInventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign inventory items
|
||||||
|
for (let key of Object.keys(initialInventory)) {
|
||||||
|
const itemName = key.toLowerCase();
|
||||||
|
const quantity = initialInventory[key];
|
||||||
|
await this.agent.bot.chat(`/give ${this.name} ${itemName} ${quantity}`);
|
||||||
|
console.log(`Gave ${this.name} ${quantity} ${itemName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait briefly for inventory commands to complete
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
console.log("Done giving inventory items.");
|
|
||||||
}
|
}
|
||||||
// Function to generate random numbers
|
|
||||||
|
if (this.initiator) {
|
||||||
|
await this.initiator.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.data.agent_count && this.data.agent_count > 1) {
|
||||||
|
// TODO wait for other bots to join
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 10000));
|
||||||
|
if (this.available_agents.length < this.data.agent_count) {
|
||||||
|
console.log(`Missing ${this.data.agent_count - this.available_agents.length} bot(s).`);
|
||||||
|
this.agent.killAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.data.conversation && this.agent.count_id === 0) {
|
||||||
|
let other_name = this.available_agents.filter(n => n !== this.name)[0];
|
||||||
|
let waitCount = 0;
|
||||||
|
while (other_name === undefined && waitCount < 20) {
|
||||||
|
other_name = this.available_agents.filter(n => n !== this.name)[0];
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
waitCount++;
|
||||||
|
}
|
||||||
|
if (other_name === undefined) {
|
||||||
|
console.log('No other agents found. Task unsuccessful.');
|
||||||
|
this.agent.killAll();
|
||||||
|
}
|
||||||
|
await executeCommand(this.agent, `!startConversation("${other_name}", "${this.data.conversation}")`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const agentGoal = this.getAgentGoal();
|
||||||
|
console.log(`Agent goal for agent Id ${this.agent.count_id}: ${agentGoal}`);
|
||||||
|
if (agentGoal) {
|
||||||
|
console.log(`Setting goal for agent ${this.agent.count_id}: ${agentGoal}`);
|
||||||
|
await executeCommand(this.agent, `!goal("${agentGoal}")`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async teleportBots() {
|
||||||
|
console.log('\n\n\n\n\nTeleporting bots');
|
||||||
function getRandomOffset(range) {
|
function getRandomOffset(range) {
|
||||||
return Math.floor(Math.random() * (range * 2 + 1)) - range;
|
return Math.floor(Math.random() * (range * 2 + 1)) - range;
|
||||||
}
|
}
|
||||||
|
|
||||||
let human_player_name = null;
|
let human_player_name = null;
|
||||||
let available_agents = settings.profiles.map((p) => JSON.parse(readFileSync(p, 'utf8')).name); // TODO this does not work with command line args
|
let bot = this.agent.bot;
|
||||||
|
|
||||||
// Finding if there is a human player on the server
|
// Finding if there is a human player on the server
|
||||||
for (const playerName in bot.players) {
|
for (const playerName in bot.players) {
|
||||||
const player = bot.players[playerName];
|
const player = bot.players[playerName];
|
||||||
if (!available_agents.some((n) => n === playerName)) {
|
if (!this.available_agents.some((n) => n === playerName)) {
|
||||||
console.log('Found human player:', player.username);
|
console.log('Found human player:', player.username);
|
||||||
human_player_name = player.username
|
human_player_name = player.username
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are multiple human players, teleport to the first one
|
|
||||||
|
|
||||||
// teleport near a human player if found by default
|
|
||||||
|
|
||||||
if (human_player_name) {
|
if (human_player_name) {
|
||||||
console.log(`Teleporting ${name} to human ${human_player_name}`)
|
console.log(`Teleporting ${this.name} to human ${human_player_name}`)
|
||||||
bot.chat(`/tp ${name} ${human_player_name}`) // teleport on top of the human player
|
bot.chat(`/tp ${this.name} ${human_player_name}`)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||||
|
|
||||||
// now all bots are teleport on top of each other (which kinda looks ugly)
|
// now all bots are teleport on top of each other (which kinda looks ugly)
|
||||||
|
@ -194,33 +379,24 @@ export class Task {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (this.data.type !== 'construction') {
|
if (this.data.type !== 'construction') {
|
||||||
const pos = getPosition(bot);
|
const pos = getPosition(bot);
|
||||||
const xOffset = getRandomOffset(5);
|
const xOffset = getRandomOffset(5);
|
||||||
const zOffset = getRandomOffset(5);
|
const zOffset = getRandomOffset(5);
|
||||||
bot.chat(`/tp ${name} ${Math.floor(pos.x + xOffset)} ${pos.y + 3} ${Math.floor(pos.z + zOffset)}`);
|
bot.chat(`/tp ${this.name} ${Math.floor(pos.x + xOffset)} ${pos.y + 3} ${Math.floor(pos.z + zOffset)}`);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.data.agent_count && this.data.agent_count > 1) {
|
if (this.data.agent_count && this.data.agent_count > 1) {
|
||||||
// TODO wait for other bots to join
|
// TODO wait for other bots to join
|
||||||
await new Promise((resolve) => setTimeout(resolve, 10000));
|
await new Promise((resolve) => setTimeout(resolve, 10000));
|
||||||
if (available_agents.length < this.data.agent_count) {
|
if (this.available_agents.length < this.data.agent_count) {
|
||||||
console.log(`Missing ${this.data.agent_count - available_agents.length} bot(s).`);
|
console.log(`Missing ${this.data.agent_count - this.available_agents.length} bot(s).`);
|
||||||
this.agent.killAll();
|
this.agent.killAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.goal) {
|
|
||||||
console.log('Setting goal:', this.goal);
|
|
||||||
await executeCommand(this.agent, `!goal("${this.goal}")`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.conversation && this.agent.count_id === 0) {
|
|
||||||
let other_name = available_agents.filter(n => n !== name)[0];
|
|
||||||
await executeCommand(this.agent, `!startConversation("${other_name}", "${this.conversation}")`);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (this.data.type === 'construction'){
|
if (this.data.type === 'construction'){
|
||||||
//Ensures construction is cleaned out first. -> relies on cheats which are turned off?
|
//Ensures construction is cleaned out first. -> relies on cheats which are turned off?
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { Qwen } from "./qwen.js";
|
||||||
import { Grok } from "./grok.js";
|
import { Grok } from "./grok.js";
|
||||||
import { DeepSeek } from './deepseek.js';
|
import { DeepSeek } from './deepseek.js';
|
||||||
import { OpenRouter } from './openrouter.js';
|
import { OpenRouter } from './openrouter.js';
|
||||||
|
import { VLLM } from './vllm.js';
|
||||||
|
|
||||||
export class Prompter {
|
export class Prompter {
|
||||||
constructor(agent, fp) {
|
constructor(agent, fp) {
|
||||||
|
@ -181,6 +182,8 @@ export class Prompter {
|
||||||
model = new DeepSeek(profile.model, profile.url, profile.params);
|
model = new DeepSeek(profile.model, profile.url, profile.params);
|
||||||
else if (profile.api === 'openrouter')
|
else if (profile.api === 'openrouter')
|
||||||
model = new OpenRouter(profile.model.replace('openrouter/', ''), profile.url, profile.params);
|
model = new OpenRouter(profile.model.replace('openrouter/', ''), profile.url, profile.params);
|
||||||
|
else if (profile.api === 'vllm')
|
||||||
|
model = new VLLM(profile.model, profile.url, profile.params);
|
||||||
else
|
else
|
||||||
throw new Error('Unknown API:', profile.api);
|
throw new Error('Unknown API:', profile.api);
|
||||||
return model;
|
return model;
|
||||||
|
|
54
src/models/vllm.js
Normal file
54
src/models/vllm.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// This code uses Dashscope and HTTP to ensure the latest support for the Qwen model.
|
||||||
|
// Qwen is also compatible with the OpenAI API format;
|
||||||
|
|
||||||
|
import OpenAIApi from 'openai';
|
||||||
|
import { getKey, hasKey } from '../utils/keys.js';
|
||||||
|
|
||||||
|
export class VLLM {
|
||||||
|
constructor(model_name, url) {
|
||||||
|
this.model_name = model_name;
|
||||||
|
|
||||||
|
// Currently use self-hosted SGLang API for text generation; use OpenAI text-embedding-3-small model for simple embedding.
|
||||||
|
let vllm_config = {};
|
||||||
|
if (url)
|
||||||
|
vllm_config.baseURL = url;
|
||||||
|
else
|
||||||
|
vllm_config.baseURL = 'http://0.0.0.0:8000/v1';
|
||||||
|
|
||||||
|
vllm_config.apiKey = ""
|
||||||
|
|
||||||
|
this.vllm = new OpenAIApi(vllm_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendRequest(turns, systemMessage, stop_seq = '***') {
|
||||||
|
let messages = [{ 'role': 'system', 'content': systemMessage }].concat(turns);
|
||||||
|
|
||||||
|
const pack = {
|
||||||
|
model: this.model_name || "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
|
||||||
|
messages,
|
||||||
|
stop: stop_seq,
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = null;
|
||||||
|
try {
|
||||||
|
console.log('Awaiting openai api response...')
|
||||||
|
// console.log('Messages:', messages);
|
||||||
|
let completion = await this.vllm.chat.completions.create(pack);
|
||||||
|
if (completion.choices[0].finish_reason == 'length')
|
||||||
|
throw new Error('Context length exceeded');
|
||||||
|
console.log('Received.')
|
||||||
|
res = completion.choices[0].message.content;
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if ((err.message == 'Context length exceeded' || err.code == 'context_length_exceeded') && turns.length > 1) {
|
||||||
|
console.log('Context length exceeded, trying again with shorter context.');
|
||||||
|
return await this.sendRequest(turns.slice(1), systemMessage, stop_seq);
|
||||||
|
} else {
|
||||||
|
console.log(err);
|
||||||
|
res = 'My brain disconnected, try again.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
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
Loading…
Add table
Reference in a new issue