plancraft 0.4.2__py3-none-any.whl → 0.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plancraft/environment/env.py +2 -3
- plancraft/environment/sampler.py +10 -4
- plancraft/mcp.py +429 -0
- plancraft/simple_evaluator.py +0 -0
- {plancraft-0.4.2.dist-info → plancraft-0.4.3.dist-info}/METADATA +1 -1
- {plancraft-0.4.2.dist-info → plancraft-0.4.3.dist-info}/RECORD +8 -9
- plancraft/data/test.curriculum.json +0 -580
- plancraft/data/train.curriculum.json +0 -1145
- plancraft/data/val.curriculum.json +0 -570
- {plancraft-0.4.2.dist-info → plancraft-0.4.3.dist-info}/WHEEL +0 -0
- {plancraft-0.4.2.dist-info → plancraft-0.4.3.dist-info}/licenses/LICENSE +0 -0
plancraft/environment/env.py
CHANGED
@@ -323,12 +323,11 @@ class PlancraftEnvironment:
|
|
323
323
|
# not enough
|
324
324
|
if self.slot_empty(slot_from) or self.state[slot_from]["quantity"] < quantity:
|
325
325
|
return
|
326
|
-
# if craft slot -
|
326
|
+
# if craft slot - move takes all
|
327
327
|
if slot_from == 0 and self.state[slot_from]["quantity"] != quantity:
|
328
|
-
|
328
|
+
quantity = self.state[slot_from]["quantity"]
|
329
329
|
|
330
330
|
item = self.state[slot_from]
|
331
|
-
|
332
331
|
# slot to is not empty or is the same type as item
|
333
332
|
if self.slot_empty(slot_to):
|
334
333
|
# add quantity to new slot
|
plancraft/environment/sampler.py
CHANGED
@@ -110,17 +110,21 @@ def sample_recipes(
|
|
110
110
|
return start_inputs, overall_exclude_set
|
111
111
|
|
112
112
|
|
113
|
-
def remove_ancestor_items(
|
113
|
+
def remove_ancestor_items(
|
114
|
+
target: str, inventory: dict[str, int]
|
115
|
+
) -> tuple[dict[str, int], list[tuple[str, int]]]:
|
114
116
|
ancestors = set(get_ancestors(target))
|
115
117
|
possible_items = set(inventory.keys())
|
116
118
|
items_to_remove = list(ancestors.intersection(possible_items))
|
117
119
|
num_items = random.randint(1, len(items_to_remove))
|
120
|
+
removed_items = []
|
118
121
|
for item in random.sample(items_to_remove, num_items):
|
119
122
|
count_to_remove = random.randint(1, inventory[item])
|
120
123
|
inventory[item] -= count_to_remove
|
121
124
|
if inventory[item] == 0:
|
122
125
|
del inventory[item]
|
123
|
-
|
126
|
+
removed_items.append((item, count_to_remove))
|
127
|
+
return inventory, removed_items
|
124
128
|
|
125
129
|
|
126
130
|
def construct_example(
|
@@ -142,9 +146,10 @@ def construct_example(
|
|
142
146
|
|
143
147
|
# sample the recipe
|
144
148
|
inventory, overall_exclude_set = sample_recipes(target, set())
|
149
|
+
removed_items = []
|
145
150
|
if impossible:
|
146
151
|
# if impossible then remove one or more items from the inventory
|
147
|
-
inventory = remove_ancestor_items(
|
152
|
+
inventory, removed_items = remove_ancestor_items(
|
148
153
|
target,
|
149
154
|
inventory,
|
150
155
|
)
|
@@ -158,7 +163,7 @@ def construct_example(
|
|
158
163
|
while (optimal_path is not None and impossible) or (
|
159
164
|
optimal_path is None and not impossible
|
160
165
|
):
|
161
|
-
inventory = remove_ancestor_items(target, inventory)
|
166
|
+
inventory, removed_items = remove_ancestor_items(target, inventory)
|
162
167
|
optimal_path = optimal_planner(target, inventory)
|
163
168
|
|
164
169
|
# assign to slots
|
@@ -169,6 +174,7 @@ def construct_example(
|
|
169
174
|
"target": target,
|
170
175
|
"num_distractors": num_distractors,
|
171
176
|
"impossible": impossible,
|
177
|
+
"missing_items": removed_items,
|
172
178
|
}
|
173
179
|
# either impossible and no path or not impossible and path exists
|
174
180
|
assert (impossible and optimal_path is None) or (
|
plancraft/mcp.py
ADDED
@@ -0,0 +1,429 @@
|
|
1
|
+
import base64
|
2
|
+
import csv
|
3
|
+
import os
|
4
|
+
import random
|
5
|
+
from collections.abc import AsyncIterator
|
6
|
+
from contextlib import asynccontextmanager
|
7
|
+
from dataclasses import dataclass, field
|
8
|
+
from typing import Any, Literal, Optional
|
9
|
+
|
10
|
+
from loguru import logger
|
11
|
+
from PIL import Image as PILImage
|
12
|
+
from plancraft.config import PlancraftExample
|
13
|
+
from plancraft.environment.actions import (
|
14
|
+
MoveAction,
|
15
|
+
SmeltAction,
|
16
|
+
StopAction,
|
17
|
+
)
|
18
|
+
from plancraft.environment.env import (
|
19
|
+
PlancraftEnvironment,
|
20
|
+
get_objective_str,
|
21
|
+
target_and_inventory_to_text_obs,
|
22
|
+
)
|
23
|
+
from plancraft.simple import get_plancraft_examples
|
24
|
+
|
25
|
+
from mcp.server.fastmcp import Context, FastMCP
|
26
|
+
from mcp.types import CallToolResult, ImageContent, TextContent
|
27
|
+
|
28
|
+
|
29
|
+
class PlancraftMCPWrapper:
|
30
|
+
def __init__(
|
31
|
+
self,
|
32
|
+
example: PlancraftExample,
|
33
|
+
max_steps: int = 30,
|
34
|
+
resolution: str = "high",
|
35
|
+
use_text_inventory: bool = True,
|
36
|
+
):
|
37
|
+
self.max_steps = max_steps
|
38
|
+
# whether to convert the inventory to text observation
|
39
|
+
# if False, only the objective string is returned
|
40
|
+
self.use_text_inventory = use_text_inventory
|
41
|
+
self.current_step = 0
|
42
|
+
self.stopped = False
|
43
|
+
self.success = False
|
44
|
+
self.example = example
|
45
|
+
self.resolution = resolution
|
46
|
+
self.environment = PlancraftEnvironment(
|
47
|
+
example.slotted_inventory, resolution=self.resolution
|
48
|
+
)
|
49
|
+
|
50
|
+
def check_done(self, inventory: dict, target: str):
|
51
|
+
"""
|
52
|
+
Check that target object is obtained
|
53
|
+
"""
|
54
|
+
for slot, item in inventory.items():
|
55
|
+
# ensure the target is in the inventory (not in slot 0)
|
56
|
+
if target == item["type"] and slot != 0:
|
57
|
+
return True
|
58
|
+
return False
|
59
|
+
|
60
|
+
def step(
|
61
|
+
self, action: Optional[StopAction | MoveAction | SmeltAction] = None
|
62
|
+
) -> tuple[dict[str, Any], bool]:
|
63
|
+
# Handle already stopped case
|
64
|
+
if self.stopped:
|
65
|
+
return (
|
66
|
+
{"text": "Plancraft environment is terminated"},
|
67
|
+
True,
|
68
|
+
)
|
69
|
+
|
70
|
+
# Handle initial step
|
71
|
+
if not action:
|
72
|
+
observation = self.environment.step()
|
73
|
+
observation["target"] = self.example.target
|
74
|
+
if self.use_text_inventory:
|
75
|
+
text = target_and_inventory_to_text_obs(
|
76
|
+
target=self.example.target, inventory=observation["inventory"]
|
77
|
+
)
|
78
|
+
else:
|
79
|
+
text = get_objective_str(self.example.target)
|
80
|
+
observation["text"] = text
|
81
|
+
return observation, self.stopped
|
82
|
+
|
83
|
+
# Handle max steps reached
|
84
|
+
if self.current_step > self.max_steps:
|
85
|
+
self.stopped = True
|
86
|
+
return (
|
87
|
+
{"text": f"Max steps ({self.max_steps}) reached"},
|
88
|
+
self.stopped,
|
89
|
+
)
|
90
|
+
|
91
|
+
self.current_step += 1
|
92
|
+
# Handle stop action
|
93
|
+
if isinstance(action, StopAction):
|
94
|
+
self.stopped = True
|
95
|
+
# success is True if example was truly impossible
|
96
|
+
self.success = self.example.impossible
|
97
|
+
observation = {
|
98
|
+
"text": "Plancraft environment is terminate due to stop action"
|
99
|
+
}
|
100
|
+
else:
|
101
|
+
observation = self.environment.step(action)
|
102
|
+
observation["target"] = self.example.target
|
103
|
+
|
104
|
+
# Generate text observation
|
105
|
+
if self.use_text_inventory:
|
106
|
+
text = target_and_inventory_to_text_obs(
|
107
|
+
target=self.example.target, inventory=observation["inventory"]
|
108
|
+
)
|
109
|
+
else:
|
110
|
+
text = get_objective_str(self.example.target)
|
111
|
+
|
112
|
+
observation["text"] = text
|
113
|
+
|
114
|
+
self.success = self.check_done(
|
115
|
+
observation["inventory"], self.example.target
|
116
|
+
)
|
117
|
+
|
118
|
+
return (
|
119
|
+
observation,
|
120
|
+
self.stopped,
|
121
|
+
)
|
122
|
+
|
123
|
+
|
124
|
+
@dataclass
|
125
|
+
class PlancraftContext:
|
126
|
+
"""Context for the Plancraft environment."""
|
127
|
+
|
128
|
+
env: Optional[Any] = None
|
129
|
+
examples: list[PlancraftExample] = field(default_factory=list)
|
130
|
+
|
131
|
+
# Default environment settings
|
132
|
+
max_steps: int = 30
|
133
|
+
resolution: Literal["high", "low"] = "high"
|
134
|
+
use_text_inventory: bool = True
|
135
|
+
terminated: bool = False
|
136
|
+
use_images: bool = False
|
137
|
+
|
138
|
+
# history and statistics
|
139
|
+
history: list[dict] = field(default_factory=list)
|
140
|
+
|
141
|
+
|
142
|
+
@asynccontextmanager
|
143
|
+
async def app_lifespan(server: FastMCP) -> AsyncIterator[PlancraftContext]:
|
144
|
+
"""Manage application lifecycle with type-safe context"""
|
145
|
+
# Initialize on startup
|
146
|
+
try:
|
147
|
+
logger.info("Starting up")
|
148
|
+
examples = get_plancraft_examples(split="train")
|
149
|
+
yield PlancraftContext(examples=examples)
|
150
|
+
finally:
|
151
|
+
# Cleanup on shutdown
|
152
|
+
logger.info("Shutting down")
|
153
|
+
|
154
|
+
|
155
|
+
# Pass lifespan to server
|
156
|
+
app = FastMCP("Plancraft", lifespan=app_lifespan)
|
157
|
+
|
158
|
+
|
159
|
+
@app.prompt()
|
160
|
+
def plancraft_environment_instructions() -> str:
|
161
|
+
return """You are crafting in Minecraft. You need to decide on the next action.
|
162
|
+
|
163
|
+
Crafting Grid: The crafting table is organized into a 3x3 grid. Each slot in the grid has a unique identifier:
|
164
|
+
- Top row: [A1] [A2] [A3]
|
165
|
+
- Middle row: [B1] [B2] [B3]
|
166
|
+
- Bottom row: [C1] [C2] [C3]
|
167
|
+
|
168
|
+
The output of the crafting process is placed in a designated output slot labeled [0] You cannot move or smelt items directly into slot [0]
|
169
|
+
|
170
|
+
Inventory Slots: The remaining inventory slots (outside of the crafting grid) are used for storing items. These slots are labeled as [I1] to [I36]
|
171
|
+
|
172
|
+
Constraints:
|
173
|
+
- You cannot move or smelt items into [0]
|
174
|
+
- If an item is not in slot [0] then the recipe is incorrect
|
175
|
+
- You need to move items from [0] to a free inventory slot to complete the crafting process"""
|
176
|
+
|
177
|
+
|
178
|
+
def observation_to_tool_result(
|
179
|
+
observation: dict,
|
180
|
+
terminated: bool = False,
|
181
|
+
success: bool = False,
|
182
|
+
add_instructions=False,
|
183
|
+
use_images=False,
|
184
|
+
) -> CallToolResult:
|
185
|
+
content = []
|
186
|
+
if add_instructions:
|
187
|
+
instructions = plancraft_environment_instructions()
|
188
|
+
content.append(TextContent(text=instructions, type="text"))
|
189
|
+
|
190
|
+
text_content = observation["text"]
|
191
|
+
# Add success message if the task was completed successfully
|
192
|
+
if success:
|
193
|
+
text_content = f"SUCCESS! You have completed the task: {text_content}"
|
194
|
+
# Add termination message if the task was terminated but not successful
|
195
|
+
elif terminated:
|
196
|
+
text_content = f"Task terminated: {text_content}"
|
197
|
+
|
198
|
+
content.append(TextContent(text=text_content, type="text"))
|
199
|
+
|
200
|
+
if use_images:
|
201
|
+
# numpy array to PIL
|
202
|
+
pil_image = PILImage.fromarray(observation["image"])
|
203
|
+
# Save the image to a BytesIO buffer in PNG format
|
204
|
+
import io
|
205
|
+
|
206
|
+
buffer = io.BytesIO()
|
207
|
+
pil_image.save(buffer, format="PNG")
|
208
|
+
buffer.seek(0)
|
209
|
+
|
210
|
+
# Encode the properly formatted PNG data
|
211
|
+
base64_data = base64.b64encode(buffer.getvalue()).decode("utf-8")
|
212
|
+
content.append(
|
213
|
+
ImageContent(type="image", data=base64_data, mimeType="image/png")
|
214
|
+
)
|
215
|
+
return CallToolResult(
|
216
|
+
content=content,
|
217
|
+
)
|
218
|
+
|
219
|
+
|
220
|
+
def add_action_to_history(
|
221
|
+
action: MoveAction | SmeltAction | StopAction, result: CallToolResult, ctx: Context
|
222
|
+
) -> None:
|
223
|
+
"""Add action call to history - storing only text content for simplicity"""
|
224
|
+
# Extract only the text content from the result
|
225
|
+
text_content = ""
|
226
|
+
for content in result.content:
|
227
|
+
if hasattr(content, "text"):
|
228
|
+
text_content = content.text
|
229
|
+
break
|
230
|
+
ctx.request_context.lifespan_context.history.append(
|
231
|
+
{"action": str(action), "observation": text_content}
|
232
|
+
)
|
233
|
+
|
234
|
+
|
235
|
+
def save_result_if_terminated(environment, terminated: bool, ctx: Context) -> None:
|
236
|
+
"""Helper function to save results if the environment is terminated"""
|
237
|
+
if terminated:
|
238
|
+
logger.info(f"Task completed or terminated in {environment.current_step} steps")
|
239
|
+
|
240
|
+
result_data = {
|
241
|
+
"example_id": environment.example.id,
|
242
|
+
"success": environment.success,
|
243
|
+
"steps": environment.current_step,
|
244
|
+
"history": ctx.request_context.lifespan_context.history.copy(),
|
245
|
+
}
|
246
|
+
|
247
|
+
# save the result data to a CSV file
|
248
|
+
pwd = os.path.dirname(os.path.abspath(__file__))
|
249
|
+
os.makedirs("results", exist_ok=True)
|
250
|
+
result_file = os.path.join(pwd, "results", "results.csv")
|
251
|
+
with open(result_file, mode="a", newline="") as f:
|
252
|
+
writer = csv.DictWriter(f, fieldnames=result_data.keys())
|
253
|
+
if f.tell() == 0:
|
254
|
+
writer.writeheader()
|
255
|
+
writer.writerow(result_data)
|
256
|
+
|
257
|
+
# Reset history after storing results
|
258
|
+
ctx.request_context.lifespan_context.history = []
|
259
|
+
|
260
|
+
|
261
|
+
def correct_slot_format(slot: str):
|
262
|
+
# helper function to correct the slot format
|
263
|
+
# Claude seems unable to generate slots with brackets
|
264
|
+
if "[" not in slot and "]" not in slot:
|
265
|
+
return f"[{slot}]"
|
266
|
+
|
267
|
+
|
268
|
+
@app.tool(
|
269
|
+
name="smelt",
|
270
|
+
description="Smelt items in the Plancraft environment. You must specify the slot to smelt from and the slot to smelt to and quantity.",
|
271
|
+
)
|
272
|
+
def smelt(from_slot: str, to_slot: str, quantity: int, ctx: Context) -> CallToolResult:
|
273
|
+
"""Smelt items in the Plancraft environment. You must specify the slot to smelt from and the slot to smelt to and quantity."""
|
274
|
+
try:
|
275
|
+
environment = ctx.request_context.lifespan_context.env
|
276
|
+
use_images = ctx.request_context.lifespan_context.use_images
|
277
|
+
|
278
|
+
if environment.stopped:
|
279
|
+
content = "Plancraft environment is terminated, first call start_new_task to start a new task"
|
280
|
+
return CallToolResult(
|
281
|
+
content=[TextContent(text=content, type="text")], isError=True
|
282
|
+
)
|
283
|
+
|
284
|
+
smelt_action = SmeltAction(
|
285
|
+
slot_from=correct_slot_format(from_slot),
|
286
|
+
slot_to=correct_slot_format(to_slot),
|
287
|
+
quantity=quantity,
|
288
|
+
)
|
289
|
+
obs, terminated = environment.step(smelt_action)
|
290
|
+
|
291
|
+
# Generate the result with appropriate success/termination messages
|
292
|
+
result = observation_to_tool_result(
|
293
|
+
obs,
|
294
|
+
terminated=terminated,
|
295
|
+
success=environment.success,
|
296
|
+
use_images=use_images,
|
297
|
+
)
|
298
|
+
add_action_to_history(smelt_action, result, ctx)
|
299
|
+
logger.info(f"Step {environment.current_step}: {obs['text']}")
|
300
|
+
|
301
|
+
# Save result if the task is terminated
|
302
|
+
save_result_if_terminated(environment, terminated, ctx)
|
303
|
+
|
304
|
+
return result
|
305
|
+
except Exception as e:
|
306
|
+
return CallToolResult(
|
307
|
+
content=[TextContent(text=str(e), type="text")], isError=True
|
308
|
+
)
|
309
|
+
|
310
|
+
|
311
|
+
@app.tool(
|
312
|
+
name="move",
|
313
|
+
description="Move items in the Plancraft environment. You must specify the slot to move from and the slot to move to and quantity.",
|
314
|
+
)
|
315
|
+
def move(from_slot: str, to_slot: str, quantity: int, ctx: Context) -> CallToolResult:
|
316
|
+
"""
|
317
|
+
Move items in the Plancraft environment. You must specify the slot to move from and the slot to move to and quantity.
|
318
|
+
"""
|
319
|
+
try:
|
320
|
+
environment = ctx.request_context.lifespan_context.env
|
321
|
+
use_images = ctx.request_context.lifespan_context.use_images
|
322
|
+
if environment.stopped:
|
323
|
+
content = "Plancraft environment is terminated, first call start_new_task to start a new task"
|
324
|
+
return CallToolResult(
|
325
|
+
content=[TextContent(text=content, type="text")], isError=True
|
326
|
+
)
|
327
|
+
|
328
|
+
move_action = MoveAction(
|
329
|
+
slot_from=correct_slot_format(from_slot),
|
330
|
+
slot_to=correct_slot_format(to_slot),
|
331
|
+
quantity=quantity,
|
332
|
+
)
|
333
|
+
obs, terminated = environment.step(move_action)
|
334
|
+
|
335
|
+
# Generresult with appropriate success/termination messages
|
336
|
+
result = observation_to_tool_result(
|
337
|
+
obs,
|
338
|
+
terminated=terminated,
|
339
|
+
success=environment.success,
|
340
|
+
use_images=use_images,
|
341
|
+
)
|
342
|
+
add_action_to_history(move_action, result, ctx)
|
343
|
+
logger.info(f"Step {environment.current_step}: {obs['text']}")
|
344
|
+
|
345
|
+
# Save result if the task is terminated
|
346
|
+
save_result_if_terminated(environment, terminated, ctx)
|
347
|
+
|
348
|
+
return result
|
349
|
+
|
350
|
+
except Exception as e:
|
351
|
+
return CallToolResult(
|
352
|
+
content=[TextContent(text=str(e), type="text")], isError=True
|
353
|
+
)
|
354
|
+
|
355
|
+
|
356
|
+
@app.tool(
|
357
|
+
name="impossible",
|
358
|
+
description="Declare the current task impossible. This will end the current task.",
|
359
|
+
)
|
360
|
+
def impossible_task(reason: str, ctx: Context) -> CallToolResult:
|
361
|
+
"""Declare the current task impossible. This will end the current task."""
|
362
|
+
try:
|
363
|
+
environment = ctx.request_context.lifespan_context.env
|
364
|
+
use_images = ctx.request_context.lifespan_context.use_images
|
365
|
+
stop_action = StopAction(reason=reason)
|
366
|
+
obs, terminated = environment.step(stop_action)
|
367
|
+
|
368
|
+
# Generate the ith appropriate success/termination messages
|
369
|
+
# For impossible action, it's successful if the task was truly impossible
|
370
|
+
result = observation_to_tool_result(
|
371
|
+
obs,
|
372
|
+
terminated=terminated,
|
373
|
+
success=environment.success,
|
374
|
+
use_images=use_images,
|
375
|
+
)
|
376
|
+
add_action_to_history(stop_action, result, ctx)
|
377
|
+
logger.info(f"Step {environment.current_step}: {obs['text']}")
|
378
|
+
|
379
|
+
# Save result if the task is terminated
|
380
|
+
save_result_if_terminated(environment, terminated, ctx)
|
381
|
+
|
382
|
+
return result
|
383
|
+
except Exception as e:
|
384
|
+
return CallToolResult(
|
385
|
+
content=[TextContent(text=str(e), type="text")], isError=True
|
386
|
+
)
|
387
|
+
|
388
|
+
|
389
|
+
@app.tool(
|
390
|
+
name="start_plancraft_task",
|
391
|
+
description="Start a new Plancraft environment (default use_images=False)",
|
392
|
+
)
|
393
|
+
def start_plancraft(use_images: bool, ctx: Context) -> CallToolResult:
|
394
|
+
"""Tool that uses initialized resources"""
|
395
|
+
# Check if there's an existing environment and if it wasn't terminated yet
|
396
|
+
current_env = ctx.request_context.lifespan_context.env
|
397
|
+
if current_env and not current_env.stopped:
|
398
|
+
# Save the current environment state in results before discarding
|
399
|
+
logger.info("Discarding existing incomplete task")
|
400
|
+
# Reset history when starting a new task
|
401
|
+
ctx.request_context.lifespan_context.history = []
|
402
|
+
|
403
|
+
ctx.request_context.lifespan_context.use_images = use_images
|
404
|
+
|
405
|
+
random_idx = random.randint(
|
406
|
+
0, len(ctx.request_context.lifespan_context.examples) - 1
|
407
|
+
)
|
408
|
+
example: PlancraftExample = ctx.request_context.lifespan_context.examples[
|
409
|
+
random_idx
|
410
|
+
]
|
411
|
+
# initialize the environment
|
412
|
+
env = PlancraftMCPWrapper(
|
413
|
+
example=example,
|
414
|
+
max_steps=ctx.request_context.lifespan_context.max_steps,
|
415
|
+
resolution=ctx.request_context.lifespan_context.resolution,
|
416
|
+
use_text_inventory=ctx.request_context.lifespan_context.use_text_inventory,
|
417
|
+
)
|
418
|
+
logger.info(f"Environment initialized with example {example.id}")
|
419
|
+
ctx.request_context.lifespan_context.env = env
|
420
|
+
|
421
|
+
obs, _ = env.step()
|
422
|
+
logger.info(f"Step {env.current_step}: {obs['text']}")
|
423
|
+
|
424
|
+
result = observation_to_tool_result(obs, add_instructions=True)
|
425
|
+
return result
|
426
|
+
|
427
|
+
|
428
|
+
if __name__ == "__main__":
|
429
|
+
app.run()
|
File without changes
|
@@ -2,26 +2,25 @@ plancraft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
plancraft/config.py,sha256=oyn8I_k0Slh-Nyg2javomFertZ5ZHiY_ndAVqfJYQvQ,4010
|
3
3
|
plancraft/evaluator.py,sha256=UQujiltf88rCnbNwoglM5tJe5gW9XASew-jLaEbtJZo,15525
|
4
4
|
plancraft/generate_dataset.py,sha256=DlrU-PmvWqSNJD1g1-8Lpb8n3N-Ogw3rje1nrRzjGKs,2382
|
5
|
+
plancraft/mcp.py,sha256=0DHYAtdgl-CD_oqKpWnTF7L1RdegPK1wU8Naq6dtVIU,15165
|
5
6
|
plancraft/simple.py,sha256=7D_SVT2sbXLnHA98P2E_nxV5VPBKbNpij4hB2ArURxA,7329
|
7
|
+
plancraft/simple_evaluator.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
8
|
plancraft/utils.py,sha256=hCE1oQ-77Me39Vo-sCL7iZPdO-WWYZnBjP41lZWRi20,6339
|
7
|
-
plancraft/data/test.curriculum.json,sha256=_mqIqwcmRCcgVA5fOKK27-y3sJdsW86nEqa6ATdyTeA,875349
|
8
9
|
plancraft/data/test.json,sha256=4jWfYMAVuZCFmGB4iZJAjlh9_8jXECdaGp8xn7_tAM4,1317131
|
9
10
|
plancraft/data/test.small.easy.json,sha256=5NZEJ2PqIgmHQecJOIVQyM1D6GFKyJq7GVmgRudaqQk,189304
|
10
11
|
plancraft/data/test.small.json,sha256=eULAG1rdolRMXPrecV-7YoDIheKGyIT5MVpWdISV0wg,270089
|
11
|
-
plancraft/data/train.curriculum.json,sha256=eOfGusDtGG1BBvTJdzjUdhTHVAfFro_vGyYgKzZuxvE,1787758
|
12
12
|
plancraft/data/train.json,sha256=asZIFnkBdgupPKRXacM4J0Ngt21B2BrMT6oPgFA96HI,2697710
|
13
|
-
plancraft/data/val.curriculum.json,sha256=fso4S2g0kqMk7Ehz6ObQmJHk4wq0gAD2YQm0R8Nb95E,866889
|
14
13
|
plancraft/data/val.json,sha256=IToAiaqUNQi_xhX1bzmInuskLaT7C2ryQjP-CZkzL24,1304403
|
15
14
|
plancraft/data/val.small.easy.json,sha256=9zEmqepjXG2NIp88xnFqOCkwsUsku3HEwHoQGxgTr6U,190252
|
16
15
|
plancraft/data/val.small.json,sha256=76E9EFaljDQyAokg97e-IblvcOe6KbrdKkXvRxhhkgo,237653
|
17
16
|
plancraft/environment/__init__.py,sha256=XFsFny4lH195AwAmL-WeCaF9ZCMgc7IgXIwhQ8FTdgE,505
|
18
17
|
plancraft/environment/actions.py,sha256=Pub21caxM5iZ9IaX-ny1-xxr_peJIwwV_QAx3BVSry0,11551
|
19
|
-
plancraft/environment/env.py,sha256=
|
18
|
+
plancraft/environment/env.py,sha256=B7VpIMcQKITyDmkHgBoR4KbmxmM1b4A6Y-1_b90EMXo,16428
|
20
19
|
plancraft/environment/items.py,sha256=Z9rhSyVDEoHF1pxRvhyiT94tyQJaWHi3wUHVcamz82o,221
|
21
20
|
plancraft/environment/planner.py,sha256=uIOJjIoyT_4pxeWeTKb8BkLJyKZG0-AMoEOkZs6Ua9A,19340
|
22
21
|
plancraft/environment/prompts.py,sha256=NU9YHAz3id-IgaukQvEi5uLlpEstpE5_Hccvvq1At2Y,6950
|
23
22
|
plancraft/environment/recipes.py,sha256=0vwzOU86eZmGN2EpZVSIvzxpx0AOBWNPxTtAOFBN2A0,19570
|
24
|
-
plancraft/environment/sampler.py,sha256=
|
23
|
+
plancraft/environment/sampler.py,sha256=BworSMWQ-TLbV9068tkNOdo4ZLP-UDox6Laeb4Weu9k,7723
|
25
24
|
plancraft/environment/search.py,sha256=z31eEwQBY7WJaYVBEEwulFS8P3h1Nwo1Th9BaCTxk5M,2085
|
26
25
|
plancraft/environment/assets/constants.json,sha256=kyOIOh82CTTMMGEIS60k5k6M-6fkEmYDoGAnvi3Zx5k,1379016
|
27
26
|
plancraft/environment/assets/minecraft_font.ttf,sha256=AzoK9cgggXwjFPHtIO7uz-YaDrminl3nvB-VsaTvTAk,60992
|
@@ -1924,7 +1923,7 @@ plancraft/models/generators.py,sha256=7COMLjjx_HbTWJqINNLqqExQv7gLikfLTViacAdSt5
|
|
1924
1923
|
plancraft/models/oracle.py,sha256=f-0KWlBuHy6wcxmDsxM3MQ_QwfBstzfbA26mlk1MgLA,1657
|
1925
1924
|
plancraft/models/utils.py,sha256=xgkP5jqCeFfkKe3Xd4ZYfTqiEJ-dA-qgFAC-J35ub3E,4029
|
1926
1925
|
plancraft/train/dataset.py,sha256=oFqEd4LG9oEQ-71teh0Wf7-jJbtybT2ZibfM2bBdBkM,5474
|
1927
|
-
plancraft-0.4.
|
1928
|
-
plancraft-0.4.
|
1929
|
-
plancraft-0.4.
|
1930
|
-
plancraft-0.4.
|
1926
|
+
plancraft-0.4.3.dist-info/METADATA,sha256=wyA9iis_caO9cCKd5h5guPpuhRXi0pTkmR0dBXsbaHc,12391
|
1927
|
+
plancraft-0.4.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
1928
|
+
plancraft-0.4.3.dist-info/licenses/LICENSE,sha256=YGR8ehDB4t-T-lOQKMfKNR-2zsOU7E3E5NA8t25HKE0,1070
|
1929
|
+
plancraft-0.4.3.dist-info/RECORD,,
|