verifiers 0.3.2.dev107__py3-none-any.whl → 0.3.2.dev109__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.
verifiers/v1/agent.py CHANGED
@@ -540,6 +540,13 @@ class Agent:
540
540
  ) -> dict:
541
541
  """Resolve one run's runtime config, pairing checks, timeouts,
542
542
  interception — shared by `run` and `interaction`."""
543
+ harness = self.harness
544
+ skills = [*task.data.skills, *harness.config.skills]
545
+ if skills:
546
+ # Skill installations can hold run-specific state, such as RLM's package environment.
547
+ harness = type(harness)(
548
+ harness.config.model_copy(update={"skills": skills})
549
+ )
543
550
  if runtime is not None:
544
551
  _check_borrowed_placement(task, runtime, self.runtime_config)
545
552
  runtime_config = runtime.config
@@ -550,7 +557,7 @@ class Agent:
550
557
  )
551
558
  run_is_local = runtime_is_local(runtime_config)
552
559
  validate_pairing(
553
- self.harness,
560
+ harness,
554
561
  type(task),
555
562
  runtime_config,
556
563
  tools=[*task.toolsets(task.config), *shared_tools.values()],
@@ -558,7 +565,7 @@ class Agent:
558
565
  timeouts = resolve_rollout_timeouts(self.timeout, task)
559
566
  return {
560
567
  "agent_config": self.config,
561
- "harness": self.harness,
568
+ "harness": harness,
562
569
  "ctx": self.ctx,
563
570
  "runtime_config": runtime_config,
564
571
  "timeouts": replace(
@@ -14,7 +14,7 @@ class TimeoutConfig(BaseConfig):
14
14
  """Timeout (in seconds) for different phases of an agent's run."""
15
15
 
16
16
  setup: float | None = None # one shared budget: task setup + provisioning
17
- """Timeout (in seconds) for the task + harness setup hooks."""
17
+ """Timeout (in seconds) for task/harness setup through session preparation."""
18
18
  rollout: float | None = None
19
19
  """Timeout (in seconds) for the agent's solve attempt. Unset: the task's own
20
20
  timeout, else 4 hours. `0` disables the timeout."""
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  from pathlib import Path
7
- from typing import Annotated
7
+ from typing import Annotated, Literal
8
8
 
9
9
  from pydantic import ConfigDict, Field, FiniteFloat
10
10
  from pydantic_config import BaseConfig
@@ -15,6 +15,14 @@ PinnedVersion = Annotated[str, Field(pattern=r"^[A-Za-z0-9._+-]+$")]
15
15
  """A release/tag a harness pins its program install to."""
16
16
 
17
17
 
18
+ SkillSource = Path | Annotated[dict[Literal["runtime"], str], Field(min_length=1)]
19
+
20
+
21
+ def skill_destination(skill: SkillSource, dest: str) -> str:
22
+ """Runtime roots merge into `dest`; host folders keep their resolved name."""
23
+ return dest if isinstance(skill, dict) else f"{dest}/{skill.resolve().name}"
24
+
25
+
18
26
  class HarnessConfig(BaseConfig):
19
27
  id: ID = "bash"
20
28
  """Installed harness package, set through the seat's
@@ -44,10 +52,10 @@ class HarnessConfig(BaseConfig):
44
52
  tool_timeout: FiniteFloat = Field(600.0, gt=0)
45
53
  """Seconds a single MCP tool call may take; raise it for tools that boot a VM."""
46
54
  disabled_tools: list[str] | None = None
47
- skills: list[Path] = Field(default_factory=list)
48
- """Skill folders to upload into the program's skill discovery directory — each
49
- lands at `<skills dir>/<folder name>`. Only harnesses whose program discovers
50
- skills natively (`SUPPORTS_SKILLS`) accept them."""
55
+ skills: list[SkillSource] = Field(default_factory=list)
56
+ """Host skill folders or `{runtime: path}` roots of skills inside the runtime.
57
+ Sources are installed in order; later files override matching earlier files.
58
+ Only harnesses with native skill support (`SUPPORTS_SKILLS`) accept them."""
51
59
 
52
60
  @property
53
61
  def name(self) -> str:
verifiers/v1/harness.py CHANGED
@@ -8,7 +8,7 @@ from collections.abc import Mapping
8
8
  from typing import TYPE_CHECKING, ClassVar, Generic, TypeVar
9
9
 
10
10
  from verifiers.v1.clients import ModelContext
11
- from verifiers.v1.configs.harness import HarnessConfig
11
+ from verifiers.v1.configs.harness import HarnessConfig, skill_destination
12
12
  from verifiers.v1.errors import HarnessError, SandboxError, boundary
13
13
  from verifiers.v1.runtimes import ProgramResult, Runtime
14
14
  from verifiers.v1.task import TaskData
@@ -45,8 +45,8 @@ class Harness(ABC, Generic[ConfigT]):
45
45
  where model-directed execution changes the rules: the subprocess-on-host
46
46
  warning, the judge env's sandbox requirement."""
47
47
  SUPPORTS_SKILLS: ClassVar[bool] = False
48
- """Whether the program discovers SKILL.md skills — its `setup` calls
49
- `install_skills` with the program's fixed discovery location; configuring
48
+ """Whether the program discovers SKILL.md skills — it calls
49
+ `install_skills` with a run-scoped discovery location; configuring
50
50
  `skills` on a harness without support is rejected up front."""
51
51
  NEEDS_CONTAINER: ClassVar[bool] = True
52
52
  """Whether the program must run in a container runtime: True for every harness
@@ -97,35 +97,64 @@ class Harness(ABC, Generic[ConfigT]):
97
97
  """Provision this harness in `runtime` before its execution timeout starts."""
98
98
 
99
99
  async def install_skills(self, runtime: Runtime, dest: str) -> None:
100
- """Upload each `config.skills` folder into `runtime` at `dest/<folder name>` —
101
- the program's fixed skill discovery location, which a supporting harness's
102
- `setup` passes."""
103
- uploads = []
104
- executables = []
100
+ """Install `config.skills` in the program's discovery directory.
101
+ Runtime roots are copied in place; host skill folders are uploaded."""
105
102
  for skill in self.config.skills:
103
+ target_dir = skill_destination(skill, dest)
104
+ if isinstance(skill, dict):
105
+ result = await runtime.run(
106
+ [
107
+ "bash",
108
+ "-e",
109
+ "-o",
110
+ "pipefail",
111
+ "-c",
112
+ r"""
113
+ [ -d "$1" ]
114
+ source=$(CDPATH= cd -- "$1/." && pwd -P)
115
+ mkdir -p -- "$2"
116
+ target=$(CDPATH= cd -- "$2/." && pwd -P)
117
+ [ "$source" != "$target" ] || exit 0
118
+ # A source such as "." must not copy the destination back into itself.
119
+ exclude=$(printf '%s' "./${target#"${source%/}/"}" | sed 's/[][\\*?]/\\&/g')
120
+ tar -C "$source" --exclude="$exclude" -cf - . | tar -xpf - -C "$target"
121
+ """,
122
+ "vf-skills",
123
+ skill["runtime"],
124
+ target_dir,
125
+ ],
126
+ {},
127
+ )
128
+ if result.exit_code:
129
+ raise RuntimeError(
130
+ f"installing runtime skills from {skill['runtime']!r} failed: {result.stderr}"
131
+ )
132
+ continue
106
133
  # Resolve so `.`/`..` entries get their real folder name (and can't
107
134
  # place files outside `dest`).
108
135
  skill = skill.resolve()
109
136
  if not skill.is_dir():
110
137
  raise ValueError(f"skill {str(skill)!r} is not a folder")
138
+ uploads = []
139
+ executables = []
111
140
  for file in skill.rglob("*"):
112
141
  if not file.is_file():
113
142
  continue
114
- target = f"{dest}/{skill.name}/{file.relative_to(skill).as_posix()}"
143
+ target = f"{target_dir}/{file.relative_to(skill).as_posix()}"
115
144
  uploads.append((target, file.read_bytes()))
116
145
  if os.access(file, os.X_OK):
117
146
  executables.append(target)
118
- # Settle every upload before returning or surfacing an error.
119
- results = await asyncio.gather(
120
- *(runtime.write(target, data) for target, data in uploads),
121
- return_exceptions=True,
122
- )
123
- for result in results:
124
- if isinstance(result, BaseException):
125
- raise result
126
- if executables:
127
- # `write` moves bytes, not modes; restore the execute bits scripts need.
128
- await runtime.run(["chmod", "+x", *executables], {})
147
+ # Finish this source before the next one overwrites matching files.
148
+ results = await asyncio.gather(
149
+ *(runtime.write(target, data) for target, data in uploads),
150
+ return_exceptions=True,
151
+ )
152
+ for result in results:
153
+ if isinstance(result, BaseException):
154
+ raise result
155
+ if executables:
156
+ # `write` moves bytes, not modes; restore the execute bits scripts need.
157
+ await runtime.run(["chmod", "+x", *executables], {})
129
158
 
130
159
  async def _check_result(
131
160
  self, trace: Trace, runtime: Runtime, result: ProgramResult
@@ -15,7 +15,6 @@ ACP_VERSION = "0.67.0"
15
15
  CLAUDE_BIN = f"{PACKAGES_DIR}/node_modules/.bin/claude"
16
16
  ACP_BIN = f"{PACKAGES_DIR}/node_modules/.bin/claude-agent-acp"
17
17
  CLAUDE_CONFIG_ROOT = ".vf-claude"
18
- SKILLS_DIR = ".claude/skills"
19
18
  ACP_INSTALL = r"""
20
19
  set -e
21
20
  export PATH="/var/tmp/vf-node/bin:$PATH"
@@ -39,7 +38,6 @@ class ClaudeCodeHarness(ACPHarness[ClaudeCodeHarnessConfig]):
39
38
  SUPPORTS_SKILLS = True
40
39
 
41
40
  async def setup(self, runtime: Runtime) -> None:
42
- await self.install_skills(runtime, SKILLS_DIR)
43
41
  await ensure_node(runtime)
44
42
  versions = {"version": self.config.version, "acp_version": ACP_VERSION}
45
43
  directory = CLAUDE_ACP_DIR.format(**versions)
@@ -74,6 +72,7 @@ class ClaudeCodeHarness(ACPHarness[ClaudeCodeHarnessConfig]):
74
72
  ) -> ACPConfig:
75
73
  system_prompt, prompt = self.resolve_prompt(data)
76
74
  config_dir = self.config_dir(trace)
75
+ await self.install_skills(runtime, f"{config_dir}/skills")
77
76
  versions = {"version": self.config.version, "acp_version": ACP_VERSION}
78
77
  session_meta = {
79
78
  "claudeCode": {
@@ -22,7 +22,6 @@ PACKAGES_DIR = f"{CODEX_DIR}/acp"
22
22
  ACP_VERSION = "1.2.0"
23
23
  CODEX_BIN = f"{PACKAGES_DIR}/node_modules/.bin/codex"
24
24
  ACP_BIN = f"{PACKAGES_DIR}/node_modules/.bin/codex-acp"
25
- SKILLS_DIR = ".agents/skills"
26
25
  INSTALL = r"""
27
26
  set -e
28
27
  export PATH="/var/tmp/vf-node/bin:$PATH"
@@ -58,7 +57,6 @@ class CodexHarness(ACPHarness[CodexHarnessConfig]):
58
57
  raise RuntimeError(f"Codex {failure['category']}: {failure['safeMessage']}")
59
58
 
60
59
  async def setup(self, runtime: Runtime) -> None:
61
- await self.install_skills(runtime, SKILLS_DIR)
62
60
  await ensure_node(runtime)
63
61
  logger.info(
64
62
  "codex: ensuring Codex %s and codex-acp %s are installed",
@@ -137,6 +135,7 @@ class CodexHarness(ACPHarness[CodexHarnessConfig]):
137
135
  mcp_urls: dict[str, str],
138
136
  ) -> dict[str, str]:
139
137
  home = self.trace_home(trace)
138
+ await self.install_skills(runtime, f"{home}/skills")
140
139
  mcp_config = "features={mcp_2026_07_28=true}\n" + (
141
140
  "mcp_servers={"
142
141
  + ",".join(
@@ -8,7 +8,7 @@ import tomli_w
8
8
  from verifiers.v1.acp import ACPConfig, ACPHarness
9
9
  from verifiers.v1.clients import ModelContext
10
10
  from verifiers.v1.configs.harness import HarnessConfig, PinnedVersion
11
- from verifiers.v1.harnesses.utils.install import ensure_installed
11
+ from verifiers.v1.harnesses.utils.install import ensure_installed, remove_dir
12
12
  from verifiers.v1.runtimes import Runtime
13
13
  from verifiers.v1.task import TaskData
14
14
  from verifiers.v1.trace import Trace
@@ -18,7 +18,6 @@ logger = logging.getLogger(__name__)
18
18
  BINARY = "/tmp/vf-kimi-code/bin/kimi"
19
19
  KIMI_HOME = ".vf-kimi-code"
20
20
  ACP_COMMAND = [BINARY, "acp"]
21
- SKILLS_DIR = f"{KIMI_HOME}/skills"
22
21
 
23
22
  INSTALL = r"""
24
23
  set -e
@@ -52,7 +51,6 @@ class KimiCodeHarness(ACPHarness[KimiCodeHarnessConfig]):
52
51
  SUPPORTS_SKILLS = True
53
52
 
54
53
  async def setup(self, runtime: Runtime) -> None:
55
- await self.install_skills(runtime, SKILLS_DIR)
56
54
  logger.info(
57
55
  "kimi-code: ensuring Kimi Code %s is installed", self.config.version
58
56
  )
@@ -77,6 +75,8 @@ class KimiCodeHarness(ACPHarness[KimiCodeHarnessConfig]):
77
75
  data: TaskData,
78
76
  ) -> ACPConfig:
79
77
  kimi_home = f"{KIMI_HOME}/{trace.id}"
78
+ skills_dir = f"{kimi_home}/skills"
79
+ await self.install_skills(runtime, skills_dir)
80
80
  provider_type = {
81
81
  "chat_completions": "openai",
82
82
  "responses": "openai_responses",
@@ -88,7 +88,7 @@ class KimiCodeHarness(ACPHarness[KimiCodeHarnessConfig]):
88
88
  else endpoint
89
89
  )
90
90
  config = {
91
- "extra_skill_dirs": [SKILLS_DIR] if self.config.skills else [],
91
+ "extra_skill_dirs": [skills_dir] if self.config.skills else [],
92
92
  **(
93
93
  {
94
94
  "permission": {
@@ -125,3 +125,6 @@ class KimiCodeHarness(ACPHarness[KimiCodeHarnessConfig]):
125
125
  prompt=prompt,
126
126
  system_prompt=system_prompt,
127
127
  )
128
+
129
+ async def cleanup(self, trace: Trace, runtime: Runtime) -> None:
130
+ await remove_dir(runtime, f"{KIMI_HOME}/{trace.id}", "Kimi Code state")
@@ -1,9 +1,7 @@
1
1
  """Run OpenClaw's Gateway-backed ACP agent against interception."""
2
2
 
3
- import asyncio
4
3
  import json
5
4
  import logging
6
- import secrets
7
5
 
8
6
  from verifiers.v1.acp import ACPConfig, ACPHarness
9
7
  from verifiers.v1.clients import ModelContext
@@ -130,22 +128,6 @@ class OpenClawHarness(ACPHarness[OpenClawHarnessConfig]):
130
128
  SUPPORTS_SKILLS = True
131
129
 
132
130
  async def setup(self, runtime: Runtime) -> None:
133
- if not hasattr(self, "_staged_skills_dir"):
134
- self._staged_skills_dir = (
135
- f".vf-openclaw/staged-skills-{secrets.token_hex(8)}"
136
- )
137
- self._skills_setup_lock = asyncio.Lock()
138
- if self.config.skills:
139
- async with self._skills_setup_lock:
140
- # A complete tree is immutable, so concurrent setups can safely reuse it.
141
- ready_path = f"{self._staged_skills_dir}/.ready"
142
- ready = await runtime.run(["test", "-f", ready_path], {})
143
- if ready.exit_code != 0:
144
- await remove_dir(
145
- runtime, self._staged_skills_dir, "OpenClaw skills"
146
- )
147
- await self.install_skills(runtime, self._staged_skills_dir)
148
- await runtime.write(ready_path, b"")
149
131
  directory = OPENCLAW_DIR.format(version=self.config.version)
150
132
  binary = OPENCLAW_BIN.format(version=self.config.version)
151
133
  logger.info("openclaw: ensuring OpenClaw %s is installed", self.config.version)
@@ -233,14 +215,7 @@ class OpenClawHarness(ACPHarness[OpenClawHarnessConfig]):
233
215
  # OpenClaw treats an empty allowlist as all; a no-match key disables the catalog.
234
216
  config.setdefault("skills", {})["allowBundled"] = ["__none__"]
235
217
  await runtime.write(config_path, json.dumps(config).encode())
236
- if self.config.skills:
237
- copied = await runtime.run(
238
- ["cp", "-R", self._staged_skills_dir, skills_dir], {}
239
- )
240
- if copied.exit_code != 0:
241
- raise RuntimeError(
242
- f"failed to isolate OpenClaw skills: {copied.stderr.strip()[-500:]}"
243
- )
218
+ await self.install_skills(runtime, skills_dir)
244
219
 
245
220
  env = {
246
221
  **self.config.resolved_env,
@@ -7,9 +7,9 @@ from typing import Literal
7
7
 
8
8
  from verifiers.v1.acp import ACPConfig, ACPHarness
9
9
  from verifiers.v1.clients import ModelContext
10
- from verifiers.v1.configs.harness import HarnessConfig, PinnedVersion
10
+ from verifiers.v1.configs.harness import HarnessConfig, PinnedVersion, skill_destination
11
11
  from verifiers.v1.harnesses.node import NODE_BIN_DIR, ensure_node
12
- from verifiers.v1.harnesses.utils.install import ensure_installed
12
+ from verifiers.v1.harnesses.utils.install import ensure_installed, remove_dir
13
13
  from verifiers.v1.runtimes import Runtime
14
14
  from verifiers.v1.task import TaskData
15
15
  from verifiers.v1.trace import Trace
@@ -21,7 +21,6 @@ KEY_VAR = "PI_INTERCEPT_KEY"
21
21
  PI_DIR = "/var/tmp/vf-pi"
22
22
  PACKAGES_DIR = f"{PI_DIR}/mcp"
23
23
  PI_BIN = f"{PACKAGES_DIR}/node_modules/.bin/pi"
24
- SKILLS_DIR = ".agents/skills"
25
24
  MCP_VERSION = "2.28.0"
26
25
  ACP_VERSION = "0.0.33"
27
26
  MCP_ADAPTER = f"{PACKAGES_DIR}/node_modules/pi-mcp-adapter/index.ts"
@@ -61,7 +60,6 @@ class PiHarness(ACPHarness[PiHarnessConfig]):
61
60
  SUPPORTS_SKILLS = True
62
61
 
63
62
  async def setup(self, runtime: Runtime) -> None:
64
- await self.install_skills(runtime, SKILLS_DIR)
65
63
  await ensure_node(runtime)
66
64
  logger.info(
67
65
  "pi: ensuring Pi %s and pi-acp %s are installed",
@@ -93,6 +91,8 @@ class PiHarness(ACPHarness[PiHarnessConfig]):
93
91
  ) -> ACPConfig:
94
92
  system_prompt, prompt = self.resolve_prompt(data)
95
93
  agent_dir = f".vf-pi-agent-{trace.id}"
94
+ skills_dir = f"{agent_dir}/skills"
95
+ await self.install_skills(runtime, skills_dir)
96
96
  reasoning = ctx.sampling.reasoning_effort not in (
97
97
  None,
98
98
  "none",
@@ -159,8 +159,7 @@ class PiHarness(ACPHarness[PiHarnessConfig]):
159
159
  skill_args = [
160
160
  arg
161
161
  for skill in self.config.skills
162
- # Resolve like `install_skills` so the path matches what it wrote.
163
- for arg in ("--skill", f"{SKILLS_DIR}/{skill.resolve().name}")
162
+ for arg in ("--skill", skill_destination(skill, skills_dir))
164
163
  ]
165
164
  pi_args = [
166
165
  PI_BIN,
@@ -190,3 +189,6 @@ class PiHarness(ACPHarness[PiHarnessConfig]):
190
189
  # Pi's extension owns the task-scoped MCP configuration.
191
190
  mcp_urls={},
192
191
  )
192
+
193
+ async def cleanup(self, trace: Trace, runtime: Runtime) -> None:
194
+ await remove_dir(runtime, f".vf-pi-agent-{trace.id}", "Pi state")
@@ -7,7 +7,7 @@ from typing import Literal
7
7
 
8
8
  from verifiers.v1.acp import ACPConfig, ACPHarness, ACPTurn
9
9
  from verifiers.v1.clients import ModelContext
10
- from verifiers.v1.configs.harness import HarnessConfig
10
+ from verifiers.v1.configs.harness import HarnessConfig, skill_destination
11
11
  from verifiers.v1.harnesses.node import NODE_BIN_DIR, ensure_node
12
12
  from verifiers.v1.harnesses.utils.install import ensure_installed, remove_dir
13
13
  from verifiers.v1.runtimes import Runtime
@@ -25,7 +25,6 @@ PRIME_AGENT_COMMIT: Literal["81ae3cb34d27d38ee37f9e205a1e73694993b344"] = (
25
25
  PRIME_AGENT_VERSION = "0.9.1"
26
26
  PRIME_AGENT_DIR = "/var/tmp/vf-prime-agent"
27
27
  STATE_ROOT = "/tmp/vf-prime-agent-runs"
28
- SKILLS_DIR = ".agents/skills"
29
28
  PROVIDER = "intercept"
30
29
  LIFECYCLE_META_NAMESPACE = "ai.primeintellect.prime-agent"
31
30
  KEY_VAR = "PRIME_AGENT_INTERCEPT_KEY"
@@ -155,7 +154,6 @@ class PrimeAgentHarness(ACPHarness[PrimeAgentHarnessConfig]):
155
154
  statuses.append(status)
156
155
 
157
156
  async def setup(self, runtime: Runtime) -> None:
158
- await self.install_skills(runtime, SKILLS_DIR)
159
157
  await ensure_node(runtime)
160
158
  logger.info("prime-agent: ensuring commit %s is installed", self.config.commit)
161
159
  await ensure_installed(
@@ -191,6 +189,7 @@ class PrimeAgentHarness(ACPHarness[PrimeAgentHarnessConfig]):
191
189
 
192
190
  root = self._root(trace)
193
191
  agent_dir = f"{root}/agent"
192
+ skills_dir = f"{agent_dir}/skills"
194
193
  created = await runtime.run(
195
194
  [
196
195
  "mkdir",
@@ -207,6 +206,7 @@ class PrimeAgentHarness(ACPHarness[PrimeAgentHarnessConfig]):
207
206
  raise RuntimeError(
208
207
  f"prime-agent state directory failed: {created.stderr.strip()[-500:]}"
209
208
  )
209
+ await self.install_skills(runtime, skills_dir)
210
210
  reasoning = ctx.sampling.reasoning_effort not in (
211
211
  None,
212
212
  "none",
@@ -251,7 +251,7 @@ class PrimeAgentHarness(ACPHarness[PrimeAgentHarnessConfig]):
251
251
  if self.config.autonomous:
252
252
  args.append("--autonomous")
253
253
  for skill in self.config.skills:
254
- args += ["--skill", f"{SKILLS_DIR}/{skill.resolve().name}"]
254
+ args += ["--skill", skill_destination(skill, skills_dir)]
255
255
  if system_prompt:
256
256
  args += ["--append-system-prompt", system_prompt]
257
257
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  import hashlib
4
4
  import logging
5
+ import secrets
5
6
  import shlex
6
7
  from typing import Any, Literal
7
8
 
@@ -18,7 +19,7 @@ from pydantic_config import BaseConfig
18
19
  from verifiers.v1.acp import ACPConfig, ACPHarness, ACPTurn, JsonObject
19
20
  from verifiers.v1.clients import ModelContext
20
21
  from verifiers.v1.configs.harness import HarnessConfig
21
- from verifiers.v1.harnesses.utils.install import ensure_installed
22
+ from verifiers.v1.harnesses.utils.install import ensure_installed, remove_dir
22
23
  from verifiers.v1.runtimes import Runtime
23
24
  from verifiers.v1.task import TaskData
24
25
  from verifiers.v1.trace import Trace
@@ -140,11 +141,15 @@ class RLMHarness(ACPHarness[RLMHarnessConfig]):
140
141
  APPENDS_SYSTEM_PROMPT = True
141
142
  SUPPORTS_MCP = True
142
143
  SUPPORTS_SKILLS = True
144
+ _skills_install_dir: str | None = None
143
145
 
144
146
  async def setup(self, runtime: Runtime) -> None:
145
- # Before the installer: install.sh packages the skills it finds.
146
- await self.install_skills(runtime, SKILLS_DIR)
147
+ if self.config.skills:
148
+ # Editable skill packages and uv's tool environment must belong to this run.
149
+ self._skills_install_dir = f"{RLM_CACHE_DIR}-skills-{secrets.token_hex(16)}"
147
150
  directory = self._install_dir()
151
+ skills_dir = f"{directory}/skills" if self.config.skills else SKILLS_DIR
152
+ await self.install_skills(runtime, skills_dir)
148
153
  binary = f"{directory}/bin/rlm"
149
154
  checkout = f"{directory}/checkout"
150
155
  ready = f"{directory}/.ready"
@@ -155,7 +160,9 @@ class RLMHarness(ACPHarness[RLMHarnessConfig]):
155
160
  "{ apt-get update -qq && apt-get install -y -qq git; } && "
156
161
  f"rm -rf {checkout} && git clone https://{RLM_REPO} {checkout} && "
157
162
  f"git -C {checkout} checkout {shlex.quote(self.config.version)} && "
163
+ f"sed -i 's|/task/rlm-skills|{skills_dir}|g' {checkout}/install.sh && "
158
164
  f"UV_INSTALL_DIR={directory}/bin UV_TOOL_BIN_DIR={directory}/bin "
165
+ f"UV_TOOL_DIR={directory}/tools "
159
166
  f"RLM_CHECKOUT_PATH={checkout} bash {checkout}/install.sh && "
160
167
  f"touch {ready})"
161
168
  )
@@ -279,6 +286,10 @@ class RLMHarness(ACPHarness[RLMHarnessConfig]):
279
286
 
280
287
  async def cleanup(self, trace: Trace, runtime: Runtime) -> None:
281
288
  await runtime.run(["rm", "-rf", f"{RLM_STATE_DIR}/{trace.id}"], {})
289
+ if self._skills_install_dir is not None:
290
+ await remove_dir(
291
+ runtime, self._skills_install_dir, "RLM skill installation"
292
+ )
282
293
 
283
294
  @staticmethod
284
295
  def _home(trace: Trace) -> str:
@@ -286,4 +297,4 @@ class RLMHarness(ACPHarness[RLMHarnessConfig]):
286
297
 
287
298
  def _install_dir(self) -> str:
288
299
  cache_key = hashlib.sha256(self.config.version.encode()).hexdigest()
289
- return f"{RLM_CACHE_DIR}-{cache_key}"
300
+ return self._skills_install_dir or f"{RLM_CACHE_DIR}-{cache_key}"
verifiers/v1/rollout.py CHANGED
@@ -43,7 +43,7 @@ class RolloutTimeouts:
43
43
  """Per-stage rollout timeouts, each bounding one rollout stage."""
44
44
 
45
45
  setup: float | None = None
46
- """Timeout (in seconds) for the task + harness setup hooks."""
46
+ """Timeout (in seconds) for task/harness setup through session preparation."""
47
47
  agent: float | None = None
48
48
  """Timeout (in seconds) for the agent's solve attempt."""
49
49
  finalize: float | None = None
@@ -221,7 +221,7 @@ class Rollout:
221
221
  self.trace.timing.boot.end = now
222
222
  self.trace.timing.setup.start = now
223
223
  self.trace.notify()
224
- # Task setup and harness provisioning share one setup-stage deadline.
224
+ # Setup hooks and harness session preparation share one deadline.
225
225
  setup_deadline = (
226
226
  None
227
227
  if self._timeouts.setup is None
@@ -271,7 +271,10 @@ class Rollout:
271
271
  # Setup and service provisioning are complete. Apply the runtime's
272
272
  # execution policy while preserving the framework routes the agent uses.
273
273
  await runtime.prepare_execution([self._endpoint, *self._urls.values()])
274
- async with boundary(HarnessError, "opening harness session"):
274
+ async with (
275
+ boundary(HarnessError, "opening harness session"),
276
+ asyncio.timeout_at(setup_deadline),
277
+ ):
275
278
  harness_data = self.trace.task.data
276
279
  if (
277
280
  self._session.request_interceptors
@@ -1,10 +1,4 @@
1
- """Remote Prime sandbox runtime.
2
-
3
- `expose` (sandbox port -> public URL) uses the SDK's native exposure (`client.expose`), so a
4
- host-side harness/framework can reach a tool server hosted in the sandbox. The reverse
5
- direction (a program in the sandbox reaching a host service) is the shared host-side
6
- `Tunnel` (interception.tunnel), not the runtime's concern.
7
- """
1
+ """Remote Prime VM sandbox runtime."""
8
2
 
9
3
  import asyncio
10
4
  import base64
@@ -25,7 +19,6 @@ from pydantic import Field, model_validator
25
19
  from verifiers.v1.configs.runtime import NetworkPolicyConfig
26
20
  from verifiers.v1.errors import SandboxError
27
21
  from verifiers.v1.runtimes.base import (
28
- SERVICE_PORT,
29
22
  BaseRuntimeInfo,
30
23
  ProgramResult,
31
24
  Runtime,
@@ -73,15 +66,11 @@ class PrimeConfig(NetworkPolicyConfig):
73
66
  type: Literal["prime"] = "prime"
74
67
  image: str = "python:3.11-slim"
75
68
  """Docker image to run. Any pullable ref works: on the first use of an image, the
76
- platform auto-builds what the sandbox needs from it (a VM image for `vm` sandboxes,
77
- ~10 minutes) and caches the result, so later sandboxes on the same ref start in
69
+ platform auto-builds the VM image that the sandbox needs from it (~10 minutes)
70
+ and caches the result, so later sandboxes on the same ref start in
78
71
  seconds."""
79
72
  workdir: str | None = None
80
73
  """Working directory override; None uses the task's workdir, or /app."""
81
- vm: bool = True
82
- """Run as a micro-VM rather than a container (kernel features / stronger isolation)."""
83
- guaranteed: bool = False
84
- """Request guaranteed (vs best-effort) capacity."""
85
74
  region: str | None = None
86
75
  """Region to provision in (None = provider-chosen)."""
87
76
  labels: list[str] = Field(default_factory=list)
@@ -106,10 +95,6 @@ class PrimeConfig(NetworkPolicyConfig):
106
95
  def _validate_egress(self) -> "PrimeConfig":
107
96
  if not self.network_restricted:
108
97
  return self
109
- if not self.vm:
110
- raise ValueError(
111
- "Prime allow/block egress lists require a VM sandbox (vm=true)"
112
- )
113
98
  if not self.allow:
114
99
  return self
115
100
  validate_egress_lists(
@@ -156,11 +141,7 @@ class PrimeRuntime(Runtime):
156
141
 
157
142
  @property
158
143
  def supports_live_processes(self) -> bool:
159
- return self.config.vm
160
-
161
- @property
162
- def published_port(self) -> int | None:
163
- return SERVICE_PORT
144
+ return True
164
145
 
165
146
  async def start(self) -> None:
166
147
  from prime_sandboxes import AsyncSandboxClient, CreateSandboxRequest
@@ -186,14 +167,7 @@ class PrimeRuntime(Runtime):
186
167
  "memory_gb": self.config.memory,
187
168
  "disk_size_gb": self.config.disk,
188
169
  "gpu_count": gpu_count,
189
- # -1 is prime's convention for no lifetime limit; containers with an
190
- # idle timeout must carry a finite lifetime as a safety fallback (which
191
- # must exceed the idle timeout)
192
- "timeout_minutes": (
193
- -1
194
- if self.config.vm or idle_minutes is None
195
- else max(EFFECTIVELY_UNBOUNDED_SECONDS // 60, idle_minutes + 1)
196
- ),
170
+ "timeout_minutes": -1,
197
171
  "idle_timeout_minutes": idle_minutes,
198
172
  "gpu_type": gpu_type,
199
173
  "region": self.config.region,
@@ -216,8 +190,6 @@ class PrimeRuntime(Runtime):
216
190
  dict.fromkeys([*BASE_LABELS, *self.config.labels])
217
191
  ),
218
192
  docker_image=self.config.image,
219
- vm=self.config.vm,
220
- guaranteed=self.config.guaranteed,
221
193
  environment_vars=self.env,
222
194
  **{k: v for k, v in options.items() if v is not None},
223
195
  )
@@ -323,11 +295,6 @@ class PrimeRuntime(Runtime):
323
295
  async def open_process(
324
296
  self, argv: list[str], env: dict[str, str]
325
297
  ) -> RuntimeProcess:
326
- if not self.config.vm:
327
- raise SandboxError(
328
- "persistent harness sessions on Prime require a VM sandbox; "
329
- "set runtime.prime.vm=true"
330
- )
331
298
  try:
332
299
  process = await self._client.open_process(
333
300
  self.info.id,
@@ -339,22 +306,11 @@ class PrimeRuntime(Runtime):
339
306
  raise SandboxError(f"prime live process failed to start: {e}") from e
340
307
  return PrimeProcess(process)
341
308
 
342
- async def expose(self, port: int) -> str | None:
343
- # Publish a server hosted IN the sandbox via the SDK's native port exposure → a public
344
- # HTTPS URL. Removed when the sandbox is deleted in stop(), so a tool in its own prime
345
- # sandbox needs no host tunnel. Port exposure is region-gated: many regions (incl. the
346
- # backend default, which lands in us-central) 400 it; `us` supports it. TODO: re-enable the
347
- # prime cases in the e2e `skip_if_unexposable` guard once prime exposes ports in any region.
348
- try:
349
- exposed = await self._client.expose(self.info.id, port)
350
- except Exception as e: # surface prime's exposure constraints actionably
351
- raise SandboxError(
352
- "prime port exposure failed — port exposure isn't supported in this sandbox's "
353
- "region; pin `tools.runtime.region` to a region that supports it (e.g. `us`), or "
354
- f"use a colocated / docker / modal tools.runtime instead. ({e})"
355
- ) from e
356
- logger.info("prime: exposed sandbox port %d at %s", port, exposed.url)
357
- return exposed.url.rstrip("/")
309
+ async def expose(self, port: int) -> str:
310
+ raise SandboxError(
311
+ "Prime VM sandboxes do not support port exposure; colocate the service "
312
+ "with its consumer, or use a docker or modal service runtime"
313
+ )
358
314
 
359
315
  async def run_background(
360
316
  self, argv: list[str], env: dict[str, str], log: str
@@ -371,7 +327,7 @@ class PrimeRuntime(Runtime):
371
327
  raise SandboxError(f"prime background launch failed: {e}") from e
372
328
 
373
329
  async def _read(self, path: str, max_bytes: int | None = None) -> bytes:
374
- if max_bytes is not None and self.config.vm:
330
+ if max_bytes is not None:
375
331
  try:
376
332
  # VM execute_command uses bash and returns the complete output stream.
377
333
  result = await self._client.execute_command(
@@ -386,8 +342,6 @@ class PrimeRuntime(Runtime):
386
342
  if result.exit_code:
387
343
  raise SandboxError(f"read {path!r}: {result.stderr.strip()[-500:]}")
388
344
  return base64.b64decode(result.stdout)
389
- if max_bytes is not None:
390
- return await super()._read(path, max_bytes)
391
345
  # Avoid background-job log limits and base64 overhead by downloading binary data directly.
392
346
  # The temporary file is removed on every exit, and its byte read stays off the event loop.
393
347
  target = (
verifiers/v1/task.py CHANGED
@@ -20,6 +20,7 @@ from typing import TYPE_CHECKING, Any, ClassVar, Generic, Self
20
20
  from pydantic import BaseModel, ConfigDict, Field
21
21
  from typing_extensions import TypeVar
22
22
 
23
+ from verifiers.v1.configs.harness import SkillSource
23
24
  from verifiers.v1.configs.task import TaskConfig
24
25
  from verifiers.v1.errors import TaskError, boundary
25
26
  from verifiers.v1.state import StateT
@@ -97,11 +98,13 @@ class TaskData(BaseModel):
97
98
  workdir: str | None = None
98
99
  """Optional working directory to use for the task. Only relevant for tasks that run in a container."""
99
100
 
101
+ skills: list[SkillSource] = Field(default_factory=list)
102
+ """Skill sources installed before the harness's configured skills for this task."""
103
+
100
104
  network_allow: list[str] = Field(default_factory=lambda: ["*"])
101
105
  """Execution-time destinations requested by this task. `*` leaves the runtime
102
106
  allowlist unchanged; a concrete list replaces a wildcard or retains entries also
103
- present in an existing allowlist. Prime runtimes accept host-level entries and
104
- require `vm=true`."""
107
+ present in an existing allowlist. Prime runtimes accept host-level entries."""
105
108
  network_block: list[str] = Field(default_factory=list)
106
109
  """Execution-time destinations denied by this task and combined with runtime
107
110
  blocks. Non-empty concrete allowlists cannot be combined with blocklists. Docker
@@ -37,7 +37,7 @@ class HarborEnv(IsolatedVerifierEnv, vf.Env[HarborEnvConfig]):
37
37
  await agents.agent.run(task)
38
38
  return
39
39
  # Resolve the verifier's box before the solve, so an impossible pairing
40
- # (e.g. a restricted Prime verifier without vm=true) costs nothing
40
+ # (e.g. an invalid network policy) costs nothing
41
41
  # rather than a full agent run.
42
42
  self.verifier_config(task)
43
43
  await agents.agent.run(task.defer_scoring(), collect_artifacts=True)
@@ -393,6 +393,7 @@ def verifier_box_data(data: HarborData) -> HarborData:
393
393
  "upload_environment": data.upload_environment if fresh else False,
394
394
  "env": dict(verifier.env),
395
395
  "healthcheck": verifier.healthcheck,
396
+ "skills": [],
396
397
  "mcp_servers": [],
397
398
  "network_allow": list(verifier.network_allow),
398
399
  "network_block": [],
@@ -612,6 +613,7 @@ def parse_task(task_dir: Path, idx: int, harbor_config: HarborConfig) -> HarborD
612
613
  tags=meta.get("tags", []),
613
614
  task_dir=str(task_dir),
614
615
  upload_environment=upload_environment,
616
+ skills=[{"runtime": environment.skills_dir}] if environment.skills_dir else [],
615
617
  **environment.model_dump(
616
618
  include={"env", "healthcheck", "mcp_servers"}, mode="json"
617
619
  ),
@@ -729,9 +731,7 @@ def parse_verifier_environment(
729
731
  "the task never declared",
730
732
  task_dir.name,
731
733
  )
732
- unsupported = [
733
- field for field in ("skills_dir", "tpu") if getattr(environment, field, None)
734
- ]
734
+ unsupported = [field for field in ("tpu",) if getattr(environment, field, None)]
735
735
  if environment.os != TaskOS.LINUX or unsupported:
736
736
  raise ValueError(
737
737
  f"{task_dir.name}: verifier environment declares "
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: verifiers
3
- Version: 0.3.2.dev107
3
+ Version: 0.3.2.dev109
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
@@ -36,7 +36,7 @@ Requires-Dist: numpy>=2.1.0
36
36
  Requires-Dist: openai<3.0.0,>=2.54.0
37
37
  Requires-Dist: prime-pydantic-config[toml]>=0.4.3
38
38
  Requires-Dist: prime-runs>=0.1.3
39
- Requires-Dist: prime-sandboxes>=0.2.39
39
+ Requires-Dist: prime-sandboxes>=0.3.0
40
40
  Requires-Dist: prime-tunnel>=0.1.8
41
41
  Requires-Dist: pydantic>=2.12.3
42
42
  Requires-Dist: pyzmq>=27.1.0
@@ -1,18 +1,18 @@
1
1
  verifiers/__init__.py,sha256=yDYsckVQbUkwoh9mU_hBeCLGvS_aWgAxuoNm5LxQpDI,517
2
2
  verifiers/cli/commands/init.py,sha256=DaT1NGrK2lnQWvHlrLkZ1D2Te49ll2Eh-DyOAhmCzfU,147
3
3
  verifiers/v1/__init__.py,sha256=zzXyzUkCJCXfPRajYNNQlgIAz6_-uu9oYNb-XsbIjeU,8434
4
- verifiers/v1/agent.py,sha256=rFjoAn9vpRXoyIZTzMgIuGb6HczTSuOenaB-U-x09to,32489
4
+ verifiers/v1/agent.py,sha256=Lc4ySCWBCZRqED-M2LwpPcewAH9k4AuS_ubq-E6-wDQ,32808
5
5
  verifiers/v1/env.py,sha256=Hon7gcepciMYgki_jN4-l4XCcKRZRYuYm7c17nfeiFE,18520
6
6
  verifiers/v1/episode.py,sha256=Fft0R2W6INAVeJhoE9b8h7L_KQSz7XuxP4FT_XhcsUY,5741
7
7
  verifiers/v1/errors.py,sha256=uQySmCUrjDYFkBIii1vBFPiEcPFPQZ9EGpas_6HvcQI,5279
8
8
  verifiers/v1/graph.py,sha256=b3Z3lCnsALnAvY82pDnjhODFYakkeLV_hXgGOvbryrQ,40737
9
- verifiers/v1/harness.py,sha256=sXEjVdrS4A2SO35C_uEebBVeUt8VL7dui7IneAp2MRs,14124
9
+ verifiers/v1/harness.py,sha256=kCJ4lvpZ1LZSCpZZPNaNlPU1kQ1U1YCX9TZ6DVKoTQI,15260
10
10
  verifiers/v1/judge.py,sha256=uqn-djkK2_7Q3kOjkDo6ipOvV_HOvuLa9y6AoDjRux8,9618
11
- verifiers/v1/rollout.py,sha256=0zkVYNUDBag3Bms4uz6TNbim3prx0AwFZiuwkpr2lKI,24308
11
+ verifiers/v1/rollout.py,sha256=oka3sNdv1EbE6LatFFRMJH-5ti6FcqFuD8xa7oVUyDA,24405
12
12
  verifiers/v1/semantic.py,sha256=VQ_buw6Ya6QtRoh_fiYI5Avs5RmIQCfWH0H0bQc4aoc,4704
13
13
  verifiers/v1/session.py,sha256=7iarEDRH2epID_O8ai-1HwveXze_o8shnLw9pFMFX5o,18900
14
14
  verifiers/v1/state.py,sha256=EckF2bWp-vV4b1jYJ9sLI5xrfGuI5spIgYYwW926toI,595
15
- verifiers/v1/task.py,sha256=p3DsvVIzMRPcoEkHJhtqLueJKQ0RCvnn-Tp7ISw6Ox8,12251
15
+ verifiers/v1/task.py,sha256=7iJLXQo7JKX5jG87atIwT_HZlSto_3a7yB3w__uQQQw,12427
16
16
  verifiers/v1/taskset.py,sha256=fp2E0IEhL_Ybj9cegZwljfTmW27p_30zTWHFKw_kXE4,4374
17
17
  verifiers/v1/trace.py,sha256=uOlrvP1-C4TYtcK3S6zcCNK6UlS78hUoL-KGvJL0IsQ,32011
18
18
  verifiers/v1/types.py,sha256=PH1SxRWXOjPCgQD9aZgM18_bECvFSNQ25gkCbulmTKU,9857
@@ -43,10 +43,10 @@ verifiers/v1/clients/client.py,sha256=zqC_AkiD9pl0kxxIbupNiehbS-YnVdp3EMZ0LOHTd8
43
43
  verifiers/v1/clients/eval.py,sha256=cJucyUFsbF1JlG8nF0Tlw2EBMSoAF0YMklgYiOSoNpg,8322
44
44
  verifiers/v1/clients/train.py,sha256=w6bUY6GCBYlscOxz-TBWjbDbFoNSyEfQgDynbB7Ef80,18698
45
45
  verifiers/v1/configs/__init__.py,sha256=X7u6X7B3ieD1HZl79Tv1kg-yPHbT0QLvAebaGqxVtvA,317
46
- verifiers/v1/configs/agent.py,sha256=Aczd-QlNYin6yGjierybBu9wDocjSPZXtKyC0knE5QU,3326
46
+ verifiers/v1/configs/agent.py,sha256=PiWMNueum67vnyLLpIgxXZDb3FTQEUFqo2Z1siOOJqs,3342
47
47
  verifiers/v1/configs/client.py,sha256=fPWtBJv5lPkqttwk0AF2ubfLdzxX2XCO0Zr-A9V4mtk,4440
48
48
  verifiers/v1/configs/env.py,sha256=-Bcdd4MEPfekVc_fnpiwsb9UDwCNdNCKrAHGoQuuXu8,7784
49
- verifiers/v1/configs/harness.py,sha256=OetAXz5ErJPvNxUd2_6iiP0JItCnJl5eS9aH6VoNywE,2569
49
+ verifiers/v1/configs/harness.py,sha256=ZrR-Egzfft95oMoqQ78bAq9TqP882Q68M_47Ajw9lE8,2918
50
50
  verifiers/v1/configs/judge.py,sha256=CBmGgyHXVpcBctvrFD5GlW75wpeFXVFajq_xiMaAVDk,2142
51
51
  verifiers/v1/configs/retries.py,sha256=-nPlgmz7J_NZ4GOYG6oCc3thXo4La2SufBmvQGvvPGo,821
52
52
  verifiers/v1/configs/runtime.py,sha256=IBX3FxiJ2RJaiX2aKghQ15clFHvJpPUXy8GWQOpNhYM,2967
@@ -91,27 +91,27 @@ verifiers/v1/harnesses/browser_use/__init__.py,sha256=yxm2IG5TDLadxZEkX8SL26XWbc
91
91
  verifiers/v1/harnesses/browser_use/harness.py,sha256=sIPRxF-dxiB5xXddCCCOMP6BF1kO01Azyr9AR16x4aw,5582
92
92
  verifiers/v1/harnesses/browser_use/program.py,sha256=5g5AnRS-brYSMmHcteLf8-XDLaTDNIOjG5dym91blOc,10051
93
93
  verifiers/v1/harnesses/claude_code/__init__.py,sha256=JkZQylMSA3o1fvBx_NM41y_umuahmOSqFjTrJ2hryTw,171
94
- verifiers/v1/harnesses/claude_code/harness.py,sha256=Racxbs1EAH3gRwSeUptAIa3kB-EUm_nreUnHMwRUHuE,4119
94
+ verifiers/v1/harnesses/claude_code/harness.py,sha256=pGfyhoxOwjZTQXwM3YwazAxsFVO9uQ3M8eDCPdS9WDk,4101
95
95
  verifiers/v1/harnesses/codex/__init__.py,sha256=ocyBvlpSO8c3pT6D1ebrQohoXYESQcCyPT5kN3j1-N4,132
96
- verifiers/v1/harnesses/codex/harness.py,sha256=S6WLiEpOmeGHbwCYHhQyNkXSVYFbwBbCvPgk2tAuDis,7516
96
+ verifiers/v1/harnesses/codex/harness.py,sha256=UKWQQkV-1Ek5OpjXO8ROPpHj7PZDLxiHqwbOccI-7NE,7492
97
97
  verifiers/v1/harnesses/hermes_agent/__init__.py,sha256=k84Y8UTTf1KOw5LGqPb2dk-hYFagPevDJBOF7qsR_vo,176
98
98
  verifiers/v1/harnesses/hermes_agent/harness.py,sha256=dSsE2VZ8jaM-U14QXO3J7P-U6NMpSuOz3DUMtDWpWk0,3622
99
99
  verifiers/v1/harnesses/hermes_agent/program.py,sha256=RaIYm6NFD8KLXERGXp6rOE4QrQjlcTnm1Fu33xYsiHw,570
100
100
  verifiers/v1/harnesses/kimi_code/__init__.py,sha256=1BEotSfuzmVcE7UrxHeAREM5d7J20cGkonHuowlrzu4,161
101
- verifiers/v1/harnesses/kimi_code/harness.py,sha256=NCkNIdOFDNiUrEmLYb-r-SjyunR5Cmu1g4F1lwuhGK0,4163
101
+ verifiers/v1/harnesses/kimi_code/harness.py,sha256=QIprdVQRSmImUdmGnuCOaIbUtiqtaTHHHj5AH56jltA,4333
102
102
  verifiers/v1/harnesses/mini_swe_agent/__init__.py,sha256=1OBu2Y-XqL72-dGhFdgB6sr5uX_peEEXT9vEjPy1ovU,182
103
103
  verifiers/v1/harnesses/mini_swe_agent/harness.py,sha256=HKGtlDyhXDJqNtDFeb3D4JYUerIgXK6HAmyqOm1mkRo,2473
104
104
  verifiers/v1/harnesses/mini_swe_agent/program.py,sha256=Beej-JLIgSqnqIqB746oKU6kJYcynvppIbmwGa3nJJ0,167
105
105
  verifiers/v1/harnesses/null/__init__.py,sha256=XDeKOPeoXUQi9US9_Z3_yH9YaZ4EiOMKJmUtNNdtD7s,127
106
106
  verifiers/v1/harnesses/null/harness.py,sha256=Bq19j8Bh_d4VvpFx9nwv6BKnG1tKweEk-2BSmaXWLkU,1330
107
107
  verifiers/v1/harnesses/openclaw/__init__.py,sha256=kNyfPB1sGwEf4K3mTfKN0VEyxun3SGvNpvArVKvH-x8,160
108
- verifiers/v1/harnesses/openclaw/harness.py,sha256=tucrQb_Osi7KAEtpyO4i55IXI5SFtLnyItB8eV4kjng,10534
108
+ verifiers/v1/harnesses/openclaw/harness.py,sha256=KUSwzLviNmFc2mIZ7jJ5Abon6EZXsEkHS675f82lG-A,9373
109
109
  verifiers/v1/harnesses/pi/__init__.py,sha256=1mSnzOf-RdEchdeg6IHtcdobG5KIpAhuTdUIgsCIn74,117
110
- verifiers/v1/harnesses/pi/harness.py,sha256=l3iZYXhSm4_dGHuxsfN20phCkTzNWYtTr--aZ0CivK4,6517
110
+ verifiers/v1/harnesses/pi/harness.py,sha256=neTkMp_FKywjUXF7Mi0TJjRHKfjG08vv5yuHRGC3LRQ,6624
111
111
  verifiers/v1/harnesses/prime_agent/__init__.py,sha256=xfPC4RrlnyYWaf38tPAOZq4YL6M55lMpj5BoRLmaK8I,171
112
- verifiers/v1/harnesses/prime_agent/harness.py,sha256=cMvkNdqEutzCoX3lrmCQ5dAi_HSDV3Vhw6K1N-LiBtA,10630
112
+ verifiers/v1/harnesses/prime_agent/harness.py,sha256=sSqVDEVtgLQA5KuqBZ8mrRMyi6EIrPz3r1zXWRiE6-g,10660
113
113
  verifiers/v1/harnesses/rlm/__init__.py,sha256=hwx51xTdEWzzYgMj-p4ETNcptoub3IPMDbEdJ4uB8Ns,122
114
- verifiers/v1/harnesses/rlm/harness.py,sha256=xADdXtDey4w4zs8YR_CP-hR55beHDUXUMkMJD13vSsQ,12609
114
+ verifiers/v1/harnesses/rlm/harness.py,sha256=Fn6lTlKxXno1jV1GrlaE9zhS9CnjC2gLlTvAm5Lrtbo,13223
115
115
  verifiers/v1/harnesses/terminus_2/__init__.py,sha256=l1pwfg1HyVDEqT9efdnFWcXqaZwtKwe7TrplkyxZSA0,166
116
116
  verifiers/v1/harnesses/terminus_2/harness.py,sha256=DMTY1bzvydyjHqzmvBSBGKJsmUzYEgxqd215a7cG7tg,3052
117
117
  verifiers/v1/harnesses/terminus_2/program.py,sha256=X8MZdyItU3gbXGXnGOlJ9LWcUTnqIDaxlhkZvoRiqKY,2703
@@ -145,7 +145,7 @@ verifiers/v1/runtimes/base.py,sha256=IKmrJSJltWX9M1nPUZExKluPJM4N82VsnqQGFz0ECV8
145
145
  verifiers/v1/runtimes/container.py,sha256=puQD8X9acP6GefoCNEnq40POi-nXPD-729bUjTVShfM,9554
146
146
  verifiers/v1/runtimes/limiters.py,sha256=C6cWDD4pwyFwUY4QFke3oiMXwydSNIfSbJSIglUC2kE,3062
147
147
  verifiers/v1/runtimes/modal.py,sha256=rFbxdDBi_VIiDA67XyZg-AOsc_XkV8aQWSKnTUAgCmU,17506
148
- verifiers/v1/runtimes/prime.py,sha256=VWzskEtMEwND6tKKhRtFM5m4Qzt001xCaI4zKqNon80,19490
148
+ verifiers/v1/runtimes/prime.py,sha256=eeYGu60f8PSGtL6g0nJslYzrQLHo6d64JP73N3q3xTw,16982
149
149
  verifiers/v1/runtimes/subprocess.py,sha256=QmpQ235_xrX6gowrr8557VgbydOXpLbfFq0KKGfJThk,8774
150
150
  verifiers/v1/runtimes/docker/__init__.py,sha256=2wceP-8V-w0dQBEeLtoJFfCZ135DxP2rcdcUBmSWiNU,18543
151
151
  verifiers/v1/runtimes/docker/egress.py,sha256=tGwSvHNgV3-uhjshg8sZ4fVRyq8Fg7DbJl_c-lacPi4,23876
@@ -158,8 +158,8 @@ verifiers/v1/serve/server.py,sha256=i6XrY_PMAapkrP54tYX8-K6iGmOmrR7BbQ-3Qhn3w4s,
158
158
  verifiers/v1/serve/types.py,sha256=Qw5IjiJhsZz4giSXUBi9dfInBnQZ5_xiUmgH2qp8jPI,1741
159
159
  verifiers/v1/tasksets/__init__.py,sha256=5hTKSPLXSZTgKBbeKQI7FEp06c0ZsaQfuwvrvVFLgb8,712
160
160
  verifiers/v1/tasksets/harbor/__init__.py,sha256=JxThzHFYEkuSfQbVf3pEnjordgdfe4MU-QOsSSbyovU,326
161
- verifiers/v1/tasksets/harbor/env.py,sha256=rZEh-1IaHpfsrwSOn7qTq7uV0K7cZZ28bHB7BEWQdnc,3622
162
- verifiers/v1/tasksets/harbor/taskset.py,sha256=o7weK05AFjeyxQOFqkSvumx_1iGNe7wViF2zskJrR1I,33693
161
+ verifiers/v1/tasksets/harbor/env.py,sha256=ATMkfwmrE_2jpOOffbjLQ91feG7TOtefBGlpwWbRq8c,3604
162
+ verifiers/v1/tasksets/harbor/taskset.py,sha256=3xCxtVVwQSpaLfoV1SaUoNQlpIGaTmwW6PvPyYh3yv4,33780
163
163
  verifiers/v1/tasksets/harbor/toolset.py,sha256=_7HXu-uuvqzhmJ1EX6c3KWLg0g0eRrLjCq1kBsZhIwo,3159
164
164
  verifiers/v1/tasksets/lean/__init__.py,sha256=oyv-GbJQBvCyGwo7Ysxm2NjZW-aX4j1uDoHU0f-E7xQ,767
165
165
  verifiers/v1/tasksets/lean/scoring.py,sha256=sfzsT6MUK0zdMgAQ57_P_0CBaPHy3M7go71QMr5hDrs,10599
@@ -192,8 +192,8 @@ verifiers/v1/utils/prime.py,sha256=UTYRjp9cbjNb6CVmBHda-1wWZAIIfxNOmTyNuT7_wL4,9
192
192
  verifiers/v1/utils/retries.py,sha256=Y2ZgrAjn-qNkRKZP_RVNL_7EK0iaRcZeCa404lpGYi4,5417
193
193
  verifiers/v1/utils/score.py,sha256=493yJVMw8teCu9JxapxMFPFzI0hNUqdo0Y2nGW4kckk,6200
194
194
  verifiers/v1/utils/version.py,sha256=-obEo_-l9-D8FLef4hYxncOe-uJpxrM1g2Hig_37Sgs,1607
195
- verifiers-0.3.2.dev107.dist-info/METADATA,sha256=8biJ4Q_vmsTiDiaQ__lQE5aS61TV0duA-4L6put9I80,4238
196
- verifiers-0.3.2.dev107.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
197
- verifiers-0.3.2.dev107.dist-info/entry_points.txt,sha256=iugElcdWPKbQM7uFF0lZ8iUpHsNr17-BwEAAjJWxV3U,259
198
- verifiers-0.3.2.dev107.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
199
- verifiers-0.3.2.dev107.dist-info/RECORD,,
195
+ verifiers-0.3.2.dev109.dist-info/METADATA,sha256=Mu8pwqCnU-tLCfuuzeDDJbnG_QIR3ctEOrwuU4lVP8o,4237
196
+ verifiers-0.3.2.dev109.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
197
+ verifiers-0.3.2.dev109.dist-info/entry_points.txt,sha256=iugElcdWPKbQM7uFF0lZ8iUpHsNr17-BwEAAjJWxV3U,259
198
+ verifiers-0.3.2.dev109.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
199
+ verifiers-0.3.2.dev109.dist-info/RECORD,,