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

synth_ai/cli/task_apps.py CHANGED
@@ -1220,12 +1220,23 @@ def _write_modal_entrypoint(
1220
1220
  except Exception:
1221
1221
  remote_file_str = None
1222
1222
  module_name = entry.config_factory.__module__
1223
+
1224
+ # Prefer a guaranteed mount for the discovered file to avoid package import issues
1225
+ guaranteed_file_str: str | None = None
1226
+ if original_path:
1227
+ guaranteed_file_str = str((Path("/opt/synth_ai_repo/__local_task_app__") / Path(original_path).stem).with_suffix('.py'))
1223
1228
 
1224
1229
  dotenv_paths = [str(Path(path)) for path in (dotenv_paths or [])]
1225
1230
 
1226
1231
  pip_packages = list(modal_cfg.pip_packages)
1227
1232
 
1228
1233
  local_dirs = [(str(Path(src)), dst) for src, dst in modal_cfg.extra_local_dirs]
1234
+ # Ensure the discovered app directory is mounted, regardless of modal_cfg
1235
+ if original_path:
1236
+ discovered_dir = str(Path(original_path).resolve().parent)
1237
+ mount_dst = "/opt/synth_ai_repo/__local_task_app__"
1238
+ if (discovered_dir, mount_dst) not in local_dirs:
1239
+ local_dirs.append((discovered_dir, mount_dst))
1229
1240
  secret_names = list(modal_cfg.secret_names)
1230
1241
  volume_mounts = [(name, mount) for name, mount in modal_cfg.volume_mounts]
1231
1242
 
@@ -1244,7 +1255,7 @@ from synth_ai.task.server import create_task_app
1244
1255
  ENTRY_ID = {entry.app_id!r}
1245
1256
  MODAL_APP_NAME = {modal_name!r}
1246
1257
  MODULE_NAME = {module_name!r}
1247
- MODULE_FILE = {remote_file_str!r}
1258
+ MODULE_FILE = {guaranteed_file_str or remote_file_str!r}
1248
1259
  DOTENV_PATHS = {dotenv_paths!r}
1249
1260
 
1250
1261
  image = Image.debian_slim(python_version={modal_cfg.python_version!r})
@@ -1278,7 +1289,22 @@ if MODULE_FILE:
1278
1289
  else:
1279
1290
  raise RuntimeError("Failed to import task app from file: " + str(MODULE_FILE))
1280
1291
  else:
1281
- importlib.import_module(MODULE_NAME)
1292
+ # Try module import; if that fails, attempt to load from the guaranteed mount
1293
+ try:
1294
+ importlib.import_module(MODULE_NAME)
1295
+ except Exception:
1296
+ import os
1297
+ fallback_file = '/opt/synth_ai_repo/__local_task_app__/' + (MODULE_NAME.split('.')[-1] if MODULE_NAME else 'task_app') + '.py'
1298
+ if os.path.exists(fallback_file):
1299
+ spec = importlib.util.spec_from_file_location(MODULE_NAME or 'task_app_module', fallback_file)
1300
+ if spec and spec.loader:
1301
+ mod = importlib.util.module_from_spec(spec)
1302
+ sys.modules[MODULE_NAME or 'task_app_module'] = mod
1303
+ spec.loader.exec_module(mod)
1304
+ else:
1305
+ raise
1306
+ else:
1307
+ raise
1282
1308
 
1283
1309
  # Get the entry from registry (now that it's registered)
1284
1310
  entry = registry.get(ENTRY_ID)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: synth-ai
3
- Version: 0.2.9.dev4
3
+ Version: 0.2.9.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
@@ -81,7 +81,6 @@ examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py,sha256=pMVwiutZ
81
81
  examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py,sha256=506KV0x0oOajTuNVVWLUxeIXG2YaZjWwfgbVg2EorcA,71477
82
82
  examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py,sha256=PRkQlVKGfn2-w4EOTTHc8T-tqFW6m21mS7BII6TUUd4,5599
83
83
  examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py,sha256=PAYPP0tWU0cQUUxJuAYbDwvWeGjAcPFRHsW2vG3vOpg,5228
84
- examples/warming_up_to_rl/task_app/synth_envs_hosted/test_stepwise_rewards.py,sha256=OfzZ18_bykLll6-4-2-OZI4a2wFx68hnTxufZeFE5t4,1836
85
84
  examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py,sha256=Qcxfa_WASxbUCbAKejiZB6QIl8eJeeIrFPt5GU-Zb6E,2013
86
85
  examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/__init__.py,sha256=5e-BmaXi_5EGcqF2hEGsnbtkHsNvPNMTX9wJ3yiz3XQ,34
87
86
  examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/__init__.py,sha256=nTmSVzOfRUnjxEN1-IHjxuvPHij-AdRu_NZoH6Ozv2M,197
@@ -120,7 +119,7 @@ synth_ai/cli/recent.py,sha256=mHhM-QrR_MfjfKSzBvvPUEC-lkXTWUZrQwqYTmb2x0Y,4173
120
119
  synth_ai/cli/rl_demo.py,sha256=P09_atVrSTfGUhAs0Obe63erniJ3EDHtm51yL2xBouM,8796
121
120
  synth_ai/cli/root.py,sha256=0fuWNO5NeWTSCANzPBfoQsZKe3iUxnJ9hsSWS-SK2UM,11370
122
121
  synth_ai/cli/status.py,sha256=M_bt7U58Ubi-q-ZlrIpgCASKq9_k6uMjpx926f6kLLA,4591
123
- synth_ai/cli/task_apps.py,sha256=bpknAGET9vUP6iRHTJcQcA_r4TCkqsP-QMIXayc7VIo,50723
122
+ synth_ai/cli/task_apps.py,sha256=AQmZtnvNDHMRhvUF0KOvnIF1tRbg0J-nwnJe1T49ajg,52077
124
123
  synth_ai/cli/traces.py,sha256=_QBdCR92u0Gv51U4DH0Ws1d5yCrbJRpaYKe7pmcHrHs,6484
125
124
  synth_ai/cli/watch.py,sha256=HBKbAcpUkkPhGvsPRofckbu8oILiVqp35NXHkIEpTTc,17808
126
125
  synth_ai/compound/cais.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -334,7 +333,6 @@ synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_
334
333
  synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py,sha256=ZCEr6LoSxKvVQzbRGwRBN62RAQPP5jiLoNqI8c4Ij2Q,3808
335
334
  synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py,sha256=99yZCBsbx3i5Wiuf786TiHQjq2tMEY0OKsOEa-obhXY,3763
336
335
  synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py,sha256=VKMXRVmVdIxfa0q_T5Dfll5HHadc5QHpktRQztEIxGs,15455
337
- synth_ai/environments/examples/sokoban/units/astar_common.py,sha256=4vG-_JrGI-yX8HY22CTY9P3DXPqCV_AHMPwH-flr0Z4,3006
338
336
  synth_ai/environments/examples/tictactoe/__init__.py,sha256=XGoOP8GEGXjG-TI_E_-3b1jOhpGNtl_LmR9G3K59Gig,31
339
337
  synth_ai/environments/examples/tictactoe/engine.py,sha256=B2OYQ3TVi_c75BRy_zHIEWjcTSaO4vnZZQJTo6wFe7k,12430
340
338
  synth_ai/environments/examples/tictactoe/environment.py,sha256=p_ZN5-AyYKUnIJ5Df46fXMlJZ6yRerkvXC9GA1W0Ht8,9336
@@ -535,9 +533,9 @@ synth_ai/v0/tracing_v1/events/manage.py,sha256=ZDXXP-ZwLH9LCsmw7Ru9o55d7bl_diPtJ
535
533
  synth_ai/v0/tracing_v1/events/scope.py,sha256=BuBkhSpVHUJt8iGT9HJZF82rbb88mQcd2vM2shg-w2I,2550
536
534
  synth_ai/v0/tracing_v1/events/store.py,sha256=0342lvAcalyJbVEIzQFaPuMQGgwiFm7M5rE6gr-G0E8,9041
537
535
  synth_ai/zyk/__init__.py,sha256=htVLnzTYQ5rxzYpzSYBm7_o6uNKZ3pB_PrqkBrgTRS4,771
538
- synth_ai-0.2.9.dev4.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
539
- synth_ai-0.2.9.dev4.dist-info/METADATA,sha256=BH5A-8mU_wP4Sid2eqWcFQu6cGs198X5_DcmFFKON8o,5200
540
- synth_ai-0.2.9.dev4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
541
- synth_ai-0.2.9.dev4.dist-info/entry_points.txt,sha256=Neq-3bT7TAijjgOIR77pKL-WYg6TWBDeO8pp_nL4vGY,91
542
- synth_ai-0.2.9.dev4.dist-info/top_level.txt,sha256=1moNHgctEUJ3F3eH3V-7FSMb2iTTze1V13dj1R04oUY,18
543
- synth_ai-0.2.9.dev4.dist-info/RECORD,,
536
+ synth_ai-0.2.9.dev5.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
537
+ synth_ai-0.2.9.dev5.dist-info/METADATA,sha256=-GRGwjAZPLUJpTxbLEiu-B_fZtBPodHuem1ySlmqiXk,5200
538
+ synth_ai-0.2.9.dev5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
539
+ synth_ai-0.2.9.dev5.dist-info/entry_points.txt,sha256=Neq-3bT7TAijjgOIR77pKL-WYg6TWBDeO8pp_nL4vGY,91
540
+ synth_ai-0.2.9.dev5.dist-info/top_level.txt,sha256=1moNHgctEUJ3F3eH3V-7FSMb2iTTze1V13dj1R04oUY,18
541
+ synth_ai-0.2.9.dev5.dist-info/RECORD,,
@@ -1,58 +0,0 @@
1
- import math
2
-
3
- from backend.app.routes.clustered_training.dev.synth_envs_hosted.rollout import (
4
- compute_stepwise_reward,
5
- )
6
-
7
-
8
- def test_compute_stepwise_reward_detects_unlock() -> None:
9
- prev = {"build_workbench": False, "pet_cow": False}
10
- new = {"build_workbench": True, "pet_cow": False}
11
- actions = [{"tool": "interact", "args": {"action": "build_workbench"}}]
12
-
13
- info, decision, stats = compute_stepwise_reward(
14
- prev,
15
- new,
16
- decision_index=2,
17
- actions_summary=actions,
18
- indicator_lambda=0.75,
19
- )
20
-
21
- assert info["decision_index"] == 2
22
- assert info["new_achievements"] == ["build_workbench"]
23
- assert info["indicator"] == 1
24
- assert math.isclose(info["reward"], 0.75)
25
-
26
- assert decision["actions"] == actions
27
- assert decision["indicator"] == 1
28
- assert math.isclose(decision["r_i"], 0.75)
29
-
30
- assert math.isclose(stats["indicator"], 1.0)
31
- assert math.isclose(stats["reward"], 0.75)
32
- assert math.isclose(stats["new_achievements_count"], 1.0)
33
-
34
-
35
- def test_compute_stepwise_reward_handles_no_unlock() -> None:
36
- prev = {"collect_wheat": True, "milk_cow": False}
37
- new = {"collect_wheat": True, "milk_cow": False}
38
- actions = [{"tool": "interact", "args": {"action": "sleep"}}]
39
-
40
- info, decision, stats = compute_stepwise_reward(
41
- prev,
42
- new,
43
- decision_index=5,
44
- actions_summary=actions,
45
- indicator_lambda=1.2,
46
- )
47
-
48
- assert info["new_achievements"] == []
49
- assert info["indicator"] == 0
50
- assert math.isclose(info["reward"], 0.0)
51
-
52
- assert decision["actions"] == actions
53
- assert decision["indicator"] == 0
54
- assert math.isclose(decision["r_i"], 0.0)
55
-
56
- assert math.isclose(stats["indicator"], 0.0)
57
- assert math.isclose(stats["reward"], 0.0)
58
- assert math.isclose(stats["new_achievements_count"], 0.0)
@@ -1,95 +0,0 @@
1
- """
2
- astar_common.py – one A* routine usable by both engine-level and
3
- environment-level unit tests.
4
- """
5
-
6
- import heapq
7
- import itertools
8
- import json
9
- from typing import Any, Awaitable, Callable, List, Tuple
10
-
11
- import numpy as np
12
-
13
-
14
- # ---------- generic utilities ------------------------------------ #
15
- def _boxes_left(env_pkg) -> int:
16
- """#targets – #boxes-on-targets (uses raw grids, never the counter)."""
17
- return int(np.sum(env_pkg.room_fixed == 2) - np.sum(env_pkg.room_state == 3))
18
-
19
-
20
- def solved(obj: Any) -> bool:
21
- """Expects obj to have a .package_sokoban_env attribute."""
22
- return _boxes_left(obj.package_sokoban_env) == 0
23
-
24
-
25
- def heuristic(obj: Any) -> int:
26
- """Expects obj to have a .package_sokoban_env attribute."""
27
- return _boxes_left(obj.package_sokoban_env)
28
-
29
-
30
- # ---------- single reusable A* ----------------------------------- #
31
- async def astar(
32
- root_obj: Any,
33
- step_fn: Callable[[Any, int], Awaitable[None]],
34
- deserialize_fn: Callable[[Any], Awaitable[Any]],
35
- max_nodes: int = 1000,
36
- ) -> List[int]:
37
- """
38
- Generic A* over Sokoban snapshots.
39
-
40
- • `root_obj` - current engine *or* environment
41
- • `step_fn(obj, action)` - async: apply one move to *obj*
42
- • `deserialize_fn(snapshot)` - async: new obj from snapshot
43
- """
44
- start_snap = await root_obj._serialize_engine()
45
-
46
- frontier: List[Tuple[int, int, Any, List[int]]] = []
47
- counter = itertools.count()
48
- frontier.append((heuristic(root_obj), next(counter), start_snap, []))
49
- seen: set[str] = set()
50
-
51
- nodes = 0
52
- while frontier and nodes < max_nodes:
53
- f, _, snap, path = heapq.heappop(frontier)
54
- cur = await deserialize_fn(snap)
55
- key = json.dumps(snap.engine_snapshot, sort_keys=True)
56
- if key in seen:
57
- continue
58
- seen.add(key)
59
- if solved(cur):
60
- return path
61
-
62
- nodes += 1
63
- for action in range(cur.package_sokoban_env.action_space.n):
64
- child = await deserialize_fn(snap) # fresh copy
65
- try:
66
- await step_fn(child, action)
67
- except Exception: # illegal/off-board
68
- continue
69
-
70
- child_snap = await child._serialize_engine()
71
- g = len(path) + 1
72
- heapq.heappush(
73
- frontier,
74
- (g + heuristic(child), next(counter), child_snap, path + [action]),
75
- )
76
- return []
77
-
78
-
79
- # convenience lambdas for the two concrete APIs
80
- async def _engine_step(e, a): # `SokobanEngine`
81
- await e._step_engine(a)
82
-
83
-
84
- async def _env_step(env, a): # `SokobanEnvironment` (expects Move wrapper)
85
- from synth_ai.environments.examples.sokoban.units.test_sokoban_environment import Move
86
-
87
- await env.step([[Move(a)]])
88
-
89
-
90
- ENGINE_ASTAR = lambda eng, **kw: astar(eng, _engine_step, eng.__class__._deserialize_engine, **kw)
91
- ENV_ASTAR = lambda env, **kw: astar(
92
- env.engine, _env_step, env.engine.__class__._deserialize_engine, **kw
93
- )
94
-
95
- # ----------------------------------------------------------------- #