synth-ai 0.2.6.dev5__py3-none-any.whl → 0.2.7__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/cli/balance.py +8 -2
- synth_ai/cli/demo.py +11 -3
- synth_ai/cli/rl_demo.py +51 -5
- synth_ai/cli/root.py +6 -0
- synth_ai/config/base_url.py +9 -0
- synth_ai/demos/core/cli.py +625 -278
- synth_ai/demos/demo_task_apps/core.py +44 -16
- synth_ai/demos/demo_task_apps/math/config.toml +98 -13
- synth_ai/handshake.py +63 -0
- synth_ai/lm/vendors/core/openai_api.py +8 -3
- synth_ai/v0/tracing/config.py +3 -1
- synth_ai/v0/tracing/decorators.py +3 -1
- synth_ai/v0/tracing/upload.py +3 -1
- synth_ai/v0/tracing_v1/config.py +3 -1
- synth_ai/v0/tracing_v1/decorators.py +3 -1
- synth_ai/v0/tracing_v1/upload.py +3 -1
- {synth_ai-0.2.6.dev5.dist-info → synth_ai-0.2.7.dist-info}/METADATA +26 -4
- {synth_ai-0.2.6.dev5.dist-info → synth_ai-0.2.7.dist-info}/RECORD +22 -21
- {synth_ai-0.2.6.dev5.dist-info → synth_ai-0.2.7.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.6.dev5.dist-info → synth_ai-0.2.7.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.6.dev5.dist-info → synth_ai-0.2.7.dist-info}/licenses/LICENSE +0 -0
- {synth_ai-0.2.6.dev5.dist-info → synth_ai-0.2.7.dist-info}/top_level.txt +0 -0
|
@@ -10,6 +10,8 @@ from typing import Any, Dict, Optional, Tuple
|
|
|
10
10
|
|
|
11
11
|
import urllib.request
|
|
12
12
|
|
|
13
|
+
from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
|
|
14
|
+
|
|
13
15
|
|
|
14
16
|
@dataclass
|
|
15
17
|
class DemoEnv:
|
|
@@ -169,7 +171,7 @@ def load_env() -> DemoEnv:
|
|
|
169
171
|
Backend URL:
|
|
170
172
|
- Use BACKEND_OVERRIDE (any) from CWD .env if set
|
|
171
173
|
- Else use DEV_BACKEND_URL from CWD .env ONLY if it's localhost/127.0.0.1 or :8000
|
|
172
|
-
- Else default to
|
|
174
|
+
- Else default to production backend (PROD_BASE_URL_DEFAULT)
|
|
173
175
|
|
|
174
176
|
API keys:
|
|
175
177
|
- SYNTH_API_KEY from OS -> CWD .env -> repo .env -> pkg demo .env -> state
|
|
@@ -194,9 +196,25 @@ def load_env() -> DemoEnv:
|
|
|
194
196
|
|
|
195
197
|
state = _read_state()
|
|
196
198
|
|
|
199
|
+
default_root = PROD_BASE_URL_DEFAULT.rstrip("/")
|
|
200
|
+
prod_default = f"{default_root}/api"
|
|
201
|
+
|
|
197
202
|
# Backend URL resolution
|
|
198
|
-
backend_override = (
|
|
199
|
-
|
|
203
|
+
backend_override = (
|
|
204
|
+
os_env.get("BACKEND_OVERRIDE")
|
|
205
|
+
or cwd_env.get("BACKEND_OVERRIDE")
|
|
206
|
+
or repo_env.get("BACKEND_OVERRIDE")
|
|
207
|
+
or pkg_env.get("BACKEND_OVERRIDE")
|
|
208
|
+
or examples_env.get("BACKEND_OVERRIDE")
|
|
209
|
+
or ""
|
|
210
|
+
).strip()
|
|
211
|
+
dev_env = (
|
|
212
|
+
os_env.get("DEV_BACKEND_URL")
|
|
213
|
+
or cwd_env.get("DEV_BACKEND_URL")
|
|
214
|
+
or repo_env.get("DEV_BACKEND_URL")
|
|
215
|
+
or pkg_env.get("DEV_BACKEND_URL")
|
|
216
|
+
or ""
|
|
217
|
+
).strip()
|
|
200
218
|
use_dev = False
|
|
201
219
|
if backend_override:
|
|
202
220
|
dev_url = backend_override
|
|
@@ -207,9 +225,9 @@ def load_env() -> DemoEnv:
|
|
|
207
225
|
dev_url = dev_env
|
|
208
226
|
use_dev = True
|
|
209
227
|
else:
|
|
210
|
-
dev_url =
|
|
228
|
+
dev_url = prod_default
|
|
211
229
|
else:
|
|
212
|
-
dev_url =
|
|
230
|
+
dev_url = prod_default
|
|
213
231
|
if not dev_url.endswith("/api"):
|
|
214
232
|
dev_url = dev_url.rstrip("/") + "/api"
|
|
215
233
|
|
|
@@ -222,7 +240,7 @@ def load_env() -> DemoEnv:
|
|
|
222
240
|
or str(state.get("SYNTH_API_KEY") or "")
|
|
223
241
|
)
|
|
224
242
|
if not synth_api_key:
|
|
225
|
-
mode = "prod" if
|
|
243
|
+
mode = "prod" if default_root in dev_url else ("local" if ("localhost" in dev_url or "127.0.0.1" in dev_url) else "dev")
|
|
226
244
|
if mode == "prod":
|
|
227
245
|
synth_api_key = (
|
|
228
246
|
os_env.get("PROD_SYNTH_API_KEY")
|
|
@@ -276,22 +294,32 @@ def load_env() -> DemoEnv:
|
|
|
276
294
|
env.task_app_name = task_app_name
|
|
277
295
|
env.task_app_secret_name = task_app_secret_name
|
|
278
296
|
|
|
279
|
-
|
|
280
|
-
print
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
print(f"
|
|
286
|
-
|
|
287
|
-
|
|
297
|
+
# Suppress environment echo by default for cleaner CLI output.
|
|
298
|
+
# If needed for debugging, set SYNTH_CLI_VERBOSE=1 to print resolved values.
|
|
299
|
+
if os.getenv("SYNTH_CLI_VERBOSE", "0") == "1":
|
|
300
|
+
print("ENV:")
|
|
301
|
+
print(f" DEV_BACKEND_URL={env.dev_backend_url}")
|
|
302
|
+
print(f" SYNTH_API_KEY={_mask(env.synth_api_key)}")
|
|
303
|
+
print(f" ENVIRONMENT_API_KEY={_mask(env.env_api_key)}")
|
|
304
|
+
print(f" TASK_APP_BASE_URL={env.task_app_base_url}")
|
|
305
|
+
if task_app_name:
|
|
306
|
+
print(f" TASK_APP_NAME={task_app_name}")
|
|
307
|
+
if task_app_secret_name:
|
|
308
|
+
print(f" TASK_APP_SECRET_NAME={task_app_secret_name}")
|
|
288
309
|
return env
|
|
289
310
|
|
|
290
311
|
|
|
291
312
|
def assert_http_ok(url: str, method: str = "GET", allow_redirects: bool = True, timeout: float = 10.0) -> bool:
|
|
292
313
|
try:
|
|
314
|
+
import ssl
|
|
315
|
+
|
|
293
316
|
req = urllib.request.Request(url, method=method)
|
|
294
|
-
|
|
317
|
+
# Default: disable SSL verification for local/dev convenience.
|
|
318
|
+
# Set SYNTH_SSL_VERIFY=1 to enable verification.
|
|
319
|
+
ctx = ssl._create_unverified_context() # nosec: disabled by default for dev
|
|
320
|
+
if os.getenv("SYNTH_SSL_VERIFY", "0") == "1":
|
|
321
|
+
ctx = None
|
|
322
|
+
with urllib.request.urlopen(req, timeout=timeout, context=ctx) as resp: # nosec - controlled URL
|
|
295
323
|
code = getattr(resp, "status", 200)
|
|
296
324
|
return 200 <= int(code) < 400
|
|
297
325
|
except Exception:
|
|
@@ -2,43 +2,128 @@
|
|
|
2
2
|
name = "Qwen/Qwen3-0.6B"
|
|
3
3
|
dtype = "bfloat16"
|
|
4
4
|
seed = 42
|
|
5
|
+
trainer_mode = "full"
|
|
6
|
+
|
|
7
|
+
[lora]
|
|
8
|
+
r = 16
|
|
9
|
+
alpha = 32
|
|
10
|
+
dropout = 0.05
|
|
11
|
+
target_modules = [
|
|
12
|
+
"q_proj", "k_proj", "v_proj", "o_proj",
|
|
13
|
+
"gate_proj", "up_proj", "down_proj",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[rdma]
|
|
17
|
+
enabled = false
|
|
18
|
+
ifname = "eth0"
|
|
19
|
+
ip_type = "ipv4"
|
|
20
|
+
p2p_disable = 0
|
|
21
|
+
shm_disable = 0
|
|
22
|
+
fast_nccl = false
|
|
23
|
+
|
|
24
|
+
gid_index = 3
|
|
25
|
+
cross_nic = 0
|
|
26
|
+
collnet_enable = 0
|
|
27
|
+
net_gdr_level = 2
|
|
28
|
+
|
|
29
|
+
nsocks_perthread = 4
|
|
30
|
+
socket_nthreads = 2
|
|
31
|
+
|
|
32
|
+
algo = "Ring"
|
|
33
|
+
proto = "Simple"
|
|
34
|
+
p2p_level = "SYS"
|
|
35
|
+
debug = "INFO"
|
|
5
36
|
|
|
6
37
|
[reference]
|
|
7
38
|
placement = "dedicated"
|
|
39
|
+
gpu_index = 1
|
|
8
40
|
port = 8002
|
|
41
|
+
tp = 1
|
|
42
|
+
health_max_wait_s = 180
|
|
43
|
+
health_interval_ms = 300
|
|
9
44
|
|
|
10
45
|
[topology]
|
|
11
46
|
type = "single_node_split"
|
|
12
|
-
|
|
47
|
+
gpu_type = "H100:4"
|
|
48
|
+
use_rdma = false
|
|
49
|
+
gpus_for_vllm = 2
|
|
13
50
|
gpus_for_training = 1
|
|
14
51
|
gpus_for_ref = 1
|
|
52
|
+
tensor_parallel = 2
|
|
15
53
|
|
|
16
54
|
[training]
|
|
17
|
-
num_epochs =
|
|
18
|
-
iterations_per_epoch =
|
|
19
|
-
batch_size =
|
|
20
|
-
group_size =
|
|
55
|
+
num_epochs = 1
|
|
56
|
+
iterations_per_epoch = 2
|
|
57
|
+
batch_size = 1
|
|
58
|
+
group_size = 8
|
|
21
59
|
learning_rate = 5e-6
|
|
22
60
|
max_grad_norm = 0.5
|
|
23
61
|
log_interval = 1
|
|
24
62
|
update_reference_interval = 0
|
|
25
63
|
weight_sync_interval = 1
|
|
26
64
|
|
|
65
|
+
[training.weight_sync]
|
|
66
|
+
enable = true
|
|
67
|
+
targets = ["policy"]
|
|
68
|
+
|
|
69
|
+
[vllm]
|
|
70
|
+
tensor_parallel_size = 2
|
|
71
|
+
gpu_memory_utilization = 0.9
|
|
72
|
+
max_model_len = 8192
|
|
73
|
+
max_num_seqs = 32
|
|
74
|
+
enforce_eager = false
|
|
75
|
+
max_parallel_generations = 4
|
|
76
|
+
|
|
27
77
|
[evaluation]
|
|
28
|
-
seeds = [0, 1, 2, 3]
|
|
78
|
+
seeds = [0, 1, 2, 3, 4, 5, 6, 7]
|
|
29
79
|
rollouts_per_seed = 1
|
|
30
|
-
instances =
|
|
80
|
+
instances = 0
|
|
31
81
|
max_concurrent_rollouts = 4
|
|
32
|
-
thinking_mode = "
|
|
33
|
-
every_n_iters =
|
|
82
|
+
thinking_mode = "think"
|
|
83
|
+
every_n_iters = 5
|
|
34
84
|
|
|
35
85
|
[rollout]
|
|
36
86
|
env_name = "math"
|
|
37
87
|
policy_name = "math-react"
|
|
38
|
-
|
|
88
|
+
env_config = {}
|
|
89
|
+
max_steps_per_episode = 5
|
|
39
90
|
sampling_temperature = 0.3
|
|
40
91
|
sampling_top_p = 0.95
|
|
41
|
-
max_tokens =
|
|
42
|
-
max_concurrent_rollouts =
|
|
43
|
-
ops_per_rollout =
|
|
92
|
+
max_tokens = 1024
|
|
93
|
+
max_concurrent_rollouts = 4
|
|
94
|
+
ops_per_rollout = 14
|
|
44
95
|
on_done = "reset"
|
|
96
|
+
thinking_mode = "think"
|
|
97
|
+
thinking_budget = 512
|
|
98
|
+
|
|
99
|
+
[policy]
|
|
100
|
+
config = {}
|
|
101
|
+
|
|
102
|
+
[hyperparams]
|
|
103
|
+
epsilon_low = 0.1
|
|
104
|
+
epsilon_high = 0.3
|
|
105
|
+
delta = 5.0
|
|
106
|
+
beta = 0.01
|
|
107
|
+
kl_penalty = 0.01
|
|
108
|
+
advantage_normalization = true
|
|
109
|
+
group_normalization = true
|
|
110
|
+
num_inner_steps = 1
|
|
111
|
+
clip_epsilon = 0.2
|
|
112
|
+
completion_only = false
|
|
113
|
+
|
|
114
|
+
[step_rewards]
|
|
115
|
+
enabled = false
|
|
116
|
+
mode = "off"
|
|
117
|
+
step_beta = 0.0
|
|
118
|
+
indicator_lambda = 0.0
|
|
119
|
+
|
|
120
|
+
[trainer]
|
|
121
|
+
allow_ref_fallback = false
|
|
122
|
+
|
|
123
|
+
[checkpoint]
|
|
124
|
+
interval = 10
|
|
125
|
+
directory = "/checkpoints"
|
|
126
|
+
keep_last_n = 3
|
|
127
|
+
save_optimizer = true
|
|
128
|
+
save_scheduler = true
|
|
129
|
+
enabled = true
|
synth_ai/handshake.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
import webbrowser
|
|
7
|
+
from typing import Any, Dict, Tuple
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class HandshakeError(Exception):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _origin() -> str:
|
|
17
|
+
# Prefer explicit env; fallback to localhost dashboard
|
|
18
|
+
return (os.getenv("SYNTH_CANONICAL_ORIGIN", "") or "http://localhost:3000").rstrip("/")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def start_handshake_session(origin: str | None = None) -> Tuple[str, str, int, int]:
|
|
22
|
+
base = (origin or _origin()).rstrip("/")
|
|
23
|
+
url = f"{base}/api/sdk/handshake/init"
|
|
24
|
+
r = requests.post(url, timeout=10)
|
|
25
|
+
if r.status_code != 200:
|
|
26
|
+
raise HandshakeError(f"init failed: {r.status_code} {r.text}")
|
|
27
|
+
data = r.json()
|
|
28
|
+
return (
|
|
29
|
+
str(data.get("device_code")),
|
|
30
|
+
str(data.get("verification_uri")),
|
|
31
|
+
int(data.get("expires_in", 600)),
|
|
32
|
+
int(data.get("interval", 3)),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def poll_handshake_token(device_code: str, origin: str | None = None, *, timeout_s: int | None = None) -> Dict[str, Any]:
|
|
37
|
+
base = (origin or _origin()).rstrip("/")
|
|
38
|
+
url = f"{base}/api/sdk/handshake/token"
|
|
39
|
+
deadline = time.time() + (timeout_s or 600)
|
|
40
|
+
while True:
|
|
41
|
+
if time.time() > deadline:
|
|
42
|
+
raise HandshakeError("handshake timed out")
|
|
43
|
+
try:
|
|
44
|
+
r = requests.post(url, json={"device_code": device_code}, timeout=10)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
time.sleep(2)
|
|
47
|
+
continue
|
|
48
|
+
if r.status_code == 200:
|
|
49
|
+
return r.json()
|
|
50
|
+
elif r.status_code in (404, 410):
|
|
51
|
+
raise HandshakeError(f"handshake failed: {r.status_code}")
|
|
52
|
+
# 428 authorization_pending or others → wait and retry
|
|
53
|
+
time.sleep(2)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def run_handshake(origin: str | None = None) -> Dict[str, Any]:
|
|
57
|
+
device_code, verification_uri, expires_in, interval = start_handshake_session(origin)
|
|
58
|
+
try:
|
|
59
|
+
webbrowser.open(verification_uri)
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
return poll_handshake_token(device_code, origin, timeout_s=expires_in)
|
|
63
|
+
|
|
@@ -15,6 +15,7 @@ import pydantic_core
|
|
|
15
15
|
# from openai import AsyncOpenAI, OpenAI
|
|
16
16
|
from pydantic import BaseModel
|
|
17
17
|
|
|
18
|
+
from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
|
|
18
19
|
from synth_ai.lm.caching.initialize import get_cache_handler
|
|
19
20
|
from synth_ai.lm.constants import OPENAI_REASONING_MODELS, SPECIAL_BASE_TEMPS
|
|
20
21
|
from synth_ai.lm.tools.base import BaseTool
|
|
@@ -45,9 +46,13 @@ class OpenAIStructuredOutputClient(OpenAIStandard):
|
|
|
45
46
|
def __init__(self, synth_logging: bool = True):
|
|
46
47
|
# Check if we should use Synth clients instead of OpenAI
|
|
47
48
|
openai_base = os.getenv("OPENAI_API_BASE", "")
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
prod_prefix = PROD_BASE_URL_DEFAULT.rstrip("/")
|
|
50
|
+
use_synth = (
|
|
51
|
+
openai_base.startswith("https://synth")
|
|
52
|
+
or (prod_prefix and openai_base.startswith(prod_prefix))
|
|
53
|
+
or os.getenv("SYNTH_BASE_URL")
|
|
54
|
+
or os.getenv("MODAL_BASE_URL")
|
|
55
|
+
)
|
|
51
56
|
|
|
52
57
|
if use_synth:
|
|
53
58
|
# Use Synth clients for Synth endpoints
|
synth_ai/v0/tracing/config.py
CHANGED
|
@@ -12,6 +12,8 @@ from opentelemetry.sdk.trace.export import (
|
|
|
12
12
|
)
|
|
13
13
|
from pydantic import BaseModel, ConfigDict, Field
|
|
14
14
|
|
|
15
|
+
from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
class InMemoryExporter(SpanExporter):
|
|
17
19
|
def __init__(self):
|
|
@@ -101,7 +103,7 @@ class EventManagement(str, Enum):
|
|
|
101
103
|
class TracingConfig(BaseModel):
|
|
102
104
|
mode: LoggingMode = Field(default=LoggingMode.DEFERRED)
|
|
103
105
|
api_key: str
|
|
104
|
-
base_url: str = Field(default=
|
|
106
|
+
base_url: str = Field(default=PROD_BASE_URL_DEFAULT)
|
|
105
107
|
max_retries: int = Field(default=3)
|
|
106
108
|
retry_backoff: float = Field(default=1.5) # exponential backoff multiplier
|
|
107
109
|
batch_size: int = Field(default=1) # for future batching support
|
|
@@ -10,6 +10,8 @@ from typing import TYPE_CHECKING, Any, Literal, ParamSpec, TypeVar, Union
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
11
|
from .trackers import SynthTrackerAsync, SynthTrackerSync
|
|
12
12
|
|
|
13
|
+
from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
|
|
14
|
+
|
|
13
15
|
from .abstractions import (
|
|
14
16
|
AgentComputeStep,
|
|
15
17
|
ArbitraryInputs,
|
|
@@ -77,7 +79,7 @@ def get_tracing_config() -> TracingConfig:
|
|
|
77
79
|
if os.getenv("SYNTH_LOGGING_MODE") == "instant"
|
|
78
80
|
else LoggingMode.DEFERRED,
|
|
79
81
|
api_key=os.getenv("SYNTH_API_KEY", ""),
|
|
80
|
-
base_url=os.getenv("SYNTH_ENDPOINT_OVERRIDE",
|
|
82
|
+
base_url=os.getenv("SYNTH_ENDPOINT_OVERRIDE", PROD_BASE_URL_DEFAULT),
|
|
81
83
|
)
|
|
82
84
|
# Initialize retry queue with config if needed
|
|
83
85
|
initialize_retry_queue(config)
|
synth_ai/v0/tracing/upload.py
CHANGED
|
@@ -13,6 +13,8 @@ from pydantic import BaseModel, ConfigDict, field_validator
|
|
|
13
13
|
from requests.adapters import HTTPAdapter
|
|
14
14
|
from urllib3.poolmanager import PoolManager
|
|
15
15
|
|
|
16
|
+
from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
|
|
17
|
+
|
|
16
18
|
from .abstractions import Dataset, SystemTrace
|
|
17
19
|
from .events.store import event_store
|
|
18
20
|
|
|
@@ -369,7 +371,7 @@ def upload_helper(
|
|
|
369
371
|
api_key = os.getenv("SYNTH_API_KEY")
|
|
370
372
|
if not api_key:
|
|
371
373
|
raise ValueError("SYNTH_API_KEY environment variable not set")
|
|
372
|
-
base_url = os.getenv("SYNTH_ENDPOINT_OVERRIDE",
|
|
374
|
+
base_url = os.getenv("SYNTH_ENDPOINT_OVERRIDE", PROD_BASE_URL_DEFAULT)
|
|
373
375
|
|
|
374
376
|
"""Legacy block below retained for reference and disabled for linting/parsing.
|
|
375
377
|
Start disabled block.
|
synth_ai/v0/tracing_v1/config.py
CHANGED
|
@@ -12,6 +12,8 @@ from opentelemetry.sdk.trace.export import (
|
|
|
12
12
|
)
|
|
13
13
|
from pydantic import BaseModel, ConfigDict, Field
|
|
14
14
|
|
|
15
|
+
from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
class InMemoryExporter(SpanExporter):
|
|
17
19
|
def __init__(self):
|
|
@@ -101,7 +103,7 @@ class EventManagement(str, Enum):
|
|
|
101
103
|
class TracingConfig(BaseModel):
|
|
102
104
|
mode: LoggingMode = Field(default=LoggingMode.DEFERRED)
|
|
103
105
|
api_key: str
|
|
104
|
-
base_url: str = Field(default=
|
|
106
|
+
base_url: str = Field(default=PROD_BASE_URL_DEFAULT)
|
|
105
107
|
max_retries: int = Field(default=3)
|
|
106
108
|
retry_backoff: float = Field(default=1.5) # exponential backoff multiplier
|
|
107
109
|
batch_size: int = Field(default=1) # for future batching support
|
|
@@ -11,6 +11,8 @@ from typing import TYPE_CHECKING, Any, Literal, ParamSpec, TypeVar, Union
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
from .trackers import SynthTrackerAsync, SynthTrackerSync
|
|
13
13
|
|
|
14
|
+
from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
|
|
15
|
+
|
|
14
16
|
from .abstractions import (
|
|
15
17
|
AgentComputeStep,
|
|
16
18
|
ArbitraryInputs,
|
|
@@ -78,7 +80,7 @@ def get_tracing_config() -> TracingConfig:
|
|
|
78
80
|
if os.getenv("SYNTH_LOGGING_MODE") == "instant"
|
|
79
81
|
else LoggingMode.DEFERRED,
|
|
80
82
|
api_key=os.getenv("SYNTH_API_KEY", ""),
|
|
81
|
-
base_url=os.getenv("SYNTH_ENDPOINT_OVERRIDE",
|
|
83
|
+
base_url=os.getenv("SYNTH_ENDPOINT_OVERRIDE", PROD_BASE_URL_DEFAULT),
|
|
82
84
|
)
|
|
83
85
|
# Initialize retry queue with config if needed
|
|
84
86
|
initialize_retry_queue(config)
|
synth_ai/v0/tracing_v1/upload.py
CHANGED
|
@@ -13,6 +13,8 @@ from pydantic import BaseModel, ConfigDict, field_validator
|
|
|
13
13
|
from requests.adapters import HTTPAdapter
|
|
14
14
|
from urllib3.poolmanager import PoolManager
|
|
15
15
|
|
|
16
|
+
from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
|
|
17
|
+
|
|
16
18
|
from .abstractions import Dataset, SystemTrace
|
|
17
19
|
from .events.store import event_store
|
|
18
20
|
|
|
@@ -388,7 +390,7 @@ def upload_helper(
|
|
|
388
390
|
api_key = os.getenv("SYNTH_API_KEY")
|
|
389
391
|
if not api_key:
|
|
390
392
|
raise ValueError("SYNTH_API_KEY environment variable not set")
|
|
391
|
-
base_url = os.getenv("SYNTH_ENDPOINT_OVERRIDE",
|
|
393
|
+
base_url = os.getenv("SYNTH_ENDPOINT_OVERRIDE", PROD_BASE_URL_DEFAULT)
|
|
392
394
|
|
|
393
395
|
from .decorators import _local, active_events_var
|
|
394
396
|
from .trackers import synth_tracker_async
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: synth-ai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: RL as a service SDK - Core AI functionality and tracing
|
|
5
5
|
Author-email: Synth AI <josh@usesynth.ai>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -14,6 +14,7 @@ Requires-Dist: pydantic>=2.0.0
|
|
|
14
14
|
Requires-Dist: python-dotenv>=1.0.1
|
|
15
15
|
Requires-Dist: requests>=2.32.3
|
|
16
16
|
Requires-Dist: urllib3>=2.3.0
|
|
17
|
+
Requires-Dist: certifi>=2024.8.30
|
|
17
18
|
Requires-Dist: tqdm>=4.66.4
|
|
18
19
|
Requires-Dist: jsonschema>=4.23.0
|
|
19
20
|
Requires-Dist: backoff>=2.0.0
|
|
@@ -97,10 +98,31 @@ synth-ai comes with a built-in RL example tailored for training Qwen/Qwen3-0.6B
|
|
|
97
98
|
Please create an account at [Synth](https://usesynth.ai) and [Modal](https://modal.com) for the Math hello‑world test run. Then run:
|
|
98
99
|
|
|
99
100
|
```bash
|
|
100
|
-
uvx synth-ai rl_demo
|
|
101
|
+
uvx synth-ai rl_demo setup
|
|
101
102
|
uvx synth-ai rl_demo deploy
|
|
102
|
-
uvx synth-ai
|
|
103
|
-
uvx synth-ai rl_demo run
|
|
103
|
+
uvx synth-ai run
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
To walk through kicking off your first RL run, see the [Synth‑AI Documentation](https://docs.usesynth.ai/synth-ai/introduction).
|
|
107
|
+
|
|
108
|
+
### What `rl_demo setup` does now
|
|
109
|
+
|
|
110
|
+
When you run `uvx synth-ai rl_demo setup`, the SDK opens your browser to the Synth dashboard for a one‑time pairing (handshake) with your signed‑in session. The SDK will automatically:
|
|
111
|
+
|
|
112
|
+
- Detect your current user and organization
|
|
113
|
+
- Ensure both API keys exist for that user+org
|
|
114
|
+
- Write the keys to your project’s `.env` file as `SYNTH_API_KEY` and `ENVIRONMENT_API_KEY`
|
|
115
|
+
|
|
116
|
+
No keys are printed or requested interactively. You’ll see a confirmation like:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Connecting SDK to your browser session…
|
|
120
|
+
Connected to Acme Labs via browser.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
If your browser isn’t already signed in, sign in when prompted and the pairing completes automatically. The dashboard’s welcome modal will reflect a successful pairing.
|
|
124
|
+
|
|
125
|
+
Environment variables:
|
|
126
|
+
|
|
127
|
+
- `SYNTH_CANONICAL_ORIGIN` (optional): override the dashboard base URL the SDK uses for the handshake (defaults to `http://localhost:3000`).
|
|
128
|
+
- Keys are stored only in your project’s `.env` file, not exported to your shell.
|
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
synth_ai/__init__.py,sha256=NixuXddy4lS2Wmj0F8eMt0HS_oYCTnq3iVVq5VYwWIc,1341
|
|
2
2
|
synth_ai/__main__.py,sha256=Kh1xBKkTE5Vs2qNMtDuuOXerHUptMcOiF3YziOpC6DA,146
|
|
3
|
+
synth_ai/handshake.py,sha256=AJR0GFFAkdAga8CXRLYbQl90-s0AQzTGxy5tQzPQb0E,1994
|
|
3
4
|
synth_ai/http.py,sha256=lqjFXDmAP_xgfywK_rDSOVxuMy4rDH9S3Rtu9k1tLmk,1028
|
|
4
5
|
synth_ai/http_client.py,sha256=_9J8rUGoItUMnJLGZw7r0uXiJeLWR939kByRkvtP1XM,4429
|
|
5
6
|
synth_ai/install_sqld.sh,sha256=AMBhlfq661PxeTTc6D4K_Nei_qwMvA84ei4NhQzmUUk,928
|
|
6
7
|
synth_ai/cli/__init__.py,sha256=ThBK5FykxAqX8Mz0E4gj94_PX9EwMEtXcmm-A8krv7E,1559
|
|
7
|
-
synth_ai/cli/balance.py,sha256=
|
|
8
|
+
synth_ai/cli/balance.py,sha256=z4h1MQSyFX60k-13L9IT0rtOCI16iKNGJeNjFMZuv_k,8010
|
|
8
9
|
synth_ai/cli/calc.py,sha256=RJyQJ41e02xn-V0vRRCAVkL59UHDqyz8XpYGsenfdm4,2085
|
|
9
|
-
synth_ai/cli/demo.py,sha256=
|
|
10
|
+
synth_ai/cli/demo.py,sha256=YGZhmCE0XLLP31OdsdGceTL6oFHmzyOc0CO-Crl54W0,5064
|
|
10
11
|
synth_ai/cli/legacy_root_backup.py,sha256=KSMADyJ2g5OVpsq_CeBzqIeDC2Um-9GyINzsJH-75uw,15872
|
|
11
12
|
synth_ai/cli/man.py,sha256=JQDon73ZkuKP9xr1_vRh5fjV9_b5xiUb7zNjny7ArB8,3765
|
|
12
13
|
synth_ai/cli/recent.py,sha256=mHhM-QrR_MfjfKSzBvvPUEC-lkXTWUZrQwqYTmb2x0Y,4173
|
|
13
|
-
synth_ai/cli/rl_demo.py,sha256=
|
|
14
|
-
synth_ai/cli/root.py,sha256=
|
|
14
|
+
synth_ai/cli/rl_demo.py,sha256=HAZqHaGFKAu7yXtjglmmNcHp4js77wCYSpa2WTcjyUE,8050
|
|
15
|
+
synth_ai/cli/root.py,sha256=7YgAxsefqscE4QEaa3kuKqBnaHbQLa4ZyXJ5l8eVl7Y,9741
|
|
15
16
|
synth_ai/cli/status.py,sha256=M_bt7U58Ubi-q-ZlrIpgCASKq9_k6uMjpx926f6kLLA,4591
|
|
16
17
|
synth_ai/cli/traces.py,sha256=_QBdCR92u0Gv51U4DH0Ws1d5yCrbJRpaYKe7pmcHrHs,6484
|
|
17
18
|
synth_ai/cli/watch.py,sha256=HBKbAcpUkkPhGvsPRofckbu8oILiVqp35NXHkIEpTTc,17808
|
|
18
19
|
synth_ai/compound/cais.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
synth_ai/config/base_url.py,sha256=
|
|
20
|
+
synth_ai/config/base_url.py,sha256=c85LaABBrvsl8Fp8KH0LNtJJrpnUwlzA5Ywbuth8fHE,3454
|
|
20
21
|
synth_ai/core/experiment.py,sha256=hLkPtzUFA7iY3-QpeJ5K8YjvQeyfqnjab5P2CFaojys,236
|
|
21
22
|
synth_ai/core/system.py,sha256=s-Z7np2ISYmYc1r9YN-y2yb3cgRlOalrh0iaqnxeo84,206
|
|
22
23
|
synth_ai/demos/core/__init__.py,sha256=A2FjhY7KXGtyzdQXqeTPCkEhHfrH-eQg6bvP8HaYhZM,36
|
|
23
|
-
synth_ai/demos/core/cli.py,sha256=
|
|
24
|
+
synth_ai/demos/core/cli.py,sha256=KkIm7nhKxHN26UQAjh-5wW-y__Z481UR23JmFl2GpM4,56329
|
|
24
25
|
synth_ai/demos/demo_task_apps/__init__.py,sha256=8aUGEGpWUw11GRb3wQXRAmQ99yjAt5qd5FCTDJpXWjI,44
|
|
25
|
-
synth_ai/demos/demo_task_apps/core.py,sha256=
|
|
26
|
+
synth_ai/demos/demo_task_apps/core.py,sha256=ifKxxRKqC-y43MaqLHNuerXAlBHO8MI8ZBo2CzYcOoU,14563
|
|
26
27
|
synth_ai/demos/demo_task_apps/math/__init__.py,sha256=WBzpZwSn7pRarBmhopQi34i9bEm05-71eM3siboOavY,43
|
|
27
28
|
synth_ai/demos/demo_task_apps/math/_common.py,sha256=SgtVW1pne4pgwGS2gYYQWkmG9BvU2sQTYzlncmUJ0NM,533
|
|
28
29
|
synth_ai/demos/demo_task_apps/math/app.py,sha256=gNopoAhwM0vzdKuCa7AwQqSwiV2xagrjMxMH9YIniv4,1160
|
|
29
|
-
synth_ai/demos/demo_task_apps/math/config.toml,sha256=
|
|
30
|
+
synth_ai/demos/demo_task_apps/math/config.toml,sha256=Kxrzuyj7Az5mvzXaipPIyngKTDqphohf6uSWOHCF5cw,2105
|
|
30
31
|
synth_ai/demos/demo_task_apps/math/deploy_modal.py,sha256=O4745sFuGEZTsygl-mz6ZOFJ7mog8CquXMgMyjFKr_c,2288
|
|
31
32
|
synth_ai/demos/demo_task_apps/math/deploy_task_app.sh,sha256=qVffbAmsiCAxzFDzcxNVF4f7yyLWnmqPc1cNydHT5BQ,791
|
|
32
33
|
synth_ai/demos/demo_task_apps/math/modal_task_app.py,sha256=DcjhzNj6hwaY4Me-kJPiGKPoVED9eW4dHoaPeMD4vzQ,18808
|
|
@@ -327,7 +328,7 @@ synth_ai/lm/vendors/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
327
328
|
synth_ai/lm/vendors/core/anthropic_api.py,sha256=mxJVF-uvSUOdbBRMmVfwBFCc7ntV5i_LNE5tQ2AxAbU,14986
|
|
328
329
|
synth_ai/lm/vendors/core/gemini_api.py,sha256=mHvQtRqoymuzsQDxNFgTDt4HsrgvIuVBSAE29QpRa34,11082
|
|
329
330
|
synth_ai/lm/vendors/core/mistral_api.py,sha256=4ggRg_4ajzZMBCb-0mHMX_ZTg10tteSfnIPE2NULFag,11875
|
|
330
|
-
synth_ai/lm/vendors/core/openai_api.py,sha256=
|
|
331
|
+
synth_ai/lm/vendors/core/openai_api.py,sha256=qVl6ZxKrcPwMMEsumFinIPML1I6UO0pt870nsBg64nw,8554
|
|
331
332
|
synth_ai/lm/vendors/core/synth_dev_api.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
332
333
|
synth_ai/lm/vendors/local/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
333
334
|
synth_ai/lm/vendors/local/ollama.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -378,15 +379,15 @@ synth_ai/v0/tracing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
378
379
|
synth_ai/v0/tracing/abstractions.py,sha256=pL9XCf9UEWdX4IRizzRK9XUNBtDeBYfkVD51F8UOB0s,6898
|
|
379
380
|
synth_ai/v0/tracing/base_client.py,sha256=IZpyuM-GIClvBBFA9iv4tpOjzY1QHF1m7vkNCYk7xLo,2931
|
|
380
381
|
synth_ai/v0/tracing/client_manager.py,sha256=rDHpOClkf1t0_6cJecQtr9IaaRmEJOCQ8StaiHyXq1E,4512
|
|
381
|
-
synth_ai/v0/tracing/config.py,sha256=
|
|
382
|
+
synth_ai/v0/tracing/config.py,sha256=ZjfJV1jMoJ6srdGMPtSaaOX7gz9KiyyxGn5p9QMrwHE,4042
|
|
382
383
|
synth_ai/v0/tracing/context.py,sha256=QZRgMgSWMcmZtQ4WDA7eCJdIAKbgU85vWDM-aiRUpCE,5113
|
|
383
|
-
synth_ai/v0/tracing/decorators.py,sha256=
|
|
384
|
+
synth_ai/v0/tracing/decorators.py,sha256=vAGItKhcdcCMenfFrnXoczl0iAki_uUvvT5n42pnAKk,30851
|
|
384
385
|
synth_ai/v0/tracing/immediate_client.py,sha256=M1J1zY9dC2u0Ta-xa6kK32mSa9g-va2Avu7hnB88tbo,6203
|
|
385
386
|
synth_ai/v0/tracing/local.py,sha256=sDNQ6ECVwZZkRlCC0_F33VOXuUUzZ1B0UVFBMKtN5R0,722
|
|
386
387
|
synth_ai/v0/tracing/log_client_base.py,sha256=Zl-dOknLd47xa-fh_3UBJkw1wF67uN1-4sm8N0Wl7CU,2297
|
|
387
388
|
synth_ai/v0/tracing/retry_queue.py,sha256=Crpt8ugbuxKfau3ioWt0jMJzsCafaxKPSC1X3gfPU34,6647
|
|
388
389
|
synth_ai/v0/tracing/trackers.py,sha256=I_5M9vAzFAsR_xKPGq_55yq2NkwztBZreMX8JhCK9UA,19005
|
|
389
|
-
synth_ai/v0/tracing/upload.py,sha256=
|
|
390
|
+
synth_ai/v0/tracing/upload.py,sha256=RdylTi_Hpjv3JdscY2Mwc0jU0Ldz7Mig7z6ltIkQRws,17387
|
|
390
391
|
synth_ai/v0/tracing/utils.py,sha256=FXoMW9qOIk8-2qv_7WpVK2UG3_0AAGwi6fQQJ5Eldqk,306
|
|
391
392
|
synth_ai/v0/tracing/events/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
392
393
|
synth_ai/v0/tracing/events/manage.py,sha256=ZDXXP-ZwLH9LCsmw7Ru9o55d7bl_diPtJV78_p7hhxQ,5956
|
|
@@ -396,24 +397,24 @@ synth_ai/v0/tracing_v1/__init__.py,sha256=AHaSAzOMVAML9T_E4OrO2K9BheZDiKBUU3uyfG
|
|
|
396
397
|
synth_ai/v0/tracing_v1/abstractions.py,sha256=pL9XCf9UEWdX4IRizzRK9XUNBtDeBYfkVD51F8UOB0s,6898
|
|
397
398
|
synth_ai/v0/tracing_v1/base_client.py,sha256=IZpyuM-GIClvBBFA9iv4tpOjzY1QHF1m7vkNCYk7xLo,2931
|
|
398
399
|
synth_ai/v0/tracing_v1/client_manager.py,sha256=rDHpOClkf1t0_6cJecQtr9IaaRmEJOCQ8StaiHyXq1E,4512
|
|
399
|
-
synth_ai/v0/tracing_v1/config.py,sha256=
|
|
400
|
+
synth_ai/v0/tracing_v1/config.py,sha256=ZjfJV1jMoJ6srdGMPtSaaOX7gz9KiyyxGn5p9QMrwHE,4042
|
|
400
401
|
synth_ai/v0/tracing_v1/context.py,sha256=QZRgMgSWMcmZtQ4WDA7eCJdIAKbgU85vWDM-aiRUpCE,5113
|
|
401
|
-
synth_ai/v0/tracing_v1/decorators.py,sha256=
|
|
402
|
+
synth_ai/v0/tracing_v1/decorators.py,sha256=Hy_CqumvZxvyDoeLuZPB8_FE8BWKKwxtPtiino0JAIo,31704
|
|
402
403
|
synth_ai/v0/tracing_v1/immediate_client.py,sha256=M1J1zY9dC2u0Ta-xa6kK32mSa9g-va2Avu7hnB88tbo,6203
|
|
403
404
|
synth_ai/v0/tracing_v1/local.py,sha256=sDNQ6ECVwZZkRlCC0_F33VOXuUUzZ1B0UVFBMKtN5R0,722
|
|
404
405
|
synth_ai/v0/tracing_v1/log_client_base.py,sha256=Zl-dOknLd47xa-fh_3UBJkw1wF67uN1-4sm8N0Wl7CU,2297
|
|
405
406
|
synth_ai/v0/tracing_v1/retry_queue.py,sha256=P1XxTzZHBBPeFTHWSh_1oP5Byn4X3bNsXZqPc1rsu5U,6650
|
|
406
407
|
synth_ai/v0/tracing_v1/trackers.py,sha256=I_5M9vAzFAsR_xKPGq_55yq2NkwztBZreMX8JhCK9UA,19005
|
|
407
|
-
synth_ai/v0/tracing_v1/upload.py,sha256=
|
|
408
|
+
synth_ai/v0/tracing_v1/upload.py,sha256=gRMx0aRQHvO1-MEJAEvdTYH9cBvcPp_Z8r2nHADrBFM,18024
|
|
408
409
|
synth_ai/v0/tracing_v1/utils.py,sha256=FXoMW9qOIk8-2qv_7WpVK2UG3_0AAGwi6fQQJ5Eldqk,306
|
|
409
410
|
synth_ai/v0/tracing_v1/events/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
410
411
|
synth_ai/v0/tracing_v1/events/manage.py,sha256=ZDXXP-ZwLH9LCsmw7Ru9o55d7bl_diPtJV78_p7hhxQ,5956
|
|
411
412
|
synth_ai/v0/tracing_v1/events/scope.py,sha256=BuBkhSpVHUJt8iGT9HJZF82rbb88mQcd2vM2shg-w2I,2550
|
|
412
413
|
synth_ai/v0/tracing_v1/events/store.py,sha256=0342lvAcalyJbVEIzQFaPuMQGgwiFm7M5rE6gr-G0E8,9041
|
|
413
414
|
synth_ai/zyk/__init__.py,sha256=htVLnzTYQ5rxzYpzSYBm7_o6uNKZ3pB_PrqkBrgTRS4,771
|
|
414
|
-
synth_ai-0.2.
|
|
415
|
-
synth_ai-0.2.
|
|
416
|
-
synth_ai-0.2.
|
|
417
|
-
synth_ai-0.2.
|
|
418
|
-
synth_ai-0.2.
|
|
419
|
-
synth_ai-0.2.
|
|
415
|
+
synth_ai-0.2.7.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
|
|
416
|
+
synth_ai-0.2.7.dist-info/METADATA,sha256=o6GogGqKFEH-uw0VOTIm-8crmH3udRYY8PdRpJA02ko,4975
|
|
417
|
+
synth_ai-0.2.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
418
|
+
synth_ai-0.2.7.dist-info/entry_points.txt,sha256=Neq-3bT7TAijjgOIR77pKL-WYg6TWBDeO8pp_nL4vGY,91
|
|
419
|
+
synth_ai-0.2.7.dist-info/top_level.txt,sha256=fBmtZyVHuKaGa29oHBaaUkrUIWTqSpoVMPiVdCDP3k8,9
|
|
420
|
+
synth_ai-0.2.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|