benchmax 0.1.2.dev19__tar.gz → 0.1.2.dev21__tar.gz

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.
Files changed (52) hide show
  1. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/PKG-INFO +1 -1
  2. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/pyproject.toml +1 -1
  3. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/bundle/bundler.py +43 -2
  4. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/bundle/loader.py +14 -0
  5. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/bundle/payload.py +29 -1
  6. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/bundle/validator.py +20 -6
  7. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax.egg-info/PKG-INFO +1 -1
  8. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/LICENSE +0 -0
  9. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/README.md +0 -0
  10. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/setup.cfg +0 -0
  11. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/adapters/__init__.py +0 -0
  12. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/adapters/benchmax_wrapper.py +0 -0
  13. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/adapters/skyrl/benchmax_data_process.py +0 -0
  14. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/adapters/skyrl/skyrl_adapter.py +0 -0
  15. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/bundle/__init__.py +0 -0
  16. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/bundle/errors.py +0 -0
  17. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/__init__.py +0 -0
  18. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/base_env.py +0 -0
  19. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/crm/crm_env.py +0 -0
  20. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/crm/workdir/reward_fn.py +0 -0
  21. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/crm/workdir/salesforce_mcp.py +0 -0
  22. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/excel/data_utils.py +0 -0
  23. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/excel/excel_env.py +0 -0
  24. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/excel/workdir/__init__.py +0 -0
  25. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/excel/workdir/excel_code_runner_mcp.py +0 -0
  26. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/excel/workdir/excel_utils.py +0 -0
  27. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/excel/workdir/reward_fn.py +0 -0
  28. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/math/math_env.py +0 -0
  29. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/math/workdir/reward_fn.py +0 -0
  30. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/__init__.py +0 -0
  31. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/example_workdir/demo_mcp_server.py +0 -0
  32. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/example_workdir/reward_fn.py +0 -0
  33. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/parallel_mcp_env.py +0 -0
  34. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/provisioners/__init__.py +0 -0
  35. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/provisioners/base_provisioner.py +0 -0
  36. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/provisioners/local_provisioner.py +0 -0
  37. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/provisioners/manual_provisioner.py +0 -0
  38. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/provisioners/skypilot_provisioner.py +0 -0
  39. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/provisioners/utils.py +0 -0
  40. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/proxy_server.py +0 -0
  41. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/server_pool.py +0 -0
  42. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/mcp/utils.py +0 -0
  43. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/tracking.py +0 -0
  44. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/types.py +0 -0
  45. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/wikipedia/utils.py +0 -0
  46. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/envs/wikipedia/wiki_env.py +0 -0
  47. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/prompts/__init__.py +0 -0
  48. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax/prompts/tools.py +0 -0
  49. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax.egg-info/SOURCES.txt +0 -0
  50. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax.egg-info/dependency_links.txt +0 -0
  51. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax.egg-info/requires.txt +0 -0
  52. {benchmax-0.1.2.dev19 → benchmax-0.1.2.dev21}/src/benchmax.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: benchmax
3
- Version: 0.1.2.dev19
3
+ Version: 0.1.2.dev21
4
4
  Summary: Framework-Agnostic RL Environments for LLM Fine-Tuning
5
5
  Author: cgft.io
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "benchmax"
3
- version = "0.1.2.dev19"
3
+ version = "0.1.2.dev21"
4
4
  description = "Framework-Agnostic RL Environments for LLM Fine-Tuning"
5
5
  readme = "README.md"
6
6
  authors = [{ name = "cgft.io" }]
@@ -70,9 +70,18 @@ def bundle_env(
70
70
  f"{mod.__name__}"
71
71
  )
72
72
 
73
- # --- Serialize the class ---
73
+ # --- Serialize the class AND constructor_args while modules are registered ---
74
+ pickled_constructor_args: bytes | None = None
74
75
  try:
75
76
  pickled_class = cloudpickle.dumps(env_class)
77
+ # Pickle constructor_args now (while local_modules are registered)
78
+ # so non-JSON-serializable objects get pickled by value.
79
+ if constructor_args is not None:
80
+ try:
81
+ import json
82
+ json.dumps(constructor_args)
83
+ except TypeError:
84
+ pickled_constructor_args = cloudpickle.dumps(constructor_args)
76
85
  except Exception as e:
77
86
  raise BundlingError(
78
87
  f"Failed to serialize {env_class.__name__} with cloudpickle: {e}"
@@ -99,8 +108,13 @@ def bundle_env(
99
108
  python_version=python_version,
100
109
  benchmax_version=benchmax_version,
101
110
  constructor_args=constructor_args,
111
+ constructor_args_pickled=pickled_constructor_args is not None,
112
+ )
113
+ payload = BundledEnv(
114
+ pickled_class=pickled_class,
115
+ metadata=metadata,
116
+ pickled_constructor_args=pickled_constructor_args,
102
117
  )
103
- payload = BundledEnv(pickled_class=pickled_class, metadata=metadata)
104
118
 
105
119
  size_kb = len(pickled_class) / 1024
106
120
  logger.info(
@@ -136,10 +150,37 @@ def write_bundle_files(
136
150
  pickle_path.write_bytes(bundle.pickled_class)
137
151
  metadata_path.write_bytes(bundle.metadata.to_json_bytes())
138
152
 
153
+ # Write pre-pickled constructor_args (pickled during bundling while
154
+ # local_modules were registered, so module code is inline).
155
+ if bundle.pickled_constructor_args is not None:
156
+ args_path = pickle_path.with_suffix(".args.pkl")
157
+ args_path.write_bytes(bundle.pickled_constructor_args)
158
+ logger.info("[bundling] Wrote pickled constructor_args to %s", args_path)
159
+
139
160
 
140
161
  def read_bundle_files(pickle_path: Path, metadata_path: Path) -> BundledEnv:
141
162
  pickle_path = Path(pickle_path)
142
163
  metadata_path = Path(metadata_path)
143
164
  pickled_class = pickle_path.read_bytes()
144
165
  metadata = BundleMetadata.from_json_bytes(metadata_path.read_bytes())
166
+
167
+ # Load pickled constructor_args if they were serialized separately.
168
+ if metadata.constructor_args_pickled:
169
+ args_pickle_path = pickle_path.with_suffix(".args.pkl")
170
+ if args_pickle_path.exists():
171
+ constructor_args = cloudpickle.loads(args_pickle_path.read_bytes())
172
+ metadata = BundleMetadata(
173
+ pip_dependencies=metadata.pip_dependencies,
174
+ python_version=metadata.python_version,
175
+ benchmax_version=metadata.benchmax_version,
176
+ constructor_args=constructor_args,
177
+ format_version=metadata.format_version,
178
+ )
179
+ logger.info("[bundling] Loaded pickled constructor_args from %s", args_pickle_path)
180
+ else:
181
+ logger.warning(
182
+ "[bundling] Metadata indicates pickled constructor_args but %s not found",
183
+ args_pickle_path,
184
+ )
185
+
145
186
  return BundledEnv(pickled_class=pickled_class, metadata=metadata)
@@ -150,6 +150,20 @@ def load_env_from_files(
150
150
  metadata_path = Path(metadata_path)
151
151
  pickled_class = pickle_path.read_bytes()
152
152
  metadata = BundleMetadata.from_json_bytes(metadata_path.read_bytes())
153
+
154
+ # If constructor_args were pickled separately, load them.
155
+ if constructor_args is None and metadata.constructor_args_pickled:
156
+ args_pickle_path = pickle_path.with_suffix(".args.pkl")
157
+ if args_pickle_path.exists():
158
+ import cloudpickle
159
+ constructor_args = cloudpickle.loads(args_pickle_path.read_bytes())
160
+ logger.info("[bundling] Loaded pickled constructor_args from %s", args_pickle_path)
161
+ else:
162
+ logger.warning(
163
+ "[bundling] Metadata indicates pickled constructor_args but %s not found",
164
+ args_pickle_path,
165
+ )
166
+
153
167
  return load_env(
154
168
  pickled_class,
155
169
  metadata,
@@ -13,6 +13,7 @@ class BundleMetadata:
13
13
  python_version: str
14
14
  benchmax_version: str
15
15
  constructor_args: Optional[Dict[str, Any]] = None
16
+ constructor_args_pickled: bool = False
16
17
  format_version: int = FORMAT_VERSION
17
18
 
18
19
  def to_dict(self) -> Dict[str, Any]:
@@ -21,11 +22,36 @@ class BundleMetadata:
21
22
  "python_version": self.python_version,
22
23
  "benchmax_version": self.benchmax_version,
23
24
  "constructor_args": self.constructor_args,
25
+ "constructor_args_pickled": self.constructor_args_pickled,
24
26
  "format_version": self.format_version,
25
27
  }
26
28
 
27
29
  def to_json_bytes(self) -> bytes:
28
- return json.dumps(self.to_dict()).encode("utf-8")
30
+ data = self.to_dict()
31
+ # constructor_args may contain non-JSON-serializable objects
32
+ # (e.g. SearchClient instances). Null them out and set the flag
33
+ # so the loader knows to look for the separate pickled args file.
34
+ if self.has_pickled_constructor_args():
35
+ data["constructor_args"] = None
36
+ data["constructor_args_pickled"] = True
37
+ return json.dumps(data).encode("utf-8")
38
+
39
+ def has_pickled_constructor_args(self) -> bool:
40
+ """True if constructor_args need separate pickle serialization."""
41
+ if self.constructor_args is None:
42
+ return False
43
+ try:
44
+ json.dumps(self.constructor_args)
45
+ return False
46
+ except TypeError:
47
+ return True
48
+
49
+ def pickled_constructor_args_bytes(self) -> bytes | None:
50
+ """Pickle constructor_args if they aren't JSON-serializable."""
51
+ if not self.has_pickled_constructor_args():
52
+ return None
53
+ import cloudpickle
54
+ return cloudpickle.dumps(self.constructor_args)
29
55
 
30
56
  @classmethod
31
57
  def from_dict(cls, data: Dict[str, Any]) -> "BundleMetadata":
@@ -34,6 +60,7 @@ class BundleMetadata:
34
60
  python_version=data.get("python_version", "unknown"),
35
61
  benchmax_version=data.get("benchmax_version", "unknown"),
36
62
  constructor_args=data.get("constructor_args"),
63
+ constructor_args_pickled=bool(data.get("constructor_args_pickled", False)),
37
64
  format_version=int(data.get("format_version", FORMAT_VERSION)),
38
65
  )
39
66
 
@@ -48,3 +75,4 @@ class BundledEnv:
48
75
 
49
76
  pickled_class: bytes
50
77
  metadata: BundleMetadata
78
+ pickled_constructor_args: Optional[bytes] = None
@@ -35,7 +35,8 @@ def validate_bundle(
35
35
  if constructor_args is None:
36
36
  constructor_args = bundle.metadata.constructor_args
37
37
  return _run_isolated_validation(
38
- bundle.pickled_class, bundle.metadata, constructor_args
38
+ bundle.pickled_class, bundle.metadata, constructor_args,
39
+ pickled_constructor_args=bundle.pickled_constructor_args,
39
40
  )
40
41
 
41
42
 
@@ -110,6 +111,7 @@ def _run_isolated_validation(
110
111
  pickled_class: bytes,
111
112
  metadata: BundleMetadata,
112
113
  constructor_args: Optional[Dict[str, Any]],
114
+ pickled_constructor_args: Optional[bytes] = None,
113
115
  ) -> List[str]:
114
116
  """Create a temp venv, install deps, unpickle the bundle, and smoke test.
115
117
 
@@ -192,18 +194,30 @@ def _run_isolated_validation(
192
194
  with open(pickle_path, "wb") as f:
193
195
  f.write(pickled_class)
194
196
 
195
- # 5. Write and run smoke test script using cloudpickle directly
196
- constructor_args_json = json.dumps(constructor_args) if constructor_args else "null"
197
+ # 5. Write constructor args as pickle (handles non-JSON-serializable objects)
198
+ args_pickle_path = os.path.join(venv_dir, "constructor_args.pkl")
199
+ if pickled_constructor_args is not None:
200
+ # Use pre-pickled args (pickled during bundling with modules registered)
201
+ with open(args_pickle_path, "wb") as f:
202
+ f.write(pickled_constructor_args)
203
+ elif constructor_args is not None:
204
+ import cloudpickle as _cp
205
+ with open(args_pickle_path, "wb") as f:
206
+ _cp.dump(constructor_args, f)
207
+
208
+ # 6. Write and run smoke test script using cloudpickle directly
197
209
  smoke_script = textwrap.dedent(f"""\
198
- import json
210
+ import os
199
211
  import asyncio
200
212
  import cloudpickle
201
213
 
202
214
  with open({pickle_path!r}, "rb") as f:
203
215
  env_class = cloudpickle.load(f)
204
216
 
205
- constructor_args = json.loads({constructor_args_json!r})
206
- if constructor_args is not None:
217
+ args_path = {args_pickle_path!r}
218
+ if os.path.exists(args_path):
219
+ with open(args_path, "rb") as f:
220
+ constructor_args = cloudpickle.load(f)
207
221
  instance = env_class(**constructor_args)
208
222
  tools = asyncio.run(instance.list_tools())
209
223
  asyncio.run(instance.shutdown())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: benchmax
3
- Version: 0.1.2.dev19
3
+ Version: 0.1.2.dev21
4
4
  Summary: Framework-Agnostic RL Environments for LLM Fine-Tuning
5
5
  Author: cgft.io
6
6
  Classifier: Programming Language :: Python :: 3
File without changes
File without changes
File without changes