synth-ai 0.2.6.dev4__py3-none-any.whl → 0.2.6.dev5__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.

@@ -224,8 +224,59 @@ def _popen_stream_capture(cmd: list[str], cwd: str | None = None, env: dict | No
224
224
  return int(proc.returncode or 0), "\n".join(buf_lines)
225
225
 
226
226
 
227
+ def _mask_secret_args(args: list[str]) -> list[str]:
228
+ masked: list[str] = []
229
+ for a in args:
230
+ if "=" in a and any(a.startswith(prefix) for prefix in ("ENVIRONMENT_API_KEY=", "OPENAI_API_KEY=", "SYNTH_API_KEY=")):
231
+ try:
232
+ key, value = a.split("=", 1)
233
+ tail = value[-5:] if len(value) >= 5 else value
234
+ masked.append(f"{key}=***{tail}")
235
+ except Exception:
236
+ masked.append("<masked>")
237
+ else:
238
+ masked.append(a)
239
+ return masked
240
+
241
+
242
+ def _ensure_modal_secret(
243
+ secret_name: str,
244
+ *,
245
+ values: dict[str, str],
246
+ label: str = "deploy",
247
+ replace: bool = False,
248
+ ) -> bool:
249
+ prefix = f"[{label}]"
250
+ if not secret_name.strip():
251
+ raise RuntimeError("Secret name is required")
252
+
253
+ if not values:
254
+ raise RuntimeError("No values provided to create Modal secret")
255
+
256
+ create_args = [f"{k}={v}" for k, v in values.items()]
257
+ create_cmd = ["uv", "run", "modal", "secret", "create", secret_name, *create_args]
258
+
259
+ if replace:
260
+ print(f"{prefix} Removing Modal secret '{secret_name}' (if present)…")
261
+ delete_cmd = ["bash", "-lc", f"printf 'y\\n' | uv run modal secret delete {secret_name}"]
262
+ print(f"{prefix} Command:", " ".join(delete_cmd))
263
+ delete_code = _popen_stream(delete_cmd)
264
+ if delete_code != 0:
265
+ print(f"{prefix} Warning: delete command exited with {delete_code}; continuing to create")
266
+
267
+ print(f"\n{prefix} Creating Modal secret '{secret_name}'…")
268
+ print(f"{prefix} Command:", " ".join(_mask_secret_args(create_cmd)))
269
+ code = _popen_stream(create_cmd)
270
+ if code != 0:
271
+ raise RuntimeError("Failed to provision Modal secret (see logs above)")
272
+
273
+ return True
274
+
275
+
227
276
  def cmd_deploy(args: argparse.Namespace) -> int:
228
277
  env = demo_core.load_env()
278
+ cwd_env_path = os.path.join(os.getcwd(), ".env")
279
+ local_env = demo_core.load_dotenv_file(cwd_env_path)
229
280
  url = ""
230
281
  app_name = env.task_app_name or ""
231
282
  try:
@@ -279,6 +330,51 @@ def cmd_deploy(args: argparse.Namespace) -> int:
279
330
  if not proceed:
280
331
  print("Aborted by user.")
281
332
  return 1
333
+
334
+ secret_name = (env.task_app_secret_name or "").strip() or f"{name_in}-secret"
335
+ env_key = (env.env_api_key or "").strip() or None
336
+ if env_key is None:
337
+ from synth_ai.rl.secrets import mint_environment_api_key
338
+
339
+ env_key = mint_environment_api_key()
340
+ demo_core.persist_env_api_key(env_key)
341
+ demo_core.persist_dotenv_values({"ENVIRONMENT_API_KEY": env_key})
342
+ os.environ["ENVIRONMENT_API_KEY"] = env_key
343
+ env.env_api_key = env_key
344
+ local_env["ENVIRONMENT_API_KEY"] = env_key
345
+ print("[deploy] Minted new ENVIRONMENT_API_KEY")
346
+
347
+ synth_key = (env.synth_api_key or os.environ.get("SYNTH_API_KEY") or local_env.get("SYNTH_API_KEY") or "").strip()
348
+ if not synth_key:
349
+ synth_key = input("Enter SYNTH_API_KEY for Modal secret (required): ").strip()
350
+ if not synth_key:
351
+ print("SYNTH_API_KEY is required to create the Modal secret.")
352
+ return 1
353
+ demo_core.persist_api_key(synth_key)
354
+ demo_core.persist_dotenv_values({"SYNTH_API_KEY": synth_key})
355
+ env.synth_api_key = synth_key
356
+
357
+ openai_key = (os.environ.get("OPENAI_API_KEY") or local_env.get("OPENAI_API_KEY") or "").strip()
358
+ if not openai_key:
359
+ openai_key = input("Enter OPENAI_API_KEY for Modal secret (required): ").strip()
360
+ if not openai_key:
361
+ print("OPENAI_API_KEY is required to create the Modal secret.")
362
+ return 1
363
+ demo_core.persist_dotenv_values({"OPENAI_API_KEY": openai_key})
364
+ local_env["OPENAI_API_KEY"] = openai_key
365
+
366
+ values = {"SYNTH_API_KEY": synth_key, "OPENAI_API_KEY": openai_key}
367
+ if env_key:
368
+ values["ENVIRONMENT_API_KEY"] = env_key
369
+
370
+ try:
371
+ created = _ensure_modal_secret(secret_name, values=values, label="deploy", replace=True)
372
+ except RuntimeError as secret_err:
373
+ print(f"Failed to prepare Modal secret '{secret_name}': {secret_err}")
374
+ return 2
375
+ if created:
376
+ print(f"[deploy] Modal secret '{secret_name}' provisioned.")
377
+
282
378
  deploy_cmd = ["uv", "run", "python", "-m", "modal", "deploy", "--name", name_in, app_path]
283
379
  print("\nStreaming Modal build/deploy logs (this can take several minutes on first run)…\n")
284
380
  code, deploy_logs = _popen_stream_capture(deploy_cmd)
@@ -346,8 +442,6 @@ def cmd_deploy(args: argparse.Namespace) -> int:
346
442
 
347
443
 
348
444
  def cmd_configure(args: argparse.Namespace) -> int:
349
- from synth_ai.rl.secrets import mint_environment_api_key
350
-
351
445
  env = demo_core.load_env()
352
446
  cwd_env_path = os.path.join(os.getcwd(), ".env")
353
447
  local_env = demo_core.load_dotenv_file(cwd_env_path)
@@ -362,13 +456,9 @@ def cmd_configure(args: argparse.Namespace) -> int:
362
456
  demo_core.persist_dotenv_values({"SYNTH_API_KEY": synth_key})
363
457
 
364
458
  env_key = env.env_api_key.strip()
365
- minted_env_key = False
366
459
  if not env_key:
367
- env_key = mint_environment_api_key()
368
- minted_env_key = True
369
- print("Minted new ENVIRONMENT_API_KEY")
370
- demo_core.persist_env_api_key(env_key)
371
- demo_core.persist_dotenv_values({"ENVIRONMENT_API_KEY": env_key})
460
+ print("ENVIRONMENT_API_KEY missing; run `uvx synth-ai rl_demo deploy` to mint and store one.")
461
+ return 1
372
462
 
373
463
  task_url = env.task_app_base_url
374
464
  if not task_url or not _is_modal_public_url(task_url):
@@ -418,43 +508,20 @@ def cmd_configure(args: argparse.Namespace) -> int:
418
508
  })
419
509
 
420
510
  # Ensure Modal secret has the environment API key (and optional extras).
421
- secret_args = [f"ENVIRONMENT_API_KEY={env_key}"]
422
511
  openai_key = (os.environ.get("OPENAI_API_KEY") or local_env.get("OPENAI_API_KEY") or "").strip()
423
- if openai_key:
424
- secret_args.append(f"OPENAI_API_KEY={openai_key}")
425
512
  synth_for_secret = synth_key
426
- if synth_for_secret:
427
- secret_args.append(f"SYNTH_API_KEY={synth_for_secret}")
428
513
 
429
- create_cmd = ["uv", "run", "modal", "secret", "create", secret_name, *secret_args]
430
- def _mask_args(args: list[str]) -> list[str]:
431
- masked: list[str] = []
432
- for a in args:
433
- if "=" in a and any(a.startswith(k + "=") for k in ("ENVIRONMENT_API_KEY", "OPENAI_API_KEY", "SYNTH_API_KEY")):
434
- try:
435
- k, v = a.split("=", 1)
436
- suf = v[-5:] if len(v) >= 5 else ""
437
- masked.append(f"{k}=***{suf}")
438
- except Exception:
439
- masked.append("<masked>")
440
- else:
441
- masked.append(a)
442
- return masked
514
+ secret_values: dict[str, str] = {"ENVIRONMENT_API_KEY": env_key}
515
+ if openai_key:
516
+ secret_values["OPENAI_API_KEY"] = openai_key
517
+ if synth_for_secret:
518
+ secret_values["SYNTH_API_KEY"] = synth_for_secret
443
519
 
444
- print("\n[configure] Creating Modal secret (streaming logs)…")
445
- print("[configure] Command:", " ".join(_mask_args(create_cmd)))
446
- code = _popen_stream(create_cmd)
447
- if code != 0:
448
- print("[configure] Secret create failed; attempting delete → create")
449
- delete_cmd = ["bash", "-lc", f"printf 'y\\n' | uv run modal secret delete {secret_name}"]
450
- print("[configure] Command:", " ".join(delete_cmd))
451
- _popen_stream(delete_cmd)
452
- print("[configure] Retrying secret create…")
453
- print("[configure] Command:", " ".join(_mask_args(create_cmd)))
454
- code = _popen_stream(create_cmd)
455
- if code != 0:
456
- print("[configure] Failed to provision Modal secret.")
457
- return 2
520
+ try:
521
+ _ensure_modal_secret(secret_name, values=secret_values, label="configure", replace=True)
522
+ except RuntimeError as err:
523
+ print(f"[configure] Failed to provision Modal secret: {err}")
524
+ return 2
458
525
 
459
526
  # Verify task app can read the secret by hitting rollout health with X-API-Key.
460
527
  rollout_url = task_url.rstrip("/") + "/health/rollout"
@@ -557,8 +624,6 @@ def cmd_configure(args: argparse.Namespace) -> int:
557
624
  "TASK_APP_NAME": app_name,
558
625
  "TASK_APP_SECRET_NAME": secret_name,
559
626
  }, indent=2))
560
- if minted_env_key:
561
- print(f"Stored minted ENVIRONMENT_API_KEY in {cwd_env_path}")
562
627
  print("Next: uvx synth-ai rl_demo run")
563
628
  return 0
564
629
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: synth-ai
3
- Version: 0.2.6.dev4
3
+ Version: 0.2.6.dev5
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
@@ -20,7 +20,7 @@ synth_ai/config/base_url.py,sha256=Bk7Bd9jKJP-LF0SW--WE01JhMfvOB6NUkFMRgPMnJuQ,3
20
20
  synth_ai/core/experiment.py,sha256=hLkPtzUFA7iY3-QpeJ5K8YjvQeyfqnjab5P2CFaojys,236
21
21
  synth_ai/core/system.py,sha256=s-Z7np2ISYmYc1r9YN-y2yb3cgRlOalrh0iaqnxeo84,206
22
22
  synth_ai/demos/core/__init__.py,sha256=A2FjhY7KXGtyzdQXqeTPCkEhHfrH-eQg6bvP8HaYhZM,36
23
- synth_ai/demos/core/cli.py,sha256=MXiKIKH0gk2yW90TCjRA9F_4-scX5ft_2acytRMKCLs,41835
23
+ synth_ai/demos/core/cli.py,sha256=MuJELXFRxtyucek9b05Oo54pmJs5QGo45SV3hDZTFO0,44729
24
24
  synth_ai/demos/demo_task_apps/__init__.py,sha256=8aUGEGpWUw11GRb3wQXRAmQ99yjAt5qd5FCTDJpXWjI,44
25
25
  synth_ai/demos/demo_task_apps/core.py,sha256=3-C2dGdaqVqrVjnsxU2n6kGcuaprwuszBcTHePBypwo,13580
26
26
  synth_ai/demos/demo_task_apps/math/__init__.py,sha256=WBzpZwSn7pRarBmhopQi34i9bEm05-71eM3siboOavY,43
@@ -411,9 +411,9 @@ synth_ai/v0/tracing_v1/events/manage.py,sha256=ZDXXP-ZwLH9LCsmw7Ru9o55d7bl_diPtJ
411
411
  synth_ai/v0/tracing_v1/events/scope.py,sha256=BuBkhSpVHUJt8iGT9HJZF82rbb88mQcd2vM2shg-w2I,2550
412
412
  synth_ai/v0/tracing_v1/events/store.py,sha256=0342lvAcalyJbVEIzQFaPuMQGgwiFm7M5rE6gr-G0E8,9041
413
413
  synth_ai/zyk/__init__.py,sha256=htVLnzTYQ5rxzYpzSYBm7_o6uNKZ3pB_PrqkBrgTRS4,771
414
- synth_ai-0.2.6.dev4.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
415
- synth_ai-0.2.6.dev4.dist-info/METADATA,sha256=PJ9UXPH-7dMKJ58dA5GVkFxDqFzoIxoAJqG-NNEBx28,3980
416
- synth_ai-0.2.6.dev4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
417
- synth_ai-0.2.6.dev4.dist-info/entry_points.txt,sha256=Neq-3bT7TAijjgOIR77pKL-WYg6TWBDeO8pp_nL4vGY,91
418
- synth_ai-0.2.6.dev4.dist-info/top_level.txt,sha256=fBmtZyVHuKaGa29oHBaaUkrUIWTqSpoVMPiVdCDP3k8,9
419
- synth_ai-0.2.6.dev4.dist-info/RECORD,,
414
+ synth_ai-0.2.6.dev5.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
415
+ synth_ai-0.2.6.dev5.dist-info/METADATA,sha256=zOL3OaxOqOJIBabHtKPJqdEvEoAEYalzrOFHTxHu3N8,3980
416
+ synth_ai-0.2.6.dev5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
417
+ synth_ai-0.2.6.dev5.dist-info/entry_points.txt,sha256=Neq-3bT7TAijjgOIR77pKL-WYg6TWBDeO8pp_nL4vGY,91
418
+ synth_ai-0.2.6.dev5.dist-info/top_level.txt,sha256=fBmtZyVHuKaGa29oHBaaUkrUIWTqSpoVMPiVdCDP3k8,9
419
+ synth_ai-0.2.6.dev5.dist-info/RECORD,,