synth-ai 0.2.0__py3-none-any.whl → 0.2.1.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. synth_ai/__init__.py +28 -2
  2. synth_ai/core/system.py +4 -0
  3. synth_ai/environments/__init__.py +35 -0
  4. synth_ai/environments/environment/__init__.py +1 -0
  5. synth_ai/environments/environment/artifacts/__init__.py +1 -0
  6. synth_ai/environments/environment/artifacts/base.py +50 -0
  7. synth_ai/environments/environment/core.py +22 -0
  8. synth_ai/environments/environment/db/__init__.py +1 -0
  9. synth_ai/environments/environment/db/sqlite.py +45 -0
  10. synth_ai/environments/environment/registry.py +24 -0
  11. synth_ai/environments/environment/resources/sqlite.py +46 -0
  12. synth_ai/environments/environment/results.py +1 -0
  13. synth_ai/environments/environment/rewards/__init__.py +1 -0
  14. synth_ai/environments/environment/rewards/core.py +28 -0
  15. synth_ai/environments/environment/shared_engine.py +26 -0
  16. synth_ai/environments/environment/tools/__init__.py +34 -0
  17. synth_ai/environments/examples/__init__.py +1 -0
  18. synth_ai/environments/examples/crafter_classic/__init__.py +8 -0
  19. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_comprehensive_evaluation.py +58 -0
  20. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_browser.py +152 -0
  21. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_framework.py +1194 -0
  22. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_quick_evaluation.py +51 -0
  23. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_react_agent.py +872 -0
  24. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_trace_evaluation.py +1412 -0
  25. synth_ai/environments/examples/crafter_classic/agent_demos/test_crafter_react_agent.py +1110 -0
  26. synth_ai/environments/examples/crafter_classic/config_logging.py +111 -0
  27. synth_ai/environments/examples/crafter_classic/engine.py +502 -0
  28. synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +63 -0
  29. synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +5 -0
  30. synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +74 -0
  31. synth_ai/environments/examples/crafter_classic/environment.py +255 -0
  32. synth_ai/environments/examples/crafter_classic/taskset.py +228 -0
  33. synth_ai/environments/examples/enron/agent_demos/test_synth_react.py +535 -0
  34. synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +156 -0
  35. synth_ai/environments/examples/enron/art_helpers/local_email_db.py +280 -0
  36. synth_ai/environments/examples/enron/art_helpers/types_enron.py +24 -0
  37. synth_ai/environments/examples/enron/engine.py +291 -0
  38. synth_ai/environments/examples/enron/environment.py +165 -0
  39. synth_ai/environments/examples/enron/taskset.py +112 -0
  40. synth_ai/environments/examples/enron/units/keyword_stats.py +111 -0
  41. synth_ai/environments/examples/enron/units/test_email_index.py +8 -0
  42. synth_ai/environments/examples/minigrid/__init__.py +48 -0
  43. synth_ai/environments/examples/minigrid/agent_demos/minigrid_evaluation_framework.py +1188 -0
  44. synth_ai/environments/examples/minigrid/agent_demos/minigrid_quick_evaluation.py +47 -0
  45. synth_ai/environments/examples/minigrid/agent_demos/minigrid_react_agent.py +562 -0
  46. synth_ai/environments/examples/minigrid/agent_demos/minigrid_trace_evaluation.py +220 -0
  47. synth_ai/environments/examples/minigrid/agent_demos/test_minigrid_react_agent.py +393 -0
  48. synth_ai/environments/examples/minigrid/engine.py +589 -0
  49. synth_ai/environments/examples/minigrid/environment.py +274 -0
  50. synth_ai/environments/examples/minigrid/environment_mapping.py +242 -0
  51. synth_ai/environments/examples/minigrid/puzzle_loader.py +416 -0
  52. synth_ai/environments/examples/minigrid/taskset.py +583 -0
  53. synth_ai/environments/examples/minigrid/units/test_action_behavior.py +226 -0
  54. synth_ai/environments/examples/minigrid/units/test_debug_messages.py +83 -0
  55. synth_ai/environments/examples/minigrid/units/test_exploration.py +120 -0
  56. synth_ai/environments/examples/minigrid/units/test_minigrid_engine.py +214 -0
  57. synth_ai/environments/examples/minigrid/units/test_minigrid_environment.py +238 -0
  58. synth_ai/environments/examples/minigrid/units/test_minigrid_environment_mapping.py +301 -0
  59. synth_ai/environments/examples/minigrid/units/test_minigrid_taskset.py +210 -0
  60. synth_ai/environments/examples/nethack/__init__.py +7 -0
  61. synth_ai/environments/examples/nethack/achievements.py +337 -0
  62. synth_ai/environments/examples/nethack/agent_demos/nethack_evaluation_framework.py +981 -0
  63. synth_ai/environments/examples/nethack/agent_demos/nethack_quick_evaluation.py +74 -0
  64. synth_ai/environments/examples/nethack/agent_demos/nethack_react_agent.py +832 -0
  65. synth_ai/environments/examples/nethack/agent_demos/test_nethack_react_agent.py +1112 -0
  66. synth_ai/environments/examples/nethack/engine.py +738 -0
  67. synth_ai/environments/examples/nethack/environment.py +255 -0
  68. synth_ai/environments/examples/nethack/helpers/__init__.py +42 -0
  69. synth_ai/environments/examples/nethack/helpers/action_mapping.py +301 -0
  70. synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +401 -0
  71. synth_ai/environments/examples/nethack/helpers/observation_utils.py +433 -0
  72. synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +201 -0
  73. synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +268 -0
  74. synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +308 -0
  75. synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +430 -0
  76. synth_ai/environments/examples/nethack/taskset.py +323 -0
  77. synth_ai/environments/examples/nethack/units/test_nethack_engine.py +277 -0
  78. synth_ai/environments/examples/nethack/units/test_nethack_environment.py +281 -0
  79. synth_ai/environments/examples/nethack/units/test_nethack_taskset.py +213 -0
  80. synth_ai/environments/examples/nethack/units/test_recording.py +307 -0
  81. synth_ai/environments/examples/red/__init__.py +7 -0
  82. synth_ai/environments/examples/red/agent_demos/__init__.py +1 -0
  83. synth_ai/environments/examples/red/agent_demos/test_synth_react.py +1471 -0
  84. synth_ai/environments/examples/red/config_logging.py +110 -0
  85. synth_ai/environments/examples/red/engine.py +693 -0
  86. synth_ai/environments/examples/red/engine_helpers/__init__.py +1 -0
  87. synth_ai/environments/examples/red/engine_helpers/memory_map.py +28 -0
  88. synth_ai/environments/examples/red/engine_helpers/reward_components.py +275 -0
  89. synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +142 -0
  90. synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +56 -0
  91. synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +283 -0
  92. synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +149 -0
  93. synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +137 -0
  94. synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +56 -0
  95. synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +330 -0
  96. synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +120 -0
  97. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +558 -0
  98. synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +312 -0
  99. synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +147 -0
  100. synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +246 -0
  101. synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +367 -0
  102. synth_ai/environments/examples/red/engine_helpers/state_extraction.py +139 -0
  103. synth_ai/environments/examples/red/environment.py +235 -0
  104. synth_ai/environments/examples/red/taskset.py +77 -0
  105. synth_ai/environments/examples/red/test_fixes.py +125 -0
  106. synth_ai/environments/examples/red/test_fixes_mock.py +148 -0
  107. synth_ai/environments/examples/red/units/__init__.py +1 -0
  108. synth_ai/environments/examples/red/units/test_basic_functionality.py +97 -0
  109. synth_ai/environments/examples/red/units/test_button_press_requirements.py +217 -0
  110. synth_ai/environments/examples/red/units/test_engine.py +192 -0
  111. synth_ai/environments/examples/red/units/test_environment.py +455 -0
  112. synth_ai/environments/examples/red/units/test_exploration_strategy.py +227 -0
  113. synth_ai/environments/examples/red/units/test_integration.py +217 -0
  114. synth_ai/environments/examples/red/units/test_memory_extraction.py +111 -0
  115. synth_ai/environments/examples/red/units/test_menu_bug_reproduction.py +1100 -0
  116. synth_ai/environments/examples/red/units/test_movement_debug.py +255 -0
  117. synth_ai/environments/examples/red/units/test_pokemon_mcts_debug.py +163 -0
  118. synth_ai/environments/examples/red/units/test_pokemon_mcts_verbose.py +117 -0
  119. synth_ai/environments/examples/red/units/test_red_basic.py +145 -0
  120. synth_ai/environments/examples/red/units/test_red_comprehensive.py +323 -0
  121. synth_ai/environments/examples/red/units/test_retry_movement.py +195 -0
  122. synth_ai/environments/examples/red/units/test_reward_components.py +186 -0
  123. synth_ai/environments/examples/red/units/test_rom_integration.py +260 -0
  124. synth_ai/environments/examples/red/units/test_taskset.py +116 -0
  125. synth_ai/environments/examples/red/units/test_tree.py +448 -0
  126. synth_ai/environments/examples/sokoban/__init__.py +1 -0
  127. synth_ai/environments/examples/sokoban/agent_demos/sokoban_full_eval.py +900 -0
  128. synth_ai/environments/examples/sokoban/agent_demos/test_dspy_react.py +1 -0
  129. synth_ai/environments/examples/sokoban/agent_demos/test_sokoban_react_agent.py +498 -0
  130. synth_ai/environments/examples/sokoban/agent_demos/test_synth_lats.py +1 -0
  131. synth_ai/environments/examples/sokoban/agent_demos/test_synth_react_locally.py +748 -0
  132. synth_ai/environments/examples/sokoban/agent_demos/test_synth_react_service.py +296 -0
  133. synth_ai/environments/examples/sokoban/engine.py +675 -0
  134. synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +1 -0
  135. synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +656 -0
  136. synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +17 -0
  137. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +3 -0
  138. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +129 -0
  139. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +370 -0
  140. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +331 -0
  141. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +305 -0
  142. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +66 -0
  143. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +114 -0
  144. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +122 -0
  145. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +394 -0
  146. synth_ai/environments/examples/sokoban/environment.py +228 -0
  147. synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +438 -0
  148. synth_ai/environments/examples/sokoban/puzzle_loader.py +311 -0
  149. synth_ai/environments/examples/sokoban/taskset.py +425 -0
  150. synth_ai/environments/examples/sokoban/units/astar_common.py +94 -0
  151. synth_ai/environments/examples/sokoban/units/test_building_task_set.py +49 -0
  152. synth_ai/environments/examples/sokoban/units/test_false_positive.py +120 -0
  153. synth_ai/environments/examples/sokoban/units/test_simple_run_through_environment.py +119 -0
  154. synth_ai/environments/examples/sokoban/units/test_sokoban_environment.py +98 -0
  155. synth_ai/environments/examples/sokoban/units/test_tree.py +364 -0
  156. synth_ai/environments/examples/tictactoe/__init__.py +1 -0
  157. synth_ai/environments/examples/tictactoe/agent_demos/test_synth_react.py +266 -0
  158. synth_ai/environments/examples/tictactoe/agent_demos/test_tictactoe_react_agent.py +470 -0
  159. synth_ai/environments/examples/tictactoe/engine.py +368 -0
  160. synth_ai/environments/examples/tictactoe/environment.py +239 -0
  161. synth_ai/environments/examples/tictactoe/taskset.py +214 -0
  162. synth_ai/environments/examples/tictactoe/units/test_tictactoe_engine.py +393 -0
  163. synth_ai/environments/examples/tictactoe/units/test_tictactoe_environment.py +493 -0
  164. synth_ai/environments/examples/tictactoe/units/test_tictactoe_taskset.py +191 -0
  165. synth_ai/environments/examples/verilog/__init__.py +10 -0
  166. synth_ai/environments/examples/verilog/agent_demos/test_synth_react.py +520 -0
  167. synth_ai/environments/examples/verilog/engine.py +328 -0
  168. synth_ai/environments/examples/verilog/environment.py +349 -0
  169. synth_ai/environments/examples/verilog/taskset.py +418 -0
  170. synth_ai/environments/examples/verilog/units/test_verilog_engine.py +466 -0
  171. synth_ai/environments/examples/verilog/units/test_verilog_environment.py +585 -0
  172. synth_ai/environments/examples/verilog/units/test_verilog_integration.py +383 -0
  173. synth_ai/environments/examples/verilog/units/test_verilog_taskset.py +457 -0
  174. synth_ai/environments/reproducibility/core.py +42 -0
  175. synth_ai/environments/reproducibility/tree.py +364 -0
  176. synth_ai/environments/service/app.py +78 -0
  177. synth_ai/environments/service/core_routes.py +775 -0
  178. synth_ai/environments/service/external_registry.py +57 -0
  179. synth_ai/environments/service/registry.py +9 -0
  180. synth_ai/environments/stateful/__init__.py +1 -0
  181. synth_ai/environments/stateful/core.py +28 -0
  182. synth_ai/environments/stateful/engine.py +21 -0
  183. synth_ai/environments/stateful/state.py +7 -0
  184. synth_ai/environments/tasks/api.py +19 -0
  185. synth_ai/environments/tasks/core.py +78 -0
  186. synth_ai/environments/tasks/filters.py +39 -0
  187. synth_ai/environments/tasks/utils.py +89 -0
  188. synth_ai/environments/v0_observability/history.py +3 -0
  189. synth_ai/environments/v0_observability/log.py +2 -0
  190. synth_ai/lm/caching/constants.py +1 -0
  191. synth_ai/{zyk/lms → lm}/caching/ephemeral.py +4 -8
  192. synth_ai/{zyk/lms → lm}/caching/handler.py +15 -15
  193. synth_ai/{zyk/lms → lm}/caching/initialize.py +2 -4
  194. synth_ai/{zyk/lms → lm}/caching/persistent.py +4 -10
  195. synth_ai/{zyk/lms → lm}/config.py +2 -1
  196. synth_ai/{zyk/lms → lm}/constants.py +2 -2
  197. synth_ai/{zyk/lms → lm}/core/all.py +10 -10
  198. synth_ai/{zyk/lms → lm}/core/main.py +57 -33
  199. synth_ai/{zyk/lms → lm}/core/vendor_clients.py +12 -10
  200. synth_ai/lm/cost/monitor.py +1 -0
  201. synth_ai/lm/cost/statefulness.py +1 -0
  202. synth_ai/lm/provider_support/__init__.py +8 -0
  203. synth_ai/lm/provider_support/anthropic.py +945 -0
  204. synth_ai/lm/provider_support/openai.py +1115 -0
  205. synth_ai/lm/provider_support/suppress_logging.py +31 -0
  206. synth_ai/{zyk/lms → lm}/structured_outputs/handler.py +58 -80
  207. synth_ai/{zyk/lms → lm}/structured_outputs/inject.py +6 -20
  208. synth_ai/{zyk/lms → lm}/structured_outputs/rehabilitate.py +6 -12
  209. synth_ai/{zyk/lms → lm}/vendors/core/anthropic_api.py +21 -30
  210. synth_ai/{zyk/lms → lm}/vendors/core/gemini_api.py +35 -32
  211. synth_ai/{zyk/lms → lm}/vendors/core/mistral_api.py +19 -28
  212. synth_ai/{zyk/lms → lm}/vendors/core/openai_api.py +26 -36
  213. synth_ai/{zyk/lms → lm}/vendors/openai_standard.py +29 -33
  214. synth_ai/{zyk/lms → lm}/vendors/retries.py +1 -1
  215. synth_ai/lm/vendors/supported/__init__.py +0 -0
  216. synth_ai/{zyk/lms → lm}/vendors/supported/custom_endpoint.py +131 -118
  217. synth_ai/{zyk/lms → lm}/vendors/supported/deepseek.py +4 -8
  218. synth_ai/{zyk/lms → lm}/vendors/supported/grok.py +6 -8
  219. synth_ai/{zyk/lms → lm}/vendors/supported/groq.py +1 -1
  220. synth_ai/{zyk/lms → lm}/vendors/supported/ollama.py +2 -2
  221. synth_ai/{zyk/lms → lm}/vendors/supported/openrouter.py +18 -16
  222. synth_ai/{zyk/lms → lm}/vendors/supported/together.py +1 -1
  223. synth_ai/tracing/__init__.py +0 -0
  224. synth_ai/tracing/abstractions.py +224 -0
  225. synth_ai/tracing/base_client.py +91 -0
  226. synth_ai/tracing/client_manager.py +131 -0
  227. synth_ai/tracing/config.py +140 -0
  228. synth_ai/tracing/context.py +146 -0
  229. synth_ai/tracing/decorators.py +679 -0
  230. synth_ai/tracing/events/__init__.py +0 -0
  231. synth_ai/tracing/events/manage.py +147 -0
  232. synth_ai/tracing/events/scope.py +86 -0
  233. synth_ai/tracing/events/store.py +227 -0
  234. synth_ai/tracing/immediate_client.py +152 -0
  235. synth_ai/tracing/local.py +18 -0
  236. synth_ai/tracing/log_client_base.py +74 -0
  237. synth_ai/tracing/retry_queue.py +187 -0
  238. synth_ai/tracing/trackers.py +515 -0
  239. synth_ai/tracing/upload.py +504 -0
  240. synth_ai/tracing/utils.py +9 -0
  241. synth_ai/zyk/__init__.py +28 -2
  242. synth_ai-0.2.1.dev0.dist-info/METADATA +349 -0
  243. synth_ai-0.2.1.dev0.dist-info/RECORD +261 -0
  244. {synth_ai-0.2.0.dist-info → synth_ai-0.2.1.dev0.dist-info}/WHEEL +1 -1
  245. synth_ai/zyk/lms/caching/constants.py +0 -1
  246. synth_ai/zyk/lms/cost/monitor.py +0 -1
  247. synth_ai/zyk/lms/cost/statefulness.py +0 -1
  248. synth_ai-0.2.0.dist-info/METADATA +0 -36
  249. synth_ai-0.2.0.dist-info/RECORD +0 -50
  250. /synth_ai/{zyk/lms/__init__.py → environments/reproducibility/helpers.py} +0 -0
  251. /synth_ai/{zyk/lms/caching → lm}/__init__.py +0 -0
  252. /synth_ai/{zyk/lms/core → lm/caching}/__init__.py +0 -0
  253. /synth_ai/{zyk/lms → lm}/caching/dbs.py +0 -0
  254. /synth_ai/{zyk/lms/cost → lm/core}/__init__.py +0 -0
  255. /synth_ai/{zyk/lms → lm}/core/exceptions.py +0 -0
  256. /synth_ai/{zyk/lms/structured_outputs → lm/cost}/__init__.py +0 -0
  257. /synth_ai/{zyk/lms/vendors → lm/structured_outputs}/__init__.py +0 -0
  258. /synth_ai/{zyk/lms → lm}/tools/__init__.py +0 -0
  259. /synth_ai/{zyk/lms → lm}/tools/base.py +0 -0
  260. /synth_ai/{zyk/lms/vendors/core → lm/vendors}/__init__.py +0 -0
  261. /synth_ai/{zyk/lms → lm}/vendors/base.py +0 -0
  262. /synth_ai/{zyk/lms/vendors/local → lm/vendors/core}/__init__.py +0 -0
  263. /synth_ai/{zyk/lms/vendors/supported → lm/vendors/local}/__init__.py +0 -0
  264. /synth_ai/{zyk/lms → lm}/vendors/local/ollama.py +0 -0
  265. {synth_ai-0.2.0.dist-info → synth_ai-0.2.1.dev0.dist-info/licenses}/LICENSE +0 -0
  266. {synth_ai-0.2.0.dist-info → synth_ai-0.2.1.dev0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,31 @@
1
+ import logging
2
+
3
+
4
+ class ExcludeLangfuseMessagesFilter(logging.Filter):
5
+ def filter(self, record):
6
+ # Return False to exclude the record, True to include it
7
+ message = record.getMessage()
8
+ excluded_messages = [
9
+ "No observation found in the current context",
10
+ "No trace found in the current context",
11
+ "Adding event to partition",
12
+ ]
13
+ return not any(msg in message for msg in excluded_messages)
14
+
15
+
16
+ # Configure root logger
17
+ root_logger = logging.getLogger()
18
+ root_logger.addFilter(ExcludeLangfuseMessagesFilter())
19
+ root_logger.setLevel(logging.ERROR)
20
+
21
+ # Configure langfuse logger
22
+ langfuse_logger = logging.getLogger("langfuse")
23
+ langfuse_logger.addFilter(ExcludeLangfuseMessagesFilter())
24
+ langfuse_logger.setLevel(logging.CRITICAL)
25
+ langfuse_logger.propagate = False
26
+
27
+ # Also configure the synth_sdk logger
28
+ synth_logger = logging.getLogger("synth_sdk")
29
+ synth_logger.addFilter(ExcludeLangfuseMessagesFilter())
30
+ synth_logger.setLevel(logging.ERROR)
31
+ synth_logger.propagate = False
@@ -5,17 +5,17 @@ from typing import Any, Callable, Dict, List, Literal, Optional, Union
5
5
 
6
6
  from pydantic import BaseModel
7
7
 
8
- from synth_ai.zyk.lms.core.exceptions import StructuredOutputCoercionFailureException
9
- from synth_ai.zyk.lms.structured_outputs.inject import (
8
+ from synth_ai.lm.core.exceptions import StructuredOutputCoercionFailureException
9
+ from synth_ai.lm.structured_outputs.inject import (
10
10
  inject_structured_output_instructions,
11
11
  )
12
- from synth_ai.zyk.lms.structured_outputs.rehabilitate import (
12
+ from synth_ai.lm.structured_outputs.rehabilitate import (
13
13
  fix_errant_forced_async,
14
14
  fix_errant_forced_sync,
15
15
  pull_out_structured_output,
16
16
  )
17
- from synth_ai.zyk.lms.vendors.base import BaseLMResponse, VendorBase
18
- from synth_ai.zyk.lms.constants import SPECIAL_BASE_TEMPS
17
+ from synth_ai.lm.vendors.base import BaseLMResponse, VendorBase
18
+ from synth_ai.lm.constants import SPECIAL_BASE_TEMPS
19
19
 
20
20
  logger = logging.getLogger(__name__)
21
21
 
@@ -31,15 +31,11 @@ class StructuredHandlerBase(ABC):
31
31
  core_client: VendorBase,
32
32
  retry_client: VendorBase,
33
33
  handler_params: Optional[Dict[str, Any]] = None,
34
- structured_output_mode: Literal[
35
- "stringified_json", "forced_json"
36
- ] = "stringified_json",
34
+ structured_output_mode: Literal["stringified_json", "forced_json"] = "stringified_json",
37
35
  ):
38
36
  self.core_client = core_client
39
37
  self.retry_client = retry_client
40
- self.handler_params = (
41
- handler_params if handler_params is not None else {"retries": 3}
42
- )
38
+ self.handler_params = handler_params if handler_params is not None else {"retries": 3}
43
39
  self.structured_output_mode = structured_output_mode
44
40
 
45
41
  async def call_async(
@@ -142,22 +138,18 @@ class StringifiedJSONHandler(StructuredHandlerBase):
142
138
  use_ephemeral_cache_only: bool = False,
143
139
  reasoning_effort: str = "high",
144
140
  ) -> BaseLMResponse:
145
- #ogger.info(f"Processing structured output call for model: {model}")
141
+ # ogger.info(f"Processing structured output call for model: {model}")
146
142
  assert callable(api_call_method), "api_call_method must be a callable"
147
- assert (
148
- response_model is not None
149
- ), "Don't use this handler for unstructured outputs"
143
+ assert response_model is not None, "Don't use this handler for unstructured outputs"
150
144
  remaining_retries = self.handler_params.get("retries", 2)
151
145
  previously_failed_error_messages = []
152
146
  structured_output = None
153
147
 
154
148
  while remaining_retries > 0:
155
- messages_with_json_formatting_instructions = (
156
- inject_structured_output_instructions(
157
- messages=messages,
158
- response_model=response_model,
159
- previously_failed_error_messages=previously_failed_error_messages,
160
- )
149
+ messages_with_json_formatting_instructions = inject_structured_output_instructions(
150
+ messages=messages,
151
+ response_model=response_model,
152
+ previously_failed_error_messages=previously_failed_error_messages,
161
153
  )
162
154
  t0 = time.time()
163
155
  raw_text_response_or_cached_hit = await api_call_method(
@@ -167,26 +159,24 @@ class StringifiedJSONHandler(StructuredHandlerBase):
167
159
  use_ephemeral_cache_only=use_ephemeral_cache_only,
168
160
  reasoning_effort=reasoning_effort,
169
161
  )
170
- #logger.debug(f"Time to get response: {time.time() - t0:.2f}s")
162
+ # logger.debug(f"Time to get response: {time.time() - t0:.2f}s")
171
163
 
172
164
  # Check if we got a cached BaseLMResponse
173
- assert (
174
- type(raw_text_response_or_cached_hit) in [str, BaseLMResponse]
175
- ), f"Expected str or BaseLMResponse, got {type(raw_text_response_or_cached_hit)}"
165
+ assert type(raw_text_response_or_cached_hit) in [str, BaseLMResponse], (
166
+ f"Expected str or BaseLMResponse, got {type(raw_text_response_or_cached_hit)}"
167
+ )
176
168
  if type(raw_text_response_or_cached_hit) == BaseLMResponse:
177
- #print("Got cached hit, returning directly")
169
+ # print("Got cached hit, returning directly")
178
170
  raw_text_response = raw_text_response_or_cached_hit.raw_response
179
171
  else:
180
172
  raw_text_response = raw_text_response_or_cached_hit
181
- #logger.debug(f"Raw response from model:\n{raw_text_response}")
173
+ # logger.debug(f"Raw response from model:\n{raw_text_response}")
182
174
 
183
- #print("Trying to parse structured output")
175
+ # print("Trying to parse structured output")
184
176
  try:
185
- structured_output = pull_out_structured_output(
186
- raw_text_response, response_model
187
- )
177
+ structured_output = pull_out_structured_output(raw_text_response, response_model)
188
178
 
189
- #print("Successfully parsed structured output on first attempt")
179
+ # print("Successfully parsed structured output on first attempt")
190
180
  break
191
181
  except Exception as e:
192
182
  logger.warning(f"Failed to parse structured output: {str(e)}")
@@ -198,8 +188,12 @@ class StringifiedJSONHandler(StructuredHandlerBase):
198
188
  response_model,
199
189
  "gpt-4o-mini",
200
190
  )
201
- assert isinstance(structured_output, BaseModel), "Structured output must be a Pydantic model"
202
- assert not isinstance(structured_output, BaseLMResponse), "Got BaseLMResponse instead of Pydantic model"
191
+ assert isinstance(structured_output, BaseModel), (
192
+ "Structured output must be a Pydantic model"
193
+ )
194
+ assert not isinstance(structured_output, BaseLMResponse), (
195
+ "Got BaseLMResponse instead of Pydantic model"
196
+ )
203
197
  print("Successfully fixed and parsed structured output")
204
198
  break
205
199
  except Exception as e:
@@ -212,13 +206,15 @@ class StringifiedJSONHandler(StructuredHandlerBase):
212
206
 
213
207
  if structured_output is None:
214
208
  logger.error("Failed to get structured output after all retries")
215
- raise StructuredOutputCoercionFailureException(
216
- "Failed to get structured output"
217
- )
218
- #print("Successfully parsed structured output")
219
- #print(structured_output)
220
- assert isinstance(structured_output, BaseModel), "Structured output must be a Pydantic model"
221
- assert not isinstance(structured_output, BaseLMResponse),"Got BaseLMResponse instead of Pydantic model"
209
+ raise StructuredOutputCoercionFailureException("Failed to get structured output")
210
+ # print("Successfully parsed structured output")
211
+ # print(structured_output)
212
+ assert isinstance(structured_output, BaseModel), (
213
+ "Structured output must be a Pydantic model"
214
+ )
215
+ assert not isinstance(structured_output, BaseLMResponse), (
216
+ "Got BaseLMResponse instead of Pydantic model"
217
+ )
222
218
  return BaseLMResponse(
223
219
  raw_response=raw_text_response,
224
220
  structured_output=structured_output,
@@ -235,22 +231,18 @@ class StringifiedJSONHandler(StructuredHandlerBase):
235
231
  use_ephemeral_cache_only: bool = False,
236
232
  reasoning_effort: str = "high",
237
233
  ) -> BaseLMResponse:
238
- #logger.info(f"Processing structured output call for model: {model}")
234
+ # logger.info(f"Processing structured output call for model: {model}")
239
235
  assert callable(api_call_method), "api_call_method must be a callable"
240
- assert (
241
- response_model is not None
242
- ), "Don't use this handler for unstructured outputs"
236
+ assert response_model is not None, "Don't use this handler for unstructured outputs"
243
237
  remaining_retries = self.handler_params.get("retries", 2)
244
238
  previously_failed_error_messages = []
245
239
  structured_output = None
246
240
 
247
241
  while remaining_retries > 0:
248
- messages_with_json_formatting_instructions = (
249
- inject_structured_output_instructions(
250
- messages=messages,
251
- response_model=response_model,
252
- previously_failed_error_messages=previously_failed_error_messages,
253
- )
242
+ messages_with_json_formatting_instructions = inject_structured_output_instructions(
243
+ messages=messages,
244
+ response_model=response_model,
245
+ previously_failed_error_messages=previously_failed_error_messages,
254
246
  )
255
247
  t0 = time.time()
256
248
  raw_text_response_or_cached_hit = api_call_method(
@@ -263,21 +255,19 @@ class StringifiedJSONHandler(StructuredHandlerBase):
263
255
  logger.debug(f"Time to get response: {time.time() - t0:.2f}s")
264
256
 
265
257
  # Check if we got a cached BaseLMResponse
266
- assert (
267
- type(raw_text_response_or_cached_hit) in [str, BaseLMResponse]
268
- ), f"Expected str or BaseLMResponse, got {type(raw_text_response_or_cached_hit)}"
258
+ assert type(raw_text_response_or_cached_hit) in [str, BaseLMResponse], (
259
+ f"Expected str or BaseLMResponse, got {type(raw_text_response_or_cached_hit)}"
260
+ )
269
261
  if type(raw_text_response_or_cached_hit) == BaseLMResponse:
270
262
  logger.info("Got cached hit, returning directly")
271
263
  raw_text_response = raw_text_response_or_cached_hit.raw_response
272
- else:
264
+ else:
273
265
  raw_text_response = raw_text_response_or_cached_hit
274
- #logger.debug(f"Raw response from model:\n{raw_text_response}")
266
+ # logger.debug(f"Raw response from model:\n{raw_text_response}")
275
267
 
276
268
  try:
277
- structured_output = pull_out_structured_output(
278
- raw_text_response, response_model
279
- )
280
- #print("Successfully parsed structured output on first attempt")
269
+ structured_output = pull_out_structured_output(raw_text_response, response_model)
270
+ # print("Successfully parsed structured output on first attempt")
281
271
  break
282
272
  except Exception as e:
283
273
  logger.warning(f"Failed to parse structured output: {str(e)}")
@@ -296,13 +286,11 @@ class StringifiedJSONHandler(StructuredHandlerBase):
296
286
  remaining_retries -= 1
297
287
  logger.warning(f"Retries remaining: {remaining_retries}")
298
288
 
299
- #print("Successfully parsed structured output")
300
- #print(structured_output)
289
+ # print("Successfully parsed structured output")
290
+ # print(structured_output)
301
291
  if structured_output is None:
302
292
  logger.error("Failed to get structured output after all retries")
303
- raise StructuredOutputCoercionFailureException(
304
- "Failed to get structured output"
305
- )
293
+ raise StructuredOutputCoercionFailureException("Failed to get structured output")
306
294
  return BaseLMResponse(
307
295
  raw_response=raw_text_response,
308
296
  structured_output=structured_output,
@@ -341,9 +329,7 @@ class ForcedJSONHandler(StructuredHandlerBase):
341
329
  reasoning_effort: str = "high",
342
330
  ) -> BaseLMResponse:
343
331
  # print("Forced JSON")
344
- assert (
345
- response_model is not None
346
- ), "Don't use this handler for unstructured outputs"
332
+ assert response_model is not None, "Don't use this handler for unstructured outputs"
347
333
  return await api_call_method(
348
334
  messages=messages,
349
335
  model=model,
@@ -363,9 +349,7 @@ class ForcedJSONHandler(StructuredHandlerBase):
363
349
  use_ephemeral_cache_only: bool = False,
364
350
  reasoning_effort: str = "high",
365
351
  ) -> BaseLMResponse:
366
- assert (
367
- response_model is not None
368
- ), "Don't use this handler for unstructured outputs"
352
+ assert response_model is not None, "Don't use this handler for unstructured outputs"
369
353
  return api_call_method(
370
354
  messages=messages,
371
355
  model=model,
@@ -390,9 +374,7 @@ class StructuredOutputHandler:
390
374
  ):
391
375
  self.mode = mode
392
376
  if self.mode == "stringified_json":
393
- self.handler = StringifiedJSONHandler(
394
- core_client, retry_client, handler_params
395
- )
377
+ self.handler = StringifiedJSONHandler(core_client, retry_client, handler_params)
396
378
  elif self.mode == "forced_json":
397
379
  # print("Forced JSON")
398
380
  self.handler = ForcedJSONHandler(core_client, retry_client, handler_params)
@@ -413,9 +395,7 @@ class StructuredOutputHandler:
413
395
  messages=messages,
414
396
  model=model,
415
397
  response_model=response_model,
416
- temperature=lm_config.get(
417
- "temperature", SPECIAL_BASE_TEMPS.get(model, 0.0)
418
- ),
398
+ temperature=lm_config.get("temperature", SPECIAL_BASE_TEMPS.get(model, 0.0)),
419
399
  use_ephemeral_cache_only=use_ephemeral_cache_only,
420
400
  reasoning_effort=reasoning_effort,
421
401
  )
@@ -433,9 +413,7 @@ class StructuredOutputHandler:
433
413
  messages=messages,
434
414
  model=model,
435
415
  response_model=response_model,
436
- temperature=lm_config.get(
437
- "temperature", SPECIAL_BASE_TEMPS.get(model, 0.0)
438
- ),
416
+ temperature=lm_config.get("temperature", SPECIAL_BASE_TEMPS.get(model, 0.0)),
439
417
  use_ephemeral_cache_only=use_ephemeral_cache_only,
440
418
  reasoning_effort=reasoning_effort,
441
419
  )
@@ -41,9 +41,7 @@ def generate_type_map() -> Dict[Any, str]:
41
41
  # Handle generic Dict type
42
42
  type_map[Dict] = "Dict[Any,Any]"
43
43
  # Provide both key and value types for Dict
44
- type_map[Dict[base_type, base_type]] = (
45
- f"{collection_name}[{name},{name}]"
46
- )
44
+ type_map[Dict[base_type, base_type]] = f"{collection_name}[{name},{name}]"
47
45
  # Handle Dict[Any, Any] explicitly
48
46
  type_map[Dict[Any, Any]] = "Dict[Any,Any]"
49
47
  else:
@@ -189,9 +187,7 @@ def get_example_value(type_hint):
189
187
  first_type = non_none_types[0]
190
188
  union_docs = []
191
189
 
192
- if all(
193
- isinstance(t, type) and issubclass(t, BaseModel) for t in non_none_types
194
- ):
190
+ if all(isinstance(t, type) and issubclass(t, BaseModel) for t in non_none_types):
195
191
  # Generate examples for all union variants
196
192
  for t in non_none_types:
197
193
  example = {}
@@ -211,10 +207,7 @@ def get_example_value(type_hint):
211
207
  for field_name, field_info in first_type.model_fields.items():
212
208
  if get_origin(field_info.annotation) is Literal:
213
209
  literal_args = get_args(field_info.annotation)
214
- if (
215
- isinstance(example[field_name], dict)
216
- and "value" in example[field_name]
217
- ):
210
+ if isinstance(example[field_name], dict) and "value" in example[field_name]:
218
211
  example[field_name]["value"] = literal_args[0]
219
212
  else:
220
213
  example[field_name] = literal_args[0]
@@ -246,25 +239,18 @@ def add_json_instructions_to_messages(
246
239
  field = response_model.model_fields[key] # Updated for Pydantic v2
247
240
 
248
241
  # Adjusted for Pydantic v2
249
- field_description = (
250
- field.description if hasattr(field, "description") else None
251
- )
242
+ field_description = field.description if hasattr(field, "description") else None
252
243
 
253
244
  if field_description:
254
245
  stringified_fields[key] = (example_value, field_description)
255
246
  else:
256
247
  stringified_fields[key] = example_value
257
248
  example_json = json.dumps(
258
- {
259
- k: v[0] if isinstance(v, tuple) else v
260
- for k, v in stringified_fields.items()
261
- },
249
+ {k: v[0] if isinstance(v, tuple) else v for k, v in stringified_fields.items()},
262
250
  indent=4,
263
251
  )
264
252
  description_comments = "\n".join(
265
- f"// {k}: {v[1]}"
266
- for k, v in stringified_fields.items()
267
- if isinstance(v, tuple)
253
+ f"// {k}: {v[1]}" for k, v in stringified_fields.items() if isinstance(v, tuple)
268
254
  )
269
255
 
270
256
  # print("Example JSON", example_json)
@@ -6,19 +6,15 @@ from typing import Dict, List, Type, Union
6
6
 
7
7
  from pydantic import BaseModel
8
8
 
9
- from synth_ai.zyk.lms.vendors.base import VendorBase
10
- from synth_ai.zyk.lms.vendors.core.openai_api import OpenAIStructuredOutputClient
9
+ from synth_ai.lm.vendors.base import VendorBase
10
+ from synth_ai.lm.vendors.core.openai_api import OpenAIStructuredOutputClient
11
11
 
12
12
 
13
- def pull_out_structured_output(
14
- response_raw: str, response_model: Type[BaseModel]
15
- ) -> BaseModel:
13
+ def pull_out_structured_output(response_raw: str, response_model: Type[BaseModel]) -> BaseModel:
16
14
  logger = logging.getLogger(__name__)
17
- #logger.debug(f"Raw response received: {response_raw}")
15
+ # logger.debug(f"Raw response received: {response_raw}")
18
16
 
19
- assert isinstance(
20
- response_raw, str
21
- ), f"Response raw is not a string: {type(response_raw)}"
17
+ assert isinstance(response_raw, str), f"Response raw is not a string: {type(response_raw)}"
22
18
 
23
19
  # Use regex to extract JSON content within ```json ... ```
24
20
  json_pattern = re.compile(r"```json\s*(\{.*\})\s*```", re.DOTALL)
@@ -52,9 +48,7 @@ def pull_out_structured_output(
52
48
  f"Failed to parse response as {response_model}: {inner_e} - {response_prepared}"
53
49
  )
54
50
  except Exception as e:
55
- raise ValueError(
56
- f"Failed to parse response as {response_model}: {e} - {response_prepared}"
57
- )
51
+ raise ValueError(f"Failed to parse response as {response_model}: {e} - {response_prepared}")
58
52
  assert isinstance(final, BaseModel), "Structured output must be a Pydantic model"
59
53
  return final
60
54
 
@@ -5,13 +5,13 @@ import anthropic
5
5
  import pydantic
6
6
  from pydantic import BaseModel
7
7
 
8
- from synth_ai.zyk.lms.caching.initialize import (
8
+ from synth_ai.lm.caching.initialize import (
9
9
  get_cache_handler,
10
10
  )
11
- from synth_ai.zyk.lms.tools.base import BaseTool
12
- from synth_ai.zyk.lms.vendors.base import BaseLMResponse, VendorBase
13
- from synth_ai.zyk.lms.constants import SPECIAL_BASE_TEMPS, CLAUDE_REASONING_MODELS, SONNET_37_BUDGETS
14
- from synth_ai.zyk.lms.vendors.core.openai_api import OpenAIStructuredOutputClient
11
+ from synth_ai.lm.tools.base import BaseTool
12
+ from synth_ai.lm.vendors.base import BaseLMResponse, VendorBase
13
+ from synth_ai.lm.constants import SPECIAL_BASE_TEMPS, CLAUDE_REASONING_MODELS, SONNET_37_BUDGETS
14
+ from synth_ai.lm.vendors.core.openai_api import OpenAIStructuredOutputClient
15
15
 
16
16
  ANTHROPIC_EXCEPTIONS_TO_RETRY: Tuple[Type[Exception], ...] = (anthropic.APIError,)
17
17
 
@@ -24,9 +24,7 @@ class AnthropicAPI(VendorBase):
24
24
 
25
25
  def __init__(
26
26
  self,
27
- exceptions_to_retry: Tuple[
28
- Type[Exception], ...
29
- ] = ANTHROPIC_EXCEPTIONS_TO_RETRY,
27
+ exceptions_to_retry: Tuple[Type[Exception], ...] = ANTHROPIC_EXCEPTIONS_TO_RETRY,
30
28
  used_for_structured_outputs: bool = False,
31
29
  reasoning_effort: str = "high",
32
30
  ):
@@ -53,9 +51,9 @@ class AnthropicAPI(VendorBase):
53
51
  tools: Optional[List[BaseTool]] = None,
54
52
  **vendor_params: Dict[str, Any],
55
53
  ) -> BaseLMResponse:
56
- assert (
57
- lm_config.get("response_model", None) is None
58
- ), "response_model is not supported for standard calls"
54
+ assert lm_config.get("response_model", None) is None, (
55
+ "response_model is not supported for standard calls"
56
+ )
59
57
  used_cache_handler = get_cache_handler(use_ephemeral_cache_only)
60
58
  lm_config["reasoning_effort"] = reasoning_effort
61
59
  cache_result = used_cache_handler.hit_managed_cache(
@@ -70,9 +68,7 @@ class AnthropicAPI(VendorBase):
70
68
  "messages": messages[1:],
71
69
  "model": model,
72
70
  "max_tokens": lm_config.get("max_tokens", 4096),
73
- "temperature": lm_config.get(
74
- "temperature", SPECIAL_BASE_TEMPS.get(model, 0)
75
- ),
71
+ "temperature": lm_config.get("temperature", SPECIAL_BASE_TEMPS.get(model, 0)),
76
72
  }
77
73
 
78
74
  # Add tools if provided
@@ -86,12 +82,12 @@ class AnthropicAPI(VendorBase):
86
82
  create_sig = inspect.signature(self.async_client.messages.create)
87
83
  if "thinking" in create_sig.parameters and model in CLAUDE_REASONING_MODELS:
88
84
  if reasoning_effort in ["high", "medium"]:
89
- budget = SONNET_37_BUDGETS[reasoning_effort]
85
+ budget = SONNET_37_BUDGETS[reasoning_effort]
90
86
  api_params["thinking"] = {
91
87
  "type": "enabled",
92
88
  "budget_tokens": budget,
93
89
  }
94
- api_params["max_tokens"] = budget+4096
90
+ api_params["max_tokens"] = budget + 4096
95
91
  api_params["temperature"] = 1
96
92
  except (ImportError, AttributeError, TypeError):
97
93
  pass
@@ -146,12 +142,10 @@ class AnthropicAPI(VendorBase):
146
142
  tools: Optional[List[BaseTool]] = None,
147
143
  **vendor_params: Dict[str, Any],
148
144
  ) -> BaseLMResponse:
149
- assert (
150
- lm_config.get("response_model", None) is None
151
- ), "response_model is not supported for standard calls"
152
- used_cache_handler = get_cache_handler(
153
- use_ephemeral_cache_only=use_ephemeral_cache_only
145
+ assert lm_config.get("response_model", None) is None, (
146
+ "response_model is not supported for standard calls"
154
147
  )
148
+ used_cache_handler = get_cache_handler(use_ephemeral_cache_only=use_ephemeral_cache_only)
155
149
  lm_config["reasoning_effort"] = reasoning_effort
156
150
  cache_result = used_cache_handler.hit_managed_cache(
157
151
  model, messages, lm_config=lm_config, tools=tools
@@ -165,9 +159,7 @@ class AnthropicAPI(VendorBase):
165
159
  "messages": messages[1:],
166
160
  "model": model,
167
161
  "max_tokens": lm_config.get("max_tokens", 4096),
168
- "temperature": lm_config.get(
169
- "temperature", SPECIAL_BASE_TEMPS.get(model, 0)
170
- ),
162
+ "temperature": lm_config.get("temperature", SPECIAL_BASE_TEMPS.get(model, 0)),
171
163
  }
172
164
 
173
165
  # Add tools if provided
@@ -188,7 +180,7 @@ class AnthropicAPI(VendorBase):
188
180
  "type": "enabled",
189
181
  "budget_tokens": budget,
190
182
  }
191
- api_params["max_tokens"] = budget+4096
183
+ api_params["max_tokens"] = budget + 4096
192
184
  api_params["temperature"] = 1
193
185
  except (ImportError, AttributeError, TypeError):
194
186
  pass
@@ -241,13 +233,12 @@ class AnthropicAPI(VendorBase):
241
233
  # First try with Anthropic
242
234
  reasoning_effort = vendor_params.get("reasoning_effort", reasoning_effort)
243
235
  if model in CLAUDE_REASONING_MODELS:
244
-
245
- #if reasoning_effort in ["high", "medium"]:
236
+ # if reasoning_effort in ["high", "medium"]:
246
237
  budgets = SONNET_37_BUDGETS
247
238
  budget = budgets[reasoning_effort]
248
- max_tokens = budget+4096
239
+ max_tokens = budget + 4096
249
240
  temperature = 1
250
-
241
+
251
242
  response = await self.async_client.messages.create(
252
243
  system=messages[0]["content"],
253
244
  messages=messages[1:],
@@ -303,7 +294,7 @@ class AnthropicAPI(VendorBase):
303
294
  if reasoning_effort in ["high", "medium"]:
304
295
  budgets = SONNET_37_BUDGETS
305
296
  budget = budgets[reasoning_effort]
306
- max_tokens = budget+4096
297
+ max_tokens = budget + 4096
307
298
  temperature = 1
308
299
  response = self.sync_client.messages.create(
309
300
  system=messages[0]["content"],