synth-ai 0.1.9__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 +37 -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/zyk/lms/caching/constants.py +0 -1
  245. synth_ai/zyk/lms/cost/monitor.py +0 -1
  246. synth_ai/zyk/lms/cost/statefulness.py +0 -1
  247. synth_ai-0.1.9.dist-info/METADATA +0 -37
  248. synth_ai-0.1.9.dist-info/RECORD +0 -50
  249. /synth_ai/{zyk/lms/__init__.py → environments/reproducibility/helpers.py} +0 -0
  250. /synth_ai/{zyk/lms/caching → lm}/__init__.py +0 -0
  251. /synth_ai/{zyk/lms/core → lm/caching}/__init__.py +0 -0
  252. /synth_ai/{zyk/lms → lm}/caching/dbs.py +0 -0
  253. /synth_ai/{zyk/lms/cost → lm/core}/__init__.py +0 -0
  254. /synth_ai/{zyk/lms → lm}/core/exceptions.py +0 -0
  255. /synth_ai/{zyk/lms/structured_outputs → lm/cost}/__init__.py +0 -0
  256. /synth_ai/{zyk/lms/vendors → lm/structured_outputs}/__init__.py +0 -0
  257. /synth_ai/{zyk/lms → lm}/tools/__init__.py +0 -0
  258. /synth_ai/{zyk/lms → lm}/tools/base.py +0 -0
  259. /synth_ai/{zyk/lms/vendors/core → lm/vendors}/__init__.py +0 -0
  260. /synth_ai/{zyk/lms → lm}/vendors/base.py +0 -0
  261. /synth_ai/{zyk/lms/vendors/local → lm/vendors/core}/__init__.py +0 -0
  262. /synth_ai/{zyk/lms/vendors/supported → lm/vendors/local}/__init__.py +0 -0
  263. /synth_ai/{zyk/lms → lm}/vendors/local/ollama.py +0 -0
  264. {synth_ai-0.1.9.dist-info → synth_ai-0.2.1.dev0.dist-info}/WHEEL +0 -0
  265. {synth_ai-0.1.9.dist-info → synth_ai-0.2.1.dev0.dist-info}/licenses/LICENSE +0 -0
  266. {synth_ai-0.1.9.dist-info → synth_ai-0.2.1.dev0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,504 @@
1
+ import asyncio
2
+ import json
3
+ import logging
4
+ import os
5
+ import ssl
6
+ import time
7
+ from typing import Any, Dict, List, Tuple, TypedDict
8
+
9
+ import requests
10
+ from dotenv import load_dotenv
11
+ from pydantic import BaseModel, ConfigDict, field_validator
12
+ from requests.adapters import HTTPAdapter
13
+ from urllib3.poolmanager import PoolManager
14
+
15
+ from synth_ai.tracing.abstractions import Dataset, SystemTrace
16
+ from synth_ai.tracing.events.store import event_store
17
+
18
+ load_dotenv()
19
+
20
+
21
+ # NOTE: This may cause memory issues in the future
22
+ def validate_json(data: Dict[str, Any]) -> None:
23
+ """Validate that a dictionary contains only JSON-serializable values.
24
+
25
+ Args:
26
+ data: Dictionary to validate for JSON serialization
27
+
28
+ Raises:
29
+ ValueError: If the dictionary contains non-serializable values
30
+ """
31
+
32
+ try:
33
+ json.dumps(data)
34
+ except (TypeError, OverflowError) as e:
35
+ raise ValueError(f"Contains non-JSON-serializable values: {e}. {data}")
36
+
37
+
38
+ def createPayload(dataset: Dataset, traces: List[SystemTrace]) -> Dict[str, Any]:
39
+ payload = {
40
+ "traces": [trace.to_dict() for trace in traces], # Convert SystemTrace objects to dicts
41
+ "dataset": dataset.to_dict(),
42
+ }
43
+ return payload
44
+
45
+
46
+ class TLSAdapter(HTTPAdapter):
47
+ def init_poolmanager(self, connections, maxsize, block=False):
48
+ """Create and initialize the urllib3 PoolManager."""
49
+ ctx = ssl.create_default_context()
50
+ ctx.set_ciphers("DEFAULT@SECLEVEL=1")
51
+ self.poolmanager = PoolManager(
52
+ num_pools=connections,
53
+ maxsize=maxsize,
54
+ block=block,
55
+ ssl_version=ssl.PROTOCOL_TLSv1_2,
56
+ ssl_context=ctx,
57
+ )
58
+
59
+
60
+ def load_signed_url(signed_url: str, dataset: Dataset, traces: List[SystemTrace]) -> None:
61
+ payload = createPayload(dataset, traces)
62
+ validate_json(payload)
63
+
64
+ session = requests.Session()
65
+ adapter = TLSAdapter()
66
+ session.mount("https://", adapter)
67
+
68
+ try:
69
+ response = session.put(
70
+ signed_url, json=payload, headers={"Content-Type": "application/json"}
71
+ )
72
+ response.raise_for_status()
73
+ except requests.exceptions.RequestException as e:
74
+ print(f"Error making request: {str(e)}")
75
+ print(f"Request payload: {payload}") # Debugging info
76
+ raise
77
+
78
+ if response.status_code != 200:
79
+ raise ValueError(
80
+ f"Failed to load signed URL Status Code: {response.status_code} "
81
+ f"Response: {response.text}, Signed URL: {signed_url}"
82
+ )
83
+ else:
84
+ pass
85
+
86
+
87
+ def send_system_traces_s3(
88
+ dataset: Dataset,
89
+ traces: List[SystemTrace],
90
+ base_url: str,
91
+ api_key: str,
92
+ system_id: str,
93
+ system_name: str,
94
+ verbose: bool = False,
95
+ ):
96
+ upload_id, signed_url = get_upload_id(base_url, api_key, system_id, system_name, verbose)
97
+ load_signed_url(signed_url, dataset, traces)
98
+
99
+ token_url = f"{base_url}/v1/auth/token"
100
+ try:
101
+ token_response = requests.get(token_url, headers={"customer_specific_api_key": api_key})
102
+ token_response.raise_for_status()
103
+ access_token = token_response.json()["access_token"]
104
+ except requests.exceptions.RequestException as e:
105
+ logging.error(f"Error obtaining access token: {e}")
106
+ raise
107
+
108
+ api_url = f"{base_url}/v1/uploads/process-upload/{upload_id}"
109
+ data = {"signed_url": signed_url}
110
+ headers = {
111
+ "Content-Type": "application/json",
112
+ "Authorization": f"Bearer {access_token}",
113
+ }
114
+
115
+ try:
116
+ response = requests.post(api_url, headers=headers, json=data)
117
+ response.raise_for_status()
118
+
119
+ response_data = response.json()
120
+ upload_id = response_data.get("upload_id")
121
+ signed_url = response_data.get("signed_url")
122
+ return upload_id, signed_url
123
+ except requests.exceptions.HTTPError as e:
124
+ logging.error(f"HTTP error occurred: {e}")
125
+ raise
126
+ except Exception as e:
127
+ logging.error(f"An error occurred: {e}")
128
+ raise
129
+
130
+
131
+ def get_upload_id(
132
+ base_url: str, api_key: str, system_id: str, system_name: str, verbose: bool = False
133
+ ) -> Tuple[str, str]:
134
+ """
135
+ Modified client-side function to send both system_id and system_name.
136
+ """
137
+ token_url = f"{base_url}/v1/auth/token"
138
+ token_response = requests.get(token_url, headers={"customer_specific_api_key": api_key})
139
+ token_response.raise_for_status()
140
+ access_token = token_response.json()["access_token"]
141
+
142
+ # Include system_name in the query parameters
143
+ api_url = (
144
+ f"{base_url}/v1/uploads/get-upload-id-signed-url?"
145
+ f"system_id={system_id}&system_name={system_name}"
146
+ )
147
+ headers = {
148
+ "Content-Type": "application/json",
149
+ "Authorization": f"Bearer {access_token}",
150
+ }
151
+
152
+ try:
153
+ response = requests.get(api_url, headers=headers)
154
+ response.raise_for_status()
155
+ upload_id = response.json()["upload_id"]
156
+ signed_url = response.json()["signed_url"]
157
+ return upload_id, signed_url
158
+ except requests.exceptions.HTTPError as e:
159
+ logging.error(f"HTTP error occurred: {e}")
160
+ raise
161
+ except Exception as e:
162
+ logging.error(f"An error occurred: {e}")
163
+ raise
164
+
165
+
166
+ class UploadValidator(BaseModel):
167
+ """Validator for upload data format."""
168
+
169
+ model_config = ConfigDict(
170
+ from_attributes=True, # Replaces the deprecated orm_mode
171
+ validate_assignment=True,
172
+ extra="forbid", # Prevent additional fields
173
+ )
174
+
175
+ traces: List[Dict[str, Any]]
176
+ dataset: Dict[str, Any]
177
+
178
+ @field_validator("traces")
179
+ @classmethod
180
+ def validate_traces(cls, traces: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
181
+ if not traces:
182
+ raise ValueError("Traces list cannot be empty")
183
+
184
+ for trace in traces:
185
+ # Validate required fields in each trace
186
+ if "system_instance_id" not in trace:
187
+ raise ValueError("Each trace must have a system_instance_id")
188
+ if "partition" not in trace:
189
+ raise ValueError("Each trace must have a partition")
190
+
191
+ # Validate metadata if present
192
+ if "metadata" in trace and trace["metadata"] is not None:
193
+ if not isinstance(trace["metadata"], dict):
194
+ raise ValueError("Metadata must be a dictionary")
195
+
196
+ # Validate partition structure
197
+ partition = trace["partition"]
198
+ if not isinstance(partition, list):
199
+ raise ValueError("Partition must be a list")
200
+
201
+ for part in partition:
202
+ if "partition_index" not in part:
203
+ raise ValueError("Each partition element must have a partition_index")
204
+ if "events" not in part:
205
+ raise ValueError("Each partition element must have an events list")
206
+
207
+ # Validate events
208
+ events = part["events"]
209
+ if not isinstance(events, list):
210
+ raise ValueError("Events must be a list")
211
+
212
+ for event in events:
213
+ required_fields = [
214
+ "event_type",
215
+ "opened",
216
+ "closed",
217
+ "partition_index",
218
+ ]
219
+ missing_fields = [f for f in required_fields if f not in event]
220
+ if missing_fields:
221
+ raise ValueError(f"Event missing required fields: {missing_fields}")
222
+
223
+ return traces
224
+
225
+ @field_validator("dataset")
226
+ @classmethod
227
+ def validate_dataset(cls, dataset: Dict[str, Any]) -> Dict[str, Any]:
228
+ required_fields = ["questions", "reward_signals"]
229
+ missing_fields = [f for f in required_fields if f not in dataset]
230
+ if missing_fields:
231
+ raise ValueError(f"Dataset missing required fields: {missing_fields}")
232
+
233
+ # Validate questions
234
+ questions = dataset["questions"]
235
+ if not isinstance(questions, list):
236
+ raise ValueError("Questions must be a list")
237
+
238
+ for question in questions:
239
+ if "intent" not in question or "criteria" not in question:
240
+ raise ValueError("Each question must have intent and criteria")
241
+
242
+ # Validate reward signals
243
+ reward_signals = dataset["reward_signals"]
244
+ if not isinstance(reward_signals, list):
245
+ raise ValueError("Reward signals must be a list")
246
+
247
+ return dataset
248
+
249
+
250
+ def validate_upload(traces: List[Dict[str, Any]], dataset: Dict[str, Any]):
251
+ # Validate the upload format before sending to server.
252
+ # Raises ValueError if validation fails.
253
+ try:
254
+ UploadValidator(traces=traces, dataset=dataset)
255
+ return True
256
+ except ValueError as e:
257
+ raise ValueError(f"Upload validation failed: {str(e)}")
258
+
259
+
260
+ def is_event_loop_running():
261
+ try:
262
+ asyncio.get_running_loop() # Check if there's a running event loop
263
+ return True
264
+ except RuntimeError:
265
+ # This exception is raised if no event loop is running
266
+ return False
267
+
268
+
269
+ def format_upload_output(
270
+ dataset: Dataset, traces: List[SystemTrace]
271
+ ) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]], List[Dict[str, Any]]]:
272
+ # Format questions array
273
+ questions_data = [
274
+ {"intent": q.intent, "criteria": q.criteria, "id": q.id} for q in dataset.questions
275
+ ]
276
+
277
+ # Format reward signals array with error handling
278
+ reward_signals_data = [
279
+ {
280
+ "system_instance_id": rs.system_instance_id,
281
+ "reward": rs.reward,
282
+ "question_id": rs.question_id,
283
+ "annotation": rs.annotation if hasattr(rs, "annotation") else None,
284
+ }
285
+ for rs in dataset.reward_signals
286
+ ]
287
+
288
+ # Format traces array
289
+ traces_data = [
290
+ {
291
+ "system_instance_id": t.system_instance_id,
292
+ "metadata": t.metadata if t.metadata else None,
293
+ "partition": [
294
+ {
295
+ "partition_index": p.partition_index,
296
+ "events": [e.to_dict() for e in p.events],
297
+ }
298
+ for p in t.partition
299
+ ],
300
+ }
301
+ for t in traces
302
+ ]
303
+
304
+ return questions_data, reward_signals_data, traces_data
305
+
306
+
307
+ class UploadIdResponse(TypedDict):
308
+ message: str
309
+ upload_id: str
310
+ signed_url: str
311
+
312
+
313
+ class ProcessUploadResponse(TypedDict):
314
+ status: str
315
+ upload_id: str
316
+ signed_url: str
317
+
318
+
319
+ def upload(
320
+ dataset: Dataset,
321
+ traces: List[SystemTrace] = [],
322
+ verbose: bool = False,
323
+ show_payload: bool = False,
324
+ ) -> Tuple[
325
+ ProcessUploadResponse,
326
+ List[Dict[str, Any]],
327
+ List[Dict[str, Any]],
328
+ List[Dict[str, Any]],
329
+ ]:
330
+ """Upload all system traces and dataset to the server.
331
+
332
+ Args:
333
+ dataset: Dataset containing questions and reward signals
334
+ traces: List of system traces to upload
335
+ verbose: Whether to print verbose output
336
+ show_payload: Whether to show the payload being sent
337
+
338
+ Returns:
339
+ Tuple containing:
340
+ - response: Server response with status, upload_id, and signed_url
341
+ - questions_json: List of formatted questions
342
+ - reward_signals_json: List of formatted reward signals
343
+ - traces_json: List of formatted traces
344
+
345
+ Raises:
346
+ ValueError: If no system traces found or validation fails
347
+ requests.exceptions.HTTPError: If server request fails
348
+ RuntimeError: If SYNTH_API_KEY environment variable not set
349
+ """
350
+ return upload_helper(dataset, traces, verbose, show_payload)
351
+
352
+
353
+ def upload_helper(
354
+ dataset: Dataset,
355
+ traces: List[SystemTrace] = [],
356
+ verbose: bool = False,
357
+ show_payload: bool = False,
358
+ ) -> Tuple[
359
+ ProcessUploadResponse,
360
+ List[Dict[str, Any]],
361
+ List[Dict[str, Any]],
362
+ List[Dict[str, Any]],
363
+ ]:
364
+ """Helper function to handle the upload process.
365
+
366
+ Returns same type as upload() function.
367
+ """
368
+ api_key = os.getenv("SYNTH_API_KEY")
369
+ if not api_key:
370
+ raise ValueError("SYNTH_API_KEY environment variable not set")
371
+ base_url = os.getenv("SYNTH_ENDPOINT_OVERRIDE", "https://agent-learning.onrender.com")
372
+
373
+ from synth_ai.tracing.decorators import _local, active_events_var
374
+ from synth_ai.tracing.trackers import synth_tracker_async, synth_tracker_sync
375
+
376
+ # First close any tracker events
377
+ if hasattr(synth_tracker_async, "active_events"):
378
+ for event_type, event in list(synth_tracker_async.active_events.items()):
379
+ if event and event.closed is None:
380
+ event.closed = time.time()
381
+ try:
382
+ event_store.add_event(
383
+ event.system_name,
384
+ event.system_id,
385
+ event.system_instance_id,
386
+ event,
387
+ )
388
+ if verbose:
389
+ print(f"Closed and stored tracker async event: {event_type}")
390
+ except Exception as e:
391
+ logging.error(f"Failed to store tracker event {event_type}: {str(e)}")
392
+ synth_tracker_async.active_events.clear()
393
+
394
+ # End all active events before uploading
395
+ if hasattr(_local, "active_events"):
396
+ for event_type, event in _local.active_events.items():
397
+ if event and event.closed is None:
398
+ event.closed = time.time()
399
+ if hasattr(_local, "system_instance_id"):
400
+ try:
401
+ event_store.add_event(
402
+ _local.system_name,
403
+ _local.system_id,
404
+ _local.system_instance_id,
405
+ event,
406
+ )
407
+ if verbose:
408
+ print(f"Closed and stored active event: {event_type}")
409
+ except Exception as e:
410
+ logging.error(f"Failed to store event {event_type}: {str(e)}")
411
+ _local.active_events.clear()
412
+
413
+ # NEW: Close all open asynchronous events
414
+ active_events_async = active_events_var.get()
415
+ if active_events_async:
416
+ current_time = time.time()
417
+ for event_type, event in list(active_events_async.items()):
418
+ if event and event.closed is None:
419
+ event.closed = current_time
420
+ try:
421
+ event_store.add_event(
422
+ event.system_name,
423
+ event.system_id,
424
+ event.system_instance_id,
425
+ event,
426
+ )
427
+ if verbose:
428
+ print(f"Closed and stored async event: {event_type}")
429
+ except Exception as e:
430
+ logging.error(f"Failed to store async event {event_type}: {str(e)}")
431
+ active_events_var.set({})
432
+
433
+ # Also close any unclosed events in existing traces
434
+ logged_traces = event_store.get_system_traces()
435
+ traces = logged_traces + traces
436
+ # traces = event_store.get_system_traces() if len(traces) == 0 else traces
437
+ current_time = time.time()
438
+ for trace in traces:
439
+ for partition in trace.partition:
440
+ for event in partition.events:
441
+ if event.closed is None:
442
+ event.closed = current_time
443
+ event_store.add_event(
444
+ trace.system_name,
445
+ trace.system_id,
446
+ trace.system_instance_id,
447
+ event,
448
+ )
449
+ if verbose:
450
+ print(f"Closed existing unclosed event: {event.event_type}")
451
+
452
+ try:
453
+ # Get traces and convert to dict format
454
+ if len(traces) == 0:
455
+ raise ValueError("No system traces found")
456
+ traces_dict = [trace.to_dict() for trace in traces]
457
+ dataset_dict = dataset.to_dict()
458
+
459
+ # Validate upload format
460
+ if verbose:
461
+ print("Validating upload format...")
462
+ validate_upload(traces_dict, dataset_dict)
463
+ if verbose:
464
+ print("Upload format validation successful")
465
+
466
+ # Send to server
467
+ upload_id, signed_url = send_system_traces_s3(
468
+ dataset=dataset,
469
+ traces=traces,
470
+ base_url=base_url,
471
+ api_key=api_key,
472
+ system_id=traces[0].system_id,
473
+ system_name=traces[0].system_name,
474
+ verbose=verbose,
475
+ )
476
+
477
+ questions_json, reward_signals_json, traces_json = format_upload_output(dataset, traces)
478
+ return (
479
+ {
480
+ "status": "success",
481
+ "upload_id": upload_id,
482
+ "signed_url": signed_url,
483
+ },
484
+ questions_json,
485
+ reward_signals_json,
486
+ traces_json,
487
+ )
488
+
489
+ except ValueError as e:
490
+ if verbose:
491
+ print("Validation error:", str(e))
492
+ print("\nTraces:")
493
+ print(json.dumps(traces_dict, indent=2))
494
+ print("\nDataset:")
495
+ print(json.dumps(dataset_dict, indent=2))
496
+ raise
497
+ except requests.exceptions.HTTPError as e:
498
+ if verbose:
499
+ print("HTTP error occurred:", e)
500
+ print("\nTraces:")
501
+ print(json.dumps(traces_dict, indent=2))
502
+ print("\nDataset:")
503
+ print(json.dumps(dataset_dict, indent=2))
504
+ raise
@@ -0,0 +1,9 @@
1
+ import uuid
2
+
3
+
4
+ def get_system_id(system_name: str) -> str:
5
+ """Create a deterministic system_instance_id from system_name using UUID5."""
6
+ if not system_name:
7
+ raise ValueError("system_name cannot be empty")
8
+ system_id = uuid.uuid5(uuid.NAMESPACE_DNS, system_name)
9
+ return str(system_id)
synth_ai/zyk/__init__.py CHANGED
@@ -1,3 +1,29 @@
1
- from synth_ai.zyk.lms.core.main import LM
2
- from synth_ai.zyk.lms.vendors.base import BaseLMResponse
1
+ """
2
+ DEPRECATED: This module has been moved to synth_ai.lm
3
+
4
+ The synth_ai.zyk module is deprecated and will be removed in a future version.
5
+ Please update your imports:
6
+
7
+ OLD: from synth_ai.zyk import LM
8
+ NEW: from synth_ai.lm.core.main import LM
9
+
10
+ or
11
+
12
+ NEW: from synth_ai import LM # (recommended)
13
+ """
14
+
15
+ import warnings
16
+
17
+ # Issue deprecation warning
18
+ warnings.warn(
19
+ "synth_ai.zyk is deprecated and will be removed in a future version. "
20
+ "Please use 'from synth_ai import LM' or 'from synth_ai.lm.core.main import LM' instead.",
21
+ DeprecationWarning,
22
+ stacklevel=2,
23
+ )
24
+
25
+ # Import from new location for backward compatibility
26
+ from synth_ai.lm.core.main import LM
27
+ from synth_ai.lm.vendors.base import BaseLMResponse
28
+
3
29
  __all__ = ["LM", "BaseLMResponse"]