synth-ai 0.2.0__py3-none-any.whl → 0.2.1.dev0__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 (266) hide show
  1. synth_ai/__init__.py +28 -2
  2. synth_ai/core/system.py +4 -0
  3. synth_ai/environments/__init__.py +35 -0
  4. synth_ai/environments/environment/__init__.py +1 -0
  5. synth_ai/environments/environment/artifacts/__init__.py +1 -0
  6. synth_ai/environments/environment/artifacts/base.py +50 -0
  7. synth_ai/environments/environment/core.py +22 -0
  8. synth_ai/environments/environment/db/__init__.py +1 -0
  9. synth_ai/environments/environment/db/sqlite.py +45 -0
  10. synth_ai/environments/environment/registry.py +24 -0
  11. synth_ai/environments/environment/resources/sqlite.py +46 -0
  12. synth_ai/environments/environment/results.py +1 -0
  13. synth_ai/environments/environment/rewards/__init__.py +1 -0
  14. synth_ai/environments/environment/rewards/core.py +28 -0
  15. synth_ai/environments/environment/shared_engine.py +26 -0
  16. synth_ai/environments/environment/tools/__init__.py +34 -0
  17. synth_ai/environments/examples/__init__.py +1 -0
  18. synth_ai/environments/examples/crafter_classic/__init__.py +8 -0
  19. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_comprehensive_evaluation.py +58 -0
  20. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_browser.py +152 -0
  21. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_framework.py +1194 -0
  22. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_quick_evaluation.py +51 -0
  23. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_react_agent.py +872 -0
  24. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_trace_evaluation.py +1412 -0
  25. synth_ai/environments/examples/crafter_classic/agent_demos/test_crafter_react_agent.py +1110 -0
  26. synth_ai/environments/examples/crafter_classic/config_logging.py +111 -0
  27. synth_ai/environments/examples/crafter_classic/engine.py +502 -0
  28. synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +63 -0
  29. synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +5 -0
  30. synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +74 -0
  31. synth_ai/environments/examples/crafter_classic/environment.py +255 -0
  32. synth_ai/environments/examples/crafter_classic/taskset.py +228 -0
  33. synth_ai/environments/examples/enron/agent_demos/test_synth_react.py +535 -0
  34. synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +156 -0
  35. synth_ai/environments/examples/enron/art_helpers/local_email_db.py +280 -0
  36. synth_ai/environments/examples/enron/art_helpers/types_enron.py +24 -0
  37. synth_ai/environments/examples/enron/engine.py +291 -0
  38. synth_ai/environments/examples/enron/environment.py +165 -0
  39. synth_ai/environments/examples/enron/taskset.py +112 -0
  40. synth_ai/environments/examples/enron/units/keyword_stats.py +111 -0
  41. synth_ai/environments/examples/enron/units/test_email_index.py +8 -0
  42. synth_ai/environments/examples/minigrid/__init__.py +48 -0
  43. synth_ai/environments/examples/minigrid/agent_demos/minigrid_evaluation_framework.py +1188 -0
  44. synth_ai/environments/examples/minigrid/agent_demos/minigrid_quick_evaluation.py +47 -0
  45. synth_ai/environments/examples/minigrid/agent_demos/minigrid_react_agent.py +562 -0
  46. synth_ai/environments/examples/minigrid/agent_demos/minigrid_trace_evaluation.py +220 -0
  47. synth_ai/environments/examples/minigrid/agent_demos/test_minigrid_react_agent.py +393 -0
  48. synth_ai/environments/examples/minigrid/engine.py +589 -0
  49. synth_ai/environments/examples/minigrid/environment.py +274 -0
  50. synth_ai/environments/examples/minigrid/environment_mapping.py +242 -0
  51. synth_ai/environments/examples/minigrid/puzzle_loader.py +416 -0
  52. synth_ai/environments/examples/minigrid/taskset.py +583 -0
  53. synth_ai/environments/examples/minigrid/units/test_action_behavior.py +226 -0
  54. synth_ai/environments/examples/minigrid/units/test_debug_messages.py +83 -0
  55. synth_ai/environments/examples/minigrid/units/test_exploration.py +120 -0
  56. synth_ai/environments/examples/minigrid/units/test_minigrid_engine.py +214 -0
  57. synth_ai/environments/examples/minigrid/units/test_minigrid_environment.py +238 -0
  58. synth_ai/environments/examples/minigrid/units/test_minigrid_environment_mapping.py +301 -0
  59. synth_ai/environments/examples/minigrid/units/test_minigrid_taskset.py +210 -0
  60. synth_ai/environments/examples/nethack/__init__.py +7 -0
  61. synth_ai/environments/examples/nethack/achievements.py +337 -0
  62. synth_ai/environments/examples/nethack/agent_demos/nethack_evaluation_framework.py +981 -0
  63. synth_ai/environments/examples/nethack/agent_demos/nethack_quick_evaluation.py +74 -0
  64. synth_ai/environments/examples/nethack/agent_demos/nethack_react_agent.py +832 -0
  65. synth_ai/environments/examples/nethack/agent_demos/test_nethack_react_agent.py +1112 -0
  66. synth_ai/environments/examples/nethack/engine.py +738 -0
  67. synth_ai/environments/examples/nethack/environment.py +255 -0
  68. synth_ai/environments/examples/nethack/helpers/__init__.py +42 -0
  69. synth_ai/environments/examples/nethack/helpers/action_mapping.py +301 -0
  70. synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +401 -0
  71. synth_ai/environments/examples/nethack/helpers/observation_utils.py +433 -0
  72. synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +201 -0
  73. synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +268 -0
  74. synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +308 -0
  75. synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +430 -0
  76. synth_ai/environments/examples/nethack/taskset.py +323 -0
  77. synth_ai/environments/examples/nethack/units/test_nethack_engine.py +277 -0
  78. synth_ai/environments/examples/nethack/units/test_nethack_environment.py +281 -0
  79. synth_ai/environments/examples/nethack/units/test_nethack_taskset.py +213 -0
  80. synth_ai/environments/examples/nethack/units/test_recording.py +307 -0
  81. synth_ai/environments/examples/red/__init__.py +7 -0
  82. synth_ai/environments/examples/red/agent_demos/__init__.py +1 -0
  83. synth_ai/environments/examples/red/agent_demos/test_synth_react.py +1471 -0
  84. synth_ai/environments/examples/red/config_logging.py +110 -0
  85. synth_ai/environments/examples/red/engine.py +693 -0
  86. synth_ai/environments/examples/red/engine_helpers/__init__.py +1 -0
  87. synth_ai/environments/examples/red/engine_helpers/memory_map.py +28 -0
  88. synth_ai/environments/examples/red/engine_helpers/reward_components.py +275 -0
  89. synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +142 -0
  90. synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +56 -0
  91. synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +283 -0
  92. synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +149 -0
  93. synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +137 -0
  94. synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +56 -0
  95. synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +330 -0
  96. synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +120 -0
  97. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +558 -0
  98. synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +312 -0
  99. synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +147 -0
  100. synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +246 -0
  101. synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +367 -0
  102. synth_ai/environments/examples/red/engine_helpers/state_extraction.py +139 -0
  103. synth_ai/environments/examples/red/environment.py +235 -0
  104. synth_ai/environments/examples/red/taskset.py +77 -0
  105. synth_ai/environments/examples/red/test_fixes.py +125 -0
  106. synth_ai/environments/examples/red/test_fixes_mock.py +148 -0
  107. synth_ai/environments/examples/red/units/__init__.py +1 -0
  108. synth_ai/environments/examples/red/units/test_basic_functionality.py +97 -0
  109. synth_ai/environments/examples/red/units/test_button_press_requirements.py +217 -0
  110. synth_ai/environments/examples/red/units/test_engine.py +192 -0
  111. synth_ai/environments/examples/red/units/test_environment.py +455 -0
  112. synth_ai/environments/examples/red/units/test_exploration_strategy.py +227 -0
  113. synth_ai/environments/examples/red/units/test_integration.py +217 -0
  114. synth_ai/environments/examples/red/units/test_memory_extraction.py +111 -0
  115. synth_ai/environments/examples/red/units/test_menu_bug_reproduction.py +1100 -0
  116. synth_ai/environments/examples/red/units/test_movement_debug.py +255 -0
  117. synth_ai/environments/examples/red/units/test_pokemon_mcts_debug.py +163 -0
  118. synth_ai/environments/examples/red/units/test_pokemon_mcts_verbose.py +117 -0
  119. synth_ai/environments/examples/red/units/test_red_basic.py +145 -0
  120. synth_ai/environments/examples/red/units/test_red_comprehensive.py +323 -0
  121. synth_ai/environments/examples/red/units/test_retry_movement.py +195 -0
  122. synth_ai/environments/examples/red/units/test_reward_components.py +186 -0
  123. synth_ai/environments/examples/red/units/test_rom_integration.py +260 -0
  124. synth_ai/environments/examples/red/units/test_taskset.py +116 -0
  125. synth_ai/environments/examples/red/units/test_tree.py +448 -0
  126. synth_ai/environments/examples/sokoban/__init__.py +1 -0
  127. synth_ai/environments/examples/sokoban/agent_demos/sokoban_full_eval.py +900 -0
  128. synth_ai/environments/examples/sokoban/agent_demos/test_dspy_react.py +1 -0
  129. synth_ai/environments/examples/sokoban/agent_demos/test_sokoban_react_agent.py +498 -0
  130. synth_ai/environments/examples/sokoban/agent_demos/test_synth_lats.py +1 -0
  131. synth_ai/environments/examples/sokoban/agent_demos/test_synth_react_locally.py +748 -0
  132. synth_ai/environments/examples/sokoban/agent_demos/test_synth_react_service.py +296 -0
  133. synth_ai/environments/examples/sokoban/engine.py +675 -0
  134. synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +1 -0
  135. synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +656 -0
  136. synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +17 -0
  137. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +3 -0
  138. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +129 -0
  139. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +370 -0
  140. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +331 -0
  141. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +305 -0
  142. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +66 -0
  143. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +114 -0
  144. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +122 -0
  145. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +394 -0
  146. synth_ai/environments/examples/sokoban/environment.py +228 -0
  147. synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +438 -0
  148. synth_ai/environments/examples/sokoban/puzzle_loader.py +311 -0
  149. synth_ai/environments/examples/sokoban/taskset.py +425 -0
  150. synth_ai/environments/examples/sokoban/units/astar_common.py +94 -0
  151. synth_ai/environments/examples/sokoban/units/test_building_task_set.py +49 -0
  152. synth_ai/environments/examples/sokoban/units/test_false_positive.py +120 -0
  153. synth_ai/environments/examples/sokoban/units/test_simple_run_through_environment.py +119 -0
  154. synth_ai/environments/examples/sokoban/units/test_sokoban_environment.py +98 -0
  155. synth_ai/environments/examples/sokoban/units/test_tree.py +364 -0
  156. synth_ai/environments/examples/tictactoe/__init__.py +1 -0
  157. synth_ai/environments/examples/tictactoe/agent_demos/test_synth_react.py +266 -0
  158. synth_ai/environments/examples/tictactoe/agent_demos/test_tictactoe_react_agent.py +470 -0
  159. synth_ai/environments/examples/tictactoe/engine.py +368 -0
  160. synth_ai/environments/examples/tictactoe/environment.py +239 -0
  161. synth_ai/environments/examples/tictactoe/taskset.py +214 -0
  162. synth_ai/environments/examples/tictactoe/units/test_tictactoe_engine.py +393 -0
  163. synth_ai/environments/examples/tictactoe/units/test_tictactoe_environment.py +493 -0
  164. synth_ai/environments/examples/tictactoe/units/test_tictactoe_taskset.py +191 -0
  165. synth_ai/environments/examples/verilog/__init__.py +10 -0
  166. synth_ai/environments/examples/verilog/agent_demos/test_synth_react.py +520 -0
  167. synth_ai/environments/examples/verilog/engine.py +328 -0
  168. synth_ai/environments/examples/verilog/environment.py +349 -0
  169. synth_ai/environments/examples/verilog/taskset.py +418 -0
  170. synth_ai/environments/examples/verilog/units/test_verilog_engine.py +466 -0
  171. synth_ai/environments/examples/verilog/units/test_verilog_environment.py +585 -0
  172. synth_ai/environments/examples/verilog/units/test_verilog_integration.py +383 -0
  173. synth_ai/environments/examples/verilog/units/test_verilog_taskset.py +457 -0
  174. synth_ai/environments/reproducibility/core.py +42 -0
  175. synth_ai/environments/reproducibility/tree.py +364 -0
  176. synth_ai/environments/service/app.py +78 -0
  177. synth_ai/environments/service/core_routes.py +775 -0
  178. synth_ai/environments/service/external_registry.py +57 -0
  179. synth_ai/environments/service/registry.py +9 -0
  180. synth_ai/environments/stateful/__init__.py +1 -0
  181. synth_ai/environments/stateful/core.py +28 -0
  182. synth_ai/environments/stateful/engine.py +21 -0
  183. synth_ai/environments/stateful/state.py +7 -0
  184. synth_ai/environments/tasks/api.py +19 -0
  185. synth_ai/environments/tasks/core.py +78 -0
  186. synth_ai/environments/tasks/filters.py +39 -0
  187. synth_ai/environments/tasks/utils.py +89 -0
  188. synth_ai/environments/v0_observability/history.py +3 -0
  189. synth_ai/environments/v0_observability/log.py +2 -0
  190. synth_ai/lm/caching/constants.py +1 -0
  191. synth_ai/{zyk/lms → lm}/caching/ephemeral.py +4 -8
  192. synth_ai/{zyk/lms → lm}/caching/handler.py +15 -15
  193. synth_ai/{zyk/lms → lm}/caching/initialize.py +2 -4
  194. synth_ai/{zyk/lms → lm}/caching/persistent.py +4 -10
  195. synth_ai/{zyk/lms → lm}/config.py +2 -1
  196. synth_ai/{zyk/lms → lm}/constants.py +2 -2
  197. synth_ai/{zyk/lms → lm}/core/all.py +10 -10
  198. synth_ai/{zyk/lms → lm}/core/main.py +57 -33
  199. synth_ai/{zyk/lms → lm}/core/vendor_clients.py +12 -10
  200. synth_ai/lm/cost/monitor.py +1 -0
  201. synth_ai/lm/cost/statefulness.py +1 -0
  202. synth_ai/lm/provider_support/__init__.py +8 -0
  203. synth_ai/lm/provider_support/anthropic.py +945 -0
  204. synth_ai/lm/provider_support/openai.py +1115 -0
  205. synth_ai/lm/provider_support/suppress_logging.py +31 -0
  206. synth_ai/{zyk/lms → lm}/structured_outputs/handler.py +58 -80
  207. synth_ai/{zyk/lms → lm}/structured_outputs/inject.py +6 -20
  208. synth_ai/{zyk/lms → lm}/structured_outputs/rehabilitate.py +6 -12
  209. synth_ai/{zyk/lms → lm}/vendors/core/anthropic_api.py +21 -30
  210. synth_ai/{zyk/lms → lm}/vendors/core/gemini_api.py +35 -32
  211. synth_ai/{zyk/lms → lm}/vendors/core/mistral_api.py +19 -28
  212. synth_ai/{zyk/lms → lm}/vendors/core/openai_api.py +26 -36
  213. synth_ai/{zyk/lms → lm}/vendors/openai_standard.py +29 -33
  214. synth_ai/{zyk/lms → lm}/vendors/retries.py +1 -1
  215. synth_ai/lm/vendors/supported/__init__.py +0 -0
  216. synth_ai/{zyk/lms → lm}/vendors/supported/custom_endpoint.py +131 -118
  217. synth_ai/{zyk/lms → lm}/vendors/supported/deepseek.py +4 -8
  218. synth_ai/{zyk/lms → lm}/vendors/supported/grok.py +6 -8
  219. synth_ai/{zyk/lms → lm}/vendors/supported/groq.py +1 -1
  220. synth_ai/{zyk/lms → lm}/vendors/supported/ollama.py +2 -2
  221. synth_ai/{zyk/lms → lm}/vendors/supported/openrouter.py +18 -16
  222. synth_ai/{zyk/lms → lm}/vendors/supported/together.py +1 -1
  223. synth_ai/tracing/__init__.py +0 -0
  224. synth_ai/tracing/abstractions.py +224 -0
  225. synth_ai/tracing/base_client.py +91 -0
  226. synth_ai/tracing/client_manager.py +131 -0
  227. synth_ai/tracing/config.py +140 -0
  228. synth_ai/tracing/context.py +146 -0
  229. synth_ai/tracing/decorators.py +679 -0
  230. synth_ai/tracing/events/__init__.py +0 -0
  231. synth_ai/tracing/events/manage.py +147 -0
  232. synth_ai/tracing/events/scope.py +86 -0
  233. synth_ai/tracing/events/store.py +227 -0
  234. synth_ai/tracing/immediate_client.py +152 -0
  235. synth_ai/tracing/local.py +18 -0
  236. synth_ai/tracing/log_client_base.py +74 -0
  237. synth_ai/tracing/retry_queue.py +187 -0
  238. synth_ai/tracing/trackers.py +515 -0
  239. synth_ai/tracing/upload.py +504 -0
  240. synth_ai/tracing/utils.py +9 -0
  241. synth_ai/zyk/__init__.py +28 -2
  242. synth_ai-0.2.1.dev0.dist-info/METADATA +349 -0
  243. synth_ai-0.2.1.dev0.dist-info/RECORD +261 -0
  244. {synth_ai-0.2.0.dist-info → synth_ai-0.2.1.dev0.dist-info}/WHEEL +1 -1
  245. synth_ai/zyk/lms/caching/constants.py +0 -1
  246. synth_ai/zyk/lms/cost/monitor.py +0 -1
  247. synth_ai/zyk/lms/cost/statefulness.py +0 -1
  248. synth_ai-0.2.0.dist-info/METADATA +0 -36
  249. synth_ai-0.2.0.dist-info/RECORD +0 -50
  250. /synth_ai/{zyk/lms/__init__.py → environments/reproducibility/helpers.py} +0 -0
  251. /synth_ai/{zyk/lms/caching → lm}/__init__.py +0 -0
  252. /synth_ai/{zyk/lms/core → lm/caching}/__init__.py +0 -0
  253. /synth_ai/{zyk/lms → lm}/caching/dbs.py +0 -0
  254. /synth_ai/{zyk/lms/cost → lm/core}/__init__.py +0 -0
  255. /synth_ai/{zyk/lms → lm}/core/exceptions.py +0 -0
  256. /synth_ai/{zyk/lms/structured_outputs → lm/cost}/__init__.py +0 -0
  257. /synth_ai/{zyk/lms/vendors → lm/structured_outputs}/__init__.py +0 -0
  258. /synth_ai/{zyk/lms → lm}/tools/__init__.py +0 -0
  259. /synth_ai/{zyk/lms → lm}/tools/base.py +0 -0
  260. /synth_ai/{zyk/lms/vendors/core → lm/vendors}/__init__.py +0 -0
  261. /synth_ai/{zyk/lms → lm}/vendors/base.py +0 -0
  262. /synth_ai/{zyk/lms/vendors/local → lm/vendors/core}/__init__.py +0 -0
  263. /synth_ai/{zyk/lms/vendors/supported → lm/vendors/local}/__init__.py +0 -0
  264. /synth_ai/{zyk/lms → lm}/vendors/local/ollama.py +0 -0
  265. {synth_ai-0.2.0.dist-info → synth_ai-0.2.1.dev0.dist-info/licenses}/LICENSE +0 -0
  266. {synth_ai-0.2.0.dist-info → synth_ai-0.2.1.dev0.dist-info}/top_level.txt +0 -0
synth_ai/__init__.py CHANGED
@@ -2,7 +2,33 @@
2
2
  Synth AI - Software for aiding the best and multiplying the will.
3
3
  """
4
4
 
5
- from synth_ai.zyk import LM # Assuming LM is in zyk.py in the same directory
5
+ from synth_ai.lm.core.main import LM # Moved from zyk to lm for better organization
6
+
7
+ # Tracing exports - moved from synth-sdk
8
+ from synth_ai.tracing import * # noqa
9
+ from synth_ai.tracing.abstractions import (
10
+ EventPartitionElement,
11
+ SystemTrace,
12
+ TrainingQuestion,
13
+ RewardSignal,
14
+ )
15
+ from synth_ai.tracing.decorators import trace_event_async, trace_event_sync
16
+ from synth_ai.tracing.upload import upload
17
+
18
+ # Provider support exports - moved from synth-sdk to synth_ai/lm
19
+ from synth_ai.lm.provider_support.openai import OpenAI, AsyncOpenAI
20
+ from synth_ai.lm.provider_support.anthropic import Anthropic, AsyncAnthropic
21
+
22
+ # Environment exports - moved from synth-env
23
+ from synth_ai.environments import * # noqa
6
24
 
7
25
  __version__ = "0.1.9"
8
- __all__ = ["LM"] # Explicitly define public API
26
+ __all__ = [
27
+ "LM",
28
+ "tracing",
29
+ "OpenAI",
30
+ "AsyncOpenAI",
31
+ "Anthropic",
32
+ "AsyncAnthropic",
33
+ "environments",
34
+ ] # Explicitly define public API
@@ -0,0 +1,4 @@
1
+
2
+
3
+ class System:
4
+ pass
@@ -0,0 +1,35 @@
1
+ """Synth Environment Package - A framework for reinforcement learning environments."""
2
+
3
+ __version__ = "0.1.5"
4
+
5
+ # Import key modules for easier access
6
+ from . import environment
7
+ from . import service
8
+ from . import stateful
9
+ from . import tasks
10
+ from . import examples
11
+
12
+ __all__ = [
13
+ "environment",
14
+ "service",
15
+ "stateful",
16
+ "tasks",
17
+ "examples",
18
+ ]
19
+
20
+ import sys
21
+ import types
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # Compatibility Shim
25
+ # Some older code imports synth_env via the namespace prefix 'src.synth_env'.
26
+ # Rather than requiring consumers to update import paths (or adding try/except
27
+ # imports which violates project style rules), we register an alias module so
28
+ # that both import styles resolve to the same package instance.
29
+ # ---------------------------------------------------------------------------
30
+ if "src" not in sys.modules:
31
+ sys.modules["src"] = types.ModuleType("src")
32
+
33
+ # Expose this package as src.synth_env
34
+ sys.modules["src.synth_env"] = sys.modules[__name__]
35
+ setattr(sys.modules["src"], "synth_env", sys.modules[__name__])
@@ -0,0 +1 @@
1
+ """Environment core module."""
@@ -0,0 +1 @@
1
+ # artifacts package
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+ from abc import ABC, abstractmethod
3
+ from pathlib import Path
4
+ from pydantic import BaseModel
5
+ import shutil
6
+
7
+
8
+ class Artifact(BaseModel, ABC):
9
+ """Generic artifact representation."""
10
+
11
+ artifact_type: str
12
+ filename: str
13
+
14
+ @abstractmethod
15
+ def bytes(self) -> bytes:
16
+ """Return raw bytes of the artifact."""
17
+ ...
18
+
19
+ def save(self, root: Path) -> None:
20
+ """Save artifact bytes to `root/filename`."""
21
+ p = root / self.filename
22
+ p.write_bytes(self.bytes())
23
+
24
+
25
+ class FileArtifact(Artifact):
26
+ """Artifact representing a file's contents."""
27
+
28
+ artifact_type: str = "file"
29
+ content: bytes
30
+
31
+ def bytes(self) -> bytes:
32
+ return self.content
33
+
34
+
35
+ class ArtifactStore:
36
+ """Filesystem-based store for artifacts."""
37
+
38
+ def __init__(self, root: Path):
39
+ self.root = root
40
+ self.root.mkdir(parents=True, exist_ok=True)
41
+
42
+ def add(self, art: Artifact) -> None:
43
+ art.save(self.root)
44
+
45
+ def list(self) -> list[Path]:
46
+ return list(self.root.iterdir())
47
+
48
+ def export_tar(self, out: Path) -> None:
49
+ """Generate `out.tar.gz` from artifact directory."""
50
+ shutil.make_archive(out.with_suffix(""), "gztar", self.root)
@@ -0,0 +1,22 @@
1
+ from synth_ai.core.system import System
2
+
3
+ class Environment(System):
4
+ """
5
+ Base class for all environments, providing a name attribute.
6
+ """
7
+
8
+ _default_name: str
9
+
10
+ def __init_subclass__(cls, **kwargs):
11
+ super().__init_subclass__(**kwargs)
12
+ # Set a default name for the subclass based on its class name
13
+ cls._default_name = cls.__name__
14
+
15
+ @property
16
+ def name(self) -> str:
17
+ """Return the environment name, defaulting to the subclass name."""
18
+ return getattr(self, "_name", self._default_name)
19
+
20
+ @name.setter
21
+ def name(self, value: str):
22
+ self._name = value
@@ -0,0 +1 @@
1
+ # db package
@@ -0,0 +1,45 @@
1
+ import sqlite3
2
+ import threading
3
+ import contextlib
4
+ from pathlib import Path
5
+
6
+
7
+ class SQLiteManager:
8
+ def __init__(self, db_path: Path, read_only: bool = True, ephemeral: bool = False):
9
+ """Initializes SQLiteManager with optional read-only or ephemeral mode."""
10
+ self.db_path = db_path
11
+ self.read_only = read_only
12
+ self.ephemeral = ephemeral
13
+ self._lock = threading.RLock()
14
+ self._conn: sqlite3.Connection | None = None
15
+
16
+ @contextlib.contextmanager
17
+ def connection(self):
18
+ with self._lock:
19
+ if self._conn is None:
20
+ uri = f"file:{self.db_path}?mode=ro" if self.read_only else str(self.db_path)
21
+ self._conn = sqlite3.connect(uri, uri=self.read_only, isolation_level="DEFERRED")
22
+ self._conn.execute("PRAGMA foreign_keys=ON;")
23
+ self._conn.execute("PRAGMA journal_mode=WAL;")
24
+ try:
25
+ yield self._conn
26
+ self._conn.commit()
27
+ except:
28
+ self._conn.rollback()
29
+ raise
30
+
31
+ def close(self):
32
+ """Closes the underlying connection for cleanup at environment teardown."""
33
+ with self._lock:
34
+ if self._conn:
35
+ self._conn.close()
36
+ self._conn = None
37
+
38
+ def reset(self, new_db_path: Path | None = None):
39
+ """Resets the connection, optionally switching to a new database path for a fresh session."""
40
+ with self._lock:
41
+ if self._conn:
42
+ self._conn.close()
43
+ if new_db_path:
44
+ self.db_path = new_db_path
45
+ self._conn = None
@@ -0,0 +1,24 @@
1
+ from typing import Type, Dict, List
2
+
3
+ from synth_ai.environments.stateful.core import StatefulEnvironment
4
+
5
+ # Global registry for environment types
6
+ ENV_REGISTRY: Dict[str, Type[StatefulEnvironment]] = {}
7
+
8
+
9
+ def register_environment(name: str, cls: Type[StatefulEnvironment]) -> None:
10
+ """Register an environment class under a unique name."""
11
+ ENV_REGISTRY[name] = cls
12
+
13
+
14
+ def get_environment_cls(env_type: str) -> Type[StatefulEnvironment]:
15
+ """Retrieve a registered environment class or raise an error."""
16
+ try:
17
+ return ENV_REGISTRY[env_type]
18
+ except KeyError:
19
+ raise ValueError(f"Unsupported environment type: {env_type}")
20
+
21
+
22
+ def list_supported_env_types() -> List[str]:
23
+ """List all registered environment type names."""
24
+ return list(ENV_REGISTRY.keys())
@@ -0,0 +1,46 @@
1
+ import sqlite3
2
+ import threading
3
+ import contextlib
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+
8
+ class SQLiteManager:
9
+ def __init__(self, db_path: Path, read_only: bool = True, ephemeral: bool = False):
10
+ """Initializes SQLiteManager with optional read-only or ephemeral mode."""
11
+ self.db_path = db_path
12
+ self.read_only = read_only
13
+ self.ephemeral = ephemeral
14
+ self._lock = threading.RLock()
15
+ self._conn: sqlite3.Connection | None = None
16
+
17
+ @contextlib.contextmanager
18
+ def connection(self):
19
+ with self._lock:
20
+ if self._conn is None:
21
+ uri = f"file:{self.db_path}?mode=ro" if self.read_only else str(self.db_path)
22
+ self._conn = sqlite3.connect(uri, uri=self.read_only, isolation_level="DEFERRED")
23
+ self._conn.execute("PRAGMA foreign_keys=ON;")
24
+ self._conn.execute("PRAGMA journal_mode=WAL;")
25
+ try:
26
+ yield self._conn
27
+ self._conn.commit()
28
+ except:
29
+ self._conn.rollback()
30
+ raise
31
+
32
+ def close(self):
33
+ """Closes the underlying connection for cleanup at environment teardown."""
34
+ with self._lock:
35
+ if self._conn:
36
+ self._conn.close()
37
+ self._conn = None
38
+
39
+ def reset(self, new_db_path: Optional[Path] = None):
40
+ """Resets the connection, optionally switching to a new database path for a fresh session."""
41
+ with self._lock:
42
+ if self._conn:
43
+ self._conn.close()
44
+ if new_db_path:
45
+ self.db_path = new_db_path
46
+ self._conn = None
@@ -0,0 +1 @@
1
+ # EnvHistory, EnvRecord, EnvironmentCheckpointObservation (customer supplied, not for agent but only designer)
@@ -0,0 +1 @@
1
+ # rewards package
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+ from abc import ABC, abstractmethod
3
+ from typing import List, Any
4
+
5
+
6
+ class RewardComponent(ABC):
7
+ """Interface for a component contributing to stepwise reward."""
8
+
9
+ weight: float = 1.0
10
+
11
+ @abstractmethod
12
+ async def score(self, state: Any, action: Any) -> float:
13
+ """Compute the component's reward given current state and action."""
14
+ ...
15
+
16
+
17
+ class RewardStack:
18
+ """Aggregates multiple RewardComponent instances to compute a total reward."""
19
+
20
+ def __init__(self, components: List[RewardComponent]):
21
+ self.components = components
22
+
23
+ async def step_reward(self, state: Any, action: Any) -> float:
24
+ """Compute the sum of weighted component rewards for a single step."""
25
+ total = 0.0
26
+ for comp in self.components:
27
+ total += comp.weight * await comp.score(state, action)
28
+ return total
@@ -0,0 +1,26 @@
1
+ from abc import abstractmethod
2
+ from typing import Any
3
+
4
+
5
+ class InternalObservation:
6
+ public_observation: Any
7
+ private_observation: Any
8
+
9
+
10
+ class GetObservationCallable:
11
+ @abstractmethod
12
+ async def get_observation(self) -> InternalObservation:
13
+ pass
14
+
15
+ pass
16
+
17
+
18
+ class Engine:
19
+ async def initialize(self):
20
+ pass
21
+
22
+ async def terminate(self):
23
+ pass
24
+
25
+ async def _step_engine(self):
26
+ pass
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+ from abc import ABC, abstractmethod
3
+ from pydantic import BaseModel, Field
4
+ from typing import Any, Dict, Type
5
+
6
+
7
+ class EnvToolCall(BaseModel):
8
+ """Agent-requested call into an environment tool."""
9
+
10
+ tool: str
11
+ args: Dict[str, Any] = Field(default_factory=dict)
12
+
13
+
14
+ class ToolResult(BaseModel):
15
+ ok: bool
16
+ payload: Any | None = None
17
+ error: str | None = None
18
+
19
+
20
+ class AbstractTool(ABC):
21
+ name: str
22
+ call_schema: Type[BaseModel]
23
+ result_schema: Type[BaseModel] = ToolResult
24
+
25
+ @abstractmethod
26
+ async def __call__(self, call: EnvToolCall) -> ToolResult: ...
27
+
28
+
29
+ TOOL_REGISTRY: dict[str, AbstractTool] = {}
30
+
31
+
32
+ def register_tool(tool: AbstractTool) -> None:
33
+ """Register a tool instance under its `name` for dispatch."""
34
+ TOOL_REGISTRY[tool.name] = tool
@@ -0,0 +1 @@
1
+ """Environment examples and demos."""
@@ -0,0 +1,8 @@
1
+ from .config_logging import configure_logging
2
+ from .environment import CrafterClassicEnvironment
3
+ from .engine import CrafterEngine
4
+
5
+ # Configure logging when crafter_classic module is imported
6
+ configure_logging()
7
+
8
+ __all__ = ["CrafterClassicEnvironment", "CrafterEngine"]
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Run script for Full Enchilada Crafter Evaluation
4
+ """
5
+
6
+ import asyncio
7
+ import argparse
8
+ from src.synth_env.examples.crafter_classic.agent_demos.full_enchilada import (
9
+ run_full_enchilada_eval,
10
+ )
11
+
12
+
13
+ async def main():
14
+ parser = argparse.ArgumentParser(description="Run Full Enchilada Crafter Evaluation")
15
+ parser.add_argument(
16
+ "--models", nargs="+", default=["gpt-4o-mini"], help="Model names to evaluate"
17
+ )
18
+ parser.add_argument(
19
+ "--difficulties",
20
+ nargs="+",
21
+ default=["easy", "hard"],
22
+ help="Difficulty levels to test",
23
+ )
24
+ parser.add_argument(
25
+ "--num-trajectories",
26
+ type=int,
27
+ default=3,
28
+ help="Number of trajectories per condition",
29
+ )
30
+ parser.add_argument("--max-turns", type=int, default=30, help="Maximum turns per trajectory")
31
+ parser.add_argument("--no-images", action="store_true", help="Disable image capture")
32
+ parser.add_argument(
33
+ "--no-viewer",
34
+ action="store_true",
35
+ help="Don't launch the viewer after evaluation",
36
+ )
37
+ parser.add_argument(
38
+ "--output-dir",
39
+ type=str,
40
+ default=None,
41
+ help="Output directory (default: src/evals/crafter/run_TIMESTAMP)",
42
+ )
43
+
44
+ args = parser.parse_args()
45
+
46
+ await run_full_enchilada_eval(
47
+ model_names=args.models,
48
+ difficulties=args.difficulties,
49
+ num_trajectories=args.num_trajectories,
50
+ max_turns=args.max_turns,
51
+ capture_images=not args.no_images,
52
+ launch_viewer=not args.no_viewer,
53
+ output_dir=args.output_dir,
54
+ )
55
+
56
+
57
+ if __name__ == "__main__":
58
+ asyncio.run(main())
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Browse existing Crafter evaluations and launch viewer for a selected run.
4
+ """
5
+
6
+ import argparse
7
+ import json
8
+ from pathlib import Path
9
+ from datetime import datetime
10
+ import asyncio
11
+ from tabulate import tabulate
12
+
13
+ from src.synth_env.examples.crafter_classic.agent_demos.full_enchilada import (
14
+ set_current_eval_dir,
15
+ app,
16
+ )
17
+ from fastapi.staticfiles import StaticFiles
18
+ import uvicorn
19
+
20
+
21
+ def list_evaluations(evals_dir: Path = Path("src/evals/crafter")):
22
+ """List all available evaluations with summary info."""
23
+ if not evals_dir.exists():
24
+ print(f"No evaluations found at {evals_dir}")
25
+ return []
26
+
27
+ evaluations = []
28
+ for run_dir in sorted(evals_dir.glob("run_*"), reverse=True):
29
+ if run_dir.is_dir():
30
+ summary_file = run_dir / "evaluation_summary.json"
31
+ if summary_file.exists():
32
+ with open(summary_file, "r") as f:
33
+ summary = json.load(f)
34
+
35
+ eval_info = {
36
+ "run_id": run_dir.name,
37
+ "timestamp": summary["evaluation_metadata"]["timestamp"],
38
+ "models": ", ".join(summary["models_evaluated"]),
39
+ "difficulties": ", ".join(summary["difficulties_evaluated"]),
40
+ "num_trajectories": summary["evaluation_metadata"]["num_trajectories"],
41
+ "path": run_dir,
42
+ }
43
+ evaluations.append(eval_info)
44
+
45
+ return evaluations
46
+
47
+
48
+ async def view_evaluation(eval_dir: Path):
49
+ """Launch viewer for a specific evaluation."""
50
+ if not eval_dir.exists():
51
+ print(f"Evaluation directory not found: {eval_dir}")
52
+ return
53
+
54
+ viewer_dir = eval_dir / "viewer"
55
+ if not viewer_dir.exists():
56
+ print(f"Viewer files not found in {eval_dir}")
57
+ return
58
+
59
+ print(f"\nšŸ“ Viewing evaluation: {eval_dir}")
60
+ print("🌐 Launching viewer at http://localhost:8000")
61
+ print(" Press Ctrl+C to stop the viewer")
62
+
63
+ # Set the current eval directory for the viewer
64
+ set_current_eval_dir(eval_dir)
65
+
66
+ # Mount static files from the viewer directory
67
+ app.mount("/", StaticFiles(directory=str(viewer_dir), html=True), name="viewer")
68
+
69
+ # Run viewer
70
+ config = uvicorn.Config(app, host="0.0.0.0", port=8000, log_level="error")
71
+ server = uvicorn.Server(config)
72
+ await server.serve()
73
+
74
+
75
+ async def main():
76
+ parser = argparse.ArgumentParser(description="Browse Crafter evaluations")
77
+ parser.add_argument(
78
+ "--eval-dir",
79
+ type=str,
80
+ default="src/evals/crafter",
81
+ help="Base directory for evaluations",
82
+ )
83
+ parser.add_argument(
84
+ "--run-id", type=str, help="Specific run ID to view (e.g., run_20240115_143022)"
85
+ )
86
+ parser.add_argument("--latest", action="store_true", help="View the latest evaluation")
87
+
88
+ args = parser.parse_args()
89
+ evals_dir = Path(args.eval_dir)
90
+
91
+ # List evaluations
92
+ evaluations = list_evaluations(evals_dir)
93
+
94
+ if not evaluations:
95
+ return
96
+
97
+ # Display table of evaluations
98
+ if not args.run_id and not args.latest:
99
+ print("\nšŸ“Š Available Crafter Evaluations:")
100
+ table_data = []
101
+ for i, eval_info in enumerate(evaluations):
102
+ # Parse timestamp for cleaner display
103
+ try:
104
+ ts = datetime.fromisoformat(eval_info["timestamp"])
105
+ ts_str = ts.strftime("%Y-%m-%d %H:%M:%S")
106
+ except:
107
+ ts_str = eval_info["timestamp"]
108
+
109
+ table_data.append(
110
+ [
111
+ i + 1,
112
+ eval_info["run_id"],
113
+ ts_str,
114
+ eval_info["models"],
115
+ eval_info["difficulties"],
116
+ eval_info["num_trajectories"],
117
+ ]
118
+ )
119
+
120
+ headers = ["#", "Run ID", "Timestamp", "Models", "Difficulties", "Trajectories"]
121
+ print(tabulate(table_data, headers=headers, tablefmt="grid"))
122
+
123
+ # Ask user to select
124
+ print("\nEnter the number of the evaluation to view (or 'q' to quit): ", end="")
125
+ choice = input().strip()
126
+
127
+ if choice.lower() == "q":
128
+ return
129
+
130
+ try:
131
+ idx = int(choice) - 1
132
+ if 0 <= idx < len(evaluations):
133
+ selected_eval = evaluations[idx]
134
+ await view_evaluation(selected_eval["path"])
135
+ else:
136
+ print("Invalid selection")
137
+ except ValueError:
138
+ print("Invalid input")
139
+
140
+ # View specific run
141
+ elif args.run_id:
142
+ eval_path = evals_dir / args.run_id
143
+ await view_evaluation(eval_path)
144
+
145
+ # View latest
146
+ elif args.latest and evaluations:
147
+ latest_eval = evaluations[0]
148
+ await view_evaluation(latest_eval["path"])
149
+
150
+
151
+ if __name__ == "__main__":
152
+ asyncio.run(main())