synth-ai 0.2.9.dev11__py3-none-any.whl → 0.4.1__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 (909) hide show
  1. synth_ai/__init__.py +44 -45
  2. synth_ai/__main__.py +30 -3
  3. synth_ai/cli/__init__.py +104 -78
  4. synth_ai/cli/__main__.py +42 -0
  5. synth_ai/cli/_internal/__init__.py +5 -0
  6. synth_ai/cli/_internal/modal_wrapper.py +31 -0
  7. synth_ai/cli/_internal/storage.py +20 -0
  8. synth_ai/cli/_internal/typer_patch.py +47 -0
  9. synth_ai/cli/_internal/validate_task_app.py +29 -0
  10. synth_ai/cli/agents/__init__.py +17 -0
  11. synth_ai/cli/agents/claude.py +77 -0
  12. synth_ai/cli/agents/codex.py +265 -0
  13. synth_ai/cli/agents/opencode.py +253 -0
  14. synth_ai/cli/commands/__init__.py +18 -0
  15. synth_ai/cli/commands/artifacts/__init__.py +13 -0
  16. synth_ai/cli/commands/artifacts/client.py +119 -0
  17. synth_ai/cli/commands/artifacts/config.py +57 -0
  18. synth_ai/cli/commands/artifacts/core.py +24 -0
  19. synth_ai/cli/commands/artifacts/download.py +188 -0
  20. synth_ai/cli/commands/artifacts/export.py +186 -0
  21. synth_ai/cli/commands/artifacts/list.py +156 -0
  22. synth_ai/cli/commands/artifacts/parsing.py +250 -0
  23. synth_ai/cli/commands/artifacts/show.py +336 -0
  24. synth_ai/cli/commands/baseline/__init__.py +12 -0
  25. synth_ai/cli/commands/baseline/core.py +636 -0
  26. synth_ai/cli/commands/baseline/list.py +94 -0
  27. synth_ai/cli/commands/demo/__init__.py +3 -0
  28. synth_ai/cli/commands/demo/core.py +153 -0
  29. synth_ai/cli/commands/eval/__init__.py +19 -0
  30. synth_ai/cli/commands/eval/core.py +1113 -0
  31. synth_ai/cli/commands/eval/errors.py +81 -0
  32. synth_ai/cli/commands/eval/validation.py +133 -0
  33. synth_ai/cli/commands/filter/__init__.py +12 -0
  34. synth_ai/cli/commands/filter/core.py +424 -0
  35. synth_ai/cli/commands/filter/errors.py +55 -0
  36. synth_ai/cli/commands/filter/validation.py +77 -0
  37. synth_ai/cli/commands/help/__init__.py +185 -0
  38. synth_ai/cli/commands/help/core.py +72 -0
  39. synth_ai/cli/commands/scan/__init__.py +19 -0
  40. synth_ai/cli/commands/scan/cloudflare_scanner.py +403 -0
  41. synth_ai/cli/commands/scan/core.py +344 -0
  42. synth_ai/cli/commands/scan/health_checker.py +242 -0
  43. synth_ai/cli/commands/scan/local_scanner.py +278 -0
  44. synth_ai/cli/commands/scan/models.py +83 -0
  45. synth_ai/cli/commands/smoke/__init__.py +7 -0
  46. synth_ai/cli/commands/smoke/core.py +1438 -0
  47. synth_ai/cli/commands/status/__init__.py +66 -0
  48. synth_ai/cli/commands/status/client.py +192 -0
  49. synth_ai/cli/commands/status/config.py +92 -0
  50. synth_ai/cli/commands/status/errors.py +20 -0
  51. synth_ai/cli/commands/status/formatters.py +164 -0
  52. synth_ai/cli/commands/status/subcommands/__init__.py +9 -0
  53. synth_ai/cli/commands/status/subcommands/files.py +79 -0
  54. synth_ai/cli/commands/status/subcommands/jobs.py +334 -0
  55. synth_ai/cli/commands/status/subcommands/models.py +79 -0
  56. synth_ai/cli/commands/status/subcommands/pricing.py +23 -0
  57. synth_ai/cli/commands/status/subcommands/runs.py +81 -0
  58. synth_ai/cli/commands/status/subcommands/session.py +182 -0
  59. synth_ai/cli/commands/status/subcommands/summary.py +47 -0
  60. synth_ai/cli/commands/status/subcommands/usage.py +203 -0
  61. synth_ai/cli/commands/status/utils.py +114 -0
  62. synth_ai/cli/commands/train/__init__.py +53 -0
  63. synth_ai/cli/commands/train/core.py +22 -0
  64. synth_ai/cli/commands/train/errors.py +117 -0
  65. synth_ai/cli/commands/train/judge_schemas.py +201 -0
  66. synth_ai/cli/commands/train/judge_validation.py +305 -0
  67. synth_ai/cli/commands/train/prompt_learning_validation.py +633 -0
  68. synth_ai/cli/commands/train/validation.py +392 -0
  69. synth_ai/cli/demo_apps/__init__.py +10 -0
  70. synth_ai/cli/demo_apps/core/__init__.py +28 -0
  71. synth_ai/cli/demo_apps/core/cli.py +1735 -0
  72. synth_ai/cli/demo_apps/crafter/crafter_fft_4b.toml +55 -0
  73. synth_ai/cli/demo_apps/crafter/grpo_crafter_task_app.py +186 -0
  74. synth_ai/cli/demo_apps/crafter/rl_from_base_qwen4b.toml +74 -0
  75. synth_ai/cli/demo_apps/demo_registry.py +176 -0
  76. synth_ai/cli/demo_apps/demo_task_apps/core.py +440 -0
  77. synth_ai/cli/demo_apps/demo_task_apps/crafter/__init__.py +1 -0
  78. synth_ai/cli/demo_apps/demo_task_apps/crafter/grpo_crafter_task_app.py +185 -0
  79. synth_ai/cli/demo_apps/demo_task_apps/math/modal_task_app.py +742 -0
  80. synth_ai/cli/demo_apps/demo_task_apps/math/task_app_entry.py +39 -0
  81. synth_ai/cli/demo_apps/math/__init__.py +1 -0
  82. synth_ai/cli/demo_apps/math/_common.py +16 -0
  83. synth_ai/cli/demo_apps/math/app.py +38 -0
  84. synth_ai/cli/demo_apps/math/config.toml +76 -0
  85. synth_ai/cli/demo_apps/math/deploy_modal.py +54 -0
  86. synth_ai/cli/demo_apps/math/modal_task_app.py +702 -0
  87. synth_ai/cli/demo_apps/math/task_app_entry.py +53 -0
  88. synth_ai/cli/demo_apps/mipro/main.py +271 -0
  89. synth_ai/cli/demo_apps/mipro/task_app.py +933 -0
  90. synth_ai/cli/demo_apps/mipro/train_cfg.toml +92 -0
  91. synth_ai/cli/demos/__init__.py +12 -0
  92. synth_ai/cli/demos/demo.py +32 -0
  93. synth_ai/cli/demos/rl_demo.py +254 -0
  94. synth_ai/cli/deploy.py +216 -0
  95. synth_ai/cli/infra/__init__.py +14 -0
  96. synth_ai/cli/infra/balance.py +216 -0
  97. synth_ai/cli/infra/mcp.py +35 -0
  98. synth_ai/cli/infra/modal_app.py +36 -0
  99. synth_ai/cli/infra/setup.py +69 -0
  100. synth_ai/cli/infra/status.py +16 -0
  101. synth_ai/cli/infra/turso.py +77 -0
  102. synth_ai/cli/lib/__init__.py +10 -0
  103. synth_ai/cli/lib/agents.py +76 -0
  104. synth_ai/cli/lib/apps/modal_app.py +101 -0
  105. synth_ai/cli/lib/apps/task_app.py +643 -0
  106. synth_ai/cli/lib/bin.py +39 -0
  107. synth_ai/cli/lib/env.py +375 -0
  108. synth_ai/cli/lib/errors.py +85 -0
  109. synth_ai/cli/lib/modal.py +315 -0
  110. synth_ai/cli/lib/plotting.py +126 -0
  111. synth_ai/cli/lib/prompt_args.py +39 -0
  112. synth_ai/cli/lib/prompts.py +284 -0
  113. synth_ai/cli/lib/sqld.py +122 -0
  114. synth_ai/cli/lib/task_app_discovery.py +884 -0
  115. synth_ai/cli/lib/task_app_env.py +295 -0
  116. synth_ai/cli/lib/train_cfgs.py +300 -0
  117. synth_ai/cli/lib/tunnel_records.py +207 -0
  118. synth_ai/cli/local/__init__.py +14 -0
  119. synth_ai/cli/local/experiment_queue/__init__.py +72 -0
  120. synth_ai/cli/local/experiment_queue/api_schemas.py +221 -0
  121. synth_ai/cli/local/experiment_queue/celery_app.py +208 -0
  122. synth_ai/cli/local/experiment_queue/config.py +128 -0
  123. synth_ai/cli/local/experiment_queue/config_utils.py +272 -0
  124. synth_ai/cli/local/experiment_queue/database.py +175 -0
  125. synth_ai/cli/local/experiment_queue/dispatcher.py +119 -0
  126. synth_ai/cli/local/experiment_queue/models.py +231 -0
  127. synth_ai/cli/local/experiment_queue/progress_info.py +160 -0
  128. synth_ai/cli/local/experiment_queue/results.py +373 -0
  129. synth_ai/cli/local/experiment_queue/schemas.py +131 -0
  130. synth_ai/cli/local/experiment_queue/service.py +344 -0
  131. synth_ai/cli/local/experiment_queue/status.py +372 -0
  132. synth_ai/cli/local/experiment_queue/status_tracker.py +360 -0
  133. synth_ai/cli/local/experiment_queue/tasks.py +1984 -0
  134. synth_ai/cli/local/experiment_queue/trace_storage.py +65 -0
  135. synth_ai/cli/local/experiment_queue/validation.py +157 -0
  136. synth_ai/cli/local/session/__init__.py +92 -0
  137. synth_ai/cli/local/session/client.py +383 -0
  138. synth_ai/cli/local/session/constants.py +63 -0
  139. synth_ai/cli/local/session/exceptions.py +105 -0
  140. synth_ai/cli/local/session/manager.py +139 -0
  141. synth_ai/cli/local/session/models.py +89 -0
  142. synth_ai/cli/local/session/query.py +110 -0
  143. synth_ai/cli/root.py +30 -103
  144. synth_ai/cli/task_apps/__init__.py +26 -0
  145. synth_ai/cli/task_apps/commands.py +3153 -0
  146. synth_ai/cli/task_apps/deploy.py +7 -0
  147. synth_ai/cli/task_apps/list.py +26 -0
  148. synth_ai/cli/task_apps/main.py +36 -0
  149. synth_ai/cli/task_apps/modal_serve.py +11 -0
  150. synth_ai/cli/task_apps/serve.py +11 -0
  151. synth_ai/cli/training/__init__.py +8 -0
  152. synth_ai/cli/training/train.py +5 -0
  153. synth_ai/cli/training/train_cfg.py +34 -0
  154. synth_ai/cli/training/watch.py +506 -0
  155. synth_ai/cli/turso.py +34 -55
  156. synth_ai/cli/usage.py +159 -0
  157. synth_ai/cli/utils/__init__.py +8 -0
  158. synth_ai/cli/utils/experiments.py +235 -0
  159. synth_ai/cli/utils/queue.py +504 -0
  160. synth_ai/cli/utils/recent.py +133 -0
  161. synth_ai/cli/utils/traces.py +164 -0
  162. synth_ai/contracts/__init__.py +67 -0
  163. synth_ai/core/__init__.py +100 -0
  164. synth_ai/core/_utils/__init__.py +54 -0
  165. synth_ai/core/_utils/base_url.py +10 -0
  166. synth_ai/core/_utils/http.py +10 -0
  167. synth_ai/core/_utils/prompts.py +14 -0
  168. synth_ai/core/_utils/task_app_state.py +12 -0
  169. synth_ai/core/_utils/user_config.py +10 -0
  170. synth_ai/core/apps/common.py +116 -0
  171. synth_ai/core/auth.py +95 -0
  172. synth_ai/core/cfgs.py +240 -0
  173. synth_ai/core/config/__init__.py +16 -0
  174. synth_ai/core/config/base.py +168 -0
  175. synth_ai/core/config/resolver.py +89 -0
  176. synth_ai/core/env.py +220 -0
  177. synth_ai/core/errors.py +126 -0
  178. synth_ai/core/http.py +230 -0
  179. synth_ai/core/integrations/__init__.py +11 -0
  180. synth_ai/core/integrations/cloudflare.py +1710 -0
  181. synth_ai/core/integrations/mcp/__init__.py +6 -0
  182. synth_ai/core/integrations/mcp/__main__.py +8 -0
  183. synth_ai/core/integrations/mcp/claude.py +36 -0
  184. synth_ai/core/integrations/mcp/main.py +254 -0
  185. synth_ai/core/integrations/mcp/setup.py +100 -0
  186. synth_ai/core/integrations/modal.py +277 -0
  187. synth_ai/core/json.py +72 -0
  188. synth_ai/core/log_filter.py +99 -0
  189. synth_ai/core/logging.py +82 -0
  190. synth_ai/core/paths.py +107 -0
  191. synth_ai/core/pricing.py +109 -0
  192. synth_ai/core/process.py +233 -0
  193. synth_ai/core/ssl.py +25 -0
  194. synth_ai/core/storage/__init__.py +71 -0
  195. synth_ai/core/task_app_state.py +318 -0
  196. synth_ai/core/telemetry.py +282 -0
  197. synth_ai/core/tracing_v3/__init__.py +99 -0
  198. synth_ai/core/tracing_v3/config.py +229 -0
  199. synth_ai/core/tracing_v3/constants.py +21 -0
  200. synth_ai/core/tracing_v3/db_config.py +182 -0
  201. synth_ai/core/tracing_v3/decorators.py +401 -0
  202. synth_ai/core/tracing_v3/examples/basic_usage.py +194 -0
  203. synth_ai/core/tracing_v3/llm_call_record_helpers.py +437 -0
  204. synth_ai/core/tracing_v3/migration_helper.py +119 -0
  205. synth_ai/core/tracing_v3/replica_sync.py +262 -0
  206. synth_ai/core/tracing_v3/serialization.py +130 -0
  207. synth_ai/core/tracing_v3/session_tracer.py +542 -0
  208. synth_ai/core/tracing_v3/storage/base.py +211 -0
  209. synth_ai/core/tracing_v3/storage/config.py +109 -0
  210. synth_ai/core/tracing_v3/storage/factory.py +39 -0
  211. synth_ai/core/tracing_v3/storage/utils.py +206 -0
  212. synth_ai/core/tracing_v3/trace_utils.py +326 -0
  213. synth_ai/core/tracing_v3/turso/__init__.py +12 -0
  214. synth_ai/core/tracing_v3/turso/daemon.py +278 -0
  215. synth_ai/core/tracing_v3/turso/models.py +470 -0
  216. synth_ai/core/tracing_v3/turso/native_manager.py +1385 -0
  217. synth_ai/core/tracing_v3/utils.py +108 -0
  218. synth_ai/core/urls.py +18 -0
  219. synth_ai/core/user_config.py +137 -0
  220. synth_ai/core/uvicorn.py +222 -0
  221. synth_ai/data/__init__.py +110 -0
  222. synth_ai/data/enums.py +141 -0
  223. synth_ai/data/rewards.py +152 -0
  224. synth_ai/data/specs.py +36 -0
  225. synth_ai/data/traces.py +35 -0
  226. synth_ai/products/__init__.py +6 -0
  227. synth_ai/products/graph_evolve/__init__.py +46 -0
  228. synth_ai/products/graph_evolve/client.py +226 -0
  229. synth_ai/products/graph_evolve/config.py +591 -0
  230. synth_ai/products/graph_evolve/converters/__init__.py +42 -0
  231. synth_ai/products/graph_evolve/converters/openai_sft.py +484 -0
  232. synth_ai/products/graph_evolve/examples/hotpotqa/config.toml +109 -0
  233. synth_ai/products/graph_evolve/run.py +222 -0
  234. synth_ai/sdk/__init__.py +119 -0
  235. synth_ai/sdk/api/__init__.py +1 -0
  236. synth_ai/sdk/api/models/supported.py +514 -0
  237. synth_ai/sdk/api/research_agent/__init__.py +86 -0
  238. synth_ai/sdk/api/research_agent/cli.py +428 -0
  239. synth_ai/sdk/api/research_agent/config.py +357 -0
  240. synth_ai/sdk/api/research_agent/job.py +717 -0
  241. synth_ai/sdk/api/train/__init__.py +85 -0
  242. synth_ai/sdk/api/train/builders.py +895 -0
  243. synth_ai/sdk/api/train/cli.py +2188 -0
  244. synth_ai/sdk/api/train/config_finder.py +267 -0
  245. synth_ai/sdk/api/train/configs/__init__.py +65 -0
  246. synth_ai/sdk/api/train/configs/prompt_learning.py +1706 -0
  247. synth_ai/sdk/api/train/configs/rl.py +188 -0
  248. synth_ai/sdk/api/train/configs/sft.py +99 -0
  249. synth_ai/sdk/api/train/configs/shared.py +81 -0
  250. synth_ai/sdk/api/train/context_learning.py +312 -0
  251. synth_ai/sdk/api/train/env_resolver.py +418 -0
  252. synth_ai/sdk/api/train/graph_validators.py +216 -0
  253. synth_ai/sdk/api/train/graphgen.py +984 -0
  254. synth_ai/sdk/api/train/graphgen_models.py +823 -0
  255. synth_ai/sdk/api/train/graphgen_validators.py +109 -0
  256. synth_ai/sdk/api/train/pollers.py +124 -0
  257. synth_ai/sdk/api/train/progress/__init__.py +97 -0
  258. synth_ai/sdk/api/train/progress/dataclasses.py +569 -0
  259. synth_ai/sdk/api/train/progress/events.py +326 -0
  260. synth_ai/sdk/api/train/progress/results.py +428 -0
  261. synth_ai/sdk/api/train/progress/tracker.py +641 -0
  262. synth_ai/sdk/api/train/prompt_learning.py +470 -0
  263. synth_ai/sdk/api/train/rl.py +442 -0
  264. synth_ai/sdk/api/train/sft.py +396 -0
  265. synth_ai/sdk/api/train/summary.py +522 -0
  266. synth_ai/sdk/api/train/supported_algos.py +147 -0
  267. synth_ai/sdk/api/train/task_app.py +331 -0
  268. synth_ai/sdk/api/train/utils.py +279 -0
  269. synth_ai/sdk/api/train/validators.py +2424 -0
  270. synth_ai/sdk/baseline/__init__.py +25 -0
  271. synth_ai/sdk/baseline/config.py +209 -0
  272. synth_ai/sdk/baseline/discovery.py +216 -0
  273. synth_ai/sdk/baseline/execution.py +154 -0
  274. synth_ai/sdk/graphs/__init__.py +15 -0
  275. synth_ai/sdk/graphs/completions.py +570 -0
  276. synth_ai/sdk/inference/__init__.py +6 -0
  277. synth_ai/sdk/inference/client.py +128 -0
  278. synth_ai/sdk/jobs/__init__.py +16 -0
  279. synth_ai/sdk/jobs/client.py +371 -0
  280. synth_ai/sdk/judging/__init__.py +15 -0
  281. synth_ai/sdk/judging/base.py +24 -0
  282. synth_ai/sdk/judging/client.py +191 -0
  283. synth_ai/sdk/judging/schemas.py +222 -0
  284. synth_ai/sdk/judging/types.py +42 -0
  285. synth_ai/sdk/learning/__init__.py +69 -0
  286. synth_ai/sdk/learning/client.py +240 -0
  287. synth_ai/sdk/learning/ft_client.py +7 -0
  288. synth_ai/sdk/learning/health.py +49 -0
  289. synth_ai/sdk/learning/jobs.py +202 -0
  290. synth_ai/sdk/learning/prompt_extraction.py +334 -0
  291. synth_ai/sdk/learning/prompt_learning_client.py +455 -0
  292. synth_ai/sdk/learning/prompt_learning_types.py +185 -0
  293. synth_ai/sdk/learning/rl/client.py +268 -0
  294. synth_ai/sdk/learning/rl/contracts.py +27 -0
  295. synth_ai/sdk/learning/rl/env_keys.py +166 -0
  296. synth_ai/sdk/learning/rl/secrets.py +13 -0
  297. synth_ai/sdk/learning/sft/client.py +95 -0
  298. synth_ai/sdk/learning/sft/config.py +270 -0
  299. synth_ai/sdk/learning/sft/data.py +698 -0
  300. synth_ai/sdk/learning/validators.py +52 -0
  301. synth_ai/sdk/research_agent/__init__.py +34 -0
  302. synth_ai/sdk/research_agent/container_builder.py +328 -0
  303. synth_ai/sdk/research_agent/container_spec.py +198 -0
  304. synth_ai/sdk/research_agent/defaults.py +34 -0
  305. synth_ai/sdk/research_agent/results_collector.py +69 -0
  306. synth_ai/sdk/specs/__init__.py +46 -0
  307. synth_ai/sdk/specs/dataclasses.py +149 -0
  308. synth_ai/sdk/specs/loader.py +144 -0
  309. synth_ai/sdk/specs/serializer.py +199 -0
  310. synth_ai/sdk/specs/validation.py +250 -0
  311. synth_ai/sdk/streaming/__init__.py +35 -0
  312. synth_ai/sdk/streaming/config.py +94 -0
  313. synth_ai/sdk/streaming/handlers.py +1997 -0
  314. synth_ai/sdk/streaming/streamer.py +704 -0
  315. synth_ai/sdk/streaming/types.py +112 -0
  316. synth_ai/sdk/task/__init__.py +151 -0
  317. synth_ai/sdk/task/apps/__init__.py +133 -0
  318. synth_ai/sdk/task/config.py +261 -0
  319. synth_ai/sdk/task/contracts.py +298 -0
  320. synth_ai/sdk/task/datasets.py +108 -0
  321. synth_ai/sdk/task/in_process.py +1190 -0
  322. synth_ai/sdk/task/in_process_runner.py +309 -0
  323. synth_ai/sdk/task/inference_api.py +299 -0
  324. synth_ai/sdk/task/proxy.py +287 -0
  325. synth_ai/sdk/task/rubrics/__init__.py +55 -0
  326. synth_ai/sdk/task/rubrics/loaders.py +156 -0
  327. synth_ai/sdk/task/rubrics/models.py +57 -0
  328. synth_ai/sdk/task/rubrics/scoring.py +116 -0
  329. synth_ai/sdk/task/rubrics/strict.py +149 -0
  330. synth_ai/sdk/task/server.py +580 -0
  331. synth_ai/sdk/task/trace_correlation_helpers.py +506 -0
  332. synth_ai/sdk/task/tracing_utils.py +95 -0
  333. synth_ai/sdk/task/validators.py +456 -0
  334. synth_ai/sdk/tracing/__init__.py +39 -0
  335. synth_ai/sdk/training/__init__.py +102 -0
  336. synth_ai/sdk/usage/__init__.py +37 -0
  337. synth_ai/sdk/usage/client.py +171 -0
  338. synth_ai/sdk/usage/models.py +261 -0
  339. synth_ai/utils/__init__.py +213 -0
  340. synth_ai-0.4.1.dist-info/METADATA +195 -0
  341. synth_ai-0.4.1.dist-info/RECORD +379 -0
  342. synth_ai-0.4.1.dist-info/entry_points.txt +2 -0
  343. synth_ai-0.4.1.dist-info/top_level.txt +1 -0
  344. examples/__init__.py +0 -16
  345. examples/analyze_semantic_words.sh +0 -17
  346. examples/crafter_debug_render.py +0 -186
  347. examples/qwen_coder/README.md +0 -102
  348. examples/qwen_coder/_shared.py +0 -113
  349. examples/qwen_coder/configs/coder_lora_30b.toml +0 -61
  350. examples/qwen_coder/configs/coder_lora_4b.toml +0 -57
  351. examples/qwen_coder/configs/coder_lora_small.toml +0 -58
  352. examples/qwen_coder/generate_dataset.py +0 -98
  353. examples/qwen_coder/infer_ft_smoke.py +0 -64
  354. examples/qwen_coder/infer_prod_proxy.py +0 -73
  355. examples/qwen_coder/infer_via_synth.py +0 -87
  356. examples/qwen_coder/scripts/infer_coder.sh +0 -18
  357. examples/qwen_coder/scripts/train_coder_30b.sh +0 -21
  358. examples/qwen_coder/sft_full_17b.py +0 -103
  359. examples/qwen_coder/sft_lora_30b.py +0 -110
  360. examples/qwen_coder/subset_jsonl.py +0 -38
  361. examples/qwen_coder/validate_jsonl.py +0 -59
  362. examples/rl/README.md +0 -169
  363. examples/rl/configs/eval_base_qwen.toml +0 -15
  364. examples/rl/configs/eval_rl_qwen.toml +0 -11
  365. examples/rl/configs/rl_from_base_qwen.toml +0 -35
  366. examples/rl/configs/rl_from_base_qwen17.toml +0 -74
  367. examples/rl/configs/rl_from_ft_qwen.toml +0 -35
  368. examples/rl/download_dataset.py +0 -80
  369. examples/rl/run_eval.py +0 -436
  370. examples/rl/run_rl_and_save.py +0 -111
  371. examples/rl/task_app/README.md +0 -22
  372. examples/rl/task_app/math_single_step.py +0 -991
  373. examples/rl/task_app/math_task_app.py +0 -115
  374. examples/run_crafter_demo.sh +0 -10
  375. examples/sft/README.md +0 -139
  376. examples/sft/configs/crafter_fft_qwen0p6b.toml +0 -44
  377. examples/sft/configs/crafter_lora_qwen0p6b.toml +0 -45
  378. examples/sft/evaluate.py +0 -117
  379. examples/sft/export_dataset.py +0 -117
  380. examples/sft/generate_traces.py +0 -162
  381. examples/swe/__init__.py +0 -12
  382. examples/swe/task_app/README.md +0 -105
  383. examples/swe/task_app/__init__.py +0 -2
  384. examples/swe/task_app/grpo_swe_mini.py +0 -571
  385. examples/swe/task_app/grpo_swe_mini_task_app.py +0 -136
  386. examples/swe/task_app/hosted/README.md +0 -173
  387. examples/swe/task_app/hosted/__init__.py +0 -5
  388. examples/swe/task_app/hosted/branching.py +0 -143
  389. examples/swe/task_app/hosted/environment_routes.py +0 -1289
  390. examples/swe/task_app/hosted/envs/__init__.py +0 -1
  391. examples/swe/task_app/hosted/envs/crafter/__init__.py +0 -6
  392. examples/swe/task_app/hosted/envs/crafter/app.py +0 -1
  393. examples/swe/task_app/hosted/envs/crafter/environment.py +0 -522
  394. examples/swe/task_app/hosted/envs/crafter/policy.py +0 -478
  395. examples/swe/task_app/hosted/envs/crafter/react_agent.py +0 -108
  396. examples/swe/task_app/hosted/envs/crafter/shared.py +0 -305
  397. examples/swe/task_app/hosted/envs/crafter/tools.py +0 -47
  398. examples/swe/task_app/hosted/envs/mini_swe/__init__.py +0 -8
  399. examples/swe/task_app/hosted/envs/mini_swe/environment.py +0 -1164
  400. examples/swe/task_app/hosted/envs/mini_swe/policy.py +0 -355
  401. examples/swe/task_app/hosted/envs/mini_swe/shared.py +0 -83
  402. examples/swe/task_app/hosted/envs/mini_swe/tools.py +0 -96
  403. examples/swe/task_app/hosted/hosted_app.py +0 -204
  404. examples/swe/task_app/hosted/inference/__init__.py +0 -5
  405. examples/swe/task_app/hosted/inference/openai_client.py +0 -618
  406. examples/swe/task_app/hosted/main.py +0 -100
  407. examples/swe/task_app/hosted/policy_routes.py +0 -1079
  408. examples/swe/task_app/hosted/registry.py +0 -195
  409. examples/swe/task_app/hosted/rollout.py +0 -1869
  410. examples/swe/task_app/hosted/storage/__init__.py +0 -5
  411. examples/swe/task_app/hosted/storage/volume.py +0 -211
  412. examples/swe/task_app/hosted/test_agents.py +0 -161
  413. examples/swe/task_app/hosted/test_service.py +0 -137
  414. examples/swe/task_app/hosted/utils.py +0 -62
  415. examples/vlm/README.md +0 -68
  416. examples/vlm/configs/crafter_vlm_gpt4o.toml +0 -44
  417. examples/vlm/crafter_image_only_agent.py +0 -207
  418. examples/vlm/crafter_openai_vlm_agent.py +0 -277
  419. examples/vlm/filter_image_rows.py +0 -63
  420. examples/vlm/run_crafter_vlm_benchmark.py +0 -316
  421. examples/warming_up_to_rl/analyze_trace_db.py +0 -422
  422. examples/warming_up_to_rl/configs/crafter_fft.toml +0 -48
  423. examples/warming_up_to_rl/configs/crafter_fft_4b.toml +0 -54
  424. examples/warming_up_to_rl/configs/eval_fft_qwen4b.toml +0 -20
  425. examples/warming_up_to_rl/configs/eval_groq_qwen32b.toml +0 -13
  426. examples/warming_up_to_rl/configs/eval_modal_qwen4b.toml +0 -23
  427. examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +0 -83
  428. examples/warming_up_to_rl/configs/rl_from_ft.toml +0 -56
  429. examples/warming_up_to_rl/export_trace_sft.py +0 -723
  430. examples/warming_up_to_rl/groq_test.py +0 -95
  431. examples/warming_up_to_rl/manage_secrets.py +0 -131
  432. examples/warming_up_to_rl/readme.md +0 -179
  433. examples/warming_up_to_rl/run_eval.py +0 -510
  434. examples/warming_up_to_rl/run_fft_and_save.py +0 -380
  435. examples/warming_up_to_rl/run_local_rollout.py +0 -237
  436. examples/warming_up_to_rl/run_local_rollout_modal.py +0 -246
  437. examples/warming_up_to_rl/run_local_rollout_parallel.py +0 -403
  438. examples/warming_up_to_rl/run_local_rollout_traced.py +0 -475
  439. examples/warming_up_to_rl/run_rl_and_save.py +0 -124
  440. examples/warming_up_to_rl/run_rollout_remote.py +0 -154
  441. examples/warming_up_to_rl/task_app/README.md +0 -42
  442. examples/warming_up_to_rl/task_app/grpo_crafter.py +0 -700
  443. examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +0 -146
  444. examples/warming_up_to_rl/task_app/synth_envs_hosted/README.md +0 -173
  445. examples/warming_up_to_rl/task_app/synth_envs_hosted/__init__.py +0 -5
  446. examples/warming_up_to_rl/task_app/synth_envs_hosted/branching.py +0 -143
  447. examples/warming_up_to_rl/task_app/synth_envs_hosted/environment_routes.py +0 -1226
  448. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/__init__.py +0 -1
  449. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/__init__.py +0 -6
  450. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/app.py +0 -1
  451. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +0 -522
  452. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +0 -478
  453. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +0 -108
  454. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +0 -305
  455. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/tools.py +0 -47
  456. examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +0 -204
  457. examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/__init__.py +0 -5
  458. examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +0 -618
  459. examples/warming_up_to_rl/task_app/synth_envs_hosted/main.py +0 -100
  460. examples/warming_up_to_rl/task_app/synth_envs_hosted/policy_routes.py +0 -1083
  461. examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py +0 -195
  462. examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py +0 -1869
  463. examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/__init__.py +0 -5
  464. examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +0 -211
  465. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py +0 -161
  466. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py +0 -137
  467. examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +0 -62
  468. synth/__init__.py +0 -14
  469. synth_ai/api/models/supported.py +0 -376
  470. synth_ai/api/train/__init__.py +0 -5
  471. synth_ai/api/train/builders.py +0 -296
  472. synth_ai/api/train/cli.py +0 -606
  473. synth_ai/api/train/config_finder.py +0 -228
  474. synth_ai/api/train/env_resolver.py +0 -347
  475. synth_ai/api/train/pollers.py +0 -75
  476. synth_ai/api/train/supported_algos.py +0 -139
  477. synth_ai/api/train/task_app.py +0 -195
  478. synth_ai/api/train/utils.py +0 -217
  479. synth_ai/cli/_modal_wrapper.py +0 -28
  480. synth_ai/cli/_typer_patch.py +0 -49
  481. synth_ai/cli/balance.py +0 -203
  482. synth_ai/cli/calc.py +0 -69
  483. synth_ai/cli/demo.py +0 -159
  484. synth_ai/cli/legacy_root_backup.py +0 -470
  485. synth_ai/cli/man.py +0 -106
  486. synth_ai/cli/recent.py +0 -127
  487. synth_ai/cli/rl_demo.py +0 -274
  488. synth_ai/cli/status.py +0 -133
  489. synth_ai/cli/task_apps.py +0 -2782
  490. synth_ai/cli/traces.py +0 -163
  491. synth_ai/cli/watch.py +0 -505
  492. synth_ai/config/base_url.py +0 -107
  493. synth_ai/core/experiment.py +0 -13
  494. synth_ai/core/system.py +0 -15
  495. synth_ai/demo_registry.py +0 -295
  496. synth_ai/demos/core/__init__.py +0 -1
  497. synth_ai/demos/core/cli.py +0 -1756
  498. synth_ai/demos/demo_task_apps/core.py +0 -440
  499. synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +0 -172
  500. synth_ai/demos/demo_task_apps/math/deploy_task_app.sh +0 -22
  501. synth_ai/demos/demo_task_apps/math/modal_task_app.py +0 -739
  502. synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -37
  503. synth_ai/environments/__init__.py +0 -31
  504. synth_ai/environments/environment/__init__.py +0 -1
  505. synth_ai/environments/environment/artifacts/__init__.py +0 -1
  506. synth_ai/environments/environment/artifacts/base.py +0 -52
  507. synth_ai/environments/environment/core.py +0 -67
  508. synth_ai/environments/environment/db/__init__.py +0 -1
  509. synth_ai/environments/environment/db/sqlite.py +0 -45
  510. synth_ai/environments/environment/registry.py +0 -233
  511. synth_ai/environments/environment/resources/sqlite.py +0 -45
  512. synth_ai/environments/environment/results.py +0 -1
  513. synth_ai/environments/environment/rewards/__init__.py +0 -1
  514. synth_ai/environments/environment/rewards/core.py +0 -29
  515. synth_ai/environments/environment/shared_engine.py +0 -26
  516. synth_ai/environments/environment/tools/__init__.py +0 -200
  517. synth_ai/environments/examples/__init__.py +0 -1
  518. synth_ai/environments/examples/bandit/__init__.py +0 -33
  519. synth_ai/environments/examples/bandit/engine.py +0 -302
  520. synth_ai/environments/examples/bandit/environment.py +0 -194
  521. synth_ai/environments/examples/bandit/taskset.py +0 -200
  522. synth_ai/environments/examples/crafter_classic/__init__.py +0 -8
  523. synth_ai/environments/examples/crafter_classic/agent_demos/analyze_semantic_words_markdown.py +0 -250
  524. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_comprehensive_evaluation.py +0 -59
  525. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_browser.py +0 -152
  526. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_config.toml +0 -24
  527. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_framework.py +0 -1194
  528. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/crafter_synth_config.toml +0 -56
  529. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_config_modal.toml +0 -32
  530. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/kick_off_ft_modal.py +0 -384
  531. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_action_results.py +0 -53
  532. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_agent_actions.py +0 -178
  533. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_latest_run.py +0 -222
  534. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_lm_traces.py +0 -183
  535. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_no_rewards.py +0 -210
  536. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_trace_issue.py +0 -206
  537. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_db_schema.py +0 -49
  538. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_latest_results.py +0 -64
  539. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/debug_agent_responses.py +0 -88
  540. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/quick_trace_check.py +0 -77
  541. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/compare_experiments.py +0 -324
  542. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/kick_off_ft_oai.py +0 -362
  543. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/multi_model_config.toml +0 -49
  544. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_enhanced_hooks.py +0 -332
  545. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_events.py +0 -97
  546. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_results.py +0 -217
  547. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_hook_storage.py +0 -87
  548. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_seeds.py +0 -88
  549. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/compare_seed_performance.py +0 -195
  550. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/custom_eval_pipelines.py +0 -400
  551. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/plot_hook_frequency.py +0 -195
  552. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/seed_analysis_summary.py +0 -56
  553. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/run_rollouts_for_models_and_compare_v3.py +0 -858
  554. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_quick_evaluation.py +0 -52
  555. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_react_agent.py +0 -874
  556. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_trace_evaluation.py +0 -1412
  557. synth_ai/environments/examples/crafter_classic/agent_demos/example_v3_usage.py +0 -216
  558. synth_ai/environments/examples/crafter_classic/agent_demos/old/compare_traces.py +0 -296
  559. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_comprehensive_evaluation.py +0 -58
  560. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_env_serialization.py +0 -464
  561. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_evaluation_browser.py +0 -152
  562. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_quick_evaluation.py +0 -51
  563. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_trace_evaluation.py +0 -1412
  564. synth_ai/environments/examples/crafter_classic/agent_demos/old/debug_player_loss.py +0 -112
  565. synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_service.py +0 -203
  566. synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_slowness.py +0 -305
  567. synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_by_difficulty.py +0 -126
  568. synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_example.py +0 -94
  569. synth_ai/environments/examples/crafter_classic/agent_demos/old/explore_saved_states.py +0 -142
  570. synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft.py +0 -26
  571. synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft_OLD.py +0 -984
  572. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_gemini.py +0 -724
  573. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_modal.py +0 -386
  574. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_metadata.py +0 -205
  575. synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_gemini.py +0 -150
  576. synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_modal.py +0 -283
  577. synth_ai/environments/examples/crafter_classic/agent_demos/old/prepare_vertex_ft.py +0 -280
  578. synth_ai/environments/examples/crafter_classic/agent_demos/old/profile_env_slowness.py +0 -456
  579. synth_ai/environments/examples/crafter_classic/agent_demos/old/replicate_issue.py +0 -166
  580. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_and_eval.py +0 -102
  581. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_comparison.py +0 -128
  582. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_qwen_rollouts.py +0 -655
  583. synth_ai/environments/examples/crafter_classic/agent_demos/old/trace_eval_OLD.py +0 -202
  584. synth_ai/environments/examples/crafter_classic/agent_demos/old/validate_openai_format.py +0 -166
  585. synth_ai/environments/examples/crafter_classic/config_logging.py +0 -111
  586. synth_ai/environments/examples/crafter_classic/debug_translation.py +0 -0
  587. synth_ai/environments/examples/crafter_classic/engine.py +0 -579
  588. synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +0 -64
  589. synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +0 -6
  590. synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +0 -75
  591. synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +0 -267
  592. synth_ai/environments/examples/crafter_classic/environment.py +0 -479
  593. synth_ai/environments/examples/crafter_classic/taskset.py +0 -233
  594. synth_ai/environments/examples/crafter_classic/trace_hooks_v3.py +0 -228
  595. synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +0 -299
  596. synth_ai/environments/examples/crafter_custom/__init__.py +0 -4
  597. synth_ai/environments/examples/crafter_custom/agent_demos/__init__.py +0 -1
  598. synth_ai/environments/examples/crafter_custom/agent_demos/trace_eval.py +0 -202
  599. synth_ai/environments/examples/crafter_custom/crafter/__init__.py +0 -7
  600. synth_ai/environments/examples/crafter_custom/crafter/config.py +0 -182
  601. synth_ai/environments/examples/crafter_custom/crafter/constants.py +0 -8
  602. synth_ai/environments/examples/crafter_custom/crafter/engine.py +0 -269
  603. synth_ai/environments/examples/crafter_custom/crafter/env.py +0 -262
  604. synth_ai/environments/examples/crafter_custom/crafter/objects.py +0 -417
  605. synth_ai/environments/examples/crafter_custom/crafter/recorder.py +0 -187
  606. synth_ai/environments/examples/crafter_custom/crafter/worldgen.py +0 -118
  607. synth_ai/environments/examples/crafter_custom/dataset_builder.py +0 -373
  608. synth_ai/environments/examples/crafter_custom/environment.py +0 -312
  609. synth_ai/environments/examples/crafter_custom/old/analyze_diamond_issue.py +0 -159
  610. synth_ai/environments/examples/crafter_custom/old/analyze_diamond_spawning.py +0 -158
  611. synth_ai/environments/examples/crafter_custom/old/compare_worlds.py +0 -71
  612. synth_ai/environments/examples/crafter_custom/old/dataset_stats.py +0 -105
  613. synth_ai/environments/examples/crafter_custom/old/diamond_spawning_summary.py +0 -119
  614. synth_ai/environments/examples/crafter_custom/old/example_dataset_usage.py +0 -52
  615. synth_ai/environments/examples/crafter_custom/run_dataset.py +0 -305
  616. synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +0 -156
  617. synth_ai/environments/examples/enron/art_helpers/local_email_db.py +0 -281
  618. synth_ai/environments/examples/enron/art_helpers/types_enron.py +0 -25
  619. synth_ai/environments/examples/enron/engine.py +0 -295
  620. synth_ai/environments/examples/enron/environment.py +0 -166
  621. synth_ai/environments/examples/enron/taskset.py +0 -112
  622. synth_ai/environments/examples/enron/units/keyword_stats.py +0 -112
  623. synth_ai/environments/examples/minigrid/__init__.py +0 -48
  624. synth_ai/environments/examples/minigrid/agent_demos/minigrid_evaluation_framework.py +0 -1188
  625. synth_ai/environments/examples/minigrid/agent_demos/minigrid_quick_evaluation.py +0 -48
  626. synth_ai/environments/examples/minigrid/agent_demos/minigrid_react_agent.py +0 -562
  627. synth_ai/environments/examples/minigrid/agent_demos/minigrid_trace_evaluation.py +0 -221
  628. synth_ai/environments/examples/minigrid/engine.py +0 -589
  629. synth_ai/environments/examples/minigrid/environment.py +0 -274
  630. synth_ai/environments/examples/minigrid/environment_mapping.py +0 -242
  631. synth_ai/environments/examples/minigrid/puzzle_loader.py +0 -417
  632. synth_ai/environments/examples/minigrid/taskset.py +0 -583
  633. synth_ai/environments/examples/nethack/__init__.py +0 -7
  634. synth_ai/environments/examples/nethack/achievements.py +0 -337
  635. synth_ai/environments/examples/nethack/agent_demos/nethack_evaluation_framework.py +0 -981
  636. synth_ai/environments/examples/nethack/agent_demos/nethack_quick_evaluation.py +0 -74
  637. synth_ai/environments/examples/nethack/agent_demos/nethack_react_agent.py +0 -831
  638. synth_ai/environments/examples/nethack/engine.py +0 -739
  639. synth_ai/environments/examples/nethack/environment.py +0 -256
  640. synth_ai/environments/examples/nethack/helpers/__init__.py +0 -41
  641. synth_ai/environments/examples/nethack/helpers/action_mapping.py +0 -301
  642. synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +0 -402
  643. synth_ai/environments/examples/nethack/helpers/observation_utils.py +0 -433
  644. synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +0 -200
  645. synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +0 -269
  646. synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +0 -308
  647. synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +0 -431
  648. synth_ai/environments/examples/nethack/taskset.py +0 -323
  649. synth_ai/environments/examples/red/__init__.py +0 -7
  650. synth_ai/environments/examples/red/agent_demos/__init__.py +0 -1
  651. synth_ai/environments/examples/red/config_logging.py +0 -110
  652. synth_ai/environments/examples/red/engine.py +0 -694
  653. synth_ai/environments/examples/red/engine_helpers/__init__.py +0 -1
  654. synth_ai/environments/examples/red/engine_helpers/memory_map.py +0 -28
  655. synth_ai/environments/examples/red/engine_helpers/reward_components.py +0 -276
  656. synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +0 -142
  657. synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +0 -57
  658. synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +0 -284
  659. synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +0 -150
  660. synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +0 -138
  661. synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +0 -57
  662. synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +0 -331
  663. synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +0 -121
  664. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +0 -559
  665. synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +0 -313
  666. synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +0 -148
  667. synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +0 -247
  668. synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +0 -368
  669. synth_ai/environments/examples/red/engine_helpers/state_extraction.py +0 -140
  670. synth_ai/environments/examples/red/environment.py +0 -238
  671. synth_ai/environments/examples/red/taskset.py +0 -79
  672. synth_ai/environments/examples/red/units/__init__.py +0 -1
  673. synth_ai/environments/examples/sokoban/__init__.py +0 -1
  674. synth_ai/environments/examples/sokoban/agent_demos/sokoban_full_eval.py +0 -899
  675. synth_ai/environments/examples/sokoban/engine.py +0 -678
  676. synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +0 -1
  677. synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +0 -657
  678. synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +0 -18
  679. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +0 -3
  680. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +0 -131
  681. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +0 -370
  682. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +0 -332
  683. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +0 -306
  684. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +0 -67
  685. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +0 -115
  686. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +0 -123
  687. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +0 -394
  688. synth_ai/environments/examples/sokoban/environment.py +0 -229
  689. synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +0 -440
  690. synth_ai/environments/examples/sokoban/puzzle_loader.py +0 -312
  691. synth_ai/environments/examples/sokoban/taskset.py +0 -428
  692. synth_ai/environments/examples/tictactoe/__init__.py +0 -1
  693. synth_ai/environments/examples/tictactoe/engine.py +0 -368
  694. synth_ai/environments/examples/tictactoe/environment.py +0 -240
  695. synth_ai/environments/examples/tictactoe/taskset.py +0 -215
  696. synth_ai/environments/examples/verilog/__init__.py +0 -10
  697. synth_ai/environments/examples/verilog/engine.py +0 -329
  698. synth_ai/environments/examples/verilog/environment.py +0 -350
  699. synth_ai/environments/examples/verilog/taskset.py +0 -420
  700. synth_ai/environments/examples/wordle/__init__.py +0 -29
  701. synth_ai/environments/examples/wordle/engine.py +0 -398
  702. synth_ai/environments/examples/wordle/environment.py +0 -159
  703. synth_ai/environments/examples/wordle/helpers/generate_instances_wordfreq.py +0 -75
  704. synth_ai/environments/examples/wordle/taskset.py +0 -230
  705. synth_ai/environments/reproducibility/core.py +0 -42
  706. synth_ai/environments/reproducibility/helpers.py +0 -0
  707. synth_ai/environments/reproducibility/tree.py +0 -363
  708. synth_ai/environments/service/app.py +0 -97
  709. synth_ai/environments/service/core_routes.py +0 -1021
  710. synth_ai/environments/service/external_registry.py +0 -56
  711. synth_ai/environments/service/registry.py +0 -9
  712. synth_ai/environments/stateful/__init__.py +0 -1
  713. synth_ai/environments/stateful/core.py +0 -163
  714. synth_ai/environments/stateful/engine.py +0 -21
  715. synth_ai/environments/stateful/state.py +0 -7
  716. synth_ai/environments/tasks/api.py +0 -19
  717. synth_ai/environments/tasks/core.py +0 -81
  718. synth_ai/environments/tasks/filters.py +0 -40
  719. synth_ai/environments/tasks/utils.py +0 -90
  720. synth_ai/environments/v0_observability/history.py +0 -3
  721. synth_ai/environments/v0_observability/log.py +0 -2
  722. synth_ai/evals/base.py +0 -13
  723. synth_ai/handshake.py +0 -109
  724. synth_ai/http.py +0 -26
  725. synth_ai/http_client.py +0 -136
  726. synth_ai/inference/__init__.py +0 -5
  727. synth_ai/inference/client.py +0 -34
  728. synth_ai/jobs/client.py +0 -271
  729. synth_ai/learning/__init__.py +0 -59
  730. synth_ai/learning/client.py +0 -241
  731. synth_ai/learning/ft_client.py +0 -7
  732. synth_ai/learning/health.py +0 -49
  733. synth_ai/learning/jobs.py +0 -201
  734. synth_ai/learning/rl/client.py +0 -267
  735. synth_ai/learning/rl/contracts.py +0 -27
  736. synth_ai/learning/rl/env_keys.py +0 -166
  737. synth_ai/learning/rl/secrets.py +0 -13
  738. synth_ai/learning/sft/client.py +0 -68
  739. synth_ai/learning/sft/config.py +0 -270
  740. synth_ai/learning/sft/data.py +0 -295
  741. synth_ai/learning/validators.py +0 -49
  742. synth_ai/lm/__init__.py +0 -25
  743. synth_ai/main.py +0 -6
  744. synth_ai/task/__init__.py +0 -102
  745. synth_ai/task/apps/__init__.py +0 -128
  746. synth_ai/task/contracts.py +0 -137
  747. synth_ai/task/datasets.py +0 -108
  748. synth_ai/task/proxy.py +0 -259
  749. synth_ai/task/server.py +0 -424
  750. synth_ai/task/tracing_utils.py +0 -84
  751. synth_ai/task/validators.py +0 -11
  752. synth_ai/tracing_v3/__init__.py +0 -97
  753. synth_ai/tracing_v3/config.py +0 -84
  754. synth_ai/tracing_v3/db_config.py +0 -194
  755. synth_ai/tracing_v3/decorators.py +0 -369
  756. synth_ai/tracing_v3/examples/basic_usage.py +0 -189
  757. synth_ai/tracing_v3/llm_call_record_helpers.py +0 -337
  758. synth_ai/tracing_v3/migration_helper.py +0 -120
  759. synth_ai/tracing_v3/replica_sync.py +0 -258
  760. synth_ai/tracing_v3/session_tracer.py +0 -530
  761. synth_ai/tracing_v3/storage/base.py +0 -210
  762. synth_ai/tracing_v3/storage/config.py +0 -75
  763. synth_ai/tracing_v3/storage/factory.py +0 -39
  764. synth_ai/tracing_v3/storage/utils.py +0 -204
  765. synth_ai/tracing_v3/turso/daemon.py +0 -149
  766. synth_ai/tracing_v3/turso/models.py +0 -469
  767. synth_ai/tracing_v3/turso/native_manager.py +0 -1173
  768. synth_ai/tracing_v3/utils.py +0 -108
  769. synth_ai/v0/api/__init__.py +0 -8
  770. synth_ai/v0/api/models/__init__.py +0 -8
  771. synth_ai/v0/api/models/supported.py +0 -8
  772. synth_ai/v0/config/__init__.py +0 -15
  773. synth_ai/v0/config/base_url.py +0 -12
  774. synth_ai/v0/lm/__init__.py +0 -51
  775. synth_ai/v0/lm/caching/constants.py +0 -6
  776. synth_ai/v0/lm/caching/dbs.py +0 -0
  777. synth_ai/v0/lm/caching/ephemeral.py +0 -100
  778. synth_ai/v0/lm/caching/handler.py +0 -137
  779. synth_ai/v0/lm/caching/initialize.py +0 -11
  780. synth_ai/v0/lm/caching/persistent.py +0 -114
  781. synth_ai/v0/lm/config.py +0 -115
  782. synth_ai/v0/lm/constants.py +0 -32
  783. synth_ai/v0/lm/core/__init__.py +0 -8
  784. synth_ai/v0/lm/core/all.py +0 -73
  785. synth_ai/v0/lm/core/exceptions.py +0 -5
  786. synth_ai/v0/lm/core/main.py +0 -331
  787. synth_ai/v0/lm/core/main_v3.py +0 -594
  788. synth_ai/v0/lm/core/synth_models.py +0 -35
  789. synth_ai/v0/lm/core/vendor_clients.py +0 -190
  790. synth_ai/v0/lm/cost/__init__.py +0 -0
  791. synth_ai/v0/lm/cost/monitor.py +0 -1
  792. synth_ai/v0/lm/cost/statefulness.py +0 -1
  793. synth_ai/v0/lm/injection.py +0 -80
  794. synth_ai/v0/lm/overrides.py +0 -206
  795. synth_ai/v0/lm/provider_support/__init__.py +0 -8
  796. synth_ai/v0/lm/provider_support/anthropic.py +0 -972
  797. synth_ai/v0/lm/provider_support/openai.py +0 -1139
  798. synth_ai/v0/lm/provider_support/suppress_logging.py +0 -31
  799. synth_ai/v0/lm/structured_outputs/__init__.py +0 -0
  800. synth_ai/v0/lm/structured_outputs/handler.py +0 -440
  801. synth_ai/v0/lm/structured_outputs/inject.py +0 -297
  802. synth_ai/v0/lm/structured_outputs/rehabilitate.py +0 -185
  803. synth_ai/v0/lm/tools/__init__.py +0 -3
  804. synth_ai/v0/lm/tools/base.py +0 -172
  805. synth_ai/v0/lm/unified_interface.py +0 -202
  806. synth_ai/v0/lm/vendors/__init__.py +0 -0
  807. synth_ai/v0/lm/vendors/base.py +0 -81
  808. synth_ai/v0/lm/vendors/core/__init__.py +0 -0
  809. synth_ai/v0/lm/vendors/core/anthropic_api.py +0 -387
  810. synth_ai/v0/lm/vendors/core/gemini_api.py +0 -292
  811. synth_ai/v0/lm/vendors/core/mistral_api.py +0 -322
  812. synth_ai/v0/lm/vendors/core/openai_api.py +0 -227
  813. synth_ai/v0/lm/vendors/core/synth_dev_api.py +0 -0
  814. synth_ai/v0/lm/vendors/local/__init__.py +0 -0
  815. synth_ai/v0/lm/vendors/local/ollama.py +0 -0
  816. synth_ai/v0/lm/vendors/openai_standard.py +0 -782
  817. synth_ai/v0/lm/vendors/openai_standard_responses.py +0 -259
  818. synth_ai/v0/lm/vendors/retries.py +0 -22
  819. synth_ai/v0/lm/vendors/supported/__init__.py +0 -0
  820. synth_ai/v0/lm/vendors/supported/custom_endpoint.py +0 -415
  821. synth_ai/v0/lm/vendors/supported/deepseek.py +0 -69
  822. synth_ai/v0/lm/vendors/supported/grok.py +0 -75
  823. synth_ai/v0/lm/vendors/supported/groq.py +0 -16
  824. synth_ai/v0/lm/vendors/supported/ollama.py +0 -15
  825. synth_ai/v0/lm/vendors/supported/openrouter.py +0 -74
  826. synth_ai/v0/lm/vendors/supported/together.py +0 -11
  827. synth_ai/v0/lm/vendors/synth_client.py +0 -835
  828. synth_ai/v0/lm/warmup.py +0 -186
  829. synth_ai/v0/tracing/__init__.py +0 -0
  830. synth_ai/v0/tracing/abstractions.py +0 -224
  831. synth_ai/v0/tracing/base_client.py +0 -91
  832. synth_ai/v0/tracing/client_manager.py +0 -131
  833. synth_ai/v0/tracing/config.py +0 -142
  834. synth_ai/v0/tracing/context.py +0 -146
  835. synth_ai/v0/tracing/decorators.py +0 -682
  836. synth_ai/v0/tracing/events/__init__.py +0 -0
  837. synth_ai/v0/tracing/events/manage.py +0 -147
  838. synth_ai/v0/tracing/events/scope.py +0 -86
  839. synth_ai/v0/tracing/events/store.py +0 -228
  840. synth_ai/v0/tracing/immediate_client.py +0 -151
  841. synth_ai/v0/tracing/local.py +0 -18
  842. synth_ai/v0/tracing/log_client_base.py +0 -73
  843. synth_ai/v0/tracing/retry_queue.py +0 -186
  844. synth_ai/v0/tracing/trackers.py +0 -515
  845. synth_ai/v0/tracing/upload.py +0 -409
  846. synth_ai/v0/tracing/utils.py +0 -9
  847. synth_ai/v0/tracing_v1/__init__.py +0 -16
  848. synth_ai/v0/tracing_v1/abstractions.py +0 -224
  849. synth_ai/v0/tracing_v1/base_client.py +0 -91
  850. synth_ai/v0/tracing_v1/client_manager.py +0 -131
  851. synth_ai/v0/tracing_v1/config.py +0 -142
  852. synth_ai/v0/tracing_v1/context.py +0 -146
  853. synth_ai/v0/tracing_v1/decorators.py +0 -703
  854. synth_ai/v0/tracing_v1/events/__init__.py +0 -0
  855. synth_ai/v0/tracing_v1/events/manage.py +0 -147
  856. synth_ai/v0/tracing_v1/events/scope.py +0 -86
  857. synth_ai/v0/tracing_v1/events/store.py +0 -228
  858. synth_ai/v0/tracing_v1/immediate_client.py +0 -151
  859. synth_ai/v0/tracing_v1/local.py +0 -18
  860. synth_ai/v0/tracing_v1/log_client_base.py +0 -73
  861. synth_ai/v0/tracing_v1/retry_queue.py +0 -186
  862. synth_ai/v0/tracing_v1/trackers.py +0 -515
  863. synth_ai/v0/tracing_v1/upload.py +0 -527
  864. synth_ai/v0/tracing_v1/utils.py +0 -9
  865. synth_ai/v0/tracing_v3/__init__.py +0 -10
  866. synth_ai/v0/tracing_v3/abstractions.py +0 -3
  867. synth_ai/v0/tracing_v3/decorators.py +0 -3
  868. synth_ai/v0/tracing_v3/llm_call_record_helpers.py +0 -3
  869. synth_ai/v0/tracing_v3/session_tracer.py +0 -3
  870. synth_ai-0.2.9.dev11.dist-info/METADATA +0 -191
  871. synth_ai-0.2.9.dev11.dist-info/RECORD +0 -571
  872. synth_ai-0.2.9.dev11.dist-info/entry_points.txt +0 -3
  873. synth_ai-0.2.9.dev11.dist-info/top_level.txt +0 -3
  874. /synth_ai/{demos/demo_task_apps → cli/demo_apps}/crafter/__init__.py +0 -0
  875. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/__init__.py +0 -0
  876. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/crafter/configs/crafter_fft_4b.toml +0 -0
  877. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/crafter/configs/rl_from_base_qwen4b.toml +0 -0
  878. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/__init__.py +0 -0
  879. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/_common.py +0 -0
  880. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/app.py +0 -0
  881. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/config.toml +0 -0
  882. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/deploy_modal.py +0 -0
  883. /synth_ai/{v0/lm/caching → core/apps}/__init__.py +0 -0
  884. /synth_ai/{tracing_v3 → core/tracing_v3}/abstractions.py +0 -0
  885. /synth_ai/{tracing_v3 → core/tracing_v3}/hooks.py +0 -0
  886. /synth_ai/{tracing_v3 → core/tracing_v3}/lm_call_record_abstractions.py +0 -0
  887. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/__init__.py +0 -0
  888. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/exceptions.py +0 -0
  889. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/types.py +0 -0
  890. /synth_ai/{compound/cais.py → py.typed} +0 -0
  891. /synth_ai/{learning → sdk/learning}/algorithms.py +0 -0
  892. /synth_ai/{learning → sdk/learning}/config.py +0 -0
  893. /synth_ai/{learning → sdk/learning}/constants.py +0 -0
  894. /synth_ai/{learning → sdk/learning}/core.py +0 -0
  895. /synth_ai/{learning → sdk/learning}/gateway.py +0 -0
  896. /synth_ai/{learning → sdk/learning}/rl/__init__.py +0 -0
  897. /synth_ai/{learning → sdk/learning}/rl/config.py +0 -0
  898. /synth_ai/{learning → sdk/learning}/rl_client.py +0 -0
  899. /synth_ai/{learning → sdk/learning}/sft/__init__.py +0 -0
  900. /synth_ai/{learning → sdk/learning}/sse.py +0 -0
  901. /synth_ai/{task → sdk/task}/auth.py +0 -0
  902. /synth_ai/{task → sdk/task}/client.py +0 -0
  903. /synth_ai/{task → sdk/task}/errors.py +0 -0
  904. /synth_ai/{task → sdk/task}/health.py +0 -0
  905. /synth_ai/{task → sdk/task}/json.py +0 -0
  906. /synth_ai/{task → sdk/task}/rubrics.py +0 -0
  907. /synth_ai/{task → sdk/task}/vendors.py +0 -0
  908. {synth_ai-0.2.9.dev11.dist-info → synth_ai-0.4.1.dist-info}/WHEEL +0 -0
  909. {synth_ai-0.2.9.dev11.dist-info → synth_ai-0.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,1021 +0,0 @@
1
- import base64
2
- import logging
3
- import os
4
- import pickle
5
- import tempfile
6
- import time
7
- from dataclasses import dataclass
8
- from io import BytesIO
9
- from types import SimpleNamespace
10
- from typing import Any
11
- from uuid import uuid4
12
-
13
- import numpy as np
14
- from fastapi import APIRouter, Body, HTTPException
15
- from pydantic import BaseModel
16
- from synth_ai.environments.environment.tools import EnvToolCall
17
- from synth_ai.environments.service.registry import get_environment_cls, list_supported_env_types
18
- from synth_ai.environments.stateful.core import StatefulEnvironment
19
-
20
- # Set up logging
21
- logger = logging.getLogger(__name__)
22
-
23
- # Import tracing abstractions from v3
24
-
25
- # Try to import Redis for persistent storage
26
- try:
27
- import redis.asyncio as aioredis
28
-
29
- REDIS_AVAILABLE = True
30
- # Create Redis client
31
- redis_client = aioredis.from_url(
32
- os.getenv("REDIS_URL", "redis://localhost:6379"),
33
- encoding="utf-8",
34
- decode_responses=False, # We need binary mode for pickle
35
- )
36
- except ImportError:
37
- REDIS_AVAILABLE = False
38
- redis_client = None
39
-
40
- # --- NEW: Global toggle to disable Redis entirely ----------------------------
41
- # Default is *in-memory* only. Set SYNTH_USE_INMEM=0 to enable Redis if available.
42
- if os.getenv("SYNTH_USE_INMEM", "1") == "1":
43
- REDIS_AVAILABLE = False
44
- redis_client = None
45
- # -----------------------------------------------------------------------------
46
-
47
- api_router = APIRouter()
48
-
49
- # Fallback in-memory store if Redis is not available
50
- instances: dict[str, StatefulEnvironment] = {}
51
-
52
-
53
- # Environment-specific task instance creation
54
- @dataclass
55
- class MinimalTaskInstanceMetadata:
56
- """Minimal metadata for environments that need it."""
57
-
58
- pass
59
-
60
-
61
- @dataclass
62
- class MinimalIntent:
63
- """Minimal intent for environments that need it."""
64
-
65
- rubric: dict[str, Any]
66
- gold_trajectories: Any | None = None
67
- gold_state_diff: dict = None
68
- deterministic_eval_functions: list = None
69
-
70
- def __post_init__(self):
71
- if self.gold_state_diff is None:
72
- self.gold_state_diff = {}
73
- if self.deterministic_eval_functions is None:
74
- self.deterministic_eval_functions = []
75
-
76
-
77
- @dataclass
78
- class MinimalImpetus:
79
- """Minimal impetus for environments that need it."""
80
-
81
- instructions: str
82
-
83
-
84
- def create_task_instance_for_environment(
85
- env_name: str,
86
- initial_state: dict[str, Any] | None = None,
87
- config: dict[str, Any] | None = None,
88
- ) -> Any:
89
- """Create appropriate task instance for different environments."""
90
-
91
- if env_name in ["Sokoban", "CrafterClassic", "MiniGrid", "TicTacToe"]:
92
- # These environments work with SimpleNamespace
93
- task = SimpleNamespace(initial_engine_snapshot=initial_state or {})
94
-
95
- # Handle seed for all environments that support it
96
- if config and "seed" in config:
97
- task.initial_engine_snapshot["seed"] = config["seed"]
98
-
99
- # For CrafterClassic, also handle difficulty
100
- if env_name == "CrafterClassic" and config and "difficulty" in config:
101
- task.initial_engine_snapshot["difficulty"] = config["difficulty"]
102
-
103
- # For MiniGrid, handle environment selection
104
- if env_name == "MiniGrid" and config and "env_name" in config:
105
- task.initial_engine_snapshot["env_name"] = config["env_name"]
106
-
107
- return task
108
-
109
- elif env_name == "Verilog":
110
- # Verilog needs a snapshot_dir attribute
111
- # Create a temporary directory for the snapshot
112
- temp_dir = tempfile.mkdtemp(prefix="verilog_task_")
113
- task = SimpleNamespace(
114
- initial_engine_snapshot=initial_state,
115
- snapshot_dir=temp_dir,
116
- metadata=MinimalTaskInstanceMetadata(),
117
- id=uuid4(),
118
- )
119
- return task
120
-
121
- elif env_name == "NetHack":
122
- # NetHack needs proper TaskInstance structure with NetHackTaskInstanceMetadata
123
- from synth_ai.environments.examples.nethack.taskset import NetHackTaskInstanceMetadata
124
-
125
- metadata = NetHackTaskInstanceMetadata(
126
- character_role="tourist", # Easy starting character
127
- starting_level=1,
128
- target_depth=3,
129
- time_limit=1000,
130
- difficulty="tutorial",
131
- special_objectives=["Explore at least 3 different dungeon levels"],
132
- seed=42,
133
- )
134
-
135
- task = SimpleNamespace(
136
- initial_engine_snapshot=initial_state,
137
- metadata=metadata,
138
- id=uuid4(),
139
- intent=MinimalIntent(rubric={"success": "reach target depth"}),
140
- impetus=MinimalImpetus(instructions="Play NetHack and achieve the highest score."),
141
- is_reproducible=False,
142
- )
143
- return task
144
-
145
- elif env_name == "Enron":
146
- # Enron needs task instance with email data
147
- # For now, provide minimal structure
148
- task = SimpleNamespace(
149
- initial_engine_snapshot=initial_state,
150
- metadata=MinimalTaskInstanceMetadata(),
151
- id=uuid4(),
152
- # Enron might need specific data structure
153
- question=initial_state.get("question", "What information can you find?")
154
- if initial_state
155
- else "What information can you find?",
156
- answer=initial_state.get("answer", "") if initial_state else "",
157
- emails=initial_state.get("emails", []) if initial_state else [],
158
- )
159
- return task
160
-
161
- else:
162
- # Default: use SimpleNamespace for unknown environments
163
- return SimpleNamespace(initial_engine_snapshot=initial_state)
164
-
165
-
166
- async def reconstruct_task_instance_from_serialized(
167
- env_name: str, serialized_data: dict[str, Any]
168
- ) -> Any:
169
- """Reconstruct a task instance from serialized data for specific environment types."""
170
-
171
- if env_name == "MiniGrid":
172
- # MiniGrid has its own TaskInstance class with deserialize method
173
- from synth_ai.environments.examples.minigrid.taskset import MiniGridTaskInstance
174
-
175
- return await MiniGridTaskInstance.deserialize(serialized_data)
176
-
177
- elif env_name == "Sokoban":
178
- # Sokoban has its own TaskInstance class with deserialize method
179
- from synth_ai.environments.examples.sokoban.taskset import SokobanTaskInstance
180
-
181
- return await SokobanTaskInstance.deserialize(serialized_data)
182
-
183
- elif env_name in ["CrafterClassic", "CrafterCustom", "TicTacToe"]:
184
- # These environments work with SimpleNamespace - convert serialized data back to SimpleNamespace
185
- from types import SimpleNamespace
186
- from uuid import UUID
187
-
188
- task = SimpleNamespace()
189
- task.id = UUID(serialized_data.get("id", str(uuid4())))
190
- task.initial_engine_snapshot = serialized_data.get("initial_engine_snapshot", {})
191
- task.metadata = SimpleNamespace(**serialized_data.get("metadata", {}))
192
-
193
- # Handle impetus
194
- impetus_data = serialized_data.get("impetus", {})
195
- if impetus_data:
196
- task.impetus = SimpleNamespace(instructions=impetus_data.get("instructions", ""))
197
-
198
- # Handle intent
199
- intent_data = serialized_data.get("intent", {})
200
- if intent_data:
201
- task.intent = SimpleNamespace(
202
- rubric=intent_data.get("rubric", ""),
203
- gold_trajectories=intent_data.get("gold_trajectories", []),
204
- gold_state_diff=intent_data.get("gold_state_diff", {}),
205
- )
206
-
207
- task.is_reproducible = serialized_data.get("is_reproducible", True)
208
-
209
- return task
210
-
211
- elif env_name == "Verilog":
212
- # Verilog needs special handling with snapshot_dir
213
- import tempfile
214
- from types import SimpleNamespace
215
- from uuid import UUID
216
-
217
- task = SimpleNamespace()
218
- task.id = UUID(serialized_data.get("id", str(uuid4())))
219
- task.initial_engine_snapshot = serialized_data.get("initial_engine_snapshot", {})
220
- task.metadata = MinimalTaskInstanceMetadata()
221
- task.snapshot_dir = tempfile.mkdtemp(prefix="verilog_task_")
222
-
223
- # Handle impetus
224
- impetus_data = serialized_data.get("impetus", {})
225
- if impetus_data:
226
- task.impetus = SimpleNamespace(instructions=impetus_data.get("instructions", ""))
227
-
228
- # Handle intent
229
- intent_data = serialized_data.get("intent", {})
230
- if intent_data:
231
- task.intent = SimpleNamespace(
232
- rubric=intent_data.get("rubric", ""),
233
- gold_trajectories=intent_data.get("gold_trajectories", []),
234
- gold_state_diff=intent_data.get("gold_state_diff", {}),
235
- )
236
-
237
- task.is_reproducible = serialized_data.get("is_reproducible", True)
238
-
239
- return task
240
-
241
- elif env_name == "NetHack":
242
- # NetHack needs proper TaskInstance structure with NetHackTaskInstanceMetadata
243
- from types import SimpleNamespace
244
- from uuid import UUID
245
-
246
- from synth_ai.environments.examples.nethack.taskset import NetHackTaskInstanceMetadata
247
-
248
- # Extract metadata from serialized data
249
- metadata_data = serialized_data.get("metadata", {})
250
- metadata = NetHackTaskInstanceMetadata(
251
- character_role=metadata_data.get("character_role", "tourist"),
252
- starting_level=metadata_data.get("starting_level", 1),
253
- target_depth=metadata_data.get("target_depth", 3),
254
- time_limit=metadata_data.get("time_limit", 1000),
255
- difficulty=metadata_data.get("difficulty", "tutorial"),
256
- special_objectives=metadata_data.get(
257
- "special_objectives", ["Explore at least 3 different dungeon levels"]
258
- ),
259
- seed=metadata_data.get("seed", 42),
260
- )
261
-
262
- task = SimpleNamespace()
263
- task.id = UUID(serialized_data.get("id", str(uuid4())))
264
- task.initial_engine_snapshot = serialized_data.get("initial_engine_snapshot", {})
265
- task.metadata = metadata
266
-
267
- # Handle impetus
268
- impetus_data = serialized_data.get("impetus", {})
269
- if impetus_data:
270
- task.impetus = MinimalImpetus(
271
- instructions=impetus_data.get(
272
- "instructions", "Play NetHack and achieve the highest score."
273
- )
274
- )
275
- else:
276
- task.impetus = MinimalImpetus(
277
- instructions="Play NetHack and achieve the highest score."
278
- )
279
-
280
- # Handle intent
281
- intent_data = serialized_data.get("intent", {})
282
- if intent_data:
283
- task.intent = MinimalIntent(
284
- rubric=intent_data.get("rubric", {"success": "reach target depth"}),
285
- gold_trajectories=intent_data.get("gold_trajectories", []),
286
- gold_state_diff=intent_data.get("gold_state_diff", {}),
287
- )
288
- else:
289
- task.intent = MinimalIntent(rubric={"success": "reach target depth"})
290
-
291
- task.is_reproducible = serialized_data.get("is_reproducible", False)
292
-
293
- return task
294
-
295
- elif env_name == "Enron":
296
- # Enron needs task instance with email data
297
- from types import SimpleNamespace
298
- from uuid import UUID
299
-
300
- task = SimpleNamespace()
301
- task.id = UUID(serialized_data.get("id", str(uuid4())))
302
- task.initial_engine_snapshot = serialized_data.get("initial_engine_snapshot", {})
303
- task.metadata = MinimalTaskInstanceMetadata()
304
-
305
- # Enron-specific fields
306
- task.question = serialized_data.get("question", "What information can you find?")
307
- task.answer = serialized_data.get("answer", "")
308
- task.emails = serialized_data.get("emails", [])
309
-
310
- # Handle impetus
311
- impetus_data = serialized_data.get("impetus", {})
312
- if impetus_data:
313
- task.impetus = SimpleNamespace(instructions=impetus_data.get("instructions", ""))
314
-
315
- # Handle intent
316
- intent_data = serialized_data.get("intent", {})
317
- if intent_data:
318
- task.intent = SimpleNamespace(
319
- rubric=intent_data.get("rubric", ""),
320
- gold_trajectories=intent_data.get("gold_trajectories", []),
321
- gold_state_diff=intent_data.get("gold_state_diff", {}),
322
- )
323
-
324
- task.is_reproducible = serialized_data.get("is_reproducible", True)
325
-
326
- return task
327
-
328
- else:
329
- # Default: use SimpleNamespace for unknown environments
330
- from types import SimpleNamespace
331
- from uuid import UUID
332
-
333
- task = SimpleNamespace()
334
- task.id = UUID(serialized_data.get("id", str(uuid4())))
335
- task.initial_engine_snapshot = serialized_data.get("initial_engine_snapshot", {})
336
-
337
- # Handle impetus
338
- impetus_data = serialized_data.get("impetus", {})
339
- if impetus_data:
340
- task.impetus = SimpleNamespace(instructions=impetus_data.get("instructions", ""))
341
-
342
- # Handle intent
343
- intent_data = serialized_data.get("intent", {})
344
- if intent_data:
345
- task.intent = SimpleNamespace(
346
- rubric=intent_data.get("rubric", ""),
347
- gold_trajectories=intent_data.get("gold_trajectories", []),
348
- gold_state_diff=intent_data.get("gold_state_diff", {}),
349
- )
350
-
351
- task.is_reproducible = serialized_data.get("is_reproducible", True)
352
-
353
- return task
354
-
355
-
356
- # Storage abstraction
357
- class InstanceStorage:
358
- """Abstract storage for environment instances"""
359
-
360
- async def store(self, env_id: str, env: StatefulEnvironment):
361
- """Store an environment instance"""
362
- # ALWAYS store in-memory as fallback
363
- instances[env_id] = env
364
-
365
- # ALSO try to store in Redis if available (but don't rely on it)
366
- if REDIS_AVAILABLE and redis_client:
367
- try:
368
- # Serialize the environment using pickle and base64 encode
369
- serialized = base64.b64encode(pickle.dumps(env)).decode("utf-8")
370
- await redis_client.set(f"env_instance:{env_id}", serialized, ex=3600) # 1 hour TTL
371
- print(f"✅ Stored environment {env_id} in Redis + in-memory")
372
- except Exception as e:
373
- print(f"⚠️ Redis storage failed, using in-memory fallback: {e}")
374
- else:
375
- print(f"✅ Stored environment {env_id} in-memory (Redis not available)")
376
-
377
- async def get(self, env_id: str) -> StatefulEnvironment | None:
378
- """Retrieve an environment instance"""
379
- # Try in-memory first (most reliable)
380
- if env_id in instances:
381
- print(f"✅ Retrieved environment {env_id} from in-memory store")
382
- return instances[env_id]
383
-
384
- # Fallback to Redis if not in memory
385
- if REDIS_AVAILABLE and redis_client:
386
- try:
387
- serialized = await redis_client.get(f"env_instance:{env_id}")
388
- if serialized:
389
- # Deserialize from base64 and pickle
390
- env = pickle.loads(base64.b64decode(serialized))
391
- print(f"✅ Retrieved environment {env_id} from Redis (restored to memory)")
392
- # Store back in memory for next time
393
- instances[env_id] = env
394
- return env
395
- except Exception as e:
396
- print(f"⚠️ Redis retrieval failed: {e}")
397
-
398
- print(f"❌ Environment {env_id} not found in either store")
399
- return None
400
-
401
- async def remove(self, env_id: str) -> StatefulEnvironment | None:
402
- """Remove and return an environment instance"""
403
- # Get the environment first
404
- env = await self.get(env_id)
405
-
406
- # Remove from in-memory store
407
- removed_env = instances.pop(env_id, None)
408
-
409
- # Also try to remove from Redis
410
- if REDIS_AVAILABLE and redis_client:
411
- try:
412
- await redis_client.delete(f"env_instance:{env_id}")
413
- print(f"✅ Removed environment {env_id} from both Redis and in-memory")
414
- except Exception as e:
415
- print(f"⚠️ Redis removal failed, removed from in-memory: {e}")
416
- else:
417
- print(f"✅ Removed environment {env_id} from in-memory")
418
-
419
- return env or removed_env
420
-
421
-
422
- # Global storage instance
423
- storage = InstanceStorage()
424
-
425
-
426
- def convert_numpy_types(obj):
427
- """Convert numpy types to native Python types for JSON serialization"""
428
- from dataclasses import is_dataclass
429
-
430
- if isinstance(obj, dict):
431
- return {key: convert_numpy_types(value) for key, value in obj.items()}
432
- elif isinstance(obj, list):
433
- return [convert_numpy_types(item) for item in obj]
434
- elif isinstance(obj, tuple):
435
- return tuple(convert_numpy_types(item) for item in obj)
436
- elif isinstance(obj, np.integer):
437
- return int(obj)
438
- elif isinstance(obj, np.floating):
439
- return float(obj)
440
- elif isinstance(obj, np.ndarray):
441
- return obj.tolist()
442
- elif isinstance(obj, np.bool_):
443
- return bool(obj)
444
- elif is_dataclass(obj):
445
- # Handle dataclasses safely - check if they have a to_dict method first
446
- if hasattr(obj, "to_dict"):
447
- return obj.to_dict()
448
- else:
449
- # Fallback to converting __dict__ but exclude numpy arrays to prevent recursion
450
- result = {}
451
- for key, value in obj.__dict__.items():
452
- if not isinstance(value, np.ndarray):
453
- result[key] = convert_numpy_types(value)
454
- else:
455
- result[key] = value.tolist() # Convert numpy arrays directly
456
- return result
457
- elif hasattr(obj, "__dict__") and not isinstance(obj, type):
458
- # Handle other objects with __dict__ but be more cautious
459
- try:
460
- # Only process if it's likely to be a simple object
461
- if len(obj.__dict__) < 50: # Avoid overly complex objects
462
- result = {}
463
- for key, value in obj.__dict__.items():
464
- if not isinstance(value, np.ndarray):
465
- result[key] = convert_numpy_types(value)
466
- else:
467
- result[key] = value.tolist()
468
- return result
469
- else:
470
- return str(obj) # Fallback to string representation
471
- except (RecursionError, AttributeError):
472
- return str(obj) # Safe fallback
473
- else:
474
- return obj
475
-
476
-
477
- # Request/Response models for better API documentation
478
- class InitializeRequest(BaseModel):
479
- initial_state: dict[str, Any] | None = None
480
- config: dict[str, Any] | None = None
481
- task_instance: dict[str, Any] | None = None # Add task_instance field
482
-
483
-
484
- class StepRequest(BaseModel):
485
- env_id: str
486
- request_id: str | None = None
487
- action: dict[str, Any]
488
-
489
-
490
- class TerminateRequest(BaseModel):
491
- env_id: str
492
-
493
-
494
- @api_router.get("/health")
495
- async def get_health():
496
- return {"status": "ok", "supported_environments": list_supported_env_types()}
497
-
498
-
499
- @api_router.post("/env/{env_name}/initialize")
500
- async def initialize_env(env_name: str, request: InitializeRequest = Body(...)) -> dict[str, Any]:
501
- """Initialize a new environment instance."""
502
- import traceback
503
-
504
- try:
505
- print(f"🔍 Initializing {env_name} environment...")
506
-
507
- cls = get_environment_cls(env_name)
508
- print(f"✅ Got environment class: {cls}")
509
-
510
- # Handle task_instance parameter - use it if provided, otherwise create a new one
511
- if request.task_instance:
512
- print("🔍 Using provided task_instance...")
513
- task = await reconstruct_task_instance_from_serialized(env_name, request.task_instance)
514
- print(f"✅ Reconstructed task instance: {type(task)}")
515
- else:
516
- print("🔍 Creating new task instance...")
517
- # Create environment-specific task instance
518
- task = create_task_instance_for_environment(
519
- env_name, request.initial_state, request.config
520
- )
521
- print(f"✅ Created task instance: {type(task)}")
522
-
523
- # This is where recursion might happen for Sokoban
524
- print("🔍 Creating environment instance...")
525
- env = cls(task)
526
- print("✅ Created environment instance")
527
-
528
- # Generate unique environment ID
529
- env_id = str(uuid4())
530
- print(f"✅ Generated env_id: {env_id}")
531
-
532
- # Initialize and get first observation - this might also cause recursion
533
- print("🔍 Calling env.initialize()...")
534
- obs = await env.initialize()
535
- print(f"✅ Environment initialized, observation type: {type(obs)}")
536
-
537
- # Store the fully initialized environment (fixes Redis initialization bug)
538
- print("🔍 Storing environment...")
539
- await storage.store(env_id, env)
540
- print("✅ Environment stored")
541
-
542
- # Convert numpy types to Python types for JSON serialization
543
- print("🔍 Converting numpy types...")
544
- obs_serializable = convert_numpy_types(obs)
545
- print("✅ Numpy types converted")
546
-
547
- return {"env_id": env_id, "observation": obs_serializable, "done": False, "info": {}}
548
-
549
- except RecursionError as e:
550
- # Capture recursion errors specifically
551
- stack_trace = traceback.format_exc()
552
- print(f"❌ RECURSION ERROR in {env_name} initialization:")
553
- print(stack_trace)
554
- raise HTTPException(
555
- status_code=400, detail=f"Recursion error during {env_name} initialization: {str(e)}"
556
- ) from e
557
-
558
- except Exception as e:
559
- # Capture all other errors
560
- stack_trace = traceback.format_exc()
561
- print(f"❌ ERROR in {env_name} initialization:")
562
- print(stack_trace)
563
- raise HTTPException(
564
- status_code=400, detail=f"Error during {env_name} initialization: {str(e)}"
565
- ) from e
566
-
567
-
568
- @api_router.post("/env/{env_name}/step")
569
- async def step_env(env_name: str, request: StepRequest = Body(...)) -> dict[str, Any]:
570
- """Execute a step in the environment."""
571
- import sys
572
- import uuid as uuid_module
573
-
574
- # Use provided request_id or generate one
575
- request_id = request.request_id or str(uuid_module.uuid4())[:8]
576
- print(
577
- f"🌐 ENVIRONMENTS SERVICE {request_id}: request_id = {request_id}",
578
- file=sys.stderr,
579
- )
580
- print(
581
- f"\n🌐 ENVIRONMENTS SERVICE {request_id}: step_env HTTP endpoint called",
582
- file=sys.stderr,
583
- )
584
- print(f"🌐 ENVIRONMENTS SERVICE {request_id}: env_name = {env_name}", file=sys.stderr)
585
- print(
586
- f"🌐 ENVIRONMENTS SERVICE {request_id}: env_id = {request.env_id}",
587
- file=sys.stderr,
588
- )
589
- print(
590
- f"🌐 ENVIRONMENTS SERVICE {request_id}: action = {request.action}",
591
- file=sys.stderr,
592
- )
593
-
594
- # Track timing
595
- start_time = time.time()
596
-
597
- # Log call stack to see where this HTTP request comes from
598
- import traceback
599
-
600
- stack = traceback.format_stack()
601
- print(
602
- f"🌐 ENVIRONMENTS SERVICE {request_id}: Call stack (last 3 frames):",
603
- file=sys.stderr,
604
- )
605
- for frame in stack[-3:]:
606
- print(f" {frame.strip()}", file=sys.stderr)
607
-
608
- print(
609
- f"🌐 ENVIRONMENTS SERVICE {request_id}: About to retrieve environment from storage",
610
- file=sys.stderr,
611
- )
612
- env = await storage.get(request.env_id)
613
- if not env:
614
- print(
615
- f"🌐 ENVIRONMENTS SERVICE {request_id}: Environment not found!",
616
- file=sys.stderr,
617
- )
618
- raise HTTPException(
619
- status_code=404, detail=f"Environment instance {request.env_id} not found"
620
- )
621
-
622
- try:
623
- print(
624
- f"🌐 ENVIRONMENTS SERVICE {request_id}: About to extract tool calls from action",
625
- file=sys.stderr,
626
- )
627
- # Extract tool calls from action
628
- raw_tool_calls = request.action.get("tool_calls", [])
629
- print(
630
- f"🌐 ENVIRONMENTS SERVICE {request_id}: Extracted raw_tool_calls = {raw_tool_calls}",
631
- file=sys.stderr,
632
- )
633
-
634
- # Convert dictionaries to EnvToolCall objects
635
- tool_calls = []
636
- for call_dict in raw_tool_calls:
637
- if isinstance(call_dict, dict):
638
- # Convert dict to EnvToolCall object
639
- tool_call = EnvToolCall(
640
- tool=call_dict.get("tool", ""), args=call_dict.get("args", {})
641
- )
642
- tool_calls.append(tool_call)
643
- else:
644
- # Already an EnvToolCall object
645
- tool_calls.append(call_dict)
646
-
647
- print(
648
- f"🌐 ENVIRONMENTS SERVICE {request_id}: Converted to EnvToolCall objects: {tool_calls}",
649
- file=sys.stderr,
650
- )
651
-
652
- print(
653
- f"🌐 ENVIRONMENTS SERVICE {request_id}: About to call env.step()",
654
- file=sys.stderr,
655
- )
656
- # Execute step
657
- result = await env.step(tool_calls)
658
- print(
659
- f"🌐 ENVIRONMENTS SERVICE {request_id}: env.step() completed, result type = {type(result)}",
660
- file=sys.stderr,
661
- )
662
-
663
- logger.debug(f"🌐 [{request_id}] Storing updated environment state...")
664
- # Store the updated environment state
665
- await storage.store(request.env_id, env)
666
- logger.debug(f"🌐 [{request_id}] Environment stored successfully")
667
-
668
- # Format response
669
- # FIX: StatefulEnvironment.step() returns observation dict directly,
670
- # not a dict with 'observation', 'reward', 'done', 'info' keys
671
- response = {
672
- "observation": result, # result IS the observation
673
- "reward": result.get("reward_last", None), # Try to get reward from obs
674
- "done": result.get("terminated", False) or result.get("truncated", False),
675
- "info": {
676
- "terminated": result.get("terminated", False),
677
- "truncated": result.get("truncated", False),
678
- },
679
- }
680
-
681
- # Convert numpy types to Python types for JSON serialization
682
- response_serializable = convert_numpy_types(response)
683
-
684
- elapsed_time = time.time() - start_time
685
- logger.info(
686
- f"🌐 [{request_id}] STEP COMPLETE - env: {env_name}, time: {elapsed_time:.3f}s, done: {response.get('done', False)}"
687
- )
688
- logger.debug(f"🌐 [{request_id}] Response keys: {list(response_serializable.keys())}")
689
- return response_serializable
690
- except Exception as e:
691
- elapsed_time = time.time() - start_time
692
- logger.error(
693
- f"🌐 [{request_id}] STEP FAILED - env: {env_name}, time: {elapsed_time:.3f}s, error: {type(e).__name__} - {e}"
694
- )
695
- raise HTTPException(status_code=400, detail=str(e)) from e
696
-
697
-
698
- @api_router.post("/env/{env_name}/terminate")
699
- async def terminate_env(env_name: str, request: TerminateRequest = Body(...)) -> dict[str, Any]:
700
- """Terminate an environment instance."""
701
- logger.info(f"🚪 Terminating environment: {env_name}, env_id: {request.env_id}")
702
- env = await storage.remove(request.env_id)
703
- if not env:
704
- logger.error(f"❌ Environment instance {request.env_id} not found for termination")
705
- raise HTTPException(
706
- status_code=404, detail=f"Environment instance {request.env_id} not found"
707
- )
708
-
709
- try:
710
- # Terminate environment and capture observation
711
- observation = await env.terminate()
712
- observation_serializable = convert_numpy_types(observation)
713
-
714
- return {
715
- "public": observation_serializable,
716
- "private": {"instance_id": request.env_id},
717
- }
718
- except Exception as e:
719
- raise HTTPException(status_code=400, detail=str(e)) from e
720
-
721
-
722
- @api_router.get("/env/{env_name}/frame")
723
- async def get_env_frame(env_name: str, env_id: str) -> dict[str, Any]:
724
- """Return the current rendered frame of the environment as base64 PNG.
725
-
726
- This provides a lightweight way for clients to capture before/after snapshots
727
- around steps without modifying core step responses.
728
- """
729
- env = await storage.get(env_id)
730
- if not env:
731
- raise HTTPException(status_code=404, detail=f"Environment instance {env_id} not found")
732
-
733
- try:
734
- # For CrafterClassic, underlying engine exposes env.render() -> RGB ndarray
735
- if (
736
- hasattr(env, "engine")
737
- and hasattr(env.engine, "env")
738
- and hasattr(env.engine.env, "render")
739
- ):
740
- rgb = env.engine.env.render()
741
- else:
742
- raise RuntimeError("Environment does not support render()")
743
-
744
- if rgb is None:
745
- raise RuntimeError("render() returned None")
746
-
747
- # Encode to PNG base64
748
- try:
749
- from PIL import Image # type: ignore
750
-
751
- img = Image.fromarray(rgb.astype("uint8"), "RGB")
752
- buf = BytesIO()
753
- img.save(buf, format="PNG")
754
- b64 = base64.b64encode(buf.getvalue()).decode("ascii")
755
- except Exception as e:
756
- raise RuntimeError(f"failed to encode frame: {e}") from e
757
-
758
- return {"env_id": env_id, "image_base64": b64}
759
- except Exception as e:
760
- logger.error(f"Error rendering frame for {env_id}: {e}")
761
- raise HTTPException(status_code=500, detail=str(e)) from e
762
-
763
-
764
- @api_router.get("/env/{env_name}/metadata")
765
- async def get_env_metadata(env_name: str, env_id: str) -> dict[str, Any]:
766
- """Get metadata about an environment instance."""
767
- env = await storage.get(env_id)
768
- if not env:
769
- raise HTTPException(status_code=404, detail=f"Environment instance {env_id} not found")
770
-
771
- try:
772
- # Check if environment has get_metadata method
773
- if hasattr(env, "get_metadata"):
774
- metadata = await env.get_metadata()
775
- else:
776
- # Fallback to basic metadata
777
- metadata = {
778
- "env_name": env_name,
779
- "env_id": env_id,
780
- "env_class": env.__class__.__name__,
781
- }
782
-
783
- # Try to get some common attributes
784
- if hasattr(env, "task_instance"):
785
- metadata["has_task_instance"] = True
786
- if hasattr(env.task_instance, "metadata"):
787
- metadata["task_metadata"] = {
788
- k: v
789
- for k, v in vars(env.task_instance.metadata).items()
790
- if not k.startswith("_")
791
- }
792
-
793
- if hasattr(env, "engine"):
794
- metadata["has_engine"] = True
795
- if hasattr(env.engine, "env"):
796
- metadata["engine_info"] = {
797
- "seed": getattr(env.engine.env, "_seed", None),
798
- "area": getattr(env.engine.env, "_area", None),
799
- "length": getattr(env.engine.env, "_length", None),
800
- "step": getattr(env.engine.env, "_step", None),
801
- }
802
-
803
- return metadata
804
- except Exception as e:
805
- logger.error(f"Error getting metadata for environment {env_id}: {e}")
806
- raise HTTPException(status_code=500, detail=str(e)) from e
807
-
808
-
809
- # Keep backward compatibility endpoints but mark as deprecated
810
- @api_router.post("/{env_type}/create", deprecated=True)
811
- async def create_env_legacy(
812
- env_type: str,
813
- config: dict[str, Any] | None = None,
814
- initial_state: dict[str, Any] | None = None,
815
- ) -> dict[str, str]:
816
- """[DEPRECATED] Use /env/{env_name}/initialize instead."""
817
- cls = get_environment_cls(env_type)
818
- task = create_task_instance_for_environment(env_type, initial_state, config)
819
- env = cls(task)
820
- instance_id = str(uuid4())
821
-
822
- # Initialize the environment before storing (fixes Redis initialization bug)
823
- await env.initialize()
824
- await storage.store(instance_id, env)
825
- return {"instance_id": instance_id}
826
-
827
-
828
- @api_router.post("/{env_type}/{instance_id}/reset", deprecated=True)
829
- async def reset_env_legacy(
830
- env_type: str, instance_id: str, seed: int | None = None
831
- ) -> dict[str, Any]:
832
- """[DEPRECATED] Use /env/{env_name}/initialize instead."""
833
- env = await storage.get(instance_id)
834
- if not env:
835
- raise HTTPException(status_code=404, detail="Instance not found")
836
- obs = await env.initialize()
837
- obs_serializable = convert_numpy_types(obs)
838
- return {"private": obs_serializable, "public": obs_serializable}
839
-
840
-
841
- @api_router.post("/{env_type}/{instance_id}/step", deprecated=True)
842
- async def step_env_legacy(env_type: str, instance_id: str, calls: list[Any]) -> dict[str, Any]:
843
- """[DEPRECATED] Use /env/{env_name}/step instead."""
844
- env = await storage.get(instance_id)
845
- if not env:
846
- raise HTTPException(status_code=404, detail="Instance not found")
847
- obs = await env.step(calls)
848
- obs_serializable = convert_numpy_types(obs)
849
- return {"private": obs_serializable, "public": obs_serializable}
850
-
851
-
852
- @api_router.post("/{env_type}/{instance_id}/terminate", deprecated=True)
853
- async def terminate_env_legacy(env_type: str, instance_id: str) -> Any:
854
- """[DEPRECATED] Use /env/{env_name}/terminate instead."""
855
- env = await storage.remove(instance_id)
856
- if not env:
857
- raise HTTPException(status_code=404, detail="Instance not found")
858
- obs = await env.terminate()
859
- obs_serializable = convert_numpy_types(obs)
860
- return obs_serializable
861
-
862
-
863
- @api_router.get("/{env_type}/{instance_id}/checkpoint")
864
- async def checkpoint_env(env_type: str, instance_id: str) -> dict[str, Any]:
865
- """Get a checkpoint of the environment state."""
866
- env = await storage.get(instance_id)
867
- if not env:
868
- raise HTTPException(status_code=404, detail="Instance not found")
869
- snapshot = await env.checkpoint()
870
- snapshot_serializable = convert_numpy_types(snapshot)
871
- return {"snapshot": snapshot_serializable}
872
-
873
-
874
- # ===== Dynamic Environment Registration API =====
875
-
876
-
877
- class RegisterEnvironmentRequest(BaseModel):
878
- name: str
879
- module_path: str
880
- class_name: str
881
- description: str | None = None
882
-
883
-
884
- class UnregisterEnvironmentRequest(BaseModel):
885
- name: str
886
-
887
-
888
- @api_router.post("/registry/environments")
889
- async def register_environment_api(request: RegisterEnvironmentRequest) -> dict[str, Any]:
890
- """
891
- Dynamically register a new environment at runtime.
892
-
893
- This endpoint allows third-party packages to register environments without
894
- restarting the service. The environment class will be imported and validated.
895
-
896
- Example:
897
- POST /registry/environments
898
- {
899
- "name": "MyCustomEnv-v1",
900
- "module_path": "my_package.environments.custom_env",
901
- "class_name": "MyCustomEnvironment",
902
- "description": "A custom environment for testing"
903
- }
904
- """
905
- try:
906
- # Import the module
907
- import importlib
908
-
909
- module = importlib.import_module(request.module_path)
910
-
911
- # Get the class from the module
912
- if not hasattr(module, request.class_name):
913
- raise HTTPException(
914
- status_code=400,
915
- detail=f"Class '{request.class_name}' not found in module '{request.module_path}'",
916
- )
917
-
918
- env_cls = getattr(module, request.class_name)
919
-
920
- # Validate that it's a StatefulEnvironment subclass
921
- from synth_ai.environments.stateful.core import StatefulEnvironment
922
-
923
- if not issubclass(env_cls, StatefulEnvironment):
924
- raise HTTPException(
925
- status_code=400,
926
- detail=f"Class '{request.class_name}' is not a subclass of StatefulEnvironment",
927
- )
928
-
929
- # Register the environment
930
- from synth_ai.environments.environment.registry import register_environment
931
-
932
- register_environment(request.name, env_cls)
933
-
934
- logger.info(f"Dynamically registered environment: {request.name}")
935
-
936
- return {
937
- "success": True,
938
- "message": f"Environment '{request.name}' registered successfully",
939
- "name": request.name,
940
- "module_path": request.module_path,
941
- "class_name": request.class_name,
942
- "description": request.description,
943
- }
944
-
945
- except ImportError as e:
946
- raise HTTPException(
947
- status_code=400, detail=f"Failed to import module '{request.module_path}': {str(e)}"
948
- ) from e
949
- except Exception as e:
950
- logger.error(f"Failed to register environment {request.name}: {e}")
951
- raise HTTPException(
952
- status_code=500, detail=f"Failed to register environment: {str(e)}"
953
- ) from e
954
-
955
-
956
- @api_router.delete("/registry/environments/{env_name}")
957
- async def unregister_environment_api(env_name: str) -> dict[str, Any]:
958
- """
959
- Unregister an environment from the registry.
960
-
961
- This removes the environment from the in-memory registry, making it
962
- unavailable for new instances. Existing instances are not affected.
963
- """
964
- try:
965
- from synth_ai.environments.environment.registry import ENV_REGISTRY
966
-
967
- if env_name not in ENV_REGISTRY:
968
- raise HTTPException(
969
- status_code=404, detail=f"Environment '{env_name}' not found in registry"
970
- )
971
-
972
- # Remove from registry
973
- removed_cls = ENV_REGISTRY.pop(env_name)
974
-
975
- logger.info(f"Unregistered environment: {env_name}")
976
-
977
- return {
978
- "success": True,
979
- "message": f"Environment '{env_name}' unregistered successfully",
980
- "name": env_name,
981
- "class_name": removed_cls.__name__,
982
- }
983
-
984
- except Exception as e:
985
- logger.error(f"Failed to unregister environment {env_name}: {e}")
986
- raise HTTPException(
987
- status_code=500, detail=f"Failed to unregister environment: {str(e)}"
988
- ) from e
989
-
990
-
991
- @api_router.get("/registry/environments")
992
- async def list_registered_environments() -> dict[str, Any]:
993
- """
994
- List all registered environments with their details.
995
-
996
- Returns information about all available environments in the registry,
997
- including both built-in and dynamically registered environments.
998
- """
999
- try:
1000
- from synth_ai.environments.environment.registry import ENV_REGISTRY
1001
-
1002
- environments = []
1003
- for name, env_cls in ENV_REGISTRY.items():
1004
- env_info = {
1005
- "name": name,
1006
- "class_name": env_cls.__name__,
1007
- "module": env_cls.__module__,
1008
- "description": getattr(env_cls, "__doc__", "").split("\n")[0]
1009
- if env_cls.__doc__
1010
- else None,
1011
- }
1012
- environments.append(env_info)
1013
-
1014
- return {
1015
- "environments": sorted(environments, key=lambda x: x["name"]),
1016
- "total_count": len(environments),
1017
- }
1018
-
1019
- except Exception as e:
1020
- logger.error(f"Failed to list environments: {e}")
1021
- raise HTTPException(status_code=500, detail=f"Failed to list environments: {str(e)}") from e