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.
- synth_ai/__init__.py +28 -2
- synth_ai/core/system.py +4 -0
- synth_ai/environments/__init__.py +35 -0
- synth_ai/environments/environment/__init__.py +1 -0
- synth_ai/environments/environment/artifacts/__init__.py +1 -0
- synth_ai/environments/environment/artifacts/base.py +50 -0
- synth_ai/environments/environment/core.py +22 -0
- synth_ai/environments/environment/db/__init__.py +1 -0
- synth_ai/environments/environment/db/sqlite.py +45 -0
- synth_ai/environments/environment/registry.py +24 -0
- synth_ai/environments/environment/resources/sqlite.py +46 -0
- synth_ai/environments/environment/results.py +1 -0
- synth_ai/environments/environment/rewards/__init__.py +1 -0
- synth_ai/environments/environment/rewards/core.py +28 -0
- synth_ai/environments/environment/shared_engine.py +26 -0
- synth_ai/environments/environment/tools/__init__.py +34 -0
- synth_ai/environments/examples/__init__.py +1 -0
- synth_ai/environments/examples/crafter_classic/__init__.py +8 -0
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_comprehensive_evaluation.py +58 -0
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_browser.py +152 -0
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_framework.py +1194 -0
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_quick_evaluation.py +51 -0
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_react_agent.py +872 -0
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_trace_evaluation.py +1412 -0
- synth_ai/environments/examples/crafter_classic/agent_demos/test_crafter_react_agent.py +1110 -0
- synth_ai/environments/examples/crafter_classic/config_logging.py +111 -0
- synth_ai/environments/examples/crafter_classic/engine.py +502 -0
- synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +63 -0
- synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +5 -0
- synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +74 -0
- synth_ai/environments/examples/crafter_classic/environment.py +255 -0
- synth_ai/environments/examples/crafter_classic/taskset.py +228 -0
- synth_ai/environments/examples/enron/agent_demos/test_synth_react.py +535 -0
- synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +156 -0
- synth_ai/environments/examples/enron/art_helpers/local_email_db.py +280 -0
- synth_ai/environments/examples/enron/art_helpers/types_enron.py +24 -0
- synth_ai/environments/examples/enron/engine.py +291 -0
- synth_ai/environments/examples/enron/environment.py +165 -0
- synth_ai/environments/examples/enron/taskset.py +112 -0
- synth_ai/environments/examples/enron/units/keyword_stats.py +111 -0
- synth_ai/environments/examples/enron/units/test_email_index.py +8 -0
- synth_ai/environments/examples/minigrid/__init__.py +48 -0
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_evaluation_framework.py +1188 -0
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_quick_evaluation.py +47 -0
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_react_agent.py +562 -0
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_trace_evaluation.py +220 -0
- synth_ai/environments/examples/minigrid/agent_demos/test_minigrid_react_agent.py +393 -0
- synth_ai/environments/examples/minigrid/engine.py +589 -0
- synth_ai/environments/examples/minigrid/environment.py +274 -0
- synth_ai/environments/examples/minigrid/environment_mapping.py +242 -0
- synth_ai/environments/examples/minigrid/puzzle_loader.py +416 -0
- synth_ai/environments/examples/minigrid/taskset.py +583 -0
- synth_ai/environments/examples/minigrid/units/test_action_behavior.py +226 -0
- synth_ai/environments/examples/minigrid/units/test_debug_messages.py +83 -0
- synth_ai/environments/examples/minigrid/units/test_exploration.py +120 -0
- synth_ai/environments/examples/minigrid/units/test_minigrid_engine.py +214 -0
- synth_ai/environments/examples/minigrid/units/test_minigrid_environment.py +238 -0
- synth_ai/environments/examples/minigrid/units/test_minigrid_environment_mapping.py +301 -0
- synth_ai/environments/examples/minigrid/units/test_minigrid_taskset.py +210 -0
- synth_ai/environments/examples/nethack/__init__.py +7 -0
- synth_ai/environments/examples/nethack/achievements.py +337 -0
- synth_ai/environments/examples/nethack/agent_demos/nethack_evaluation_framework.py +981 -0
- synth_ai/environments/examples/nethack/agent_demos/nethack_quick_evaluation.py +74 -0
- synth_ai/environments/examples/nethack/agent_demos/nethack_react_agent.py +832 -0
- synth_ai/environments/examples/nethack/agent_demos/test_nethack_react_agent.py +1112 -0
- synth_ai/environments/examples/nethack/engine.py +738 -0
- synth_ai/environments/examples/nethack/environment.py +255 -0
- synth_ai/environments/examples/nethack/helpers/__init__.py +42 -0
- synth_ai/environments/examples/nethack/helpers/action_mapping.py +301 -0
- synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +401 -0
- synth_ai/environments/examples/nethack/helpers/observation_utils.py +433 -0
- synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +201 -0
- synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +268 -0
- synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +308 -0
- synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +430 -0
- synth_ai/environments/examples/nethack/taskset.py +323 -0
- synth_ai/environments/examples/nethack/units/test_nethack_engine.py +277 -0
- synth_ai/environments/examples/nethack/units/test_nethack_environment.py +281 -0
- synth_ai/environments/examples/nethack/units/test_nethack_taskset.py +213 -0
- synth_ai/environments/examples/nethack/units/test_recording.py +307 -0
- synth_ai/environments/examples/red/__init__.py +7 -0
- synth_ai/environments/examples/red/agent_demos/__init__.py +1 -0
- synth_ai/environments/examples/red/agent_demos/test_synth_react.py +1471 -0
- synth_ai/environments/examples/red/config_logging.py +110 -0
- synth_ai/environments/examples/red/engine.py +693 -0
- synth_ai/environments/examples/red/engine_helpers/__init__.py +1 -0
- synth_ai/environments/examples/red/engine_helpers/memory_map.py +28 -0
- synth_ai/environments/examples/red/engine_helpers/reward_components.py +275 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +142 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +56 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +283 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +149 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +137 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +56 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +330 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +120 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +558 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +312 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +147 -0
- synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +246 -0
- synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +367 -0
- synth_ai/environments/examples/red/engine_helpers/state_extraction.py +139 -0
- synth_ai/environments/examples/red/environment.py +235 -0
- synth_ai/environments/examples/red/taskset.py +77 -0
- synth_ai/environments/examples/red/test_fixes.py +125 -0
- synth_ai/environments/examples/red/test_fixes_mock.py +148 -0
- synth_ai/environments/examples/red/units/__init__.py +1 -0
- synth_ai/environments/examples/red/units/test_basic_functionality.py +97 -0
- synth_ai/environments/examples/red/units/test_button_press_requirements.py +217 -0
- synth_ai/environments/examples/red/units/test_engine.py +192 -0
- synth_ai/environments/examples/red/units/test_environment.py +455 -0
- synth_ai/environments/examples/red/units/test_exploration_strategy.py +227 -0
- synth_ai/environments/examples/red/units/test_integration.py +217 -0
- synth_ai/environments/examples/red/units/test_memory_extraction.py +111 -0
- synth_ai/environments/examples/red/units/test_menu_bug_reproduction.py +1100 -0
- synth_ai/environments/examples/red/units/test_movement_debug.py +255 -0
- synth_ai/environments/examples/red/units/test_pokemon_mcts_debug.py +163 -0
- synth_ai/environments/examples/red/units/test_pokemon_mcts_verbose.py +117 -0
- synth_ai/environments/examples/red/units/test_red_basic.py +145 -0
- synth_ai/environments/examples/red/units/test_red_comprehensive.py +323 -0
- synth_ai/environments/examples/red/units/test_retry_movement.py +195 -0
- synth_ai/environments/examples/red/units/test_reward_components.py +186 -0
- synth_ai/environments/examples/red/units/test_rom_integration.py +260 -0
- synth_ai/environments/examples/red/units/test_taskset.py +116 -0
- synth_ai/environments/examples/red/units/test_tree.py +448 -0
- synth_ai/environments/examples/sokoban/__init__.py +1 -0
- synth_ai/environments/examples/sokoban/agent_demos/sokoban_full_eval.py +900 -0
- synth_ai/environments/examples/sokoban/agent_demos/test_dspy_react.py +1 -0
- synth_ai/environments/examples/sokoban/agent_demos/test_sokoban_react_agent.py +498 -0
- synth_ai/environments/examples/sokoban/agent_demos/test_synth_lats.py +1 -0
- synth_ai/environments/examples/sokoban/agent_demos/test_synth_react_locally.py +748 -0
- synth_ai/environments/examples/sokoban/agent_demos/test_synth_react_service.py +296 -0
- synth_ai/environments/examples/sokoban/engine.py +675 -0
- synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +1 -0
- synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +656 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +17 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +3 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +129 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +370 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +331 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +305 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +66 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +114 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +122 -0
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +394 -0
- synth_ai/environments/examples/sokoban/environment.py +228 -0
- synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +438 -0
- synth_ai/environments/examples/sokoban/puzzle_loader.py +311 -0
- synth_ai/environments/examples/sokoban/taskset.py +425 -0
- synth_ai/environments/examples/sokoban/units/astar_common.py +94 -0
- synth_ai/environments/examples/sokoban/units/test_building_task_set.py +49 -0
- synth_ai/environments/examples/sokoban/units/test_false_positive.py +120 -0
- synth_ai/environments/examples/sokoban/units/test_simple_run_through_environment.py +119 -0
- synth_ai/environments/examples/sokoban/units/test_sokoban_environment.py +98 -0
- synth_ai/environments/examples/sokoban/units/test_tree.py +364 -0
- synth_ai/environments/examples/tictactoe/__init__.py +1 -0
- synth_ai/environments/examples/tictactoe/agent_demos/test_synth_react.py +266 -0
- synth_ai/environments/examples/tictactoe/agent_demos/test_tictactoe_react_agent.py +470 -0
- synth_ai/environments/examples/tictactoe/engine.py +368 -0
- synth_ai/environments/examples/tictactoe/environment.py +239 -0
- synth_ai/environments/examples/tictactoe/taskset.py +214 -0
- synth_ai/environments/examples/tictactoe/units/test_tictactoe_engine.py +393 -0
- synth_ai/environments/examples/tictactoe/units/test_tictactoe_environment.py +493 -0
- synth_ai/environments/examples/tictactoe/units/test_tictactoe_taskset.py +191 -0
- synth_ai/environments/examples/verilog/__init__.py +10 -0
- synth_ai/environments/examples/verilog/agent_demos/test_synth_react.py +520 -0
- synth_ai/environments/examples/verilog/engine.py +328 -0
- synth_ai/environments/examples/verilog/environment.py +349 -0
- synth_ai/environments/examples/verilog/taskset.py +418 -0
- synth_ai/environments/examples/verilog/units/test_verilog_engine.py +466 -0
- synth_ai/environments/examples/verilog/units/test_verilog_environment.py +585 -0
- synth_ai/environments/examples/verilog/units/test_verilog_integration.py +383 -0
- synth_ai/environments/examples/verilog/units/test_verilog_taskset.py +457 -0
- synth_ai/environments/reproducibility/core.py +42 -0
- synth_ai/environments/reproducibility/tree.py +364 -0
- synth_ai/environments/service/app.py +78 -0
- synth_ai/environments/service/core_routes.py +775 -0
- synth_ai/environments/service/external_registry.py +57 -0
- synth_ai/environments/service/registry.py +9 -0
- synth_ai/environments/stateful/__init__.py +1 -0
- synth_ai/environments/stateful/core.py +28 -0
- synth_ai/environments/stateful/engine.py +21 -0
- synth_ai/environments/stateful/state.py +7 -0
- synth_ai/environments/tasks/api.py +19 -0
- synth_ai/environments/tasks/core.py +78 -0
- synth_ai/environments/tasks/filters.py +39 -0
- synth_ai/environments/tasks/utils.py +89 -0
- synth_ai/environments/v0_observability/history.py +3 -0
- synth_ai/environments/v0_observability/log.py +2 -0
- synth_ai/lm/caching/constants.py +1 -0
- synth_ai/{zyk/lms → lm}/caching/ephemeral.py +4 -8
- synth_ai/{zyk/lms → lm}/caching/handler.py +15 -15
- synth_ai/{zyk/lms → lm}/caching/initialize.py +2 -4
- synth_ai/{zyk/lms → lm}/caching/persistent.py +4 -10
- synth_ai/{zyk/lms → lm}/config.py +2 -1
- synth_ai/{zyk/lms → lm}/constants.py +2 -2
- synth_ai/{zyk/lms → lm}/core/all.py +10 -10
- synth_ai/{zyk/lms → lm}/core/main.py +57 -33
- synth_ai/{zyk/lms → lm}/core/vendor_clients.py +12 -10
- synth_ai/lm/cost/monitor.py +1 -0
- synth_ai/lm/cost/statefulness.py +1 -0
- synth_ai/lm/provider_support/__init__.py +8 -0
- synth_ai/lm/provider_support/anthropic.py +945 -0
- synth_ai/lm/provider_support/openai.py +1115 -0
- synth_ai/lm/provider_support/suppress_logging.py +31 -0
- synth_ai/{zyk/lms → lm}/structured_outputs/handler.py +58 -80
- synth_ai/{zyk/lms → lm}/structured_outputs/inject.py +6 -20
- synth_ai/{zyk/lms → lm}/structured_outputs/rehabilitate.py +6 -12
- synth_ai/{zyk/lms → lm}/vendors/core/anthropic_api.py +21 -30
- synth_ai/{zyk/lms → lm}/vendors/core/gemini_api.py +37 -32
- synth_ai/{zyk/lms → lm}/vendors/core/mistral_api.py +19 -28
- synth_ai/{zyk/lms → lm}/vendors/core/openai_api.py +26 -36
- synth_ai/{zyk/lms → lm}/vendors/openai_standard.py +29 -33
- synth_ai/{zyk/lms → lm}/vendors/retries.py +1 -1
- synth_ai/lm/vendors/supported/__init__.py +0 -0
- synth_ai/{zyk/lms → lm}/vendors/supported/custom_endpoint.py +131 -118
- synth_ai/{zyk/lms → lm}/vendors/supported/deepseek.py +4 -8
- synth_ai/{zyk/lms → lm}/vendors/supported/grok.py +6 -8
- synth_ai/{zyk/lms → lm}/vendors/supported/groq.py +1 -1
- synth_ai/{zyk/lms → lm}/vendors/supported/ollama.py +2 -2
- synth_ai/{zyk/lms → lm}/vendors/supported/openrouter.py +18 -16
- synth_ai/{zyk/lms → lm}/vendors/supported/together.py +1 -1
- synth_ai/tracing/__init__.py +0 -0
- synth_ai/tracing/abstractions.py +224 -0
- synth_ai/tracing/base_client.py +91 -0
- synth_ai/tracing/client_manager.py +131 -0
- synth_ai/tracing/config.py +140 -0
- synth_ai/tracing/context.py +146 -0
- synth_ai/tracing/decorators.py +679 -0
- synth_ai/tracing/events/__init__.py +0 -0
- synth_ai/tracing/events/manage.py +147 -0
- synth_ai/tracing/events/scope.py +86 -0
- synth_ai/tracing/events/store.py +227 -0
- synth_ai/tracing/immediate_client.py +152 -0
- synth_ai/tracing/local.py +18 -0
- synth_ai/tracing/log_client_base.py +74 -0
- synth_ai/tracing/retry_queue.py +187 -0
- synth_ai/tracing/trackers.py +515 -0
- synth_ai/tracing/upload.py +504 -0
- synth_ai/tracing/utils.py +9 -0
- synth_ai/zyk/__init__.py +28 -2
- synth_ai-0.2.1.dev0.dist-info/METADATA +349 -0
- synth_ai-0.2.1.dev0.dist-info/RECORD +261 -0
- synth_ai/zyk/lms/caching/constants.py +0 -1
- synth_ai/zyk/lms/cost/monitor.py +0 -1
- synth_ai/zyk/lms/cost/statefulness.py +0 -1
- synth_ai-0.1.9.dist-info/METADATA +0 -37
- synth_ai-0.1.9.dist-info/RECORD +0 -50
- /synth_ai/{zyk/lms/__init__.py → environments/reproducibility/helpers.py} +0 -0
- /synth_ai/{zyk/lms/caching → lm}/__init__.py +0 -0
- /synth_ai/{zyk/lms/core → lm/caching}/__init__.py +0 -0
- /synth_ai/{zyk/lms → lm}/caching/dbs.py +0 -0
- /synth_ai/{zyk/lms/cost → lm/core}/__init__.py +0 -0
- /synth_ai/{zyk/lms → lm}/core/exceptions.py +0 -0
- /synth_ai/{zyk/lms/structured_outputs → lm/cost}/__init__.py +0 -0
- /synth_ai/{zyk/lms/vendors → lm/structured_outputs}/__init__.py +0 -0
- /synth_ai/{zyk/lms → lm}/tools/__init__.py +0 -0
- /synth_ai/{zyk/lms → lm}/tools/base.py +0 -0
- /synth_ai/{zyk/lms/vendors/core → lm/vendors}/__init__.py +0 -0
- /synth_ai/{zyk/lms → lm}/vendors/base.py +0 -0
- /synth_ai/{zyk/lms/vendors/local → lm/vendors/core}/__init__.py +0 -0
- /synth_ai/{zyk/lms/vendors/supported → lm/vendors/local}/__init__.py +0 -0
- /synth_ai/{zyk/lms → lm}/vendors/local/ollama.py +0 -0
- {synth_ai-0.1.9.dist-info → synth_ai-0.2.1.dev0.dist-info}/WHEEL +0 -0
- {synth_ai-0.1.9.dist-info → synth_ai-0.2.1.dev0.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
2
|
-
|
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"]
|