synth-ai 0.2.8.dev6__py3-none-any.whl → 0.2.8.dev8__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.

Potentially problematic release.


This version of synth-ai might be problematic. Click here for more details.

@@ -13,7 +13,22 @@ import textwrap
13
13
 
14
14
  from synth_ai.demos.demo_task_apps import core as demo_core
15
15
  from synth_ai.handshake import run_handshake, HandshakeError
16
- from synth_ai.demos.demo_task_apps.core import DemoEnv
16
+ from synth_ai.demos.demo_task_apps.core import DemoEnv, DEFAULT_TASK_APP_SECRET_NAME
17
+
18
+
19
+ TASK_APP_MODAL_SECRET = DEFAULT_TASK_APP_SECRET_NAME
20
+
21
+
22
+ def _key_preview(value: str, label: str) -> str:
23
+ """Return a short descriptor for a secret without leaking the full value."""
24
+ try:
25
+ text = value or ""
26
+ length = len(text)
27
+ prefix = text[:6] if length >= 6 else text
28
+ suffix = text[-5:] if length >= 5 else text
29
+ return f"{label} len={length} prefix={prefix} last5={suffix}"
30
+ except Exception:
31
+ return f"{label} len=0"
17
32
 
18
33
 
19
34
  def _is_modal_public_url(u: str) -> bool:
@@ -100,7 +115,7 @@ def cmd_setup(_args: argparse.Namespace) -> int:
100
115
  dotenv_values = {
101
116
  "TASK_APP_BASE_URL": new_url,
102
117
  "TASK_APP_NAME": env.task_app_name,
103
- "TASK_APP_SECRET_NAME": env.task_app_secret_name or f"{env.task_app_name}-secret",
118
+ "TASK_APP_SECRET_NAME": TASK_APP_MODAL_SECRET,
104
119
  }
105
120
  demo_core.persist_dotenv_values(dotenv_values)
106
121
  os.environ["TASK_APP_BASE_URL"] = new_url
@@ -224,8 +239,13 @@ def _popen_stream_capture(cmd: list[str], cwd: str | None = None, env: dict | No
224
239
 
225
240
  def _mask_secret_args(args: list[str]) -> list[str]:
226
241
  masked: list[str] = []
242
+ sensitive_prefixes = (
243
+ "ENVIRONMENT_API_KEY=",
244
+ "OPENAI_API_KEY=",
245
+ "SYNTH_API_KEY=",
246
+ )
227
247
  for a in args:
228
- if "=" in a and any(a.startswith(prefix) for prefix in ("ENVIRONMENT_API_KEY=", "OPENAI_API_KEY=", "SYNTH_API_KEY=")):
248
+ if "=" in a and any(a.startswith(prefix) for prefix in sensitive_prefixes):
229
249
  try:
230
250
  key, value = a.split("=", 1)
231
251
  tail = value[-5:] if len(value) >= 5 else value
@@ -256,11 +276,18 @@ def _ensure_modal_secret(
256
276
 
257
277
  if replace:
258
278
  print(f"{prefix} Removing Modal secret '{secret_name}' (if present)…")
259
- delete_cmd = ["bash", "-lc", f"printf 'y\\n' | uv run modal secret delete {secret_name}"]
260
- print(f"{prefix} Command:", " ".join(delete_cmd))
261
- delete_code = _popen_stream(delete_cmd)
262
- if delete_code != 0:
263
- print(f"{prefix} Warning: delete command exited with {delete_code}; continuing to create")
279
+ delete_commands = [
280
+ ["bash", "-lc", f"printf 'y\\n' | uv run modal secret delete {secret_name}"],
281
+ ["bash", "-lc", f"printf 'y\\n' | modal secret delete {secret_name}"],
282
+ ]
283
+ delete_code = None
284
+ for delete_cmd in delete_commands:
285
+ print(f"{prefix} Command:", " ".join(delete_cmd))
286
+ delete_code = _popen_stream(delete_cmd)
287
+ if delete_code in (0, 1):
288
+ break
289
+ if delete_code not in (0, 1):
290
+ print(f"{prefix} Warning: delete command exited with {delete_code}; continuing to recreate")
264
291
 
265
292
  print(f"\n{prefix} Creating Modal secret '{secret_name}'…")
266
293
  print(f"{prefix} Command:", " ".join(_mask_secret_args(create_cmd)))
@@ -639,7 +666,7 @@ def _ensure_task_app_ready(env: DemoEnv, synth_key: str, *, label: str) -> DemoE
639
666
  app_name = fallback
640
667
  demo_core.persist_task_url(task_url, name=app_name)
641
668
 
642
- secret_name = env.task_app_secret_name.strip() or f"{app_name}-secret"
669
+ secret_name = TASK_APP_MODAL_SECRET
643
670
  demo_core.persist_task_url(task_url, name=app_name)
644
671
  demo_core.persist_dotenv_values({
645
672
  "TASK_APP_BASE_URL": task_url,
@@ -660,9 +687,7 @@ def _ensure_task_app_ready(env: DemoEnv, synth_key: str, *, label: str) -> DemoE
660
687
  print(f"[{label}] Verifying rollout health:")
661
688
  try:
662
689
  ek = (env_key or "").strip()
663
- ek_len = len(ek)
664
- ek_tail = ek[-5:] if ek_len >= 5 else ek
665
- print(f"[{label}] Using ENVIRONMENT_API_KEY len={ek_len} last5={ek_tail}")
690
+ print(f"[{label}] {_key_preview(ek, 'ENVIRONMENT_API_KEY')}")
666
691
  except Exception:
667
692
  pass
668
693
  health_base = task_url.rstrip("/")
@@ -685,6 +710,12 @@ def _ensure_task_app_ready(env: DemoEnv, synth_key: str, *, label: str) -> DemoE
685
710
  print(f"[{label}] body:", preview)
686
711
  if rc != 200:
687
712
  print(f"[{label}] Warning: rollout health check failed ({rc}). Response: {body}")
713
+ try:
714
+ print(f"[{label}] Sent header X-API-Key → {_key_preview(env_key, 'X-API-Key')}")
715
+ if secret_name:
716
+ print(f"[{label}] Modal secret name={secret_name}")
717
+ except Exception:
718
+ pass
688
719
  else:
689
720
  print(f"[{label}] Task app rollout health check OK.")
690
721
 
@@ -777,11 +808,7 @@ def cmd_deploy(args: argparse.Namespace) -> int:
777
808
  print("Aborted by user.")
778
809
  return 1
779
810
 
780
- prev_secret = (env.task_app_secret_name or "").strip()
781
- default_secret = f"{name_in}-secret"
782
- secret_name = default_secret if not prev_secret else prev_secret
783
- if prev_secret and prev_secret != default_secret:
784
- secret_name = default_secret
811
+ secret_name = TASK_APP_MODAL_SECRET
785
812
  existing_env_key = (env.env_api_key or "").strip()
786
813
  env_key: str | None = existing_env_key or None
787
814
  if existing_env_key:
@@ -853,7 +880,10 @@ def cmd_deploy(args: argparse.Namespace) -> int:
853
880
  demo_core.persist_dotenv_values({"OPENAI_API_KEY": openai_key})
854
881
  local_env["OPENAI_API_KEY"] = openai_key
855
882
 
856
- values = {"SYNTH_API_KEY": synth_key, "OPENAI_API_KEY": openai_key}
883
+ values = {
884
+ "SYNTH_API_KEY": synth_key,
885
+ "OPENAI_API_KEY": openai_key,
886
+ }
857
887
  if env_key:
858
888
  values["ENVIRONMENT_API_KEY"] = env_key
859
889
 
@@ -913,7 +943,7 @@ def cmd_deploy(args: argparse.Namespace) -> int:
913
943
  dotenv_values = {"TASK_APP_BASE_URL": url}
914
944
  if app_name:
915
945
  dotenv_values["TASK_APP_NAME"] = app_name
916
- dotenv_values["TASK_APP_SECRET_NAME"] = f"{app_name}-secret"
946
+ dotenv_values["TASK_APP_SECRET_NAME"] = TASK_APP_MODAL_SECRET
917
947
  dotenv_path = demo_core.persist_dotenv_values(dotenv_values)
918
948
  print(f"TASK_APP_BASE_URL={url}")
919
949
  if app_name:
@@ -922,7 +952,7 @@ def cmd_deploy(args: argparse.Namespace) -> int:
922
952
  print(f" export TASK_APP_BASE_URL={url}")
923
953
  if app_name:
924
954
  print(f" export TASK_APP_NAME={app_name}")
925
- print(f" export TASK_APP_SECRET_NAME={app_name}-secret")
955
+ print(f" export TASK_APP_SECRET_NAME={TASK_APP_MODAL_SECRET}")
926
956
  print(f"Persisted to {dotenv_path}")
927
957
  print("\nNext step:\n$ uvx synth-ai run")
928
958
  return 0
@@ -1195,9 +1225,9 @@ def cmd_run(args: argparse.Namespace) -> int:
1195
1225
  ek = (env.env_api_key or "").strip()
1196
1226
  print("Hint: If backend responded 401, verify SYNTH_API_KEY for:", base_url)
1197
1227
  if sk:
1198
- print(f" SYNTH_API_KEY len={len(sk)} last5={sk[-5:]}")
1228
+ print(f" {_key_preview(sk, 'SYNTH_API_KEY')}")
1199
1229
  if ek:
1200
- print(f" ENVIRONMENT_API_KEY len={len(ek)} last5={ek[-5:]}")
1230
+ print(f" {_key_preview(ek, 'ENVIRONMENT_API_KEY')}")
1201
1231
  print("Also ensure your Modal secret contains ENVIRONMENT_API_KEY and matches the task app.")
1202
1232
  return code
1203
1233
 
@@ -1218,7 +1248,7 @@ def cmd_run(args: argparse.Namespace) -> int:
1218
1248
  sk_len = len(sk)
1219
1249
  sk_tail = sk[-5:] if sk_len >= 5 else sk
1220
1250
  print(f"[run] Backend API: {api}")
1221
- print(f"[run] Using SYNTH_API_KEY len={sk_len} last5={sk_tail}")
1251
+ print(f"[run] {_key_preview(sk, 'SYNTH_API_KEY')}")
1222
1252
  except Exception:
1223
1253
  pass
1224
1254
  data_fragment: Dict[str, Any] = {
@@ -1274,7 +1304,7 @@ def cmd_run(args: argparse.Namespace) -> int:
1274
1304
  base_url = env.dev_backend_url
1275
1305
  print("Hint: HTTP 401 Unauthorized from backend. Verify SYNTH_API_KEY for:", base_url)
1276
1306
  if sk:
1277
- print(f" SYNTH_API_KEY len={len(sk)} last5={sk[-5:]}")
1307
+ print(f" {_key_preview(sk, 'SYNTH_API_KEY')}")
1278
1308
  print("Also ensure your Modal secret contains a valid ENVIRONMENT_API_KEY.")
1279
1309
  except Exception:
1280
1310
  pass
@@ -23,6 +23,8 @@ class DemoEnv:
23
23
  task_app_secret_name: str = ""
24
24
 
25
25
 
26
+ DEFAULT_TASK_APP_SECRET_NAME = "hendrycks-math-task-app-secret"
27
+
26
28
  def _mask(value: str, keep: int = 4) -> str:
27
29
  if not value:
28
30
  return ""
@@ -285,7 +287,7 @@ def load_env() -> DemoEnv:
285
287
  )
286
288
 
287
289
  task_app_name = str(state.get("TASK_APP_NAME") or "")
288
- task_app_secret_name = str(state.get("TASK_APP_SECRET_NAME") or "")
290
+ task_app_secret_name = DEFAULT_TASK_APP_SECRET_NAME
289
291
 
290
292
  env.dev_backend_url = dev_url.rstrip("/")
291
293
  env.synth_api_key = synth_api_key
@@ -367,7 +369,7 @@ def persist_task_url(url: str, *, name: str | None = None) -> None:
367
369
  if data.get("TASK_APP_NAME") != name:
368
370
  data["TASK_APP_NAME"] = name
369
371
  changed.append("TASK_APP_NAME")
370
- secret_name = f"{name}-secret"
372
+ secret_name = DEFAULT_TASK_APP_SECRET_NAME
371
373
  if data.get("TASK_APP_SECRET_NAME") != secret_name:
372
374
  data["TASK_APP_SECRET_NAME"] = secret_name
373
375
  if "TASK_APP_NAME" not in changed:
@@ -7,6 +7,7 @@ from pathlib import Path
7
7
 
8
8
  from modal import App, Image, Secret, asgi_app
9
9
  from functools import lru_cache
10
+ from synth_ai.demos.demo_task_apps.core import DEFAULT_TASK_APP_SECRET_NAME
10
11
 
11
12
  # Self-contained: no external problem bank installer required
12
13
 
@@ -43,24 +44,14 @@ if _SYNTH_HOSTED is not None:
43
44
  # No extra local dirs required; app is self-contained
44
45
 
45
46
  app = App("hendrycks-math-task-app")
46
- _SECRET_NAME = (
47
- os.getenv("TASK_APP_SECRET_NAME")
48
- or os.getenv("MATH_TASK_APP_SECRET")
49
- or os.getenv("TASK_APP_NAME", "").strip()
50
- )
51
- if not _SECRET_NAME:
52
- _SECRET_NAME = "synth-math-demo-secret"
53
- elif not _SECRET_NAME.endswith("-secret"):
54
- _SECRET_NAME = f"{_SECRET_NAME}-secret"
55
-
56
-
47
+ hendryks_secret = DEFAULT_TASK_APP_SECRET_NAME
57
48
  @app.function(
58
49
  image=image,
59
50
  timeout=600,
60
51
  memory=16384,
61
52
  cpu=4,
62
53
  min_containers=1,
63
- secrets=[Secret.from_name(_SECRET_NAME)],
54
+ secrets=[Secret.from_name(hendryks_secret)],
64
55
  )
65
56
  @asgi_app()
66
57
  def fastapi_app():
@@ -112,6 +103,23 @@ def fastapi_app():
112
103
  allow_headers=["*"],
113
104
  )
114
105
 
106
+ import logging
107
+
108
+ logger = logging.getLogger("hendrycks_math_task_app")
109
+ if not logger.handlers:
110
+ logger.addHandler(logging.StreamHandler())
111
+ logger.setLevel(logging.INFO)
112
+
113
+ def _log_env_key_prefix(source: str, env_key: str | None) -> str | None:
114
+ if not env_key:
115
+ return None
116
+ half = max(1, len(env_key) // 2)
117
+ prefix = env_key[:half]
118
+ msg = f"[{source}] expected ENVIRONMENT_API_KEY prefix: {prefix}"
119
+ print(msg)
120
+ logger.info(msg)
121
+ return prefix
122
+
115
123
  @app.get("/info")
116
124
  async def info():
117
125
  return {
@@ -125,7 +133,14 @@ def fastapi_app():
125
133
  if not env_key:
126
134
  return JSONResponse(status_code=503, content={"status": "unhealthy", "detail": "Missing ENVIRONMENT_API_KEY"})
127
135
  if x_api_key is not None and x_api_key != env_key:
128
- return JSONResponse(status_code=401, content={"status": "unauthorized", "detail": "Invalid API key"})
136
+ prefix = _log_env_key_prefix("health", env_key)
137
+ content = {"status": "unauthorized", "detail": "Invalid API key"}
138
+ headers = None
139
+ if prefix:
140
+ content["detail"] = f"Invalid API key (expected prefix: {prefix})"
141
+ content["expected_api_key_prefix"] = prefix
142
+ headers = {"X-Expected-API-Key-Prefix": prefix}
143
+ return JSONResponse(status_code=401, content=content, headers=headers)
129
144
  return {"status": "healthy"}
130
145
 
131
146
  # Optional rollout-specific health for CLI compatibility
@@ -135,7 +150,14 @@ def fastapi_app():
135
150
  if not env_key:
136
151
  return JSONResponse(status_code=503, content={"status": "unhealthy", "detail": "Missing ENVIRONMENT_API_KEY"})
137
152
  if not x_api_key or x_api_key != env_key:
138
- return JSONResponse(status_code=401, content={"status": "unauthorized", "detail": "Invalid or missing API key"})
153
+ prefix = _log_env_key_prefix("health/rollout", env_key)
154
+ content = {"status": "unauthorized", "detail": "Invalid or missing API key"}
155
+ headers = None
156
+ if prefix:
157
+ content["detail"] = f"Invalid or missing API key (expected prefix: {prefix})"
158
+ content["expected_api_key_prefix"] = prefix
159
+ headers = {"X-Expected-API-Key-Prefix": prefix}
160
+ return JSONResponse(status_code=401, content=content, headers=headers)
139
161
  return {"ok": True}
140
162
 
141
163
  # _load_hendrycks_problem is defined at fastapi_app scope
synth_ai/handshake.py CHANGED
@@ -30,6 +30,7 @@ def _origin() -> str:
30
30
 
31
31
  dev_flag = (os.getenv("SYNTH_CANONICAL_DEV") or "").strip().lower()
32
32
  if dev_flag in _TRUTHY:
33
+ print("USING DEV ORIGIN")
33
34
  return "http://localhost:3000"
34
35
 
35
36
  return "https://www.usesynth.ai/dashboard"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: synth-ai
3
- Version: 0.2.8.dev6
3
+ Version: 0.2.8.dev8
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
@@ -1,6 +1,6 @@
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=OwIHbvdIn75tPKArJQKq2qfBD_2VlVaPU7CuX2_ce0Y,3701
3
+ synth_ai/handshake.py,sha256=uzoTOpkf9JQgsyKWrlx8gjfQmK3HpqFQAZY1gZDtiIo,3735
4
4
  synth_ai/http.py,sha256=lqjFXDmAP_xgfywK_rDSOVxuMy4rDH9S3Rtu9k1tLmk,1028
5
5
  synth_ai/http_client.py,sha256=_9J8rUGoItUMnJLGZw7r0uXiJeLWR939kByRkvtP1XM,4429
6
6
  synth_ai/install_sqld.sh,sha256=AMBhlfq661PxeTTc6D4K_Nei_qwMvA84ei4NhQzmUUk,928
@@ -21,16 +21,16 @@ synth_ai/config/base_url.py,sha256=c85LaABBrvsl8Fp8KH0LNtJJrpnUwlzA5Ywbuth8fHE,3
21
21
  synth_ai/core/experiment.py,sha256=hLkPtzUFA7iY3-QpeJ5K8YjvQeyfqnjab5P2CFaojys,236
22
22
  synth_ai/core/system.py,sha256=s-Z7np2ISYmYc1r9YN-y2yb3cgRlOalrh0iaqnxeo84,206
23
23
  synth_ai/demos/core/__init__.py,sha256=A2FjhY7KXGtyzdQXqeTPCkEhHfrH-eQg6bvP8HaYhZM,36
24
- synth_ai/demos/core/cli.py,sha256=lwkW1j638pOaLpmo6vPtDvEjsWdtLDCTwjbHoSHOdA8,56220
24
+ synth_ai/demos/core/cli.py,sha256=kXvW6hqEbjLp5m8tnsqbLxBbEt-c5gVAzphg4mPf2ik,56914
25
25
  synth_ai/demos/demo_task_apps/__init__.py,sha256=8aUGEGpWUw11GRb3wQXRAmQ99yjAt5qd5FCTDJpXWjI,44
26
- synth_ai/demos/demo_task_apps/core.py,sha256=ifKxxRKqC-y43MaqLHNuerXAlBHO8MI8ZBo2CzYcOoU,14563
26
+ synth_ai/demos/demo_task_apps/core.py,sha256=1JZBTW7J9lR_I4mSal7XlcK0QtVDQm-bA9WiNmPha4A,14624
27
27
  synth_ai/demos/demo_task_apps/math/__init__.py,sha256=WBzpZwSn7pRarBmhopQi34i9bEm05-71eM3siboOavY,43
28
28
  synth_ai/demos/demo_task_apps/math/_common.py,sha256=SgtVW1pne4pgwGS2gYYQWkmG9BvU2sQTYzlncmUJ0NM,533
29
29
  synth_ai/demos/demo_task_apps/math/app.py,sha256=gNopoAhwM0vzdKuCa7AwQqSwiV2xagrjMxMH9YIniv4,1160
30
30
  synth_ai/demos/demo_task_apps/math/config.toml,sha256=Kxrzuyj7Az5mvzXaipPIyngKTDqphohf6uSWOHCF5cw,2105
31
31
  synth_ai/demos/demo_task_apps/math/deploy_modal.py,sha256=O4745sFuGEZTsygl-mz6ZOFJ7mog8CquXMgMyjFKr_c,2288
32
32
  synth_ai/demos/demo_task_apps/math/deploy_task_app.sh,sha256=qVffbAmsiCAxzFDzcxNVF4f7yyLWnmqPc1cNydHT5BQ,791
33
- synth_ai/demos/demo_task_apps/math/modal_task_app.py,sha256=PE6LtRmz-56nbMT0tCInSr5IRUIpq-jVOrhZMTmMna4,19026
33
+ synth_ai/demos/demo_task_apps/math/modal_task_app.py,sha256=1hv0CYNmIV-6aiiUYw_myR1cM1_ApcMiCQ6NmavLP94,20244
34
34
  synth_ai/environments/__init__.py,sha256=BQW0Nc_BFQq_N-pcqTyJVjW56kSEXu7XZyaSer-U95Q,1032
35
35
  synth_ai/environments/environment/__init__.py,sha256=EBol9AKxPTIPXWcbH9Tja-l3yL-N2kB8e5atyf6F66c,31
36
36
  synth_ai/environments/environment/core.py,sha256=0jd0CZ88_s_qqA3d1lOgVsnv-ucw_1lJDAIUj1gTSt0,2201
@@ -412,9 +412,9 @@ synth_ai/v0/tracing_v1/events/manage.py,sha256=ZDXXP-ZwLH9LCsmw7Ru9o55d7bl_diPtJ
412
412
  synth_ai/v0/tracing_v1/events/scope.py,sha256=BuBkhSpVHUJt8iGT9HJZF82rbb88mQcd2vM2shg-w2I,2550
413
413
  synth_ai/v0/tracing_v1/events/store.py,sha256=0342lvAcalyJbVEIzQFaPuMQGgwiFm7M5rE6gr-G0E8,9041
414
414
  synth_ai/zyk/__init__.py,sha256=htVLnzTYQ5rxzYpzSYBm7_o6uNKZ3pB_PrqkBrgTRS4,771
415
- synth_ai-0.2.8.dev6.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
416
- synth_ai-0.2.8.dev6.dist-info/METADATA,sha256=wGvVtvCrYUcNC-rdZ3Lt3WXVqElpGwelyKJaJdbVMs4,5152
417
- synth_ai-0.2.8.dev6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
418
- synth_ai-0.2.8.dev6.dist-info/entry_points.txt,sha256=Neq-3bT7TAijjgOIR77pKL-WYg6TWBDeO8pp_nL4vGY,91
419
- synth_ai-0.2.8.dev6.dist-info/top_level.txt,sha256=fBmtZyVHuKaGa29oHBaaUkrUIWTqSpoVMPiVdCDP3k8,9
420
- synth_ai-0.2.8.dev6.dist-info/RECORD,,
415
+ synth_ai-0.2.8.dev8.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
416
+ synth_ai-0.2.8.dev8.dist-info/METADATA,sha256=nHpXX9X8FZHz-rYwQul-fAM8ImsHge6OGUQEXJuUrc0,5152
417
+ synth_ai-0.2.8.dev8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
418
+ synth_ai-0.2.8.dev8.dist-info/entry_points.txt,sha256=Neq-3bT7TAijjgOIR77pKL-WYg6TWBDeO8pp_nL4vGY,91
419
+ synth_ai-0.2.8.dev8.dist-info/top_level.txt,sha256=fBmtZyVHuKaGa29oHBaaUkrUIWTqSpoVMPiVdCDP3k8,9
420
+ synth_ai-0.2.8.dev8.dist-info/RECORD,,