synth-ai 0.2.4.dev4__py3-none-any.whl → 0.2.4.dev5__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.
Files changed (104) hide show
  1. synth_ai/environments/examples/__init__.py +1 -0
  2. synth_ai/environments/examples/crafter_classic/__init__.py +8 -0
  3. synth_ai/environments/examples/crafter_classic/config_logging.py +111 -0
  4. synth_ai/environments/examples/crafter_classic/debug_translation.py +0 -0
  5. synth_ai/environments/examples/crafter_classic/engine.py +575 -0
  6. synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +63 -0
  7. synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +5 -0
  8. synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +74 -0
  9. synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +266 -0
  10. synth_ai/environments/examples/crafter_classic/environment.py +364 -0
  11. synth_ai/environments/examples/crafter_classic/taskset.py +233 -0
  12. synth_ai/environments/examples/crafter_classic/trace_hooks_v3.py +229 -0
  13. synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +298 -0
  14. synth_ai/environments/examples/crafter_custom/__init__.py +4 -0
  15. synth_ai/environments/examples/crafter_custom/crafter/__init__.py +7 -0
  16. synth_ai/environments/examples/crafter_custom/crafter/config.py +182 -0
  17. synth_ai/environments/examples/crafter_custom/crafter/constants.py +8 -0
  18. synth_ai/environments/examples/crafter_custom/crafter/engine.py +269 -0
  19. synth_ai/environments/examples/crafter_custom/crafter/env.py +266 -0
  20. synth_ai/environments/examples/crafter_custom/crafter/objects.py +418 -0
  21. synth_ai/environments/examples/crafter_custom/crafter/recorder.py +187 -0
  22. synth_ai/environments/examples/crafter_custom/crafter/worldgen.py +119 -0
  23. synth_ai/environments/examples/crafter_custom/dataset_builder.py +373 -0
  24. synth_ai/environments/examples/crafter_custom/environment.py +312 -0
  25. synth_ai/environments/examples/crafter_custom/run_dataset.py +305 -0
  26. synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +156 -0
  27. synth_ai/environments/examples/enron/art_helpers/local_email_db.py +280 -0
  28. synth_ai/environments/examples/enron/art_helpers/types_enron.py +24 -0
  29. synth_ai/environments/examples/enron/engine.py +291 -0
  30. synth_ai/environments/examples/enron/environment.py +165 -0
  31. synth_ai/environments/examples/enron/taskset.py +112 -0
  32. synth_ai/environments/examples/minigrid/__init__.py +48 -0
  33. synth_ai/environments/examples/minigrid/engine.py +589 -0
  34. synth_ai/environments/examples/minigrid/environment.py +274 -0
  35. synth_ai/environments/examples/minigrid/environment_mapping.py +242 -0
  36. synth_ai/environments/examples/minigrid/puzzle_loader.py +416 -0
  37. synth_ai/environments/examples/minigrid/taskset.py +583 -0
  38. synth_ai/environments/examples/nethack/__init__.py +7 -0
  39. synth_ai/environments/examples/nethack/achievements.py +337 -0
  40. synth_ai/environments/examples/nethack/engine.py +738 -0
  41. synth_ai/environments/examples/nethack/environment.py +255 -0
  42. synth_ai/environments/examples/nethack/helpers/__init__.py +42 -0
  43. synth_ai/environments/examples/nethack/helpers/action_mapping.py +301 -0
  44. synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +401 -0
  45. synth_ai/environments/examples/nethack/helpers/observation_utils.py +433 -0
  46. synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +201 -0
  47. synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +268 -0
  48. synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +308 -0
  49. synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +430 -0
  50. synth_ai/environments/examples/nethack/taskset.py +323 -0
  51. synth_ai/environments/examples/red/__init__.py +7 -0
  52. synth_ai/environments/examples/red/config_logging.py +110 -0
  53. synth_ai/environments/examples/red/engine.py +693 -0
  54. synth_ai/environments/examples/red/engine_helpers/__init__.py +1 -0
  55. synth_ai/environments/examples/red/engine_helpers/memory_map.py +28 -0
  56. synth_ai/environments/examples/red/engine_helpers/reward_components.py +275 -0
  57. synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +142 -0
  58. synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +56 -0
  59. synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +283 -0
  60. synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +149 -0
  61. synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +137 -0
  62. synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +56 -0
  63. synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +330 -0
  64. synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +120 -0
  65. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +558 -0
  66. synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +312 -0
  67. synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +147 -0
  68. synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +246 -0
  69. synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +367 -0
  70. synth_ai/environments/examples/red/engine_helpers/state_extraction.py +139 -0
  71. synth_ai/environments/examples/red/environment.py +235 -0
  72. synth_ai/environments/examples/red/taskset.py +77 -0
  73. synth_ai/environments/examples/sokoban/__init__.py +1 -0
  74. synth_ai/environments/examples/sokoban/engine.py +675 -0
  75. synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +1 -0
  76. synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +656 -0
  77. synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +17 -0
  78. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +3 -0
  79. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +129 -0
  80. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +370 -0
  81. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +331 -0
  82. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +305 -0
  83. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +66 -0
  84. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +114 -0
  85. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +122 -0
  86. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +394 -0
  87. synth_ai/environments/examples/sokoban/environment.py +228 -0
  88. synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +438 -0
  89. synth_ai/environments/examples/sokoban/puzzle_loader.py +311 -0
  90. synth_ai/environments/examples/sokoban/taskset.py +425 -0
  91. synth_ai/environments/examples/tictactoe/__init__.py +1 -0
  92. synth_ai/environments/examples/tictactoe/engine.py +368 -0
  93. synth_ai/environments/examples/tictactoe/environment.py +239 -0
  94. synth_ai/environments/examples/tictactoe/taskset.py +214 -0
  95. synth_ai/environments/examples/verilog/__init__.py +10 -0
  96. synth_ai/environments/examples/verilog/engine.py +328 -0
  97. synth_ai/environments/examples/verilog/environment.py +349 -0
  98. synth_ai/environments/examples/verilog/taskset.py +418 -0
  99. {synth_ai-0.2.4.dev4.dist-info → synth_ai-0.2.4.dev5.dist-info}/METADATA +1 -1
  100. {synth_ai-0.2.4.dev4.dist-info → synth_ai-0.2.4.dev5.dist-info}/RECORD +104 -6
  101. {synth_ai-0.2.4.dev4.dist-info → synth_ai-0.2.4.dev5.dist-info}/WHEEL +0 -0
  102. {synth_ai-0.2.4.dev4.dist-info → synth_ai-0.2.4.dev5.dist-info}/entry_points.txt +0 -0
  103. {synth_ai-0.2.4.dev4.dist-info → synth_ai-0.2.4.dev5.dist-info}/licenses/LICENSE +0 -0
  104. {synth_ai-0.2.4.dev4.dist-info → synth_ai-0.2.4.dev5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,349 @@
1
+ from typing import List, Optional, Any, Dict, Union
2
+ from pydantic import BaseModel
3
+
4
+ from synth_ai.environments.examples.verilog.engine import (
5
+ VerilogEngine,
6
+ VerilogPrivateState,
7
+ VerilogPublicState,
8
+ VerilogEngineSnapshot,
9
+ )
10
+ from synth_ai.environments.environment.shared_engine import (
11
+ GetObservationCallable,
12
+ InternalObservation,
13
+ )
14
+ from synth_ai.environments.stateful.core import StatefulEnvironment
15
+ from synth_ai.environments.tasks.core import TaskInstance
16
+ from synth_ai.environments.environment.tools import (
17
+ AbstractTool,
18
+ EnvToolCall,
19
+ ToolResult,
20
+ TOOL_REGISTRY,
21
+ register_tool,
22
+ )
23
+
24
+
25
+ # Tool Input Schemas
26
+ class WriteFileInput(BaseModel):
27
+ path: str
28
+ content: str
29
+
30
+
31
+ class CompileInput(BaseModel):
32
+ sources: Optional[List[str]] = None
33
+ testbench: Optional[str] = None
34
+
35
+
36
+ class SimulateInput(BaseModel):
37
+ binary: Optional[str] = None
38
+
39
+
40
+ class SubmitInput(BaseModel):
41
+ pass # No arguments needed for submit
42
+
43
+
44
+ # Tool Implementations
45
+ class VerilogWriteFileTool(AbstractTool):
46
+ name = "write_file"
47
+ description = "Write content to a Verilog file"
48
+ call_schema = WriteFileInput
49
+ result_schema = ToolResult
50
+
51
+ def __init__(self, engine: VerilogEngine):
52
+ self.engine = engine
53
+
54
+ async def __call__(self, call: EnvToolCall) -> ToolResult:
55
+ try:
56
+ validated_args = self.call_schema(**call.args)
57
+ result = await self.engine.write_file(validated_args.path, validated_args.content)
58
+ return ToolResult(ok=result["ok"], payload=result)
59
+ except Exception as e:
60
+ return ToolResult(ok=False, error=str(e))
61
+
62
+
63
+ class VerilogCompileTool(AbstractTool):
64
+ name = "compile"
65
+ description = "Compile Verilog sources with iverilog"
66
+ call_schema = CompileInput
67
+ result_schema = ToolResult
68
+
69
+ def __init__(self, engine: VerilogEngine):
70
+ self.engine = engine
71
+
72
+ async def __call__(self, call: EnvToolCall) -> ToolResult:
73
+ try:
74
+ validated_args = self.call_schema(**call.args)
75
+ result = await self.engine.compile(validated_args.sources, validated_args.testbench)
76
+ return ToolResult(ok=result["ok"], payload=result)
77
+ except Exception as e:
78
+ return ToolResult(ok=False, error=str(e))
79
+
80
+
81
+ class VerilogSimulateTool(AbstractTool):
82
+ name = "simulate"
83
+ description = "Run vvp on compiled binary"
84
+ call_schema = SimulateInput
85
+ result_schema = ToolResult
86
+
87
+ def __init__(self, engine: VerilogEngine):
88
+ self.engine = engine
89
+
90
+ async def __call__(self, call: EnvToolCall) -> ToolResult:
91
+ try:
92
+ validated_args = self.call_schema(**call.args)
93
+ result = await self.engine.simulate(validated_args.binary)
94
+ return ToolResult(ok=result["ok"], payload=result)
95
+ except Exception as e:
96
+ return ToolResult(ok=False, error=str(e))
97
+
98
+
99
+ class VerilogSubmitTool(AbstractTool):
100
+ name = "submit"
101
+ description = "Submit solution for grading"
102
+ call_schema = SubmitInput
103
+ result_schema = ToolResult
104
+
105
+ def __init__(self, engine: VerilogEngine):
106
+ self.engine = engine
107
+
108
+ async def __call__(self, call: EnvToolCall) -> ToolResult:
109
+ try:
110
+ result = await self.engine.submit()
111
+ return ToolResult(ok=result["ok"], payload=result)
112
+ except Exception as e:
113
+ return ToolResult(ok=False, error=str(e))
114
+
115
+
116
+ class VerilogObservationCallable(GetObservationCallable):
117
+ async def get_observation(
118
+ self, pub: VerilogPublicState, priv: VerilogPrivateState
119
+ ) -> InternalObservation:
120
+ files_summary = f"{len(pub.files)} Verilog files available"
121
+ if pub.files:
122
+ files_summary += f": {', '.join(pub.files.keys())}"
123
+
124
+ compile_status = ""
125
+ if pub.last_compile_output is not None:
126
+ # Check for common error indicators in compile output
127
+ output_lower = pub.last_compile_output.lower()
128
+ is_success = not any(
129
+ indicator in output_lower for indicator in ["error", "failed", "syntax"]
130
+ )
131
+ if is_success:
132
+ compile_status = "Last compile: Success"
133
+ else:
134
+ # Include the actual error message to help the agent debug
135
+ compile_status = f"Last compile: Failed\n{pub.last_compile_output}"
136
+
137
+ simulate_status = ""
138
+ if pub.last_simulate_output:
139
+ # Use same success detection logic as in engine
140
+ stdout = pub.last_simulate_output
141
+ passed = (
142
+ "ALL_TESTS_PASSED" in stdout
143
+ or ("Mismatches: 0 " in stdout and "samples" in stdout)
144
+ or ("no mismatches" in stdout.lower() and "errors" not in stdout.lower())
145
+ )
146
+ simulate_status = f"Last simulation: {'Passed' if passed else 'Failed'}"
147
+
148
+ observation: Dict[str, Any] = {
149
+ "files": pub.files,
150
+ "build_dir": pub.build_dir,
151
+ "files_summary": files_summary,
152
+ "task_completed": pub.task_completed,
153
+ "reward_last": priv.reward_last,
154
+ "total_reward": priv.total_reward,
155
+ "terminated": priv.terminated,
156
+ "compile_status": compile_status,
157
+ "simulate_status": simulate_status,
158
+ }
159
+ return observation # type: ignore[return-value]
160
+
161
+
162
+ class VerilogEnvironment(StatefulEnvironment):
163
+ def __init__(
164
+ self,
165
+ task_instance: TaskInstance,
166
+ custom_obs: Optional[GetObservationCallable] = None,
167
+ ):
168
+ self.name = "VerilogEval"
169
+ self.task_instance = task_instance
170
+ self.custom_observation_callable = custom_obs or VerilogObservationCallable()
171
+ self.engine: VerilogEngine = VerilogEngine(task_instance)
172
+
173
+ # Initialize tools
174
+ self._tools_instances = {
175
+ "write_file": VerilogWriteFileTool(self.engine),
176
+ "compile": VerilogCompileTool(self.engine),
177
+ "simulate": VerilogSimulateTool(self.engine),
178
+ "submit": VerilogSubmitTool(self.engine),
179
+ }
180
+
181
+ # Register tools
182
+ for tool_name, tool_instance in self._tools_instances.items():
183
+ if tool_name not in TOOL_REGISTRY:
184
+ register_tool(tool_instance)
185
+
186
+ async def initialize(self) -> InternalObservation:
187
+ priv, pub = await self.engine._reset_engine()
188
+ return await self._to_observation(priv, pub)
189
+
190
+ async def terminate(self) -> InternalObservation:
191
+ # Get current state and mark as terminated
192
+ try:
193
+ # Try to get current state from engine
194
+ current_files = self.engine._get_file_contents()
195
+ build_dir = str(self.engine.build_dir) if self.engine.build_dir else ""
196
+
197
+ priv = VerilogPrivateState(
198
+ reward_last=0.0,
199
+ total_reward=self.engine._total_reward,
200
+ terminated=True,
201
+ truncated=False,
202
+ )
203
+
204
+ pub = VerilogPublicState(files=current_files, build_dir=build_dir, task_completed=False)
205
+ except Exception:
206
+ # Fallback if engine state is not accessible
207
+ priv = VerilogPrivateState(
208
+ reward_last=0.0, total_reward=0.0, terminated=True, truncated=False
209
+ )
210
+
211
+ pub = VerilogPublicState(files={}, build_dir="", task_completed=False)
212
+
213
+ obs = await self._to_observation(priv, pub)
214
+ if isinstance(obs, dict):
215
+ obs["terminated"] = True
216
+ obs["message"] = "Environment terminated."
217
+ return obs
218
+
219
+ def validate_tool_calls(
220
+ self,
221
+ tool_calls: Union[
222
+ EnvToolCall,
223
+ List[Dict[str, Any]],
224
+ List[List[Dict[str, Any]]],
225
+ Dict[str, Any],
226
+ ],
227
+ ) -> EnvToolCall:
228
+ """Normalize and validate tool calls to a single EnvToolCall."""
229
+ raw_call_data: Dict[str, Any]
230
+
231
+ if isinstance(tool_calls, list):
232
+ if not tool_calls:
233
+ raise ValueError("Received empty list of tool calls.")
234
+ first_item = tool_calls[0]
235
+ if isinstance(first_item, list):
236
+ if not first_item:
237
+ raise ValueError("Received empty inner list of tool calls.")
238
+ raw_call_data = first_item[0]
239
+ elif isinstance(first_item, dict):
240
+ raw_call_data = first_item
241
+ elif isinstance(first_item, EnvToolCall):
242
+ return first_item
243
+ else:
244
+ raise TypeError(f"Unexpected type in tool_calls list: {type(first_item)}")
245
+ elif isinstance(tool_calls, dict):
246
+ raw_call_data = tool_calls
247
+ elif isinstance(tool_calls, EnvToolCall):
248
+ return tool_calls
249
+ else:
250
+ raise TypeError(f"Unexpected type for tool_calls: {type(tool_calls)}")
251
+
252
+ if not isinstance(raw_call_data, dict):
253
+ raise TypeError(f"Processed call data is not a dict: {type(raw_call_data)}")
254
+
255
+ # Convert dict to EnvToolCall instance
256
+ tool_name = raw_call_data.get("tool")
257
+ tool_args = raw_call_data.get("args", {})
258
+
259
+ valid_tools = {"write_file", "compile", "simulate", "submit"}
260
+ if tool_name not in valid_tools:
261
+ raise ValueError(f"Unknown tool: {tool_name}. Expected one of: {valid_tools}")
262
+
263
+ return EnvToolCall(tool=tool_name, args=tool_args)
264
+
265
+ async def step(
266
+ self,
267
+ tool_calls: Union[
268
+ EnvToolCall,
269
+ List[Dict[str, Any]],
270
+ List[List[Dict[str, Any]]],
271
+ Dict[str, Any],
272
+ ],
273
+ ) -> InternalObservation:
274
+ agent_call = self.validate_tool_calls(tool_calls)
275
+
276
+ # Get the appropriate tool
277
+ tool_instance = self._tools_instances.get(agent_call.tool)
278
+ if not tool_instance:
279
+ tool_instance = TOOL_REGISTRY.get(agent_call.tool)
280
+ if not tool_instance:
281
+ raise ValueError(f"Tool '{agent_call.tool}' not found.")
282
+
283
+ # Execute the tool
284
+ tool_result: ToolResult = await tool_instance(agent_call)
285
+
286
+ # Update engine state with tool result
287
+ if tool_result.payload:
288
+ action_result = tool_result.payload
289
+ elif not tool_result.ok:
290
+ action_result = {
291
+ "ok": False,
292
+ "error": tool_result.error,
293
+ "type": agent_call.tool,
294
+ }
295
+ else:
296
+ action_result = {}
297
+
298
+ priv_state, pub_state = await self.engine._step_engine(action_result)
299
+
300
+ return await self._to_observation(priv_state, pub_state)
301
+
302
+ async def checkpoint(self) -> InternalObservation:
303
+ engine_snapshot: VerilogEngineSnapshot = await self.engine._serialize_engine()
304
+
305
+ # Get current state for observation
306
+ try:
307
+ current_files = self.engine._get_file_contents()
308
+ build_dir = str(self.engine.build_dir) if self.engine.build_dir else ""
309
+
310
+ priv = VerilogPrivateState(
311
+ reward_last=0.0,
312
+ total_reward=self.engine._total_reward,
313
+ terminated=False,
314
+ truncated=False,
315
+ )
316
+
317
+ pub = VerilogPublicState(files=current_files, build_dir=build_dir, task_completed=False)
318
+
319
+ obs_data = await self._to_observation(priv, pub)
320
+ except Exception:
321
+ obs_data = {"message": "Checkpoint created"}
322
+
323
+ if isinstance(obs_data, dict):
324
+ obs_data["engine_snapshot_data"] = engine_snapshot.model_dump()
325
+
326
+ return obs_data
327
+
328
+ async def _to_observation(
329
+ self,
330
+ priv: VerilogPrivateState,
331
+ pub: VerilogPublicState,
332
+ extra_obs: Optional[Dict[str, Any]] = None,
333
+ ) -> InternalObservation:
334
+ observation = await self.custom_observation_callable.get_observation(pub, priv)
335
+ if extra_obs and isinstance(observation, dict):
336
+ observation.update(extra_obs)
337
+ return observation
338
+
339
+ async def _serialize_engine(self) -> VerilogEngineSnapshot:
340
+ return await self.engine._serialize_engine()
341
+
342
+ @classmethod
343
+ async def _deserialize_engine(
344
+ cls, snapshot: VerilogEngineSnapshot, task_instance: TaskInstance
345
+ ) -> "VerilogEnvironment":
346
+ eng = await VerilogEngine._deserialize_engine(snapshot)
347
+ env = cls(task_instance)
348
+ env.engine = eng
349
+ return env