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,808 +0,0 @@
1
- """
2
- OpenAI-compatible client for Synth backend.
3
- Provides async and sync interfaces matching OpenAI's API.
4
- """
5
-
6
- import asyncio
7
- import json
8
- import logging
9
- import os
10
- from typing import Any, Optional
11
-
12
- import httpx
13
-
14
- from ..config import SynthConfig
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
-
19
- class ChatInterface:
20
- """Nested interface to match OpenAI client structure."""
21
-
22
- def __init__(self, client):
23
- self._client = client
24
- self.completions = self
25
-
26
- async def create(self, **kwargs):
27
- """Create chat completion - matches OpenAI interface."""
28
- result = await self._client.chat_completions_create(**kwargs)
29
- # If streaming was requested and the result is an async-iterable, return it directly
30
- if kwargs.get("stream") and hasattr(result, "__aiter__"):
31
- return result
32
- # Convert dict response to object-like structure for OpenAI compatibility
33
- return OpenAIResponse(result)
34
-
35
-
36
- class OpenAIResponse:
37
- """Wrapper to make dict response behave like OpenAI response object."""
38
-
39
- def __init__(self, data: dict):
40
- self._data = data
41
-
42
- @property
43
- def choices(self):
44
- return [OpenAIChoice(choice) for choice in self._data.get("choices", [])]
45
-
46
- @property
47
- def usage(self):
48
- return self._data.get("usage")
49
-
50
- @property
51
- def id(self):
52
- return self._data.get("id")
53
-
54
- @property
55
- def model(self):
56
- return self._data.get("model")
57
-
58
- @property
59
- def object(self):
60
- return self._data.get("object")
61
-
62
-
63
- class OpenAIChoice:
64
- """Wrapper for choice objects."""
65
-
66
- def __init__(self, data: dict):
67
- self._data = data
68
-
69
- @property
70
- def message(self):
71
- return OpenAIMessage(self._data.get("message", {}))
72
-
73
- @property
74
- def finish_reason(self):
75
- return self._data.get("finish_reason")
76
-
77
-
78
- class OpenAIMessage:
79
- """Wrapper for message objects."""
80
-
81
- def __init__(self, data: dict):
82
- self._data = data
83
-
84
- @property
85
- def role(self):
86
- return self._data.get("role")
87
-
88
- @property
89
- def content(self):
90
- return self._data.get("content")
91
-
92
- @property
93
- def tool_calls(self):
94
- return self._data.get("tool_calls")
95
-
96
-
97
- class StreamDelta:
98
- """Wrapper for stream delta objects."""
99
-
100
- def __init__(self, data: dict):
101
- self._data = data or {}
102
-
103
- @property
104
- def content(self) -> Optional[str]:
105
- return self._data.get("content")
106
-
107
-
108
- class StreamChoice:
109
- """Wrapper for stream choice objects."""
110
-
111
- def __init__(self, data: dict):
112
- self._data = data or {}
113
-
114
- @property
115
- def delta(self) -> StreamDelta:
116
- return StreamDelta(self._data.get("delta", {}))
117
-
118
-
119
- class StreamChunk:
120
- """Wrapper for stream chunk to expose .choices[0].delta.content."""
121
-
122
- def __init__(self, data: dict):
123
- self._data = data or {}
124
-
125
- @property
126
- def choices(self):
127
- return [StreamChoice(c) for c in self._data.get("choices", [])]
128
-
129
-
130
- def _wrap_stream_chunk(data: dict) -> StreamChunk:
131
- return StreamChunk(data)
132
-
133
-
134
- class AsyncSynthClient:
135
- """Async client with OpenAI-compatible interface."""
136
-
137
- def __init__(
138
- self,
139
- config: SynthConfig | None = None,
140
- api_key: Optional[str] = None,
141
- base_url: Optional[str] = None,
142
- **_: Any,
143
- ):
144
- """Initialize with config or OpenAI-style parameters/env.
145
-
146
- Precedence: explicit args -> OPENAI_* env -> SYNTH_* env -> SynthConfig.from_env().
147
- """
148
- if config is None and (api_key or base_url):
149
- config = SynthConfig(
150
- base_url=base_url or os.getenv("OPENAI_API_BASE") or os.getenv("SYNTH_BASE_URL"),
151
- api_key=api_key or os.getenv("OPENAI_API_KEY") or os.getenv("SYNTH_API_KEY"),
152
- )
153
- elif config is None and (os.getenv("OPENAI_API_BASE") and os.getenv("OPENAI_API_KEY")):
154
- config = SynthConfig(
155
- base_url=os.getenv("OPENAI_API_BASE"),
156
- api_key=os.getenv("OPENAI_API_KEY"),
157
- )
158
- self.config = config or SynthConfig.from_env()
159
- self._client = None
160
-
161
- # Create nested OpenAI-style interface
162
- self.chat = ChatInterface(self)
163
- self.completions = self.chat # Alias for backward compatibility
164
-
165
- async def __aenter__(self):
166
- self._client = httpx.AsyncClient(
167
- timeout=self.config.timeout,
168
- headers={
169
- "Authorization": f"Bearer {self.config.api_key}",
170
- "Content-Type": "application/json",
171
- },
172
- )
173
- return self
174
-
175
- async def __aexit__(self, *args):
176
- if self._client:
177
- await self._client.aclose()
178
-
179
- async def _ensure_client(self):
180
- """Ensure client is initialized."""
181
- if self._client is None:
182
- self._client = httpx.AsyncClient(
183
- timeout=self.config.timeout,
184
- headers={
185
- "Authorization": f"Bearer {self.config.api_key}",
186
- "Content-Type": "application/json",
187
- },
188
- )
189
-
190
- async def responses_create(
191
- self,
192
- model: str,
193
- messages: list[dict[str, Any]],
194
- previous_response_id: str | None = None,
195
- tools: list[dict[str, Any]] | None = None,
196
- tool_choice: str | dict[str, Any] | None = "auto",
197
- **kwargs,
198
- ) -> dict[str, Any]:
199
- """
200
- Create response using Synth Responses API.
201
-
202
- Args:
203
- model: Model identifier
204
- messages: List of message dicts with 'role' and 'content'
205
- previous_response_id: Optional ID of previous response for thread management
206
- tools: List of available tools
207
- tool_choice: How to choose tools
208
- **kwargs: Additional parameters
209
-
210
- Returns:
211
- Responses API-compatible response dict
212
- """
213
- await self._ensure_client()
214
-
215
- # Build payload for Responses API
216
- payload = {
217
- "model": model,
218
- "messages": messages,
219
- }
220
-
221
- # Add optional parameters
222
- if previous_response_id is not None:
223
- payload["previous_response_id"] = previous_response_id
224
- if tools is not None:
225
- payload["tools"] = tools
226
- payload["tool_choice"] = tool_choice
227
-
228
- # Add any additional kwargs
229
- payload.update(kwargs)
230
-
231
- # Retry logic
232
- for attempt in range(self.config.max_retries):
233
- try:
234
- url = f"{self.config.get_base_url_without_v1()}/v1/responses"
235
- response = await self._client.post(url, json=payload)
236
-
237
- if response.status_code == 200:
238
- return response.json()
239
-
240
- # Handle rate limits with exponential backoff
241
- if response.status_code == 429:
242
- wait_time = 2**attempt
243
- await asyncio.sleep(wait_time)
244
- continue
245
-
246
- # Other errors
247
- response.raise_for_status()
248
-
249
- except Exception as e:
250
- if attempt == self.config.max_retries - 1:
251
- logger.error(f"Failed after {self.config.max_retries} attempts: {e}")
252
- raise
253
- await asyncio.sleep(2**attempt)
254
-
255
- raise Exception(f"Failed to create response after {self.config.max_retries} attempts")
256
-
257
- async def chat_completions_create(
258
- self,
259
- model: str,
260
- messages: list[dict[str, Any]],
261
- temperature: float = 0.7,
262
- max_tokens: int | None = None,
263
- top_p: float = 1.0,
264
- frequency_penalty: float = 0.0,
265
- presence_penalty: float = 0.0,
266
- stop: str | list[str] | None = None,
267
- stream: bool = False,
268
- tools: list[dict[str, Any]] | None = None,
269
- tool_choice: str | dict[str, Any] | None = "auto",
270
- response_format: dict[str, Any] | None = None,
271
- seed: int | None = None,
272
- **kwargs,
273
- ) -> dict[str, Any]:
274
- """
275
- Create chat completion with OpenAI-compatible API.
276
- This method provides the OpenAI client interface structure.
277
- """
278
- return await self._chat_completions_create(
279
- model, messages, temperature, max_tokens, top_p, frequency_penalty,
280
- presence_penalty, stop, stream, tools, tool_choice, response_format, seed, **kwargs
281
- )
282
-
283
- async def _chat_completions_create(
284
- self,
285
- model: str,
286
- messages: list[dict[str, Any]],
287
- temperature: float = 0.7,
288
- max_tokens: int | None = None,
289
- top_p: float = 1.0,
290
- frequency_penalty: float = 0.0,
291
- presence_penalty: float = 0.0,
292
- stop: str | list[str] | None = None,
293
- stream: bool = False,
294
- tools: list[dict[str, Any]] | None = None,
295
- tool_choice: str | dict[str, Any] | None = "auto",
296
- response_format: dict[str, Any] | None = None,
297
- seed: int | None = None,
298
- **kwargs,
299
- ) -> dict[str, Any]:
300
- """
301
- Create chat completion with OpenAI-compatible API.
302
-
303
- Args:
304
- model: Model identifier
305
- messages: List of message dicts with 'role' and 'content'
306
- temperature: Sampling temperature (0-2)
307
- max_tokens: Maximum tokens to generate
308
- top_p: Nucleus sampling parameter
309
- frequency_penalty: Frequency penalty (-2 to 2)
310
- presence_penalty: Presence penalty (-2 to 2)
311
- stop: Stop sequences
312
- stream: Whether to stream responses
313
- tools: List of available tools
314
- tool_choice: How to choose tools
315
- response_format: Response format constraints
316
- seed: Random seed for deterministic output
317
- **kwargs: Additional parameters
318
-
319
- Returns:
320
- OpenAI-compatible response dict
321
- """
322
- await self._ensure_client()
323
-
324
- # Build payload
325
- payload = {
326
- "model": model,
327
- "messages": messages,
328
- "temperature": temperature,
329
- "top_p": top_p,
330
- "frequency_penalty": frequency_penalty,
331
- "presence_penalty": presence_penalty,
332
- "stream": stream,
333
- }
334
-
335
- # Add optional parameters
336
- if max_tokens is not None:
337
- payload["max_tokens"] = max_tokens
338
- if stop is not None:
339
- payload["stop"] = stop
340
- if tools is not None:
341
- payload["tools"] = tools
342
- payload["tool_choice"] = tool_choice
343
- if response_format is not None:
344
- payload["response_format"] = response_format
345
- if seed is not None:
346
- payload["seed"] = seed
347
-
348
- # Add any additional kwargs (including thinking_mode and thinking_budget)
349
- payload.update(kwargs)
350
-
351
- # Apply env defaults for thinking if not set explicitly
352
- try:
353
- if "thinking_mode" not in payload:
354
- env_mode = os.getenv("SYNTH_THINKING_MODE")
355
- if env_mode in ("think", "no_think"):
356
- payload["thinking_mode"] = env_mode
357
- if "thinking_budget" not in payload:
358
- env_budget = os.getenv("SYNTH_THINKING_BUDGET")
359
- if env_budget and str(env_budget).strip().isdigit():
360
- payload["thinking_budget"] = int(env_budget)
361
- except Exception:
362
- pass
363
-
364
- # Local warn if budget exceeds max_tokens (do not mutate payload)
365
- try:
366
- bt = payload.get("thinking_budget")
367
- mt = payload.get("max_tokens")
368
- if isinstance(bt, int) and isinstance(mt, int) and bt > mt:
369
- logger.warning(
370
- "thinking_budget (%s) exceeds max_tokens (%s) – forwarding as-is",
371
- str(bt), str(mt)
372
- )
373
- except Exception:
374
- pass
375
-
376
- # Retry logic
377
- for attempt in range(self.config.max_retries):
378
- try:
379
- url = f"{self.config.get_base_url_without_v1()}/v1/chat/completions"
380
- _debug_client = os.getenv("SYNTH_CLIENT_DEBUG") == "1"
381
- if _debug_client:
382
- print(f"🔍 SYNTH DEBUG: Making request to URL: {url}")
383
- print(f"🔍 SYNTH DEBUG: Payload keys: {list(payload.keys())}")
384
- if "tools" in payload:
385
- # Only print counts, avoid dumping tool schemas unless explicitly enabled
386
- print(f"🔍 SYNTH DEBUG: Tools in payload: {len(payload['tools'])} tools")
387
-
388
- # If streaming requested, return an async stream adapter
389
- if stream:
390
- async def _astream():
391
- await self._ensure_client()
392
- async with self._client.stream("POST", url, json=payload) as r: # type: ignore
393
- r.raise_for_status()
394
- async for line in r.aiter_lines():
395
- if not line:
396
- continue
397
- if line.startswith("data:"):
398
- data_line = line[len("data:") :].strip()
399
- if data_line == "[DONE]":
400
- return
401
- try:
402
- chunk = json.loads(data_line)
403
- yield _wrap_stream_chunk(chunk)
404
- except json.JSONDecodeError:
405
- logger.debug("Non-JSON stream line: %s", data_line)
406
-
407
- class _AsyncStream:
408
- def __aiter__(self):
409
- return _astream()
410
-
411
- async def __aenter__(self):
412
- return self
413
-
414
- async def __aexit__(self, *exc):
415
- return False
416
-
417
- return _AsyncStream()
418
-
419
- response = await self._client.post(url, json=payload)
420
-
421
- if _debug_client:
422
- print(f"🔍 SYNTH DEBUG: Response status: {response.status_code}")
423
-
424
- if response.status_code == 200:
425
- result = response.json()
426
- if _debug_client:
427
- print(f"🔍 SYNTH DEBUG: Response keys: {list(result.keys())}")
428
- if "choices" in result and result["choices"]:
429
- choice = result["choices"][0]
430
- print(f"🔍 SYNTH DEBUG: Choice keys: {list(choice.keys())}")
431
- if "message" in choice:
432
- message = choice["message"]
433
- print(f"🔍 SYNTH DEBUG: Message keys: {list(message.keys())}")
434
- return result
435
-
436
- # Handle rate limits with exponential backoff
437
- if response.status_code == 429:
438
- wait_time = 2**attempt
439
- logger.warning(f"Rate limited, waiting {wait_time}s...")
440
- await asyncio.sleep(wait_time)
441
- continue
442
-
443
- # Other errors
444
- error_msg = f"API error {response.status_code}: {response.text}"
445
- logger.error(error_msg)
446
- raise Exception(error_msg)
447
-
448
- except httpx.TimeoutException:
449
- if attempt < self.config.max_retries - 1:
450
- logger.warning(f"Timeout on attempt {attempt + 1}, retrying...")
451
- continue
452
- raise
453
- except Exception as e:
454
- if attempt < self.config.max_retries - 1 and "rate" in str(e).lower():
455
- wait_time = 2**attempt
456
- logger.warning(f"Error on attempt {attempt + 1}, waiting {wait_time}s...")
457
- await asyncio.sleep(wait_time)
458
- continue
459
- raise
460
-
461
- raise Exception(f"Failed after {self.config.max_retries} attempts")
462
-
463
- async def close(self):
464
- """Close the client."""
465
- if self._client:
466
- await self._client.aclose()
467
-
468
-
469
- class SyncChatInterface:
470
- """Nested interface to match OpenAI client structure (sync version)."""
471
-
472
- def __init__(self, client):
473
- self._client = client
474
- self.completions = self
475
-
476
- def create(self, **kwargs):
477
- """Create chat completion - matches OpenAI interface."""
478
- result = self._client.chat_completions_create(**kwargs)
479
- # Convert dict response to object-like structure for OpenAI compatibility
480
- return OpenAIResponse(result)
481
-
482
-
483
- class SyncSynthClient:
484
- """Sync client with OpenAI-compatible interface."""
485
-
486
- def __init__(
487
- self,
488
- config: SynthConfig | None = None,
489
- api_key: Optional[str] = None,
490
- base_url: Optional[str] = None,
491
- **_: Any,
492
- ):
493
- """Initialize with config or OpenAI-style parameters/env."""
494
- if config is None and (api_key or base_url):
495
- config = SynthConfig(
496
- base_url=base_url or os.getenv("OPENAI_API_BASE") or os.getenv("SYNTH_BASE_URL"),
497
- api_key=api_key or os.getenv("OPENAI_API_KEY") or os.getenv("SYNTH_API_KEY"),
498
- )
499
- elif config is None and (os.getenv("OPENAI_API_BASE") and os.getenv("OPENAI_API_KEY")):
500
- config = SynthConfig(
501
- base_url=os.getenv("OPENAI_API_BASE"),
502
- api_key=os.getenv("OPENAI_API_KEY"),
503
- )
504
- self.config = config or SynthConfig.from_env()
505
- self._client = None
506
-
507
- # Create nested OpenAI-style interface
508
- self.chat = SyncChatInterface(self)
509
- self.completions = self.chat # Alias for backward compatibility
510
-
511
- def __enter__(self):
512
- self._client = httpx.Client(
513
- timeout=self.config.timeout,
514
- headers={
515
- "Authorization": f"Bearer {self.config.api_key}",
516
- "Content-Type": "application/json",
517
- },
518
- )
519
- return self
520
-
521
- def __exit__(self, *args):
522
- if self._client:
523
- self._client.close()
524
-
525
- def _ensure_client(self):
526
- """Ensure client is initialized."""
527
- if self._client is None:
528
- self._client = httpx.Client(
529
- timeout=self.config.timeout,
530
- headers={
531
- "Authorization": f"Bearer {self.config.api_key}",
532
- "Content-Type": "application/json",
533
- },
534
- )
535
-
536
- def responses_create(
537
- self,
538
- model: str,
539
- messages: list[dict[str, Any]],
540
- previous_response_id: str | None = None,
541
- tools: list[dict[str, Any]] | None = None,
542
- tool_choice: str | dict[str, Any] | None = "auto",
543
- **kwargs,
544
- ) -> dict[str, Any]:
545
- """
546
- Create response using Synth Responses API (sync version).
547
-
548
- See AsyncSynthClient.responses_create for full parameter documentation.
549
- """
550
- self._ensure_client()
551
-
552
- # Build payload for Responses API
553
- payload = {
554
- "model": model,
555
- "messages": messages,
556
- }
557
-
558
- # Add optional parameters
559
- if previous_response_id is not None:
560
- payload["previous_response_id"] = previous_response_id
561
- if tools is not None:
562
- payload["tools"] = tools
563
- payload["tool_choice"] = tool_choice
564
-
565
- # Add any additional kwargs
566
- payload.update(kwargs)
567
-
568
- # Retry logic
569
- for attempt in range(self.config.max_retries):
570
- try:
571
- response = self._client.post(
572
- f"{self.config.get_base_url_without_v1()}/v1/responses", json=payload
573
- )
574
-
575
- if response.status_code == 200:
576
- return response.json()
577
-
578
- # Handle rate limits
579
- if response.status_code == 429:
580
- wait_time = 2**attempt
581
- logger.warning(f"Rate limited, waiting {wait_time}s...")
582
- import time
583
-
584
- time.sleep(wait_time)
585
- continue
586
-
587
- # Other errors
588
- error_msg = f"API error {response.status_code}: {response.text}"
589
- logger.error(error_msg)
590
- raise Exception(error_msg)
591
-
592
- except httpx.TimeoutException:
593
- if attempt < self.config.max_retries - 1:
594
- logger.warning(f"Timeout on attempt {attempt + 1}, retrying...")
595
- continue
596
- raise
597
-
598
- raise Exception(f"Failed after {self.config.max_retries} attempts")
599
-
600
- def chat_completions_create(
601
- self, model: str, messages: list[dict[str, Any]], **kwargs
602
- ) -> dict[str, Any]:
603
- """
604
- Create chat completion with OpenAI-compatible API (sync version).
605
-
606
- See AsyncSynthClient.chat_completions_create for full parameter documentation.
607
- """
608
- self._ensure_client()
609
-
610
- # Build payload (same as async version)
611
- payload = {"model": model, "messages": messages, **kwargs}
612
-
613
- # Retry logic
614
- for attempt in range(self.config.max_retries):
615
- try:
616
- response = self._client.post(
617
- f"{self.config.get_base_url_without_v1()}/v1/chat/completions", json=payload
618
- )
619
-
620
- if response.status_code == 200:
621
- return response.json()
622
-
623
- # Handle rate limits
624
- if response.status_code == 429:
625
- wait_time = 2**attempt
626
- logger.warning(f"Rate limited, waiting {wait_time}s...")
627
- import time
628
-
629
- time.sleep(wait_time)
630
- continue
631
-
632
- # Other errors
633
- error_msg = f"API error {response.status_code}: {response.text}"
634
- logger.error(error_msg)
635
- raise Exception(error_msg)
636
-
637
- except httpx.TimeoutException:
638
- if attempt < self.config.max_retries - 1:
639
- logger.warning(f"Timeout on attempt {attempt + 1}, retrying...")
640
- continue
641
- raise
642
-
643
- raise Exception(f"Failed after {self.config.max_retries} attempts")
644
-
645
- def close(self):
646
- """Close the client."""
647
- if self._client:
648
- self._client.close()
649
-
650
-
651
- # Factory functions for easy instantiation
652
- def create_async_client(config: SynthConfig | None = None) -> AsyncSynthClient:
653
- """
654
- Create async Synth client.
655
-
656
- Args:
657
- config: Optional SynthConfig. If not provided, loads from environment.
658
-
659
- Returns:
660
- AsyncSynthClient instance
661
- """
662
- return AsyncSynthClient(config)
663
-
664
-
665
- def create_sync_client(config: SynthConfig | None = None) -> SyncSynthClient:
666
- """
667
- Create sync Synth client.
668
-
669
- Args:
670
- config: Optional SynthConfig. If not provided, loads from environment.
671
-
672
- Returns:
673
- SyncSynthClient instance
674
- """
675
- return SyncSynthClient(config)
676
-
677
-
678
- # Drop-in replacements for OpenAI clients
679
- # These allow Synth to be used as a complete replacement for OpenAI
680
-
681
- class AsyncOpenAI(AsyncSynthClient):
682
- """
683
- Drop-in replacement for openai.AsyncOpenAI.
684
-
685
- Use Synth backend instead of OpenAI while maintaining the same API.
686
-
687
- Example:
688
- from synth_ai.lm.vendors.synth_client import AsyncOpenAI
689
-
690
- client = AsyncOpenAI(
691
- api_key="sk_live_...",
692
- base_url="https://synth-backend-dev-docker.onrender.com/api"
693
- )
694
-
695
- # Works exactly like openai.AsyncOpenAI!
696
- response = await client.chat.completions.create(
697
- model="Qwen/Qwen3-0.6B",
698
- messages=[{"role": "user", "content": "Hello"}]
699
- )
700
- """
701
-
702
- def __init__(self, api_key: str | None = None, base_url: str | None = None, **kwargs):
703
- """
704
- Initialize AsyncOpenAI-compatible Synth client.
705
-
706
- Args:
707
- api_key: Synth API key (if not provided, uses SYNTH_API_KEY env var)
708
- base_url: Synth base URL (if not provided, uses OPENAI_API_BASE env var)
709
- **kwargs: Additional arguments passed to AsyncSynthClient
710
- """
711
- # Handle OpenAI-style initialization
712
- from ..config import SynthConfig
713
- if api_key or base_url:
714
- config = SynthConfig(
715
- base_url=base_url or os.getenv("OPENAI_API_BASE", "https://synth-backend-dev-docker.onrender.com/api"),
716
- api_key=api_key or os.getenv("OPENAI_API_KEY", "")
717
- )
718
- else:
719
- # Fallback to environment variables (OPENAI_* first, then SYNTH_*)
720
- env_base = os.getenv("OPENAI_API_BASE") or os.getenv("SYNTH_BASE_URL")
721
- env_key = os.getenv("OPENAI_API_KEY") or os.getenv("SYNTH_API_KEY")
722
- config = SynthConfig(base_url=env_base, api_key=env_key) if env_base and env_key else None
723
-
724
- super().__init__(config, **kwargs)
725
-
726
-
727
- class OpenAI(SyncSynthClient):
728
- """
729
- Drop-in replacement for openai.OpenAI.
730
-
731
- Synchronous version of AsyncOpenAI for Synth backend.
732
- """
733
-
734
- def __init__(self, api_key: str | None = None, base_url: str | None = None, **kwargs):
735
- """
736
- Initialize OpenAI-compatible Synth client.
737
-
738
- Args:
739
- api_key: Synth API key (if not provided, uses SYNTH_API_KEY env var)
740
- base_url: Synth base URL (if not provided, uses OPENAI_API_BASE env var)
741
- **kwargs: Additional arguments passed to SyncSynthClient
742
- """
743
- # Handle OpenAI-style initialization
744
- from ..config import SynthConfig
745
- if api_key or base_url:
746
- config = SynthConfig(
747
- base_url=base_url or os.getenv("OPENAI_API_BASE", "https://synth-backend-dev-docker.onrender.com/api"),
748
- api_key=api_key or os.getenv("OPENAI_API_KEY", "")
749
- )
750
- else:
751
- env_base = os.getenv("OPENAI_API_BASE") or os.getenv("SYNTH_BASE_URL")
752
- env_key = os.getenv("OPENAI_API_KEY") or os.getenv("SYNTH_API_KEY")
753
- config = SynthConfig(base_url=env_base, api_key=env_key) if env_base and env_key else None
754
-
755
- super().__init__(config, **kwargs)
756
-
757
-
758
- # Convenience imports for easy usage
759
- __all__ = [
760
- "AsyncSynthClient",
761
- "SyncSynthClient",
762
- "AsyncOpenAI", # Drop-in replacement for openai.AsyncOpenAI
763
- "OpenAI", # Drop-in replacement for openai.OpenAI
764
- "create_async_client",
765
- "create_sync_client",
766
- "create_chat_completion_async",
767
- "create_chat_completion_sync",
768
- "SynthConfig",
769
- ]
770
-
771
-
772
- # Convenience functions for one-off requests
773
- async def create_chat_completion_async(
774
- model: str, messages: list[dict[str, Any]], config: SynthConfig | None = None, **kwargs
775
- ) -> dict[str, Any]:
776
- """
777
- Create a chat completion with automatic client management.
778
-
779
- Args:
780
- model: Model identifier
781
- messages: List of message dicts
782
- config: Optional SynthConfig
783
- **kwargs: Additional parameters for chat completion
784
-
785
- Returns:
786
- OpenAI-compatible response dict
787
- """
788
- async with create_async_client(config) as client:
789
- return await client.chat_completions_create(model, messages, **kwargs)
790
-
791
-
792
- def create_chat_completion_sync(
793
- model: str, messages: list[dict[str, Any]], config: SynthConfig | None = None, **kwargs
794
- ) -> dict[str, Any]:
795
- """
796
- Create a chat completion with automatic client management (sync version).
797
-
798
- Args:
799
- model: Model identifier
800
- messages: List of message dicts
801
- config: Optional SynthConfig
802
- **kwargs: Additional parameters for chat completion
803
-
804
- Returns:
805
- OpenAI-compatible response dict
806
- """
807
- with create_sync_client(config) as client:
808
- return client.chat_completions_create(model, messages, **kwargs)