synth-ai 0.2.4.dev5__py3-none-any.whl → 0.2.4.dev7__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 +18 -9
- synth_ai/cli/__init__.py +10 -5
- synth_ai/cli/balance.py +22 -17
- synth_ai/cli/calc.py +2 -3
- synth_ai/cli/demo.py +3 -5
- synth_ai/cli/legacy_root_backup.py +58 -32
- synth_ai/cli/man.py +22 -19
- synth_ai/cli/recent.py +9 -8
- synth_ai/cli/root.py +58 -13
- synth_ai/cli/status.py +13 -6
- synth_ai/cli/traces.py +45 -21
- synth_ai/cli/watch.py +40 -37
- synth_ai/config/base_url.py +1 -3
- synth_ai/core/experiment.py +1 -2
- synth_ai/environments/__init__.py +2 -6
- synth_ai/environments/environment/artifacts/base.py +3 -1
- synth_ai/environments/environment/db/sqlite.py +1 -1
- synth_ai/environments/environment/registry.py +19 -20
- synth_ai/environments/environment/resources/sqlite.py +2 -3
- synth_ai/environments/environment/rewards/core.py +3 -2
- synth_ai/environments/environment/tools/__init__.py +6 -4
- synth_ai/environments/examples/crafter_classic/__init__.py +1 -1
- synth_ai/environments/examples/crafter_classic/engine.py +21 -17
- synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +1 -0
- synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +2 -1
- synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +2 -1
- synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +3 -2
- synth_ai/environments/examples/crafter_classic/environment.py +16 -15
- synth_ai/environments/examples/crafter_classic/taskset.py +2 -2
- synth_ai/environments/examples/crafter_classic/trace_hooks_v3.py +2 -3
- synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +2 -1
- synth_ai/environments/examples/crafter_custom/crafter/__init__.py +2 -2
- synth_ai/environments/examples/crafter_custom/crafter/config.py +2 -2
- synth_ai/environments/examples/crafter_custom/crafter/env.py +1 -5
- synth_ai/environments/examples/crafter_custom/crafter/objects.py +1 -2
- synth_ai/environments/examples/crafter_custom/crafter/worldgen.py +1 -2
- synth_ai/environments/examples/crafter_custom/dataset_builder.py +5 -5
- synth_ai/environments/examples/crafter_custom/environment.py +13 -13
- synth_ai/environments/examples/crafter_custom/run_dataset.py +5 -5
- synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +2 -2
- synth_ai/environments/examples/enron/art_helpers/local_email_db.py +5 -4
- synth_ai/environments/examples/enron/art_helpers/types_enron.py +2 -1
- synth_ai/environments/examples/enron/engine.py +18 -14
- synth_ai/environments/examples/enron/environment.py +12 -11
- synth_ai/environments/examples/enron/taskset.py +7 -7
- synth_ai/environments/examples/minigrid/__init__.py +6 -6
- synth_ai/environments/examples/minigrid/engine.py +6 -6
- synth_ai/environments/examples/minigrid/environment.py +6 -6
- synth_ai/environments/examples/minigrid/puzzle_loader.py +3 -2
- synth_ai/environments/examples/minigrid/taskset.py +13 -13
- synth_ai/environments/examples/nethack/achievements.py +1 -1
- synth_ai/environments/examples/nethack/engine.py +8 -7
- synth_ai/environments/examples/nethack/environment.py +10 -9
- synth_ai/environments/examples/nethack/helpers/__init__.py +8 -9
- synth_ai/environments/examples/nethack/helpers/action_mapping.py +1 -1
- synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +2 -1
- synth_ai/environments/examples/nethack/helpers/observation_utils.py +1 -1
- synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +3 -4
- synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +6 -5
- synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +5 -5
- synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +7 -6
- synth_ai/environments/examples/nethack/taskset.py +5 -5
- synth_ai/environments/examples/red/engine.py +9 -8
- synth_ai/environments/examples/red/engine_helpers/reward_components.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +7 -7
- synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +2 -1
- synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +3 -2
- synth_ai/environments/examples/red/engine_helpers/state_extraction.py +2 -1
- synth_ai/environments/examples/red/environment.py +18 -15
- synth_ai/environments/examples/red/taskset.py +5 -3
- synth_ai/environments/examples/sokoban/engine.py +16 -13
- synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +3 -2
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +2 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +1 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +7 -5
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +1 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +2 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +5 -4
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +3 -2
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +2 -1
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +5 -4
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +1 -1
- synth_ai/environments/examples/sokoban/environment.py +15 -14
- synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +5 -3
- synth_ai/environments/examples/sokoban/puzzle_loader.py +3 -2
- synth_ai/environments/examples/sokoban/taskset.py +13 -10
- synth_ai/environments/examples/tictactoe/engine.py +6 -6
- synth_ai/environments/examples/tictactoe/environment.py +8 -7
- synth_ai/environments/examples/tictactoe/taskset.py +6 -5
- synth_ai/environments/examples/verilog/engine.py +4 -3
- synth_ai/environments/examples/verilog/environment.py +11 -10
- synth_ai/environments/examples/verilog/taskset.py +14 -12
- synth_ai/environments/examples/wordle/__init__.py +29 -0
- synth_ai/environments/examples/wordle/engine.py +398 -0
- synth_ai/environments/examples/wordle/environment.py +159 -0
- synth_ai/environments/examples/wordle/helpers/generate_instances_wordfreq.py +75 -0
- synth_ai/environments/examples/wordle/taskset.py +230 -0
- synth_ai/environments/reproducibility/core.py +1 -1
- synth_ai/environments/reproducibility/tree.py +21 -21
- synth_ai/environments/service/app.py +11 -2
- synth_ai/environments/service/core_routes.py +137 -105
- synth_ai/environments/service/external_registry.py +1 -2
- synth_ai/environments/service/registry.py +1 -1
- synth_ai/environments/stateful/core.py +1 -2
- synth_ai/environments/stateful/engine.py +1 -1
- synth_ai/environments/tasks/api.py +4 -4
- synth_ai/environments/tasks/core.py +14 -12
- synth_ai/environments/tasks/filters.py +6 -4
- synth_ai/environments/tasks/utils.py +13 -11
- synth_ai/evals/base.py +2 -3
- synth_ai/experimental/synth_oss.py +4 -4
- synth_ai/learning/gateway.py +1 -3
- synth_ai/learning/prompts/banking77_injection_eval.py +168 -0
- synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +213 -0
- synth_ai/learning/prompts/mipro.py +282 -1
- synth_ai/learning/prompts/random_search.py +246 -0
- synth_ai/learning/prompts/run_mipro_banking77.py +172 -0
- synth_ai/learning/prompts/run_random_search_banking77.py +324 -0
- synth_ai/lm/__init__.py +5 -5
- synth_ai/lm/caching/ephemeral.py +9 -9
- synth_ai/lm/caching/handler.py +20 -20
- synth_ai/lm/caching/persistent.py +10 -10
- synth_ai/lm/config.py +3 -3
- synth_ai/lm/constants.py +7 -7
- synth_ai/lm/core/all.py +17 -3
- synth_ai/lm/core/exceptions.py +0 -2
- synth_ai/lm/core/main.py +26 -41
- synth_ai/lm/core/main_v3.py +20 -10
- synth_ai/lm/core/vendor_clients.py +18 -17
- synth_ai/lm/injection.py +80 -0
- synth_ai/lm/overrides.py +206 -0
- synth_ai/lm/provider_support/__init__.py +1 -1
- synth_ai/lm/provider_support/anthropic.py +51 -24
- synth_ai/lm/provider_support/openai.py +51 -22
- synth_ai/lm/structured_outputs/handler.py +34 -32
- synth_ai/lm/structured_outputs/inject.py +24 -27
- synth_ai/lm/structured_outputs/rehabilitate.py +19 -15
- synth_ai/lm/tools/base.py +17 -16
- synth_ai/lm/unified_interface.py +17 -18
- synth_ai/lm/vendors/base.py +20 -18
- synth_ai/lm/vendors/core/anthropic_api.py +50 -25
- synth_ai/lm/vendors/core/gemini_api.py +31 -36
- synth_ai/lm/vendors/core/mistral_api.py +19 -19
- synth_ai/lm/vendors/core/openai_api.py +11 -10
- synth_ai/lm/vendors/openai_standard.py +144 -88
- synth_ai/lm/vendors/openai_standard_responses.py +74 -61
- synth_ai/lm/vendors/retries.py +9 -1
- synth_ai/lm/vendors/supported/custom_endpoint.py +26 -26
- synth_ai/lm/vendors/supported/deepseek.py +10 -10
- synth_ai/lm/vendors/supported/grok.py +8 -8
- synth_ai/lm/vendors/supported/ollama.py +2 -1
- synth_ai/lm/vendors/supported/openrouter.py +11 -9
- synth_ai/lm/vendors/synth_client.py +69 -63
- synth_ai/lm/warmup.py +8 -7
- synth_ai/tracing/__init__.py +22 -10
- synth_ai/tracing_v1/__init__.py +22 -20
- synth_ai/tracing_v3/__init__.py +7 -7
- synth_ai/tracing_v3/abstractions.py +56 -52
- synth_ai/tracing_v3/config.py +4 -2
- synth_ai/tracing_v3/db_config.py +6 -8
- synth_ai/tracing_v3/decorators.py +29 -30
- synth_ai/tracing_v3/examples/basic_usage.py +12 -12
- synth_ai/tracing_v3/hooks.py +21 -21
- synth_ai/tracing_v3/llm_call_record_helpers.py +85 -98
- synth_ai/tracing_v3/lm_call_record_abstractions.py +2 -4
- synth_ai/tracing_v3/migration_helper.py +3 -5
- synth_ai/tracing_v3/replica_sync.py +30 -32
- synth_ai/tracing_v3/session_tracer.py +35 -29
- synth_ai/tracing_v3/storage/__init__.py +1 -1
- synth_ai/tracing_v3/storage/base.py +8 -7
- synth_ai/tracing_v3/storage/config.py +4 -4
- synth_ai/tracing_v3/storage/factory.py +4 -4
- synth_ai/tracing_v3/storage/utils.py +9 -9
- synth_ai/tracing_v3/turso/__init__.py +3 -3
- synth_ai/tracing_v3/turso/daemon.py +9 -9
- synth_ai/tracing_v3/turso/manager.py +60 -48
- synth_ai/tracing_v3/turso/models.py +24 -19
- synth_ai/tracing_v3/utils.py +5 -5
- synth_ai/tui/__main__.py +1 -1
- synth_ai/tui/cli/query_experiments.py +2 -3
- synth_ai/tui/cli/query_experiments_v3.py +2 -3
- synth_ai/tui/dashboard.py +97 -86
- synth_ai/v0/tracing/abstractions.py +28 -28
- synth_ai/v0/tracing/base_client.py +9 -9
- synth_ai/v0/tracing/client_manager.py +7 -7
- synth_ai/v0/tracing/config.py +7 -7
- synth_ai/v0/tracing/context.py +6 -6
- synth_ai/v0/tracing/decorators.py +6 -5
- synth_ai/v0/tracing/events/manage.py +1 -1
- synth_ai/v0/tracing/events/store.py +5 -4
- synth_ai/v0/tracing/immediate_client.py +4 -5
- synth_ai/v0/tracing/local.py +3 -3
- synth_ai/v0/tracing/log_client_base.py +4 -5
- synth_ai/v0/tracing/retry_queue.py +5 -6
- synth_ai/v0/tracing/trackers.py +25 -25
- synth_ai/v0/tracing/upload.py +6 -0
- synth_ai/v0/tracing_v1/__init__.py +1 -1
- synth_ai/v0/tracing_v1/abstractions.py +28 -28
- synth_ai/v0/tracing_v1/base_client.py +9 -9
- synth_ai/v0/tracing_v1/client_manager.py +7 -7
- synth_ai/v0/tracing_v1/config.py +7 -7
- synth_ai/v0/tracing_v1/context.py +6 -6
- synth_ai/v0/tracing_v1/decorators.py +7 -6
- synth_ai/v0/tracing_v1/events/manage.py +1 -1
- synth_ai/v0/tracing_v1/events/store.py +5 -4
- synth_ai/v0/tracing_v1/immediate_client.py +4 -5
- synth_ai/v0/tracing_v1/local.py +3 -3
- synth_ai/v0/tracing_v1/log_client_base.py +4 -5
- synth_ai/v0/tracing_v1/retry_queue.py +5 -6
- synth_ai/v0/tracing_v1/trackers.py +25 -25
- synth_ai/v0/tracing_v1/upload.py +25 -24
- synth_ai/zyk/__init__.py +1 -0
- {synth_ai-0.2.4.dev5.dist-info → synth_ai-0.2.4.dev7.dist-info}/METADATA +2 -11
- synth_ai-0.2.4.dev7.dist-info/RECORD +299 -0
- synth_ai-0.2.4.dev5.dist-info/RECORD +0 -287
- {synth_ai-0.2.4.dev5.dist-info → synth_ai-0.2.4.dev7.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.4.dev5.dist-info → synth_ai-0.2.4.dev7.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.4.dev5.dist-info → synth_ai-0.2.4.dev7.dist-info}/licenses/LICENSE +0 -0
- {synth_ai-0.2.4.dev5.dist-info → synth_ai-0.2.4.dev7.dist-info}/top_level.txt +0 -0
@@ -4,10 +4,11 @@ Provides async and sync interfaces matching OpenAI's API.
|
|
4
4
|
"""
|
5
5
|
|
6
6
|
import asyncio
|
7
|
-
import httpx
|
8
7
|
import json
|
9
8
|
import logging
|
10
|
-
from typing import
|
9
|
+
from typing import Any
|
10
|
+
|
11
|
+
import httpx
|
11
12
|
|
12
13
|
from ..config import SynthConfig
|
13
14
|
|
@@ -17,7 +18,7 @@ logger = logging.getLogger(__name__)
|
|
17
18
|
class AsyncSynthClient:
|
18
19
|
"""Async client with OpenAI-compatible interface."""
|
19
20
|
|
20
|
-
def __init__(self, config:
|
21
|
+
def __init__(self, config: SynthConfig | None = None):
|
21
22
|
"""Initialize with config from environment if not provided."""
|
22
23
|
self.config = config or SynthConfig.from_env()
|
23
24
|
self._client = None
|
@@ -50,15 +51,15 @@ class AsyncSynthClient:
|
|
50
51
|
async def responses_create(
|
51
52
|
self,
|
52
53
|
model: str,
|
53
|
-
messages:
|
54
|
-
previous_response_id:
|
55
|
-
tools:
|
56
|
-
tool_choice:
|
54
|
+
messages: list[dict[str, Any]],
|
55
|
+
previous_response_id: str | None = None,
|
56
|
+
tools: list[dict[str, Any]] | None = None,
|
57
|
+
tool_choice: str | dict[str, Any] | None = "auto",
|
57
58
|
**kwargs,
|
58
|
-
) ->
|
59
|
+
) -> dict[str, Any]:
|
59
60
|
"""
|
60
61
|
Create response using Synth Responses API.
|
61
|
-
|
62
|
+
|
62
63
|
Args:
|
63
64
|
model: Model identifier
|
64
65
|
messages: List of message dicts with 'role' and 'content'
|
@@ -66,71 +67,71 @@ class AsyncSynthClient:
|
|
66
67
|
tools: List of available tools
|
67
68
|
tool_choice: How to choose tools
|
68
69
|
**kwargs: Additional parameters
|
69
|
-
|
70
|
+
|
70
71
|
Returns:
|
71
72
|
Responses API-compatible response dict
|
72
73
|
"""
|
73
74
|
await self._ensure_client()
|
74
|
-
|
75
|
+
|
75
76
|
# Build payload for Responses API
|
76
77
|
payload = {
|
77
78
|
"model": model,
|
78
79
|
"messages": messages,
|
79
80
|
}
|
80
|
-
|
81
|
+
|
81
82
|
# Add optional parameters
|
82
83
|
if previous_response_id is not None:
|
83
84
|
payload["previous_response_id"] = previous_response_id
|
84
85
|
if tools is not None:
|
85
86
|
payload["tools"] = tools
|
86
87
|
payload["tool_choice"] = tool_choice
|
87
|
-
|
88
|
+
|
88
89
|
# Add any additional kwargs
|
89
90
|
payload.update(kwargs)
|
90
|
-
|
91
|
+
|
91
92
|
# Retry logic
|
92
93
|
for attempt in range(self.config.max_retries):
|
93
94
|
try:
|
94
95
|
url = f"{self.config.get_base_url_without_v1()}/v1/responses"
|
95
96
|
response = await self._client.post(url, json=payload)
|
96
|
-
|
97
|
+
|
97
98
|
if response.status_code == 200:
|
98
99
|
return response.json()
|
99
|
-
|
100
|
+
|
100
101
|
# Handle rate limits with exponential backoff
|
101
102
|
if response.status_code == 429:
|
102
103
|
wait_time = 2**attempt
|
103
104
|
await asyncio.sleep(wait_time)
|
104
105
|
continue
|
105
|
-
|
106
|
+
|
106
107
|
# Other errors
|
107
108
|
response.raise_for_status()
|
108
|
-
|
109
|
+
|
109
110
|
except Exception as e:
|
110
111
|
if attempt == self.config.max_retries - 1:
|
111
112
|
logger.error(f"Failed after {self.config.max_retries} attempts: {e}")
|
112
113
|
raise
|
113
114
|
await asyncio.sleep(2**attempt)
|
114
|
-
|
115
|
+
|
115
116
|
raise Exception(f"Failed to create response after {self.config.max_retries} attempts")
|
116
117
|
|
117
118
|
async def chat_completions_create(
|
118
119
|
self,
|
119
120
|
model: str,
|
120
|
-
messages:
|
121
|
+
messages: list[dict[str, Any]],
|
121
122
|
temperature: float = 0.7,
|
122
|
-
max_tokens:
|
123
|
+
max_tokens: int | None = None,
|
123
124
|
top_p: float = 1.0,
|
124
125
|
frequency_penalty: float = 0.0,
|
125
126
|
presence_penalty: float = 0.0,
|
126
|
-
stop:
|
127
|
+
stop: str | list[str] | None = None,
|
127
128
|
stream: bool = False,
|
128
|
-
tools:
|
129
|
-
tool_choice:
|
130
|
-
response_format:
|
131
|
-
seed:
|
129
|
+
tools: list[dict[str, Any]] | None = None,
|
130
|
+
tool_choice: str | dict[str, Any] | None = "auto",
|
131
|
+
response_format: dict[str, Any] | None = None,
|
132
|
+
seed: int | None = None,
|
132
133
|
**kwargs,
|
133
|
-
) ->
|
134
|
+
) -> dict[str, Any]:
|
134
135
|
"""
|
135
136
|
Create chat completion with OpenAI-compatible API.
|
136
137
|
|
@@ -188,28 +189,32 @@ class AsyncSynthClient:
|
|
188
189
|
url = f"{self.config.get_base_url_without_v1()}/v1/chat/completions"
|
189
190
|
print(f"🔍 SYNTH DEBUG: Making request to URL: {url}")
|
190
191
|
print(f"🔍 SYNTH DEBUG: Payload keys: {list(payload.keys())}")
|
191
|
-
if
|
192
|
+
if "tools" in payload:
|
192
193
|
print(f"🔍 SYNTH DEBUG: Tools in payload: {len(payload['tools'])} tools")
|
193
|
-
print(
|
194
|
-
|
194
|
+
print(
|
195
|
+
f"🔍 SYNTH DEBUG: First tool: {json.dumps(payload['tools'][0], indent=2)}"
|
196
|
+
)
|
197
|
+
|
195
198
|
response = await self._client.post(url, json=payload)
|
196
|
-
|
199
|
+
|
197
200
|
print(f"🔍 SYNTH DEBUG: Response status: {response.status_code}")
|
198
|
-
|
201
|
+
|
199
202
|
if response.status_code == 200:
|
200
203
|
result = response.json()
|
201
204
|
print(f"🔍 SYNTH DEBUG: Response keys: {list(result.keys())}")
|
202
|
-
if
|
203
|
-
choice = result[
|
205
|
+
if "choices" in result and result["choices"]:
|
206
|
+
choice = result["choices"][0]
|
204
207
|
print(f"🔍 SYNTH DEBUG: Choice keys: {list(choice.keys())}")
|
205
|
-
if
|
206
|
-
message = choice[
|
208
|
+
if "message" in choice:
|
209
|
+
message = choice["message"]
|
207
210
|
print(f"🔍 SYNTH DEBUG: Message keys: {list(message.keys())}")
|
208
|
-
if
|
211
|
+
if "tool_calls" in message:
|
209
212
|
print(f"🔍 SYNTH DEBUG: Tool calls: {message['tool_calls']}")
|
210
213
|
else:
|
211
|
-
print(
|
212
|
-
print(
|
214
|
+
print("🔍 SYNTH DEBUG: No tool_calls in message")
|
215
|
+
print(
|
216
|
+
f"🔍 SYNTH DEBUG: Message content: {message.get('content', 'N/A')[:200]}..."
|
217
|
+
)
|
213
218
|
return result
|
214
219
|
|
215
220
|
# Handle rate limits with exponential backoff
|
@@ -248,7 +253,7 @@ class AsyncSynthClient:
|
|
248
253
|
class SyncSynthClient:
|
249
254
|
"""Sync client with OpenAI-compatible interface."""
|
250
255
|
|
251
|
-
def __init__(self, config:
|
256
|
+
def __init__(self, config: SynthConfig | None = None):
|
252
257
|
"""Initialize with config from environment if not provided."""
|
253
258
|
self.config = config or SynthConfig.from_env()
|
254
259
|
self._client = None
|
@@ -281,69 +286,70 @@ class SyncSynthClient:
|
|
281
286
|
def responses_create(
|
282
287
|
self,
|
283
288
|
model: str,
|
284
|
-
messages:
|
285
|
-
previous_response_id:
|
286
|
-
tools:
|
287
|
-
tool_choice:
|
289
|
+
messages: list[dict[str, Any]],
|
290
|
+
previous_response_id: str | None = None,
|
291
|
+
tools: list[dict[str, Any]] | None = None,
|
292
|
+
tool_choice: str | dict[str, Any] | None = "auto",
|
288
293
|
**kwargs,
|
289
|
-
) ->
|
294
|
+
) -> dict[str, Any]:
|
290
295
|
"""
|
291
296
|
Create response using Synth Responses API (sync version).
|
292
|
-
|
297
|
+
|
293
298
|
See AsyncSynthClient.responses_create for full parameter documentation.
|
294
299
|
"""
|
295
300
|
self._ensure_client()
|
296
|
-
|
301
|
+
|
297
302
|
# Build payload for Responses API
|
298
303
|
payload = {
|
299
304
|
"model": model,
|
300
305
|
"messages": messages,
|
301
306
|
}
|
302
|
-
|
307
|
+
|
303
308
|
# Add optional parameters
|
304
309
|
if previous_response_id is not None:
|
305
310
|
payload["previous_response_id"] = previous_response_id
|
306
311
|
if tools is not None:
|
307
312
|
payload["tools"] = tools
|
308
313
|
payload["tool_choice"] = tool_choice
|
309
|
-
|
314
|
+
|
310
315
|
# Add any additional kwargs
|
311
316
|
payload.update(kwargs)
|
312
|
-
|
317
|
+
|
313
318
|
# Retry logic
|
314
319
|
for attempt in range(self.config.max_retries):
|
315
320
|
try:
|
316
321
|
response = self._client.post(
|
317
322
|
f"{self.config.get_base_url_without_v1()}/v1/responses", json=payload
|
318
323
|
)
|
319
|
-
|
324
|
+
|
320
325
|
if response.status_code == 200:
|
321
326
|
return response.json()
|
322
|
-
|
327
|
+
|
323
328
|
# Handle rate limits
|
324
329
|
if response.status_code == 429:
|
325
330
|
wait_time = 2**attempt
|
326
331
|
logger.warning(f"Rate limited, waiting {wait_time}s...")
|
327
332
|
import time
|
333
|
+
|
328
334
|
time.sleep(wait_time)
|
329
335
|
continue
|
330
|
-
|
336
|
+
|
331
337
|
# Other errors
|
332
338
|
error_msg = f"API error {response.status_code}: {response.text}"
|
333
339
|
logger.error(error_msg)
|
334
340
|
raise Exception(error_msg)
|
335
|
-
|
341
|
+
|
336
342
|
except httpx.TimeoutException:
|
337
343
|
if attempt < self.config.max_retries - 1:
|
338
344
|
logger.warning(f"Timeout on attempt {attempt + 1}, retrying...")
|
339
345
|
continue
|
340
346
|
raise
|
341
|
-
|
347
|
+
|
342
348
|
raise Exception(f"Failed after {self.config.max_retries} attempts")
|
343
349
|
|
344
350
|
def chat_completions_create(
|
345
|
-
self, model: str, messages:
|
346
|
-
) ->
|
351
|
+
self, model: str, messages: list[dict[str, Any]], **kwargs
|
352
|
+
) -> dict[str, Any]:
|
347
353
|
"""
|
348
354
|
Create chat completion with OpenAI-compatible API (sync version).
|
349
355
|
|
@@ -393,7 +399,7 @@ class SyncSynthClient:
|
|
393
399
|
|
394
400
|
|
395
401
|
# Factory functions for easy instantiation
|
396
|
-
def create_async_client(config:
|
402
|
+
def create_async_client(config: SynthConfig | None = None) -> AsyncSynthClient:
|
397
403
|
"""
|
398
404
|
Create async Synth client.
|
399
405
|
|
@@ -406,7 +412,7 @@ def create_async_client(config: Optional[SynthConfig] = None) -> AsyncSynthClien
|
|
406
412
|
return AsyncSynthClient(config)
|
407
413
|
|
408
414
|
|
409
|
-
def create_sync_client(config:
|
415
|
+
def create_sync_client(config: SynthConfig | None = None) -> SyncSynthClient:
|
410
416
|
"""
|
411
417
|
Create sync Synth client.
|
412
418
|
|
@@ -421,8 +427,8 @@ def create_sync_client(config: Optional[SynthConfig] = None) -> SyncSynthClient:
|
|
421
427
|
|
422
428
|
# Convenience functions for one-off requests
|
423
429
|
async def create_chat_completion_async(
|
424
|
-
model: str, messages:
|
425
|
-
) ->
|
430
|
+
model: str, messages: list[dict[str, Any]], config: SynthConfig | None = None, **kwargs
|
431
|
+
) -> dict[str, Any]:
|
426
432
|
"""
|
427
433
|
Create a chat completion with automatic client management.
|
428
434
|
|
@@ -440,8 +446,8 @@ async def create_chat_completion_async(
|
|
440
446
|
|
441
447
|
|
442
448
|
def create_chat_completion_sync(
|
443
|
-
model: str, messages:
|
444
|
-
) ->
|
449
|
+
model: str, messages: list[dict[str, Any]], config: SynthConfig | None = None, **kwargs
|
450
|
+
) -> dict[str, Any]:
|
445
451
|
"""
|
446
452
|
Create a chat completion with automatic client management (sync version).
|
447
453
|
|
synth_ai/lm/warmup.py
CHANGED
@@ -3,13 +3,14 @@ Model warmup utilities for Synth backend.
|
|
3
3
|
Handles model preloading and warmup polling.
|
4
4
|
"""
|
5
5
|
|
6
|
-
import httpx
|
7
6
|
import asyncio
|
8
7
|
import logging
|
9
8
|
import sys
|
10
9
|
import time
|
11
|
-
from typing import Optional, Dict, Any
|
12
10
|
from datetime import datetime, timedelta
|
11
|
+
|
12
|
+
import httpx
|
13
|
+
|
13
14
|
from .config import SynthConfig
|
14
15
|
|
15
16
|
logger = logging.getLogger(__name__)
|
@@ -19,7 +20,7 @@ class WarmupStatus:
|
|
19
20
|
"""Track warmup status for models with TTL."""
|
20
21
|
|
21
22
|
def __init__(self):
|
22
|
-
self._warmed_models:
|
23
|
+
self._warmed_models: dict[str, datetime] = {}
|
23
24
|
self._ttl = timedelta(minutes=10) # Consider models warm for 10 minutes
|
24
25
|
|
25
26
|
def is_warm(self, model_name: str) -> bool:
|
@@ -47,11 +48,11 @@ _warmup_status = WarmupStatus()
|
|
47
48
|
|
48
49
|
async def warmup_synth_model(
|
49
50
|
model_name: str,
|
50
|
-
config:
|
51
|
-
max_attempts:
|
51
|
+
config: SynthConfig | None = None,
|
52
|
+
max_attempts: int | None = None,
|
52
53
|
force: bool = False,
|
53
54
|
verbose: bool = True,
|
54
|
-
gpu_preference:
|
55
|
+
gpu_preference: str | None = None,
|
55
56
|
) -> bool:
|
56
57
|
"""
|
57
58
|
Warm up a model on the Synth backend using fire-and-forget approach.
|
@@ -161,7 +162,7 @@ async def warmup_synth_model(
|
|
161
162
|
)
|
162
163
|
sys.stdout.flush()
|
163
164
|
await asyncio.sleep(1.0)
|
164
|
-
except Exception
|
165
|
+
except Exception:
|
165
166
|
# Continue polling; update spinner line with error label
|
166
167
|
elapsed = int(time.time() - start_time)
|
167
168
|
wheel = spinner[spin_idx % len(spinner)]
|
synth_ai/tracing/__init__.py
CHANGED
@@ -1,18 +1,30 @@
|
|
1
|
-
import sys as _sys
|
2
1
|
import importlib as _importlib
|
2
|
+
import sys as _sys
|
3
3
|
|
4
|
-
_pkg = _importlib.import_module(
|
4
|
+
_pkg = _importlib.import_module("synth_ai.v0.tracing")
|
5
5
|
_sys.modules[__name__] = _pkg
|
6
6
|
|
7
7
|
_SUBMODULES = [
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
"abstractions",
|
9
|
+
"base_client",
|
10
|
+
"client_manager",
|
11
|
+
"config",
|
12
|
+
"context",
|
13
|
+
"decorators",
|
14
|
+
"immediate_client",
|
15
|
+
"local",
|
16
|
+
"log_client_base",
|
17
|
+
"retry_queue",
|
18
|
+
"trackers",
|
19
|
+
"upload",
|
20
|
+
"utils",
|
11
21
|
]
|
12
22
|
for _m in _SUBMODULES:
|
13
|
-
_sys.modules[f
|
23
|
+
_sys.modules[f"{__name__}.{_m}"] = _importlib.import_module(f"synth_ai.v0.tracing.{_m}")
|
14
24
|
|
15
|
-
_events_pkg = _importlib.import_module(
|
16
|
-
_sys.modules[f
|
17
|
-
for _m in [
|
18
|
-
_sys.modules[f
|
25
|
+
_events_pkg = _importlib.import_module("synth_ai.v0.tracing.events")
|
26
|
+
_sys.modules[f"{__name__}.events"] = _events_pkg
|
27
|
+
for _m in ["manage", "scope", "store"]:
|
28
|
+
_sys.modules[f"{__name__}.events.{_m}"] = _importlib.import_module(
|
29
|
+
f"synth_ai.v0.tracing.events.{_m}"
|
30
|
+
)
|
synth_ai/tracing_v1/__init__.py
CHANGED
@@ -1,31 +1,33 @@
|
|
1
|
-
import sys as _sys
|
2
1
|
import importlib as _importlib
|
2
|
+
import sys as _sys
|
3
3
|
|
4
4
|
# Forward top-level package
|
5
|
-
_pkg = _importlib.import_module(
|
5
|
+
_pkg = _importlib.import_module("synth_ai.v0.tracing_v1")
|
6
6
|
_sys.modules[__name__] = _pkg
|
7
7
|
|
8
8
|
# Explicitly forward submodules so `synth_ai.tracing_v1.X` works
|
9
9
|
_SUBMODULES = [
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
10
|
+
"abstractions",
|
11
|
+
"base_client",
|
12
|
+
"client_manager",
|
13
|
+
"config",
|
14
|
+
"context",
|
15
|
+
"decorators",
|
16
|
+
"immediate_client",
|
17
|
+
"local",
|
18
|
+
"log_client_base",
|
19
|
+
"retry_queue",
|
20
|
+
"trackers",
|
21
|
+
"upload",
|
22
|
+
"utils",
|
23
23
|
]
|
24
24
|
for _m in _SUBMODULES:
|
25
|
-
_sys.modules[f
|
25
|
+
_sys.modules[f"{__name__}.{_m}"] = _importlib.import_module(f"synth_ai.v0.tracing_v1.{_m}")
|
26
26
|
|
27
27
|
# Forward events package and its submodules
|
28
|
-
_events_pkg = _importlib.import_module(
|
29
|
-
_sys.modules[f
|
30
|
-
for _m in [
|
31
|
-
_sys.modules[f
|
28
|
+
_events_pkg = _importlib.import_module("synth_ai.v0.tracing_v1.events")
|
29
|
+
_sys.modules[f"{__name__}.events"] = _events_pkg
|
30
|
+
for _m in ["manage", "scope", "store"]:
|
31
|
+
_sys.modules[f"{__name__}.events.{_m}"] = _importlib.import_module(
|
32
|
+
f"synth_ai.v0.tracing_v1.events.{_m}"
|
33
|
+
)
|
synth_ai/tracing_v3/__init__.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
"""Tracing v3 - Turso/sqld based tracing implementation.
|
2
2
|
|
3
3
|
This module provides a modern, async-first tracing system for capturing and storing
|
4
|
-
detailed execution traces from AI systems. It's designed to handle high-throughput
|
4
|
+
detailed execution traces from AI systems. It's designed to handle high-throughput
|
5
5
|
scenarios with proper async/await patterns throughout.
|
6
6
|
|
7
7
|
Architecture Overview:
|
@@ -49,10 +49,10 @@ Key Features:
|
|
49
49
|
Usage Example:
|
50
50
|
-------------
|
51
51
|
from synth_ai.tracing_v3 import SessionTracer
|
52
|
-
|
52
|
+
|
53
53
|
tracer = SessionTracer()
|
54
54
|
await tracer.initialize()
|
55
|
-
|
55
|
+
|
56
56
|
async with tracer.session() as session_id:
|
57
57
|
async with tracer.timestep("step1", turn_number=1):
|
58
58
|
# Record events during execution
|
@@ -70,17 +70,17 @@ The system uses environment variables for configuration:
|
|
70
70
|
See `config.py` for full configuration options.
|
71
71
|
"""
|
72
72
|
|
73
|
-
from .session_tracer import SessionTracer
|
74
73
|
from .abstractions import (
|
75
|
-
SessionTrace,
|
76
|
-
SessionTimeStep,
|
77
74
|
BaseEvent,
|
78
|
-
RuntimeEvent,
|
79
75
|
EnvironmentEvent,
|
76
|
+
RuntimeEvent,
|
80
77
|
SessionEventMarkovBlanketMessage,
|
78
|
+
SessionTimeStep,
|
79
|
+
SessionTrace,
|
81
80
|
TimeRecord,
|
82
81
|
)
|
83
82
|
from .config import TursoConfig
|
83
|
+
from .session_tracer import SessionTracer
|
84
84
|
|
85
85
|
__all__ = [
|
86
86
|
"SessionTracer",
|