verifiers 0.4.1.dev3__py3-none-any.whl → 0.4.1.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.
@@ -147,6 +147,9 @@ class Runtime(ABC):
147
147
  use a host `Tunnel` inward plus `expose` outward."""
148
148
 
149
149
  supports_user: ClassVar[bool] = False
150
+ supports_expose: ClassVar[bool] = True
151
+ """Whether `expose` can publish a port inside this runtime to the outside, so a
152
+ server here is reachable from another runtime."""
150
153
  """Whether `with_user` can run this runtime's commands as another existing user."""
151
154
 
152
155
  scripts_dir: ClassVar[str] = "/tmp/vf-scripts"
@@ -149,6 +149,7 @@ class PrimeProcess(RuntimeProcess):
149
149
 
150
150
  class PrimeRuntime(Runtime):
151
151
  supports_user: ClassVar[bool] = True
152
+ supports_expose: ClassVar[bool] = False
152
153
  is_local: ClassVar[bool] = False
153
154
 
154
155
  def __init__(self, config: PrimeConfig, name: str | None = None) -> None:
@@ -27,11 +27,21 @@ from verifiers.v1.utils.generic import concrete_type, prefix_validation_error
27
27
 
28
28
 
29
29
  def builtin_harness_ids() -> list[str]:
30
- """The harness ids that ship with verifiers (the `verifiers.v1.harnesses`
31
- subpackages)."""
30
+ """The harness ids that ship with verifiers: the `verifiers.v1.harnesses`
31
+ subpackages that export a `Harness`, by their hyphenated id."""
32
32
  from verifiers.v1 import harnesses
33
33
 
34
- return sorted(m.name for m in pkgutil.iter_modules(harnesses.__path__))
34
+ ids = []
35
+ for info in pkgutil.iter_modules(harnesses.__path__):
36
+ if not info.ispkg:
37
+ continue
38
+ module = importlib.import_module(f"{harnesses.__name__}.{info.name}")
39
+ try:
40
+ _plugin_class(module, Harness, "harness")
41
+ except (AttributeError, TypeError):
42
+ continue
43
+ ids.append(info.name.replace("_", "-"))
44
+ return sorted(ids)
35
45
 
36
46
 
37
47
  def narrow_plugin_field(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: verifiers
3
- Version: 0.4.1.dev3
3
+ Version: 0.4.1.dev5
4
4
  Summary: Verifiers: Environments for LLM Reinforcement Learning
5
5
  Project-URL: Homepage, https://github.com/primeintellect-ai/verifiers
6
6
  Project-URL: Documentation, https://github.com/primeintellect-ai/verifiers
@@ -91,6 +91,34 @@ uv tool install prime
91
91
  - The [docs](docs/) contain short, human-written guides and overviews about the architecture.
92
92
  - The [AGENTS.md](AGENTS.md) and [skills](skills/) are for coding agents and go into more details.
93
93
 
94
+ ## Contributing
95
+
96
+ We welcome community contributions. We use [issues](https://github.com/PrimeIntellect-ai/verifiers/issues) to track bugs and feature requests. If you hit a bug, a pain point, or have an idea for a feature, please open an issue.
97
+
98
+ Contributions are welcome via PR. Please follow these guidelines:
99
+
100
+ 1. Install the [pre-commit hooks](#pre-commit-hooks) so your code is formatted and type-checked.
101
+ 2. Keep your PR in "Draft" until it is ready for review.
102
+ 3. If your PR resolves an issue, link the issue in the PR description.
103
+ 4. Run the [tests](#tests) for the areas you touched.
104
+
105
+ ### Pre-commit hooks
106
+
107
+ ```bash
108
+ uv run pre-commit install
109
+ ```
110
+
111
+ ### Tests
112
+
113
+ Unit tests run one component in isolation, with no network, and mirror the `verifiers/v1` layout. Integration tests run real evals: they need `PRIME_API_KEY` and skip without it.
114
+
115
+ ```bash
116
+ uv run pytest tests/unit -n auto # unit
117
+ uv run pytest tests/integration -n 8 # integration
118
+ uv run pytest tests/integration/test_single_turn.py # one behavior
119
+ uv run pytest tests/integration -m "docker and codex" # one runtime and harness
120
+ ```
121
+
94
122
  ## Citation
95
123
 
96
124
  Originally created by Will Brown ([@willccbb](https://github.com/willccbb)).
@@ -20,7 +20,6 @@ verifiers/v1/acp/runner.py,sha256=sFsg0UgWeDjpjihejUidIV2yTapVj1Ap0cDTaEktjkI,15
20
20
  verifiers/v1/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  verifiers/v1/cli/debug.py,sha256=OgzXCW9HaTNruZil4f70WP5tR6toKliKaVvV98C5qzE,11665
22
22
  verifiers/v1/cli/gepa.py,sha256=IyS3YZCCHVydb-OyPeGdtCYsz6OYqXXddXqYq8RLucM,4374
23
- verifiers/v1/cli/init.py,sha256=k1wawdQBquiiepPrb0enBT-vdKvfSievgs4CiwSdFUc,7601
24
23
  verifiers/v1/cli/output.py,sha256=4FRuQ6UIZCigMfUUO2nCFFJKxls3DtWDXswMCVTxjIA,5010
25
24
  verifiers/v1/cli/replay.py,sha256=LkeaV8Sxa7kHue9JKHDg0V_N6KXOcjN_r6RmeQVcxfk,10396
26
25
  verifiers/v1/cli/resolve.py,sha256=Q1EHM7wWQo0YkwJA898qtZbYLaIkjIVq3Q7kUp2YIxs,4346
@@ -57,7 +56,6 @@ verifiers/v1/configs/cli/__init__.py,sha256=YMDUPdbRlDJ77dhj3QqzmyRhqNgUvuQdpj_b
57
56
  verifiers/v1/configs/cli/debug.py,sha256=CcUZ9MEcv0iAL9w2BkTfnZg20yWJ-Vn8P30-e5tuCic,2741
58
57
  verifiers/v1/configs/cli/env.py,sha256=qg2LNOasAU0yg3b0xqXpx3cIj4nHbHSlK3Ldc3NhiT4,2667
59
58
  verifiers/v1/configs/cli/eval.py,sha256=9Zw7mAUipMhoIcwRa_lgo5gII4rMmMEBAgzcPxPWPjw,6895
60
- verifiers/v1/configs/cli/init.py,sha256=JvIUOdhfZfNOXg2wm2i06jLLHpb97tNMzZqmcK_9wVw,916
61
59
  verifiers/v1/configs/cli/replay.py,sha256=vUCNs-9j1CXcAZhGozN1EaztcXK_dYVK3iN_fRmbSXw,2929
62
60
  verifiers/v1/configs/cli/validate.py,sha256=m5ReEfF4-_hOlsvuCtCdeCDywXAfQoKR-NpH6Fzv1u0,3990
63
61
  verifiers/v1/dialects/__init__.py,sha256=MNOYM2NdTlSxGK4VtoEjMtD5zya2MpjPDX5jMvZUWEo,736
@@ -143,12 +141,12 @@ verifiers/v1/mcp/server.py,sha256=Jqi8OMT8DnoZegXqM3UNNRzhVnbdrPEwx0DjOJo_K2A,13
143
141
  verifiers/v1/mcp/toolset.py,sha256=G2wzNdEMGLXoQUcrwF0TartJkqokNPI3o7YUOAaaa6U,1007
144
142
  verifiers/v1/runtimes/__init__.py,sha256=zOG9BYsK19VRNqvggqh3f6g1_UGIq7VjIBcK8kDlmnQ,3515
145
143
  verifiers/v1/runtimes/apptainer.py,sha256=Ru9QJna_l0goIzg71G-4RU_D-7wZUNz139S5TEvbzog,8211
146
- verifiers/v1/runtimes/base.py,sha256=5tRDqGGnYvpy2qDa-V6K5EuwLKjEeI9U4gZV_8TJQZE,19947
144
+ verifiers/v1/runtimes/base.py,sha256=4ma91e_M1KXOAx74dNBVPJoxrqnQaOuvbkSBlHMmujE,20128
147
145
  verifiers/v1/runtimes/container.py,sha256=_hNhGOo1Zvorj7THSj2UrZTkgewySUVJe4Kd777-QnI,12563
148
146
  verifiers/v1/runtimes/e2b.py,sha256=yBeocAutsv2l5x-C5IMqrlgBz6Cb-t6vWbX4qTjlztE,30306
149
147
  verifiers/v1/runtimes/limiters.py,sha256=rOfQJcMdYcLSKq8AL9O09BfGOLqpYmNgrCxXXNcHLmU,2849
150
148
  verifiers/v1/runtimes/modal.py,sha256=ZHA4vtNIZwTV-bnVUlambgc8l34j_ZulvtrwvvkE2Kg,17945
151
- verifiers/v1/runtimes/prime.py,sha256=EzKfjtBIfH8ehjrvOI4khm6BIEZ87r84B5gmgFJQvU4,20836
149
+ verifiers/v1/runtimes/prime.py,sha256=xo9vFn6gNQRhG_8DFPcSyKcTCcZRf4n5UPS7cnbRFm8,20880
152
150
  verifiers/v1/runtimes/subprocess.py,sha256=vnGVAI3J7pYmRei4MQ7MN4nb8SglLi70NtVTINMPVvQ,8855
153
151
  verifiers/v1/runtimes/docker/__init__.py,sha256=QoFOTMgRjoWD--O25Jsft9eD2vjcrMpJQyhfQXqWraI,21828
154
152
  verifiers/v1/runtimes/docker/egress.py,sha256=wtKWTL2_zFidxMR7lDRmfevQlOsl2Iyk88ebdO4Kqqw,24566
@@ -185,7 +183,7 @@ verifiers/v1/utils/generic.py,sha256=isejTTgRoFDJQOM18L3sWqfzBRQyYUkQvk-gNbrYAVc
185
183
  verifiers/v1/utils/git.py,sha256=MTRinOvG4EddfjdahHkFZUihHmhJ37n5ROtgjzjE1NA,8366
186
184
  verifiers/v1/utils/image.py,sha256=OFw_wdwVtbdwa8uJ3X3vYfhpUAi0CTH5HMBupjVsRRQ,282
187
185
  verifiers/v1/utils/interrupt.py,sha256=F-KKhc5ndPJJfhd3SuMqyqhXhA32FhCRy5KWFJpEoM4,1179
188
- verifiers/v1/utils/loaders.py,sha256=2TrgZK3MzKub1GnfaTVIQhlwF6q4qATXZCjicH6nT9c,12299
186
+ verifiers/v1/utils/loaders.py,sha256=WhIHRnAXfFpfCEgH35J1XHd95KRarmg62nxUkUB4HME,12670
189
187
  verifiers/v1/utils/logging.py,sha256=-zgaM-HZsgxumZ4wYNlRMZepp6JanCSjeL2wSVulwJM,2296
190
188
  verifiers/v1/utils/memory.py,sha256=ZkIvGk6uITAH5sKon65LifKPbvZr8mJ__PVc23FZpOQ,1835
191
189
  verifiers/v1/utils/paths.py,sha256=it_4JWf_8bPZe4TRcyvL7_KJ4fsbEsxhhIY_xA8Ikus,308
@@ -196,8 +194,8 @@ verifiers/v1/utils/scope.py,sha256=bzUEiWDOVdbj7dXOwGOlzsQ_-Xu0j9NR5TalQB-8TS8,8
196
194
  verifiers/v1/utils/score.py,sha256=493yJVMw8teCu9JxapxMFPFzI0hNUqdo0Y2nGW4kckk,6200
197
195
  verifiers/v1/utils/trace_store.py,sha256=RsCDonGR-bs-tvEstcppiJm3jFmAdIiG83fA5KtCbAw,2801
198
196
  verifiers/v1/utils/version.py,sha256=-obEo_-l9-D8FLef4hYxncOe-uJpxrM1g2Hig_37Sgs,1607
199
- verifiers-0.4.1.dev3.dist-info/METADATA,sha256=0csv8E7xavXWUlwAD-nPkvlQUl3txcdVBDBDbDpFIBI,4221
200
- verifiers-0.4.1.dev3.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
201
- verifiers-0.4.1.dev3.dist-info/entry_points.txt,sha256=iugElcdWPKbQM7uFF0lZ8iUpHsNr17-BwEAAjJWxV3U,259
202
- verifiers-0.4.1.dev3.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
203
- verifiers-0.4.1.dev3.dist-info/RECORD,,
197
+ verifiers-0.4.1.dev5.dist-info/METADATA,sha256=12xwkEJs-6xoBi01_gAkwto_zrPPL5Ps77wBUJ9UXNA,5361
198
+ verifiers-0.4.1.dev5.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
199
+ verifiers-0.4.1.dev5.dist-info/entry_points.txt,sha256=O1bIO0gyJWuLfWtTGF0h-JkNz6FkyXP7Z9iMFYnjeMI,222
200
+ verifiers-0.4.1.dev5.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
201
+ verifiers-0.4.1.dev5.dist-info/RECORD,,
@@ -2,6 +2,5 @@
2
2
  vf-debug = verifiers.v1.cli.debug:main
3
3
  vf-eval = verifiers.v1.cli.eval.main:main
4
4
  vf-gepa = verifiers.v1.cli.gepa:main
5
- vf-init = verifiers.v1.cli.init:main
6
5
  vf-replay = verifiers.v1.cli.replay:main
7
6
  vf-validate = verifiers.v1.cli.validate:main
verifiers/v1/cli/init.py DELETED
@@ -1,252 +0,0 @@
1
- """Scaffold v1 environment packages."""
2
-
3
- import sys
4
- from pathlib import Path
5
-
6
- from pydantic_config import cli
7
-
8
- from verifiers.v1.configs.cli.init import InitConfig
9
-
10
- USAGE = (
11
- "usage: uv run vf-init <name> [--path ./environments] [-T/--add-tool] "
12
- "[-H/--add-harness]\n"
13
- " scaffold a new environment package"
14
- )
15
-
16
-
17
- def _names(name: str) -> tuple[str, str, str, str]:
18
- dash = name.strip().strip("/").replace("_", "-").lower()
19
- pkg = dash.replace("-", "_")
20
- stem = pkg.removesuffix("_v1")
21
- prefix = "".join(part[:1].upper() + part[1:] for part in stem.split("_") if part)
22
- if not prefix or not prefix[0].isalpha():
23
- prefix = f"Env{prefix}"
24
- return dash, pkg, stem, prefix
25
-
26
-
27
- def _write(path: Path, content: str) -> None:
28
- path.parent.mkdir(parents=True, exist_ok=True)
29
- path.write_text(content)
30
- print(f" write {path}")
31
-
32
-
33
- def _pyproject(dash: str, pkg: str) -> str:
34
- return f"""\
35
- [project]
36
- name = "{dash}"
37
- version = "0.1.0"
38
- description = "{dash} — <one-line description>."
39
- requires-python = ">=3.11"
40
- dependencies = ["verifiers"]
41
-
42
- [build-system]
43
- requires = ["hatchling"]
44
- build-backend = "hatchling.build"
45
-
46
- [tool.hatch.build.targets.wheel]
47
- packages = ["{pkg}"]
48
- """
49
-
50
-
51
- def _init_py(pkg: str, prefix: str, add_harness: bool) -> str:
52
- lines = [f"from {pkg}.taskset import {prefix}Taskset"]
53
- exports = [f"{prefix}Taskset"]
54
- if add_harness:
55
- lines.append(f"from {pkg}.harness import {prefix}Harness")
56
- exports.append(f"{prefix}Harness")
57
- exports_repr = ", ".join(f'"{e}"' for e in exports)
58
- return "\n".join(lines) + f"\n\n__all__ = [{exports_repr}]\n"
59
-
60
-
61
- def _taskset_py(pkg: str, prefix: str, *, add_tool: bool) -> str:
62
- imports = "import verifiers.v1 as vf"
63
- local_imports: list[str] = []
64
- task_config_fields = ""
65
- task_decls = ""
66
- if add_tool:
67
- local_imports.append(f"from {pkg}.servers.tool import {prefix}Toolset")
68
- task_config_fields += "\n tools: vf.ToolsetConfig = vf.ToolsetConfig()"
69
- task_decls += (
70
- "\n\n @classmethod"
71
- f"\n def toolsets(cls, config: {prefix}TaskConfig) -> list[vf.Toolset]:"
72
- f"\n return [{prefix}Toolset(config.tools)]"
73
- "\n"
74
- )
75
- if local_imports:
76
- imports += "\n\n" + "\n".join(local_imports)
77
- task_config = (
78
- f"\n\nclass {prefix}TaskConfig(vf.TaskConfig):\n"
79
- ' """Knobs the task reads from ``self.config``; configure them under '
80
- f'``--env.taskset.task.*``."""{task_config_fields}\n'
81
- if add_tool
82
- else ""
83
- )
84
- task_generic = (
85
- f"{prefix}Data, vf.State, {prefix}TaskConfig" if add_tool else f"{prefix}Data"
86
- )
87
- config_body = ' num_tasks: int = 5\n """How many tasks to build."""\n' + (
88
- f" task: {prefix}TaskConfig = {prefix}TaskConfig()\n" if add_tool else ""
89
- )
90
- return f'''\
91
- {imports}
92
-
93
-
94
- class {prefix}Data(vf.TaskData):
95
- """One row's data. Add task-specific fields here, such as a reference answer."""
96
- {task_config}
97
-
98
- class {prefix}Task(vf.Task[{task_generic}]):
99
- """Rewards, hooks, and servers, with row data available on ``self.data``."""{task_decls}
100
- @vf.reward(weight=1.0)
101
- async def reward(self, trace: vf.Trace) -> float:
102
- raise NotImplementedError("Score the rollout and return a float (e.g. in [0, 1]).")
103
-
104
-
105
- class {prefix}Config(vf.TasksetConfig):
106
- {config_body}
107
-
108
- class {prefix}Taskset(vf.Taskset[{prefix}Task, {prefix}Config]):
109
- def load(self) -> list[{prefix}Task]:
110
- raise NotImplementedError(
111
- "Return this taskset's tasks, e.g. "
112
- "[{prefix}Task({prefix}Data(prompt=...), self.config.task) "
113
- "for i in range(self.config.num_tasks)]."
114
- )
115
- '''
116
-
117
-
118
- def _tool_py(stem: str, prefix: str) -> str:
119
- return f'''\
120
- import verifiers.v1 as vf
121
-
122
-
123
- class {prefix}Toolset(vf.Toolset[vf.ToolsetConfig]):
124
- TOOL_PREFIX = "{stem}"
125
-
126
- @vf.tool
127
- def echo(self, text: str) -> str:
128
- """Return the given text unchanged (replace with a real tool)."""
129
- return text
130
-
131
-
132
- if __name__ == "__main__":
133
- {prefix}Toolset.run()
134
- '''
135
-
136
-
137
- def _harness_py(prefix: str) -> str:
138
- return f'''\
139
- import verifiers.v1 as vf
140
-
141
-
142
- class {prefix}HarnessConfig(vf.HarnessConfig):
143
- """Run knobs for this harness. Add fields here (e.g. a CLI version to install)."""
144
-
145
-
146
- class {prefix}Harness(vf.Harness[{prefix}HarnessConfig]):
147
- APPENDS_SYSTEM_PROMPT = True
148
-
149
- async def launch(
150
- self,
151
- ctx: vf.ModelContext,
152
- trace: vf.Trace,
153
- runtime: vf.Runtime,
154
- endpoint: str,
155
- secret: str,
156
- mcp_urls: dict[str, str],
157
- data: vf.TaskData,
158
- ) -> vf.ProgramResult:
159
- raise NotImplementedError(
160
- "Implement launch: run your agent in `runtime`, pointing its model calls at "
161
- "`endpoint` with bearer token `secret`."
162
- )
163
- '''
164
-
165
-
166
- def _readme(dash: str, pkg: str, *, add_tool: bool, add_harness: bool) -> str:
167
- layout = [
168
- (
169
- f"- `{pkg}/taskset.py` — the task (`@reward` scoring + behavior) and the taskset: "
170
- "`load` (data + prompts)."
171
- )
172
- ]
173
- if add_tool:
174
- layout.append(
175
- f"- `{pkg}/servers/tool.py` — a `vf.Toolset` tool server, constructed in `Task.toolsets`."
176
- )
177
- if add_harness:
178
- layout.append(
179
- f"- `{pkg}/harness.py` — a custom harness, selectable with `--env.agent.harness.id {dash}`."
180
- )
181
- layout_block = "\n".join(layout)
182
- return f"""\
183
- # {dash}
184
-
185
- A v1 verifiers environment, scaffolded with `init`.
186
-
187
- ## Develop
188
-
189
- 1. Implement `load` and the `@reward` in `{pkg}/taskset.py` (see `environments/`).
190
- 2. Install + run:
191
-
192
- ```bash
193
- uv pip install -e . # install this package (or register it in your project)
194
- uv run vf-eval {dash} -n 3 # evaluate a few tasks with the bash harness
195
- ```
196
-
197
- ## Layout
198
-
199
- {layout_block}
200
-
201
- Tune knobs from the CLI: `--env.taskset.num-tasks 10`, `--model <id>`, `-n`, and `-r`.
202
- """
203
-
204
-
205
- def scaffold(config: InitConfig) -> Path:
206
- dash, pkg, stem, prefix = _names(config.name)
207
- env_dir = Path(config.path) / pkg
208
- pkg_dir = env_dir / pkg
209
- if env_dir.exists() and not config.force:
210
- raise SystemExit(
211
- f"error: {env_dir} already exists - refusing to overwrite (pass --force to overwrite)"
212
- )
213
- print(f"scaffolding v1 environment {dash!r} in {env_dir}")
214
-
215
- _write(env_dir / "pyproject.toml", _pyproject(dash, pkg))
216
- _write(
217
- env_dir / "README.md",
218
- _readme(dash, pkg, add_tool=config.add_tool, add_harness=config.add_harness),
219
- )
220
- _write(pkg_dir / "__init__.py", _init_py(pkg, prefix, config.add_harness))
221
- _write(
222
- pkg_dir / "taskset.py",
223
- _taskset_py(pkg, prefix, add_tool=config.add_tool),
224
- )
225
- if config.add_harness:
226
- _write(pkg_dir / "harness.py", _harness_py(prefix))
227
- if config.add_tool:
228
- _write(pkg_dir / "servers" / "__init__.py", "")
229
- _write(pkg_dir / "servers" / "tool.py", _tool_py(stem, prefix))
230
-
231
- print(f"\ndone. next:\n uv pip install -e {env_dir}\n uv run vf-eval {dash} -n 3")
232
- return env_dir
233
-
234
-
235
- def main(argv: list[str] | None = None) -> None:
236
- argv = list(sys.argv[1:]) if argv is None else list(argv)
237
- if argv and not argv[0].startswith(("-", "@")):
238
- argv = ["--name", argv[0], *argv[1:]]
239
-
240
- if not argv or any(arg in ("-h", "--help") for arg in argv):
241
- print(USAGE)
242
- sys.argv = [sys.argv[0], "--help"]
243
- cli(InitConfig)
244
- return
245
-
246
- sys.argv = [sys.argv[0], *argv]
247
- config = cli(InitConfig)
248
- scaffold(config)
249
-
250
-
251
- if __name__ == "__main__":
252
- main()
@@ -1,17 +0,0 @@
1
- """Environment-scaffold CLI configuration."""
2
-
3
- from pydantic import AliasChoices, Field
4
- from pydantic_config import BaseConfig
5
-
6
-
7
- class InitConfig(BaseConfig):
8
- name: str = Field(min_length=1)
9
- """The new environment id, e.g. `my-task-v1` (positional: `init my-task-v1`)."""
10
- path: str = Field("./environments", validation_alias=AliasChoices("path", "p"))
11
- """Parent directory the package is created in (default `./environments`)."""
12
- add_tool: bool = Field(False, validation_alias=AliasChoices("add_tool", "T"))
13
- """Also scaffold a `vf.Toolset` declared on the task (`-T`)."""
14
- add_harness: bool = Field(False, validation_alias=AliasChoices("add_harness", "H"))
15
- """Also scaffold a custom `vf.Harness` (`harness.py`), selectable via `--env.agent.harness.id <name>` (`-H`)."""
16
- force: bool = False
17
- """Overwrite an existing environment package (default: refuse if it already exists)."""