synth-ai 0.2.6.dev1__py3-none-any.whl → 0.4.3__py3-none-any.whl

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