synth-ai 0.2.13.dev1__py3-none-any.whl → 0.2.14__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.

Potentially problematic release.


This version of synth-ai might be problematic. Click here for more details.

Files changed (291) hide show
  1. examples/multi_step/configs/README_verilog_rl.md +77 -0
  2. examples/multi_step/configs/VERILOG_REWARDS.md +90 -0
  3. examples/multi_step/configs/VERILOG_RL_CHECKLIST.md +183 -0
  4. examples/multi_step/configs/crafter_eval_synth_qwen4b.toml +35 -0
  5. examples/multi_step/configs/crafter_eval_text_only_groq_qwen32b.toml +36 -0
  6. examples/multi_step/configs/crafter_rl_stepwise_hosted_judge.toml +17 -5
  7. examples/multi_step/configs/crafter_synth_backend.md +40 -0
  8. examples/multi_step/configs/verilog_eval_groq_qwen32b.toml +31 -0
  9. examples/multi_step/configs/verilog_eval_synth_qwen8b.toml +33 -0
  10. examples/multi_step/configs/verilog_rl_lora.toml +190 -0
  11. examples/multi_step/judges/crafter_backend_judge.py +220 -0
  12. examples/multi_step/judges/verilog_backend_judge.py +234 -0
  13. examples/multi_step/readme.md +48 -0
  14. examples/multi_step/verilog_rl_lora.md +218 -0
  15. examples/qwen_coder/configs/coder_lora_30b.toml +1 -1
  16. examples/sft/evaluate.py +2 -0
  17. examples/sft/generate_traces.py +2 -0
  18. examples/swe/task_app/grpo_swe_mini.py +56 -26
  19. examples/swe/task_app/hosted/rollout.py +42 -0
  20. examples/swe/task_app/hosted/test_service.py +5 -6
  21. examples/task_apps/IMAGE_ONLY_EVAL_QUICKSTART.md +258 -0
  22. examples/task_apps/TESTING.md +275 -0
  23. examples/task_apps/__init__.py +0 -0
  24. examples/task_apps/crafter/CREATE_SFT_DATASET.md +273 -0
  25. examples/task_apps/crafter/EVAL_IMAGE_ONLY_RESULTS.md +152 -0
  26. examples/task_apps/crafter/FILTER_COMMAND_STATUS.md +174 -0
  27. examples/task_apps/crafter/FILTER_COMMAND_SUCCESS.md +268 -0
  28. examples/task_apps/crafter/QUERY_EXAMPLES.md +203 -0
  29. examples/task_apps/crafter/README_IMAGE_ONLY_EVAL.md +316 -0
  30. examples/task_apps/crafter/__init__.py +0 -0
  31. examples/task_apps/crafter/eval_image_only_gpt4o.toml +28 -0
  32. examples/task_apps/crafter/eval_text_only_groq_llama.toml +36 -0
  33. examples/task_apps/crafter/filter_sft_dataset.toml +16 -0
  34. examples/task_apps/crafter/task_app/__init__.py +5 -0
  35. examples/{warming_up_to_rl → task_apps/crafter}/task_app/grpo_crafter.py +324 -21
  36. examples/{warming_up_to_rl → task_apps/crafter}/task_app/grpo_crafter_task_app.py +1 -1
  37. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/environment.py +10 -0
  38. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/policy.py +76 -7
  39. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/react_agent.py +17 -2
  40. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/inference/openai_client.py +25 -3
  41. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/policy_routes.py +77 -4
  42. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/rollout.py +117 -9
  43. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/test_service.py +5 -6
  44. examples/task_apps/crafter/task_app/synth_envs_hosted/utils.py +218 -0
  45. examples/task_apps/dev/pokemon_emerald/__init__.py +2 -0
  46. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/README.md +811 -0
  47. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/__init__.py +120 -0
  48. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/action.py +160 -0
  49. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/memory.py +155 -0
  50. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/perception.py +69 -0
  51. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/planning.py +96 -0
  52. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/simple.py +1502 -0
  53. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/system_prompt.py +4 -0
  54. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/grab_map.py +68 -0
  55. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/manual.py +216 -0
  56. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/__init__.py +35 -0
  57. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emerald_utils.py +631 -0
  58. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emulator.py +1544 -0
  59. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/enums.py +1428 -0
  60. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/memory_reader.py +4848 -0
  61. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/types.py +41 -0
  62. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/utils.py +298 -0
  63. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pyproject.toml +95 -0
  64. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/run.py +204 -0
  65. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/__init__.py +0 -0
  66. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/app.py +2152 -0
  67. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/client.py +429 -0
  68. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/frame_server.py +155 -0
  69. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/README.md +78 -0
  70. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/__init__.py +0 -0
  71. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/run_tests.py +122 -0
  72. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_direct.py +76 -0
  73. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_prompts.py +413 -0
  74. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_battle_state_formatting.py +204 -0
  75. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection.py +133 -0
  76. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection_comprehensive.py +229 -0
  77. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_direct_agent_emulator.py +300 -0
  78. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_fps_adjustment_pytest.py +205 -0
  79. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_direct.py +200 -0
  80. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_transition.py +284 -0
  81. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_map_ground_truth_comparison.py +468 -0
  82. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_memory_map.py +575 -0
  83. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_server_map_validation.py +311 -0
  84. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_torchic_state.py +259 -0
  85. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/__init__.py +0 -0
  86. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/anticheat.py +372 -0
  87. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/checkpoint.py +296 -0
  88. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/error_handler.py +275 -0
  89. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/get_local_ip.py +22 -0
  90. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/helpers.py +44 -0
  91. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/llm_logger.py +514 -0
  92. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_formatter.py +415 -0
  93. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher.py +1763 -0
  94. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher_singleton.py +33 -0
  95. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_trimmer.py +106 -0
  96. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_visualizer.py +334 -0
  97. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/ocr_dialogue.py +1020 -0
  98. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/recording.py +188 -0
  99. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/state_formatter.py +1481 -0
  100. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/vlm.py +862 -0
  101. examples/task_apps/dev/pokemon_emerald/modal_app.py +114 -0
  102. examples/task_apps/dev/pokemon_emerald/task_app/README.md +81 -0
  103. examples/task_apps/dev/pokemon_emerald/task_app/__init__.py +6 -0
  104. examples/task_apps/dev/pokemon_emerald/task_app/pokemon_emerald.py +685 -0
  105. examples/task_apps/enron/__init__.py +1 -0
  106. examples/task_apps/enron/eval_groq_qwen32.toml +16 -0
  107. examples/task_apps/enron/filter_sft.toml +5 -0
  108. examples/task_apps/enron/task_app/README.md +14 -0
  109. examples/task_apps/enron/task_app/__init__.py +1 -0
  110. examples/task_apps/enron/task_app/grpo_enron.py +906 -0
  111. examples/task_apps/enron/task_app/grpo_enron_task_app.py +146 -0
  112. examples/task_apps/enron/tests/__init__.py +4 -0
  113. examples/task_apps/enron/tests/conftest.py +115 -0
  114. examples/task_apps/enron/tests/integration/__init__.py +4 -0
  115. examples/task_apps/enron/tests/integration/test_enron_eval.py +179 -0
  116. examples/task_apps/enron/tests/integration/test_enron_rollout.py +135 -0
  117. examples/task_apps/enron/tests/unit/__init__.py +4 -0
  118. examples/task_apps/enron/tests/unit/test_enron_environment.py +126 -0
  119. examples/task_apps/math/__init__.py +0 -0
  120. examples/{rl/task_app → task_apps/math}/math_single_step.py +19 -10
  121. examples/task_apps/pokemon_battle/__init__.py +2 -0
  122. examples/task_apps/pokemon_battle/modal_app.py +104 -0
  123. examples/task_apps/pokemon_battle/task_app/README.md +68 -0
  124. examples/task_apps/pokemon_battle/task_app/__init__.py +6 -0
  125. examples/task_apps/pokemon_battle/task_app/pokemon_showdown.py +932 -0
  126. examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_COMPLETE.md +283 -0
  127. examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_STATUS.md +155 -0
  128. examples/task_apps/pokemon_red/README.md +357 -0
  129. examples/task_apps/pokemon_red/README_IMAGE_ONLY_EVAL.md +415 -0
  130. examples/task_apps/pokemon_red/__init__.py +3 -0
  131. examples/task_apps/pokemon_red/eval_image_only_gpt4o.toml +29 -0
  132. examples/task_apps/pokemon_red/eval_pokemon_red_policy.py +225 -0
  133. examples/task_apps/pokemon_red/pallet_town_rl_config.toml +75 -0
  134. examples/task_apps/pokemon_red/task_app.py +799 -0
  135. examples/task_apps/pokemon_red/test_pallet_town_rewards.py +193 -0
  136. examples/task_apps/sokoban/README.md +307 -0
  137. examples/task_apps/sokoban/__init__.py +3 -0
  138. examples/task_apps/sokoban/eval_groq_qwen32.toml +16 -0
  139. examples/task_apps/sokoban/eval_openai_gpt5.toml +16 -0
  140. examples/task_apps/sokoban/filter_sft.toml +5 -0
  141. examples/task_apps/sokoban/task_app.py +1058 -0
  142. examples/task_apps/sokoban/tests/__init__.py +4 -0
  143. examples/task_apps/sokoban/tests/conftest.py +113 -0
  144. examples/task_apps/sokoban/tests/integration/__init__.py +4 -0
  145. examples/task_apps/sokoban/tests/integration/test_sokoban_eval.py +57 -0
  146. examples/task_apps/sokoban/tests/integration/test_sokoban_rollout.py +198 -0
  147. examples/task_apps/sokoban/tests/unit/__init__.py +4 -0
  148. examples/task_apps/sokoban/tests/unit/test_sokoban_environment.py +114 -0
  149. examples/task_apps/verilog/__init__.py +1 -0
  150. examples/task_apps/verilog/eval_groq_qwen32b.toml +24 -0
  151. examples/task_apps/verilog/filter_sft.toml +5 -0
  152. examples/task_apps/verilog/task_app/README.md +12 -0
  153. examples/task_apps/verilog/task_app/__init__.py +1 -0
  154. examples/task_apps/verilog/task_app/grpo_verilog.py +1166 -0
  155. examples/task_apps/verilog/task_app/grpo_verilog_task_app.py +145 -0
  156. examples/task_apps/verilog/tests/__init__.py +4 -0
  157. examples/task_apps/verilog/tests/conftest.py +115 -0
  158. examples/task_apps/verilog/tests/integration/__init__.py +4 -0
  159. examples/task_apps/verilog/tests/integration/test_verilog_eval.py +181 -0
  160. examples/task_apps/verilog/tests/integration/test_verilog_rollout.py +55 -0
  161. examples/task_apps/verilog/tests/unit/__init__.py +4 -0
  162. examples/task_apps/verilog/tests/unit/test_verilog_scoring.py +118 -0
  163. examples/vlm/crafter_openai_vlm_agent.py +4 -4
  164. examples/vlm/run_crafter_vlm_benchmark.py +4 -4
  165. examples/warming_up_to_rl/groq_test.py +2 -0
  166. examples/warming_up_to_rl/run_local_rollout.py +2 -0
  167. examples/warming_up_to_rl/run_local_rollout_modal.py +2 -0
  168. examples/warming_up_to_rl/run_local_rollout_parallel.py +2 -0
  169. examples/warming_up_to_rl/run_local_rollout_traced.py +2 -0
  170. examples/warming_up_to_rl/run_rollout_remote.py +2 -0
  171. examples/workflows/__init__.py +0 -0
  172. examples/workflows/math_rl/__init__.py +0 -0
  173. examples/workflows/math_rl/download_dataset.py +80 -0
  174. synth_ai/__init__.py +2 -2
  175. synth_ai/api/models/supported.py +1 -0
  176. synth_ai/api/train/builders.py +25 -11
  177. synth_ai/api/train/cli.py +12 -6
  178. synth_ai/api/train/configs/__init__.py +10 -10
  179. synth_ai/api/train/configs/rl.py +5 -4
  180. synth_ai/api/train/configs/sft.py +4 -3
  181. synth_ai/api/train/env_resolver.py +5 -2
  182. synth_ai/api/train/supported_algos.py +10 -5
  183. synth_ai/api/train/utils.py +7 -4
  184. synth_ai/cli/__init__.py +48 -59
  185. synth_ai/cli/_modal_wrapper.py +3 -2
  186. synth_ai/cli/_storage.py +4 -3
  187. synth_ai/cli/_validate_task_app.py +11 -0
  188. synth_ai/cli/balance.py +4 -3
  189. synth_ai/cli/calc.py +2 -2
  190. synth_ai/cli/demo.py +14 -7
  191. synth_ai/cli/legacy_root_backup.py +1 -1
  192. synth_ai/cli/recent.py +1 -1
  193. synth_ai/cli/rl_demo.py +8 -7
  194. synth_ai/cli/root.py +0 -97
  195. synth_ai/cli/status.py +1 -1
  196. synth_ai/cli/task_apps.py +1922 -190
  197. synth_ai/cli/traces.py +1 -1
  198. synth_ai/cli/tui.py +57 -0
  199. synth_ai/cli/turso.py +1 -1
  200. synth_ai/cli/watch.py +1 -1
  201. synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +29 -17
  202. synth_ai/environments/examples/crafter_classic/environment.py +1 -1
  203. synth_ai/environments/examples/enron/engine.py +7 -2
  204. synth_ai/environments/examples/enron/environment.py +68 -0
  205. synth_ai/environments/examples/red/engine.py +27 -0
  206. synth_ai/environments/examples/red/engine_helpers/memory_map.py +7 -0
  207. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_progression.py +477 -0
  208. synth_ai/environments/examples/red/engine_helpers/state_extraction.py +32 -0
  209. synth_ai/environments/examples/red/environment.py +60 -0
  210. synth_ai/environments/examples/sokoban/taskset.py +116 -0
  211. synth_ai/environments/examples/verilog/engine.py +104 -12
  212. synth_ai/evals/client.py +58 -61
  213. synth_ai/jobs/client.py +16 -4
  214. synth_ai/judge_schemas.py +9 -9
  215. synth_ai/py.typed +0 -0
  216. synth_ai/task/__init__.py +24 -5
  217. synth_ai/task/apps/__init__.py +1 -0
  218. synth_ai/task/config.py +257 -0
  219. synth_ai/task/contracts.py +138 -39
  220. synth_ai/task/proxy.py +48 -56
  221. synth_ai/task/rubrics/__init__.py +56 -0
  222. synth_ai/task/rubrics/loaders.py +152 -0
  223. synth_ai/task/rubrics/models.py +57 -0
  224. synth_ai/task/rubrics/scoring.py +116 -0
  225. synth_ai/{rubrics/validators.py → task/rubrics/strict.py} +53 -30
  226. synth_ai/task/server.py +8 -7
  227. synth_ai/task/trace_correlation_helpers.py +315 -0
  228. synth_ai/task/validators.py +413 -6
  229. synth_ai/tracing_v3/abstractions.py +3 -3
  230. synth_ai/tracing_v3/decorators.py +7 -3
  231. synth_ai/tracing_v3/llm_call_record_helpers.py +5 -5
  232. synth_ai/tracing_v3/replica_sync.py +4 -4
  233. synth_ai/tracing_v3/serialization.py +5 -5
  234. synth_ai/tracing_v3/session_tracer.py +16 -6
  235. synth_ai/tracing_v3/storage/base.py +29 -29
  236. synth_ai/tracing_v3/storage/config.py +3 -3
  237. synth_ai/tracing_v3/trace_utils.py +317 -0
  238. synth_ai/tracing_v3/turso/daemon.py +8 -7
  239. synth_ai/tracing_v3/turso/native_manager.py +66 -43
  240. synth_ai/tracing_v3/utils.py +3 -3
  241. synth_ai/tui/__init__.py +5 -0
  242. synth_ai/tui/__main__.py +13 -0
  243. synth_ai/tui/cli/__init__.py +1 -0
  244. synth_ai/tui/cli/query_experiments.py +164 -0
  245. synth_ai/tui/cli/query_experiments_v3.py +164 -0
  246. synth_ai/tui/dashboard.py +906 -0
  247. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/METADATA +4 -1
  248. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/RECORD +278 -126
  249. examples/agora_ex/README_MoE.md +0 -224
  250. examples/agora_ex/__init__.py +0 -7
  251. examples/agora_ex/agora_ex.py +0 -65
  252. examples/agora_ex/agora_ex_task_app.py +0 -590
  253. examples/agora_ex/configs/rl_lora_qwen3_moe_2xh200.toml +0 -121
  254. examples/agora_ex/reward_fn_grpo-human.py +0 -129
  255. examples/agora_ex/system_prompt_CURRENT.md +0 -63
  256. examples/agora_ex/task_app/agora_ex_task_app.py +0 -590
  257. examples/agora_ex/task_app/reward_fn_grpo-human.py +0 -129
  258. examples/agora_ex/task_app/system_prompt_CURRENT.md +0 -63
  259. examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +0 -62
  260. synth_ai/rubrics/__init__.py +0 -22
  261. synth_ai/task/rubrics.py +0 -219
  262. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/README.md +0 -0
  263. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/README.md +0 -0
  264. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/__init__.py +0 -0
  265. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/branching.py +0 -0
  266. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/environment_routes.py +0 -0
  267. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/__init__.py +0 -0
  268. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/__init__.py +0 -0
  269. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/app.py +0 -0
  270. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/shared.py +0 -0
  271. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/tools.py +0 -0
  272. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/hosted_app.py +0 -0
  273. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/inference/__init__.py +0 -0
  274. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/main.py +0 -0
  275. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/registry.py +0 -0
  276. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/storage/__init__.py +0 -0
  277. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/storage/volume.py +0 -0
  278. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/test_agents.py +0 -0
  279. /examples/{rl/task_app → task_apps/math}/README.md +0 -0
  280. /examples/{rl/task_app → task_apps/math}/math_task_app.py +0 -0
  281. /examples/{rl → workflows/math_rl}/configs/eval_base_qwen.toml +0 -0
  282. /examples/{rl → workflows/math_rl}/configs/eval_rl_qwen.toml +0 -0
  283. /examples/{rl → workflows/math_rl}/configs/rl_from_base_qwen.toml +0 -0
  284. /examples/{rl → workflows/math_rl}/configs/rl_from_base_qwen17.toml +0 -0
  285. /examples/{rl → workflows/math_rl}/configs/rl_from_ft_qwen.toml +0 -0
  286. /examples/{rl → workflows/math_rl}/run_eval.py +0 -0
  287. /examples/{rl → workflows/math_rl}/run_rl_and_save.py +0 -0
  288. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/WHEEL +0 -0
  289. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/entry_points.txt +0 -0
  290. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/licenses/LICENSE +0 -0
  291. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,575 @@
1
+ import os
2
+ import pytest
3
+ from pathlib import Path
4
+ import numpy as np
5
+ from pprint import pprint
6
+
7
+ from pokemon_env.emulator import EmeraldEmulator
8
+ from pokemon_env.enums import MetatileBehavior
9
+
10
+ def format_map_data(map_data, title="Map Data"):
11
+ """Format the map data into a string using the agent's format"""
12
+ print(f"Map data: {map_data}")
13
+ lines = []
14
+ lines.append(f"=== {title} ===")
15
+ lines.append("Format: (MetatileID, Behavior, X, Y)")
16
+ lines.append(f"Map dimensions: {len(map_data)}x{len(map_data[0])}")
17
+ lines.append("")
18
+ lines.append("--- TRAVERSABILITY MAP ---")
19
+
20
+ # Column headers
21
+ header = " "
22
+ for i in range(len(map_data[0])):
23
+ header += f"{i:2} "
24
+ lines.append(header)
25
+ lines.append(" " + "--" * len(map_data[0]))
26
+
27
+ # Find player position (center of the grid)
28
+ center_y = len(map_data) // 2
29
+ center_x = len(map_data[0]) // 2
30
+
31
+ # Format each row
32
+ for y in range(len(map_data)):
33
+ row = f"{y:2}: "
34
+ for x in range(len(map_data[y])):
35
+ if y == center_y and x == center_x:
36
+ row += "P" # Player position
37
+ else:
38
+ tile = map_data[y][x]
39
+ behavior = tile[1]
40
+ # Convert behavior to map symbol using same logic as get_comprehensive_state
41
+ tile_id, behavior, collision, elevation = tile
42
+
43
+ # Handle both enum objects and raw integers from server API
44
+ if hasattr(behavior, 'name'):
45
+ behavior_name = behavior.name
46
+ elif isinstance(behavior, int):
47
+ try:
48
+ behavior_enum = MetatileBehavior(behavior)
49
+ behavior_name = behavior_enum.name
50
+ except ValueError:
51
+ behavior_name = "UNKNOWN"
52
+ else:
53
+ behavior_name = "UNKNOWN"
54
+
55
+ if behavior_name == "NORMAL":
56
+ # For normal tiles, use collision data to determine if passable
57
+ row += "." if collision == 0 else "#"
58
+ elif "TALL_GRASS" in behavior_name:
59
+ row += "~" # Tall grass
60
+ elif "WATER" in behavior_name:
61
+ row += "W" # Water
62
+ elif "JUMP" in behavior_name:
63
+ # Show jump direction
64
+ if "JUMP_EAST" in behavior_name:
65
+ row += "→"
66
+ elif "JUMP_WEST" in behavior_name:
67
+ row += "←"
68
+ elif "JUMP_NORTH" in behavior_name:
69
+ row += "↑"
70
+ elif "JUMP_SOUTH" in behavior_name:
71
+ row += "↓"
72
+ elif "JUMP_NORTHEAST" in behavior_name:
73
+ row += "↗"
74
+ elif "JUMP_NORTHWEST" in behavior_name:
75
+ row += "↖"
76
+ elif "JUMP_SOUTHEAST" in behavior_name:
77
+ row += "↘"
78
+ elif "JUMP_SOUTHWEST" in behavior_name:
79
+ row += "↙"
80
+ else:
81
+ row += "J"
82
+ elif "DOOR" in behavior_name:
83
+ row += "D" # Door
84
+ else:
85
+ # For other behaviors, show abbreviated name
86
+ short_name = behavior_name.replace("_", "")[:4]
87
+ row += f"{short_name[:2]}"
88
+ row += " " # Add space between tiles
89
+ lines.append(row.rstrip())
90
+
91
+ return "\n".join(lines)
92
+
93
+ def print_map_data(map_data, title="Map Data"):
94
+ """Pretty print the map data and return the formatted string"""
95
+ formatted_map = format_map_data(map_data, title)
96
+ print("\n" + formatted_map)
97
+ print("\nLegend:")
98
+ print(" P = Player position")
99
+ print(" . = Normal walkable path")
100
+ print(" # = Blocked/wall")
101
+ print(" D = Door (can be entered)")
102
+ print(" ~ = Tall grass (wild Pokemon encounters)")
103
+ print(" W = Water (requires Surf)")
104
+ print(" IM = Impassable terrain")
105
+ print(" SE = Sealed area (cannot enter)")
106
+ print(" EA = East arrow (direction indicator)")
107
+ print(" SO = Sound mat (makes sound when stepped on)")
108
+ print(" TE = Television")
109
+ print(" →←↑↓↗↖↘↙ = Jump ledge directions (can jump in that direction)")
110
+ return formatted_map
111
+
112
+ # Get the absolute path to the test states directory
113
+ TEST_STATES_DIR = os.path.join(os.path.dirname(__file__), "states")
114
+
115
+ @pytest.fixture
116
+ def emulator():
117
+ """Create and initialize an emulator instance"""
118
+ # Get path to ROM file
119
+ project_root = Path(__file__).parent.parent
120
+ rom_path = str(project_root / "Emerald-GBAdvance" / "rom.gba")
121
+
122
+ # Initialize emulator
123
+ emu = EmeraldEmulator(rom_path, headless=True, sound=False)
124
+ emu.initialize()
125
+
126
+ yield emu
127
+
128
+ # Cleanup
129
+ emu.stop()
130
+
131
+ def test_house_state_map_reading(emulator):
132
+ """Test map reading functionality in the house state"""
133
+ # Load the house state
134
+ state_path = os.path.join(TEST_STATES_DIR, "house.state")
135
+ emulator.load_state(state_path)
136
+
137
+ # Get map data around player using the same function as the agent
138
+ map_data = emulator.memory_reader.read_map_around_player(radius=7)
139
+
140
+ # Format the map data
141
+ formatted_map = print_map_data(map_data, "House State Map")
142
+
143
+ # Load ground truth
144
+ truth_path = os.path.join(TEST_STATES_DIR, "house_map_truth.txt")
145
+ with open(truth_path, 'r') as f:
146
+ expected_map = f.read().strip()
147
+
148
+ # Compare with ground truth
149
+ assert formatted_map == expected_map, "Map output does not match ground truth"
150
+
151
+ # Basic structure tests
152
+ assert map_data is not None, "Map data should not be None"
153
+ assert isinstance(map_data, list), "Map data should be a list"
154
+ assert len(map_data) > 0, "Map data should not be empty"
155
+ assert isinstance(map_data[0], list), "Map data should be a 2D list"
156
+
157
+ # Test map dimensions
158
+ height = len(map_data)
159
+ width = len(map_data[0])
160
+ assert height == 15, f"Map height should be 15 (2*radius + 1), got {height}"
161
+ assert width == 15, f"Map width should be 15 (2*radius + 1), got {width}"
162
+
163
+ # Test tile data structure
164
+ center_tile = map_data[7][7] # Center tile where player is
165
+ assert isinstance(center_tile, tuple), "Tile data should be a tuple"
166
+ assert len(center_tile) == 4, "Tile data should contain metatile ID, behavior, x, and y coordinates"
167
+
168
+ # Test that we're indoors (should have indoor tiles)
169
+ center_behavior = center_tile[1]
170
+ assert isinstance(center_behavior, MetatileBehavior), "Tile behavior should be MetatileBehavior enum"
171
+ assert center_behavior in [MetatileBehavior.INDOOR_ENCOUNTER, MetatileBehavior.NORMAL], \
172
+ "Center tile should be an indoor tile"
173
+
174
+ def test_truck_state_map_reading(emulator):
175
+ """Test map reading functionality in the truck state (game start)"""
176
+ # Load the truck state
177
+ state_path = os.path.join(TEST_STATES_DIR, "truck.state")
178
+ emulator.load_state(state_path)
179
+
180
+ # Get map data around player using the same function as the agent
181
+ map_data = emulator.memory_reader.read_map_around_player(radius=7)
182
+
183
+ # Format the map data
184
+ formatted_map = print_map_data(map_data, "Truck State Map")
185
+
186
+ # Load ground truth
187
+ truth_path = os.path.join(TEST_STATES_DIR, "truck_map_truth.txt")
188
+ with open(truth_path, 'r') as f:
189
+ expected_map = f.read().strip()
190
+
191
+ # Compare with ground truth
192
+ assert formatted_map == expected_map, "Map output does not match ground truth"
193
+
194
+ # Basic structure tests
195
+ assert map_data is not None, "Map data should not be None"
196
+ assert isinstance(map_data, list), "Map data should be a list"
197
+ assert len(map_data) > 0, "Map data should not be empty"
198
+ assert isinstance(map_data[0], list), "Map data should be a 2D list"
199
+
200
+ # Test map dimensions
201
+ height = len(map_data)
202
+ width = len(map_data[0])
203
+ assert height == 15, f"Map height should be 15 (2*radius + 1), got {height}"
204
+ assert width == 15, f"Map width should be 15 (2*radius + 1), got {width}"
205
+
206
+ # Test tile data structure
207
+ center_tile = map_data[7][7] # Center tile where player is
208
+ assert isinstance(center_tile, tuple), "Tile data should be a tuple"
209
+ assert len(center_tile) == 4, "Tile data should contain metatile ID, behavior, x, and y coordinates"
210
+
211
+ # Test that we're in the truck (should have indoor/special tiles)
212
+ center_behavior = center_tile[1]
213
+ assert isinstance(center_behavior, MetatileBehavior), "Tile behavior should be MetatileBehavior enum"
214
+ assert center_behavior in [MetatileBehavior.INDOOR_ENCOUNTER, MetatileBehavior.NORMAL], \
215
+ "Center tile should be an indoor tile"
216
+
217
+ def test_door_behavior(emulator):
218
+ """Test that doors are properly identified and not marked as blocked"""
219
+ # Load the house state
220
+ state_path = os.path.join(TEST_STATES_DIR, "house.state")
221
+ emulator.load_state(state_path)
222
+
223
+ # Get map data around player using the same function as the agent
224
+ map_data = emulator.memory_reader.read_map_around_player(radius=7)
225
+
226
+ # Print the map data for visual inspection
227
+ print_map_data(map_data, "House State Map (Door Test)")
228
+
229
+ # Find any door tiles
230
+ door_found = False
231
+ door_behaviors = [MetatileBehavior.NON_ANIMATED_DOOR,
232
+ MetatileBehavior.ANIMATED_DOOR,
233
+ MetatileBehavior.WATER_DOOR]
234
+
235
+ for row in map_data:
236
+ for tile in row:
237
+ behavior = tile[1]
238
+ if behavior in door_behaviors:
239
+ door_found = True
240
+ # Verify door tile is not marked as blocked
241
+ assert behavior != MetatileBehavior.NORMAL, "Door should not be marked as normal path"
242
+ assert behavior in door_behaviors, "Door should have proper door behavior"
243
+
244
+ # We should find at least one door in the house state
245
+ assert door_found, "No doors found in house state"
246
+
247
+ def test_map_data_validation(emulator):
248
+ """Test validation of map data structure and content"""
249
+ # Load any state (using truck state)
250
+ state_path = os.path.join(TEST_STATES_DIR, "truck.state")
251
+ emulator.load_state(state_path)
252
+
253
+ # Test different radius values
254
+ for radius in [3, 5, 7]:
255
+ map_data = emulator.memory_reader.read_map_around_player(radius=radius)
256
+
257
+ # Check dimensions
258
+ expected_size = 2 * radius + 1
259
+ assert len(map_data) == expected_size, f"Map height should be {expected_size} for radius {radius}"
260
+ assert all(len(row) == expected_size for row in map_data), \
261
+ f"All rows should have width {expected_size} for radius {radius}"
262
+
263
+ # Check tile data consistency
264
+ for row in map_data:
265
+ for tile in row:
266
+ # Check tile structure
267
+ assert isinstance(tile, tuple), "Tile data should be a tuple"
268
+ assert len(tile) == 4, "Tile data should contain metatile ID, behavior, x, and y coordinates"
269
+
270
+ # Check metatile ID
271
+ metatile_id = tile[0]
272
+ assert isinstance(metatile_id, int), "Metatile ID should be an integer"
273
+ assert metatile_id >= 0, "Metatile ID should be non-negative"
274
+
275
+ # Check behavior
276
+ behavior = tile[1]
277
+ assert isinstance(behavior, MetatileBehavior), "Behavior should be MetatileBehavior enum"
278
+ assert behavior.value >= 0, "Behavior value should be non-negative"
279
+
280
+ def test_upstairs_state_map_reading(emulator):
281
+ """Test map reading functionality in the upstairs state"""
282
+ # Load the upstairs state
283
+ state_path = os.path.join(TEST_STATES_DIR, "upstairs.state")
284
+ emulator.load_state(state_path)
285
+
286
+ # Get map data around player using the same function as the agent
287
+ map_data = emulator.memory_reader.read_map_around_player(radius=7)
288
+
289
+ # Format the map data
290
+ formatted_map = print_map_data(map_data, "Upstairs State Map")
291
+
292
+ # Basic structure tests
293
+ assert map_data is not None, "Map data should not be None"
294
+ assert isinstance(map_data, list), "Map data should be a list"
295
+ assert len(map_data) > 0, "Map data should not be empty"
296
+ assert isinstance(map_data[0], list), "Map data should be a 2D list"
297
+
298
+ # Test map dimensions
299
+ height = len(map_data)
300
+ width = len(map_data[0])
301
+ assert height == 15, f"Map height should be 15 (2*radius + 1), got {height}"
302
+ assert width == 15, f"Map width should be 15 (2*radius + 1), got {width}"
303
+
304
+ # Test tile data structure
305
+ center_tile = map_data[7][7] # Center tile where player is
306
+ assert isinstance(center_tile, tuple), "Tile data should be a tuple"
307
+ assert len(center_tile) == 4, "Tile data should contain metatile ID, behavior, x, and y coordinates"
308
+
309
+ # Test that we're indoors (should have indoor tiles)
310
+ center_behavior = center_tile[1]
311
+ assert isinstance(center_behavior, MetatileBehavior), "Tile behavior should be MetatileBehavior enum"
312
+
313
+ # Print detailed information for debugging
314
+ # print(f"\n=== UPSTAIRS STATE DEBUG INFO ===")
315
+ print(f"Map dimensions: {width}x{height}")
316
+ print(f"Center tile: {center_tile}")
317
+ print(f"Center behavior: {center_behavior}")
318
+
319
+ # Check for specific upstairs characteristics
320
+ # Upstairs should have indoor tiles, possibly doors, and specific layout
321
+ indoor_tiles = 0
322
+ door_tiles = 0
323
+ wall_tiles = 0
324
+ impassable_tiles = 0
325
+ normal_tiles = 0
326
+
327
+ # Analyze the map data more thoroughly
328
+ for y, row in enumerate(map_data):
329
+ for x, tile in enumerate(row):
330
+ if len(tile) >= 2:
331
+ metatile_id, behavior, collision, elevation = tile
332
+
333
+ # Count different tile types
334
+ if behavior == MetatileBehavior.INDOOR_ENCOUNTER:
335
+ indoor_tiles += 1
336
+ elif behavior in [MetatileBehavior.NON_ANIMATED_DOOR, MetatileBehavior.ANIMATED_DOOR]:
337
+ door_tiles += 1
338
+ elif behavior == MetatileBehavior.NORMAL:
339
+ if collision > 0:
340
+ wall_tiles += 1
341
+ else:
342
+ normal_tiles += 1
343
+ else:
344
+ # Check if this is an impassable tile
345
+ if metatile_id == 0 or behavior.value == 0:
346
+ impassable_tiles += 1
347
+
348
+ print(f"Indoor tiles found: {indoor_tiles}")
349
+ print(f"Door tiles found: {door_tiles}")
350
+ print(f"Wall tiles found: {wall_tiles}")
351
+ print(f"Normal walkable tiles found: {normal_tiles}")
352
+ print(f"Impassable tiles found: {impassable_tiles}")
353
+
354
+ # Check map buffer addresses
355
+ print(f"\nMap buffer info:")
356
+ print(f"Map buffer address: 0x{emulator.memory_reader._map_buffer_addr:08X}")
357
+ print(f"Map width: {emulator.memory_reader._map_width}")
358
+ print(f"Map height: {emulator.memory_reader._map_height}")
359
+
360
+ # Check player coordinates
361
+ player_coords = emulator.memory_reader.read_coordinates()
362
+ print(f"Player coordinates: {player_coords}")
363
+
364
+ # Check if behaviors are being loaded correctly
365
+ all_behaviors = emulator.memory_reader.get_all_metatile_behaviors()
366
+ print(f"Total behaviors loaded: {len(all_behaviors) if all_behaviors else 0}")
367
+
368
+ # Check specific tiles around the player
369
+ print(f"\nTile analysis around player (center):")
370
+ for dy in range(-2, 3):
371
+ for dx in range(-2, 3):
372
+ y = 7 + dy
373
+ x = 7 + dx
374
+ if 0 <= y < len(map_data) and 0 <= x < len(map_data[0]):
375
+ tile = map_data[y][x]
376
+ if len(tile) >= 4:
377
+ metatile_id, behavior, collision, elevation = tile
378
+ symbol = "P" if dy == 0 and dx == 0 else f"{metatile_id:03X}"
379
+ print(f" ({dx:+2d},{dy:+2d}): {symbol} {behavior.name} c{collision} e{elevation}")
380
+
381
+ # Upstairs should have some indoor characteristics
382
+ assert indoor_tiles > 0 or door_tiles > 0, "Upstairs state should have indoor or door tiles"
383
+
384
+ # Check if we have too many impassable tiles (might indicate map reading issues)
385
+ total_tiles = width * height
386
+ impassable_ratio = impassable_tiles / total_tiles
387
+ print(f"Impassable tile ratio: {impassable_ratio:.2%}")
388
+
389
+ # If more than 50% of tiles are impassable, there might be an issue
390
+ if impassable_ratio > 0.5:
391
+ print("WARNING: High ratio of impassable tiles detected. This might indicate map reading issues.")
392
+
393
+ # Save the formatted map for future reference
394
+ truth_path = os.path.join(TEST_STATES_DIR, "upstairs_map_truth.txt")
395
+ with open(truth_path, 'w') as f:
396
+ f.write(formatted_map)
397
+
398
+ print(f"\nMap data saved to {truth_path}")
399
+ # print("=== END UPSTAIRS STATE DEBUG INFO ===\n")
400
+
401
+ def test_map_reading_area_transitions(emulator):
402
+ """Test that map reading handles area transitions and new saves correctly"""
403
+ # Test 1: Load upstairs state and verify map reading
404
+ state_path = os.path.join(TEST_STATES_DIR, "upstairs.state")
405
+ emulator.load_state(state_path)
406
+
407
+ # Force invalidate map cache to simulate area transition
408
+ emulator.memory_reader.invalidate_map_cache()
409
+
410
+ # Try to read map - should work correctly
411
+ map_data = emulator.memory_reader.read_map_around_player(radius=7)
412
+
413
+ # Verify map data is valid
414
+ assert map_data is not None, "Map data should not be None after cache invalidation"
415
+ assert len(map_data) > 0, "Map data should not be empty after cache invalidation"
416
+ assert len(map_data) == 15, "Map height should be 15 after cache invalidation"
417
+ assert len(map_data[0]) == 15, "Map width should be 15 after cache invalidation"
418
+
419
+ # Test 2: Load house state and verify map reading
420
+ state_path = os.path.join(TEST_STATES_DIR, "house.state")
421
+ emulator.load_state(state_path)
422
+
423
+ # Map cache should be automatically invalidated by load_state
424
+ map_data = emulator.memory_reader.read_map_around_player(radius=7)
425
+
426
+ # Verify map data is valid
427
+ assert map_data is not None, "Map data should not be None after loading house state"
428
+ assert len(map_data) > 0, "Map data should not be empty after loading house state"
429
+ assert len(map_data) == 15, "Map height should be 15 after loading house state"
430
+ assert len(map_data[0]) == 15, "Map width should be 15 after loading house state"
431
+
432
+ # Test 3: Load truck state and verify map reading
433
+ state_path = os.path.join(TEST_STATES_DIR, "truck.state")
434
+ emulator.load_state(state_path)
435
+
436
+ map_data = emulator.memory_reader.read_map_around_player(radius=7)
437
+
438
+ # Verify map data is valid
439
+ assert map_data is not None, "Map data should not be None after loading truck state"
440
+ assert len(map_data) > 0, "Map data should not be empty after loading truck state"
441
+ assert len(map_data) == 15, "Map height should be 15 after loading truck state"
442
+ assert len(map_data[0]) == 15, "Map width should be 15 after loading truck state"
443
+
444
+ print("✅ All area transition tests passed - map reading handles transitions correctly")
445
+
446
+ def test_simple_test_state_map_reading(emulator):
447
+ """Test map reading functionality in the simple_test state (rival's bedroom)"""
448
+ # Load the simple_test state
449
+ state_path = os.path.join(TEST_STATES_DIR, "simple_test.state")
450
+ emulator.load_state(state_path)
451
+
452
+ # Get map data around player using the same function as the agent
453
+ map_data = emulator.memory_reader.read_map_around_player(radius=7)
454
+
455
+ # Format the map data
456
+ formatted_map = print_map_data(map_data, "Simple Test State Map")
457
+
458
+ # Basic structure tests
459
+ assert map_data is not None, "Map data should not be None"
460
+ assert isinstance(map_data, list), "Map data should be a list"
461
+ assert len(map_data) > 0, "Map data should not be empty"
462
+ assert isinstance(map_data[0], list), "Map data should be a 2D list"
463
+
464
+ # Test map dimensions
465
+ height = len(map_data)
466
+ width = len(map_data[0])
467
+ assert height == 15, f"Map height should be 15 (2*radius + 1), got {height}"
468
+ assert width == 15, f"Map width should be 15 (2*radius + 1), got {width}"
469
+
470
+ # Test tile data structure
471
+ center_tile = map_data[7][7] # Center tile where player is
472
+ assert isinstance(center_tile, tuple), "Tile data should be a tuple"
473
+ assert len(center_tile) == 4, "Tile data should contain metatile ID, behavior, x, and y coordinates"
474
+
475
+ # Print detailed information for debugging
476
+ # print(f"\n=== SIMPLE TEST STATE DEBUG INFO ===")
477
+ print(f"Map dimensions: {width}x{height}")
478
+ print(f"Center tile: {center_tile}")
479
+ print(f"Center behavior: {center_tile[1]}")
480
+
481
+ # Check map buffer addresses
482
+ print(f"\nMap buffer info:")
483
+ print(f"Map buffer address: 0x{emulator.memory_reader._map_buffer_addr:08X}")
484
+ print(f"Map width: {emulator.memory_reader._map_width}")
485
+ print(f"Map height: {emulator.memory_reader._map_height}")
486
+
487
+ # Check player coordinates
488
+ player_coords = emulator.memory_reader.read_coordinates()
489
+ print(f"Player coordinates: {player_coords}")
490
+
491
+ # Check if behaviors are being loaded correctly
492
+ all_behaviors = emulator.memory_reader.get_all_metatile_behaviors()
493
+ print(f"Total behaviors loaded: {len(all_behaviors) if all_behaviors else 0}")
494
+
495
+ # Check specific tiles around the player
496
+ print(f"\nTile analysis around player (center):")
497
+ for dy in range(-2, 3):
498
+ for dx in range(-2, 3):
499
+ y = 7 + dy
500
+ x = 7 + dx
501
+ if 0 <= y < len(map_data) and 0 <= x < len(map_data[0]):
502
+ tile = map_data[y][x]
503
+ if len(tile) >= 4:
504
+ metatile_id, behavior, collision, elevation = tile
505
+ symbol = "P" if dy == 0 and dx == 0 else f"{metatile_id:03X}"
506
+ print(f" ({dx:+2d},{dy:+2d}): {symbol} {behavior.name} c{collision} e{elevation}")
507
+
508
+ # Count different tile types
509
+ indoor_tiles = 0
510
+ door_tiles = 0
511
+ wall_tiles = 0
512
+ impassable_tiles = 0
513
+ normal_tiles = 0
514
+ decoration_tiles = 0
515
+
516
+ for y, row in enumerate(map_data):
517
+ for x, tile in enumerate(row):
518
+ if len(tile) >= 2:
519
+ metatile_id, behavior, collision, elevation = tile
520
+
521
+ # Count different tile types
522
+ if behavior == MetatileBehavior.INDOOR_ENCOUNTER:
523
+ indoor_tiles += 1
524
+ elif behavior in [MetatileBehavior.NON_ANIMATED_DOOR, MetatileBehavior.ANIMATED_DOOR]:
525
+ door_tiles += 1
526
+ elif behavior == MetatileBehavior.NORMAL:
527
+ if collision > 0:
528
+ wall_tiles += 1
529
+ else:
530
+ normal_tiles += 1
531
+ elif "DECORATION" in behavior.name or "HOLDS" in behavior.name:
532
+ decoration_tiles += 1
533
+ else:
534
+ # Check if this is an impassable tile
535
+ if metatile_id == 0 or behavior.value == 0:
536
+ impassable_tiles += 1
537
+
538
+ print(f"\nTile counts:")
539
+ print(f"Indoor tiles found: {indoor_tiles}")
540
+ print(f"Door tiles found: {door_tiles}")
541
+ print(f"Wall tiles found: {wall_tiles}")
542
+ print(f"Normal walkable tiles found: {normal_tiles}")
543
+ print(f"Decoration tiles found: {decoration_tiles}")
544
+ print(f"Impassable tiles found: {impassable_tiles}")
545
+
546
+ # Check if we have too many impassable tiles (might indicate map reading issues)
547
+ total_tiles = width * height
548
+ impassable_ratio = impassable_tiles / total_tiles
549
+ print(f"Impassable tile ratio: {impassable_ratio:.2%}")
550
+
551
+ # If more than 50% of tiles are impassable, there might be an issue
552
+ if impassable_ratio > 0.5:
553
+ print("WARNING: High ratio of impassable tiles detected. This might indicate map reading issues.")
554
+
555
+ # Try to force re-find map buffer addresses
556
+ print("Attempting to force re-find map buffer addresses...")
557
+ emulator.memory_reader.invalidate_map_cache()
558
+ if emulator.memory_reader._find_map_buffer_addresses():
559
+ print("Successfully re-found map buffer addresses")
560
+ # Try reading map again
561
+ new_map_data = emulator.memory_reader.read_map_around_player(radius=7)
562
+ if new_map_data and len(new_map_data) > 0:
563
+ print("Map reading improved after cache invalidation")
564
+ formatted_map = print_map_data(new_map_data, "Simple Test State Map (After Cache Invalidation)")
565
+
566
+ # Save the formatted map for future reference
567
+ truth_path = os.path.join(TEST_STATES_DIR, "simple_test_map_truth.txt")
568
+ with open(truth_path, 'w') as f:
569
+ f.write(formatted_map)
570
+
571
+ print(f"\nMap data saved to {truth_path}")
572
+ # print("=== END SIMPLE TEST STATE DEBUG INFO ===\n")
573
+
574
+ # Simple test state is actually outdoors in tall grass, so it should have outdoor characteristics
575
+ assert normal_tiles > 0 or wall_tiles > 0, "Simple test state should have normal walkable tiles or walls"