dsh-eval-guard 0.7.2 → 0.7.4
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.
- package/ISSUES.md +239 -0
- package/README.md +48 -18
- package/assets/neural-cifar/workspace.zip +0 -0
- package/assets/neural-cpp/workspace.zip +0 -0
- package/assets/neural-fp32/workspace.zip +0 -0
- package/assets/neural-pendulum/SPEC.md +43 -35
- package/assets/neural-pendulum/TASK.md +139 -33
- package/assets/neural-pendulum/rl-feasibility/README.md +60 -0
- package/assets/neural-pendulum/rl-feasibility/RESULTS.md +370 -0
- package/assets/neural-pendulum/rl-feasibility/evaluate.py +107 -0
- package/assets/neural-pendulum/rl-feasibility/finalize_run.py +168 -0
- package/assets/neural-pendulum/rl-feasibility/models.py +124 -0
- package/assets/neural-pendulum/rl-feasibility/obs.py +205 -0
- package/assets/neural-pendulum/rl-feasibility/plot_selected.py +55 -0
- package/assets/neural-pendulum/rl-feasibility/reference_controller.py +112 -0
- package/assets/neural-pendulum/rl-feasibility/results/curves_selected.png +0 -0
- package/assets/neural-pendulum/rl-feasibility/results/reference_controller.json +417 -0
- package/assets/neural-pendulum/rl-feasibility/results/summary.json +1599 -0
- package/assets/neural-pendulum/rl-feasibility/results/table.md +39 -0
- package/assets/neural-pendulum/rl-feasibility/sim.py +324 -0
- package/assets/neural-pendulum/rl-feasibility/summarize.py +175 -0
- package/assets/neural-pendulum/rl-feasibility/task.py +342 -0
- package/assets/neural-pendulum/rl-feasibility/test_contract.py +188 -0
- package/assets/neural-pendulum/rl-feasibility/train_ppo.py +403 -0
- package/assets/neural-pendulum/rl-feasibility/train_sac.py +406 -0
- package/assets/neural-pendulum/sim.cpp +13 -2
- package/assets/neural-pendulum/sim_eval +0 -0
- package/assets/neural-pendulum/workspace.zip +0 -0
- package/eval/README.md +19 -9
- package/eval/bomberman.py +5 -3
- package/eval/commit0.py +10 -3
- package/eval/common.py +169 -5
- package/eval/ctf.py +4 -2
- package/eval/featurebench.py +12 -8
- package/eval/land.py +4 -2
- package/eval/legacy/bomberman.py +5 -2
- package/eval/legacy/ctf.py +5 -2
- package/eval/legacy/featurebench.py +55 -15
- package/eval/legacy/land.py +6 -3
- package/eval/legacy/swe_bench_pro.py +57 -16
- package/eval/legacy/tank.py +2 -2
- package/eval/legacy/warehouse.py +4 -4
- package/eval/neural-cpp.py +9 -6
- package/eval/neural-fp32.py +17 -5
- package/eval/swe-bench-pro.py +11 -7
- package/eval/tank.py +11 -2
- package/eval/warehouse.py +17 -1
- package/lib/client/index.js +56 -29
- package/lib/client/index.js.map +1 -1
- package/lib/index.js +883 -298
- package/native/dsh-eval-supervisor +0 -0
- package/native/supervisor.c +232 -36
- package/neural-cifar-eval/README.md +5 -0
- package/neural-cifar-eval/common.py +13 -0
- package/neural-cifar-eval/ops_eval.py +17 -5
- package/neural-cifar-eval/run_eval.py +42 -32
- package/neural-pendulum-eval/README.md +62 -0
- package/neural-pendulum-eval/ops_eval.py +603 -0
- package/neural-pendulum-eval/run_eval.py +218 -137
- package/neural-pendulum-eval/sim_eval +0 -0
- package/package.json +7 -11
- package/assets/neural-pendulum/hidden/test_infra.cpp +0 -631
- package/assets/neural-pendulum/include/nn/nn.hpp +0 -88
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Standalone evaluator for the Neural-Pendulum task.
|
|
3
3
|
|
|
4
|
-
It
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
the
|
|
4
|
+
It takes the latest host-side submission, builds it once, runs the same
|
|
5
|
+
PyTorch-referenced operator oracle as Neural-FP32 / Neural-CIFAR (every
|
|
6
|
+
operation must be executable and within its error threshold), then drives the
|
|
7
|
+
candidate controller against the fixed-initial-state evaluation simulator and
|
|
8
|
+
computes the task's time-integral score from the host events staged under
|
|
9
|
+
.eval/.
|
|
8
10
|
"""
|
|
9
11
|
from __future__ import annotations
|
|
10
12
|
|
|
13
|
+
import argparse
|
|
11
14
|
import json
|
|
12
15
|
import math
|
|
13
16
|
import os
|
|
@@ -20,30 +23,74 @@ import time
|
|
|
20
23
|
from pathlib import Path
|
|
21
24
|
|
|
22
25
|
HERE = Path(__file__).resolve().parent
|
|
26
|
+
sys.path.insert(0, str(HERE))
|
|
27
|
+
import ops_eval # noqa: E402
|
|
28
|
+
|
|
23
29
|
SIM = HERE / 'sim_eval'
|
|
30
|
+
HOST_EVAL_KEYS = frozenset({
|
|
31
|
+
'EVAL_RESULT_FILE', 'EVAL_JOB_DIR', 'EVAL_INSTALL_TOKEN',
|
|
32
|
+
'EVAL_BASELINE_DIR', 'EVAL_VENV_MANIFEST',
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def child_env() -> dict[str, str]:
|
|
37
|
+
"""Environment for build/simulator/candidate children."""
|
|
38
|
+
return {
|
|
39
|
+
key: value for key, value in os.environ.items()
|
|
40
|
+
if key not in HOST_EVAL_KEYS and key not in {'PYTHONPATH', 'PYTHONHOME'}
|
|
41
|
+
}
|
|
42
|
+
|
|
24
43
|
DT = 0.01
|
|
25
44
|
MAX_STEPS = 3000
|
|
26
45
|
T_TGT = 10.0
|
|
27
46
|
UP_TOL = 0.05
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
# The score changes at the test request instant. This process is started for
|
|
48
|
+
# one request, so module import is the closest available request timestamp.
|
|
49
|
+
TEST_TIME = time.time()
|
|
50
|
+
# Hard budgets so a pathological submission cannot stall the evaluation job.
|
|
51
|
+
OPS_DEADLINE_SECONDS = 240.0
|
|
52
|
+
CONTROL_DEADLINE_SECONDS = 360.0
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class LineReader:
|
|
56
|
+
"""Binary line reader with a per-read deadline.
|
|
57
|
+
|
|
58
|
+
A selector on the raw fd plus an internal buffer avoids the classic bug of
|
|
59
|
+
select() missing lines that a text wrapper already buffered.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, proc: subprocess.Popen) -> None:
|
|
63
|
+
assert proc.stdout is not None
|
|
64
|
+
self._fd = proc.stdout.fileno()
|
|
65
|
+
self._buffer = b''
|
|
66
|
+
self._selector = selectors.DefaultSelector()
|
|
67
|
+
self._selector.register(self._fd, selectors.EVENT_READ)
|
|
68
|
+
|
|
69
|
+
def readline(self, timeout: float) -> str:
|
|
70
|
+
deadline = time.monotonic() + timeout
|
|
71
|
+
while b'\n' not in self._buffer:
|
|
72
|
+
remaining = deadline - time.monotonic()
|
|
73
|
+
if remaining <= 0:
|
|
74
|
+
raise RuntimeError('timeout')
|
|
75
|
+
if not self._selector.select(remaining):
|
|
76
|
+
raise RuntimeError('timeout')
|
|
77
|
+
chunk = os.read(self._fd, 65536)
|
|
78
|
+
if not chunk:
|
|
79
|
+
raise RuntimeError('process closed')
|
|
80
|
+
self._buffer += chunk
|
|
81
|
+
line, self._buffer = self._buffer.split(b'\n', 1)
|
|
82
|
+
return line.decode('utf-8', 'replace').strip()
|
|
83
|
+
|
|
84
|
+
def close(self) -> None:
|
|
85
|
+
try:
|
|
86
|
+
self._selector.close()
|
|
87
|
+
except Exception:
|
|
88
|
+
pass
|
|
42
89
|
|
|
43
90
|
|
|
44
91
|
def write_line(proc: subprocess.Popen, obj: dict) -> None:
|
|
45
92
|
assert proc.stdin is not None
|
|
46
|
-
proc.stdin.write(json.dumps(obj) + '\n')
|
|
93
|
+
proc.stdin.write((json.dumps(obj) + '\n').encode('utf-8'))
|
|
47
94
|
proc.stdin.flush()
|
|
48
95
|
|
|
49
96
|
|
|
@@ -87,7 +134,7 @@ def score_for(event: dict) -> float:
|
|
|
87
134
|
|
|
88
135
|
|
|
89
136
|
def final_score(workspace: Path, events: list[dict], now: float | None = None) -> tuple[float, float | None]:
|
|
90
|
-
"""Return (integral, T_done); negative score is penalized over time."""
|
|
137
|
+
"""Return (integral, T_done); a negative score is penalized over time."""
|
|
91
138
|
now = time.time() if now is None else now
|
|
92
139
|
start = task_start(workspace, events)
|
|
93
140
|
tests = [e for e in events if (e.get('event') or e.get('type')) == 'test']
|
|
@@ -112,25 +159,6 @@ def final_score(workspace: Path, events: list[dict], now: float | None = None) -
|
|
|
112
159
|
return total, done_at
|
|
113
160
|
|
|
114
161
|
|
|
115
|
-
def archive_submissions(workspace: Path) -> int:
|
|
116
|
-
root = os.environ.get('EVAL_SUBMISSIONS_ROOT', '')
|
|
117
|
-
src_root = workspace / '.eval' / 'submissions'
|
|
118
|
-
if not root or not src_root.is_dir():
|
|
119
|
-
return 0
|
|
120
|
-
target = Path(root)
|
|
121
|
-
target.mkdir(parents=True, exist_ok=True)
|
|
122
|
-
count = 0
|
|
123
|
-
for source in src_root.iterdir():
|
|
124
|
-
if not source.is_dir():
|
|
125
|
-
continue
|
|
126
|
-
destination = target / source.name
|
|
127
|
-
if destination.exists():
|
|
128
|
-
continue
|
|
129
|
-
shutil.copytree(source, destination, symlinks=True)
|
|
130
|
-
count += 1
|
|
131
|
-
return count
|
|
132
|
-
|
|
133
|
-
|
|
134
162
|
def latest_submission(workspace: Path) -> Path | None:
|
|
135
163
|
root = workspace / '.eval' / 'submissions'
|
|
136
164
|
if not root.is_dir():
|
|
@@ -141,106 +169,151 @@ def latest_submission(workspace: Path) -> Path | None:
|
|
|
141
169
|
return max(dirs, key=lambda p: p.stat().st_mtime)
|
|
142
170
|
|
|
143
171
|
|
|
144
|
-
def
|
|
145
|
-
|
|
146
|
-
if
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
172
|
+
def submission_count(workspace: Path) -> int:
|
|
173
|
+
root = workspace / '.eval' / 'submissions'
|
|
174
|
+
return len(list(root.glob('*'))) if root.is_dir() else 0
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def emit(result: dict) -> int:
|
|
178
|
+
target = os.environ.get('EVAL_RESULT_FILE')
|
|
179
|
+
text = json.dumps(result, ensure_ascii=False, indent=2)
|
|
180
|
+
if target:
|
|
181
|
+
Path(target).write_text(text, encoding='utf-8')
|
|
182
|
+
else:
|
|
183
|
+
print(text)
|
|
184
|
+
return 0
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def final_score_with_current(workspace: Path, events: list[dict], stage: str,
|
|
188
|
+
t_can: float, success: bool) -> tuple[float, float | None]:
|
|
189
|
+
"""Score including the test this process is performing at TEST_TIME."""
|
|
190
|
+
current = {
|
|
191
|
+
'event': 'test', 'time': TEST_TIME, 'stage': stage,
|
|
192
|
+
't_can': float(t_can), 'completed': bool(success),
|
|
193
|
+
}
|
|
194
|
+
return final_score(workspace, [*events, current])
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def build_result(stage: str, workspace: Path, events: list[dict], error: str = '',
|
|
198
|
+
ops: dict | None = None, source: str = '', t_can: float = 0.0,
|
|
199
|
+
success: bool = False) -> dict:
|
|
200
|
+
integral, done_at = final_score_with_current(workspace, events, stage, t_can, success)
|
|
201
|
+
result = {
|
|
202
|
+
'task': 'neural-pendulum',
|
|
203
|
+
'ok': True,
|
|
204
|
+
'stage': stage,
|
|
205
|
+
'infra_ok': False,
|
|
206
|
+
't_can': float(t_can),
|
|
207
|
+
'success': bool(success),
|
|
208
|
+
'error': error,
|
|
209
|
+
'final_score': integral,
|
|
210
|
+
'done_at': done_at,
|
|
211
|
+
'submissions': submission_count(workspace),
|
|
212
|
+
'source': source,
|
|
213
|
+
}
|
|
214
|
+
if ops is not None:
|
|
215
|
+
result.update({
|
|
216
|
+
'all_operations_executable': ops.get('all_operations_executable'),
|
|
217
|
+
'all_operations_passed': ops.get('all_operations_passed'),
|
|
218
|
+
'max_weighted_mean_relative_error': ops.get('max_weighted_mean_relative_error'),
|
|
219
|
+
'speed_geomean': ops.get('speed_geomean'),
|
|
220
|
+
'operations': ops.get('operations', []),
|
|
221
|
+
})
|
|
151
222
|
return result
|
|
152
223
|
|
|
153
224
|
|
|
225
|
+
def fail(message: str, stage: str, workspace: Path, events: list[dict],
|
|
226
|
+
ops: dict | None = None) -> dict:
|
|
227
|
+
return build_result(stage, workspace, events, error=message, ops=ops)
|
|
228
|
+
|
|
229
|
+
|
|
154
230
|
def main() -> int:
|
|
155
|
-
|
|
156
|
-
parser = argparse.ArgumentParser()
|
|
231
|
+
parser = argparse.ArgumentParser(description='Neural-Pendulum evaluator')
|
|
157
232
|
parser.add_argument('--workspace', required=True)
|
|
158
233
|
args = parser.parse_args()
|
|
159
|
-
|
|
160
234
|
workspace = Path(args.workspace).resolve()
|
|
161
235
|
events = read_events(workspace)
|
|
162
236
|
root = Path(tempfile.mkdtemp(prefix='neural-pendulum-eval-'))
|
|
163
|
-
candidate = root / 'candidate'
|
|
164
|
-
result = {'infra_ok': False, 't_can': 0.0, 'success': False, 'error': ''}
|
|
165
237
|
sim = None
|
|
166
238
|
control = None
|
|
239
|
+
sim_reader = None
|
|
240
|
+
control_reader = None
|
|
167
241
|
try:
|
|
168
|
-
archived = archive_submissions(workspace)
|
|
169
242
|
selected = latest_submission(workspace)
|
|
170
243
|
if selected is None:
|
|
171
|
-
return emit(fail('no submission', workspace
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
)
|
|
187
|
-
if cfg.returncode != 0:
|
|
188
|
-
return emit(fail('cmake configure failed\n' + (cfg.stdout + cfg.stderr)[-4000:], workspace=workspace))
|
|
189
|
-
made = subprocess.run(
|
|
190
|
-
['cmake', '--build', 'build', '-j4'],
|
|
191
|
-
cwd=str(candidate), capture_output=True, text=True, env=env, timeout=1800,
|
|
192
|
-
)
|
|
193
|
-
if made.returncode != 0:
|
|
194
|
-
return emit(fail('build failed\n' + (made.stdout + made.stderr)[-4000:], workspace=workspace))
|
|
195
|
-
|
|
196
|
-
lib = candidate / 'build' / 'libnn.a'
|
|
197
|
-
if not lib.is_file():
|
|
198
|
-
return emit(fail('build/libnn.a missing', workspace=workspace))
|
|
199
|
-
hidden = HERE.parent / 'assets' / 'neural-pendulum' / 'hidden' / 'test_infra.cpp'
|
|
200
|
-
if not hidden.is_file():
|
|
201
|
-
return emit(fail('hidden infrastructure test missing', workspace=workspace))
|
|
202
|
-
infra_exe = root / 'test_infra'
|
|
203
|
-
compiler = shutil.which('g++')
|
|
204
|
-
if compiler is None:
|
|
205
|
-
return emit(fail('g++ missing', workspace=workspace))
|
|
206
|
-
ic = subprocess.run([compiler, '-std=c++17', '-O3', '-pthread',
|
|
207
|
-
'-I', str(candidate / 'include'), str(hidden), str(lib),
|
|
208
|
-
'-lm', '-o', str(infra_exe)], cwd=str(root), capture_output=True,
|
|
209
|
-
text=True, env=env, timeout=300)
|
|
210
|
-
if ic.returncode != 0:
|
|
211
|
-
return emit(fail('hidden infrastructure test compile failed\n' + (ic.stdout + ic.stderr)[-4000:], workspace=workspace))
|
|
212
|
-
it = subprocess.run([str(infra_exe)], cwd=str(root), capture_output=True,
|
|
213
|
-
text=True, env=env, timeout=600)
|
|
214
|
-
if it.returncode != 0:
|
|
215
|
-
return emit(fail('hidden infrastructure test failed\n' + (it.stdout + it.stderr)[-4000:], workspace=workspace))
|
|
216
|
-
|
|
217
|
-
control_path = candidate / 'build' / 'control'
|
|
218
|
-
if not control_path.is_file():
|
|
219
|
-
return emit(fail('build/control missing', infra_ok=True, workspace=workspace))
|
|
244
|
+
return emit(fail('no submission', 'no_submission', workspace, events))
|
|
245
|
+
source_name = str(selected.relative_to(workspace))
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
source = ops_eval.prepare_source(selected, root)
|
|
249
|
+
build = ops_eval.build_binaries(source)
|
|
250
|
+
except Exception as exc:
|
|
251
|
+
return emit(fail(str(exc), 'compile', workspace, events))
|
|
252
|
+
|
|
253
|
+
ops_binary = build / 'nn_task'
|
|
254
|
+
control_path = build / 'control'
|
|
255
|
+
missing = [name for name, path in (('build/nn_task', ops_binary), ('build/control', control_path))
|
|
256
|
+
if not path.is_file()]
|
|
257
|
+
if missing:
|
|
258
|
+
return emit(fail('build output missing: ' + ', '.join(missing), 'compile', workspace, events))
|
|
220
259
|
|
|
260
|
+
try:
|
|
261
|
+
ops = ops_eval.evaluate_ops(ops_binary, root, deadline=time.monotonic() + OPS_DEADLINE_SECONDS)
|
|
262
|
+
except Exception as exc:
|
|
263
|
+
return emit(fail('operator evaluation failed: ' + str(exc), 'infra', workspace, events))
|
|
264
|
+
ops_eval.print_summary(ops)
|
|
265
|
+
if not ops['all_operations_passed']:
|
|
266
|
+
return emit(fail(ops_eval.infrastructure_error(ops), 'infra', workspace, events, ops=ops))
|
|
267
|
+
|
|
268
|
+
env = child_env()
|
|
221
269
|
sim = subprocess.Popen([str(SIM), '--eval'], stdin=subprocess.PIPE,
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
270
|
+
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=env)
|
|
271
|
+
control = subprocess.Popen([str(control_path)], cwd=str(source),
|
|
272
|
+
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
|
273
|
+
stderr=subprocess.DEVNULL, env=env)
|
|
274
|
+
sim_reader = LineReader(sim)
|
|
275
|
+
control_reader = LineReader(control)
|
|
227
276
|
|
|
228
277
|
write_line(sim, {'cmd': 'reset'})
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return emit(fail('
|
|
278
|
+
try:
|
|
279
|
+
reply = json.loads(sim_reader.readline(10.0))
|
|
280
|
+
obs = reply['obs']
|
|
281
|
+
except Exception as exc:
|
|
282
|
+
return emit(fail('simulator reset failed: ' + str(exc), 'simulation', workspace, events, ops=ops))
|
|
283
|
+
try:
|
|
284
|
+
write_line(control, {'type': 'reset'})
|
|
285
|
+
ready = json.loads(control_reader.readline(10.0))
|
|
286
|
+
except Exception as exc:
|
|
287
|
+
return emit(fail('controller reset failed: ' + str(exc), 'controller', workspace, events, ops=ops))
|
|
288
|
+
if not isinstance(ready, dict) or ready.get('type') != 'ready':
|
|
289
|
+
return emit(fail('controller did not reply ready', 'controller', workspace, events, ops=ops))
|
|
234
290
|
|
|
235
291
|
t_can = 0.0
|
|
236
292
|
up_start = None
|
|
237
293
|
completed = False
|
|
238
294
|
error = ''
|
|
295
|
+
stage = 'scoring'
|
|
296
|
+
control_deadline = time.monotonic() + CONTROL_DEADLINE_SECONDS
|
|
239
297
|
for step in range(MAX_STEPS):
|
|
298
|
+
if time.monotonic() > control_deadline:
|
|
299
|
+
error = 'control evaluation deadline exceeded'
|
|
300
|
+
stage = 'simulation'
|
|
301
|
+
break
|
|
240
302
|
if not isinstance(obs, list) or len(obs) != 3:
|
|
241
303
|
error = 'simulator returned bad observation'
|
|
304
|
+
stage = 'simulation'
|
|
305
|
+
break
|
|
306
|
+
try:
|
|
307
|
+
angles = [float(x) for x in obs]
|
|
308
|
+
except Exception:
|
|
309
|
+
error = 'simulator returned non-numeric observation'
|
|
310
|
+
stage = 'simulation'
|
|
242
311
|
break
|
|
243
|
-
if
|
|
312
|
+
if not all(math.isfinite(x) for x in angles):
|
|
313
|
+
error = 'simulator returned non-finite observation'
|
|
314
|
+
stage = 'simulation'
|
|
315
|
+
break
|
|
316
|
+
if max(abs(x) for x in angles) <= UP_TOL:
|
|
244
317
|
if up_start is None:
|
|
245
318
|
up_start = step * DT
|
|
246
319
|
t_can = max(t_can, step * DT - up_start)
|
|
@@ -248,33 +321,51 @@ def main() -> int:
|
|
|
248
321
|
up_start = None
|
|
249
322
|
if t_can >= T_TGT:
|
|
250
323
|
completed = True
|
|
324
|
+
stage = 'completed'
|
|
251
325
|
break
|
|
252
326
|
|
|
253
|
-
write_line(control, {'type': 'step', 'step': step, 'state':
|
|
254
|
-
|
|
255
|
-
|
|
327
|
+
write_line(control, {'type': 'step', 'step': step, 'state': angles})
|
|
328
|
+
try:
|
|
329
|
+
action = json.loads(control_reader.readline(0.1))
|
|
330
|
+
except Exception as exc:
|
|
331
|
+
error = 'controller did not reply in time: ' + str(exc)
|
|
332
|
+
stage = 'controller'
|
|
333
|
+
break
|
|
334
|
+
torque = action.get('torque') if isinstance(action, dict) else None
|
|
256
335
|
if (not isinstance(torque, list) or len(torque) != 2
|
|
257
|
-
or not all(isinstance(v, (int, float)) and
|
|
336
|
+
or not all(isinstance(v, (int, float)) and not isinstance(v, bool)
|
|
337
|
+
and math.isfinite(v) for v in torque)
|
|
258
338
|
or any(abs(float(v)) > 1.0 for v in torque)):
|
|
259
339
|
error = 'controller returned invalid torque'
|
|
340
|
+
stage = 'controller'
|
|
341
|
+
break
|
|
342
|
+
write_line(sim, {'cmd': 'step', 'torque': [float(torque[0]), float(torque[1])]})
|
|
343
|
+
try:
|
|
344
|
+
reply = json.loads(sim_reader.readline(10.0))
|
|
345
|
+
except Exception as exc:
|
|
346
|
+
error = 'simulator did not reply: ' + str(exc)
|
|
347
|
+
stage = 'simulation'
|
|
348
|
+
break
|
|
349
|
+
if not isinstance(reply, dict):
|
|
350
|
+
error = 'simulator returned bad reply'
|
|
351
|
+
stage = 'simulation'
|
|
260
352
|
break
|
|
261
|
-
write_line(sim, {'cmd': 'step', 'torque': torque})
|
|
262
|
-
reply = json.loads(read_line(sim, 10.0))
|
|
263
353
|
if 'error' in reply:
|
|
354
|
+
error = 'simulator error: ' + str(reply['error'])
|
|
355
|
+
stage = 'simulation'
|
|
264
356
|
break
|
|
265
|
-
obs = reply
|
|
357
|
+
obs = reply.get('obs')
|
|
266
358
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
'final_score': integral, 'done_at': done_at,
|
|
271
|
-
'submissions': len(list((workspace / '.eval' / 'submissions').glob('*'))) if (workspace / '.eval' / 'submissions').is_dir() else 0,
|
|
272
|
-
'archived_submissions': archived,
|
|
273
|
-
'source': str(selected.relative_to(workspace)) if selected is not None else 'live-workspace'}
|
|
359
|
+
result = build_result(stage, workspace, events, error=error, ops=ops, source=source_name,
|
|
360
|
+
t_can=t_can, success=completed)
|
|
361
|
+
result['infra_ok'] = True
|
|
274
362
|
return emit(result)
|
|
275
363
|
except Exception as exc:
|
|
276
|
-
return emit(fail(str(exc), workspace
|
|
364
|
+
return emit(fail(str(exc), 'simulation', workspace, events))
|
|
277
365
|
finally:
|
|
366
|
+
for reader in (control_reader, sim_reader):
|
|
367
|
+
if reader is not None:
|
|
368
|
+
reader.close()
|
|
278
369
|
for proc in (control, sim):
|
|
279
370
|
if proc is not None:
|
|
280
371
|
try:
|
|
@@ -288,15 +379,5 @@ def main() -> int:
|
|
|
288
379
|
shutil.rmtree(root, ignore_errors=True)
|
|
289
380
|
|
|
290
381
|
|
|
291
|
-
def emit(result: dict) -> int:
|
|
292
|
-
target = os.environ.get('EVAL_RESULT_FILE')
|
|
293
|
-
text = json.dumps(result, ensure_ascii=False, indent=2)
|
|
294
|
-
if target:
|
|
295
|
-
Path(target).write_text(text, encoding='utf-8')
|
|
296
|
-
else:
|
|
297
|
-
print(text)
|
|
298
|
-
return 0
|
|
299
|
-
|
|
300
|
-
|
|
301
382
|
if __name__ == '__main__':
|
|
302
383
|
raise SystemExit(main())
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-eval-guard",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Evaluation guard for DSH: workspace-only filesystem, no network/subagents, wall-clock limits, and task installation for
|
|
5
|
+
"description": "Evaluation guard for DSH: workspace-only filesystem, no network/subagents, wall-clock limits, and task installation for meow-ai-arena and benchmark tasks.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "huhu23333",
|
|
@@ -28,14 +28,8 @@
|
|
|
28
28
|
],
|
|
29
29
|
"main": "lib/index.js",
|
|
30
30
|
"exports": {
|
|
31
|
-
".":
|
|
32
|
-
|
|
33
|
-
"default": "./lib/index.js"
|
|
34
|
-
},
|
|
35
|
-
"./client": {
|
|
36
|
-
"types": "./lib/client/index.d.ts",
|
|
37
|
-
"default": "./lib/client/index.js"
|
|
38
|
-
},
|
|
31
|
+
".": "./lib/index.js",
|
|
32
|
+
"./client": "./lib/client/index.js",
|
|
39
33
|
"./package.json": "./package.json"
|
|
40
34
|
},
|
|
41
35
|
"files": [
|
|
@@ -45,14 +39,16 @@
|
|
|
45
39
|
"eval",
|
|
46
40
|
"cordis.patch.yml",
|
|
47
41
|
"README.md",
|
|
42
|
+
"ISSUES.md",
|
|
48
43
|
"scripts",
|
|
49
44
|
"neural-cifar-eval",
|
|
50
45
|
"neural-pendulum-eval"
|
|
51
46
|
],
|
|
52
47
|
"scripts": {
|
|
53
|
-
"build": "tsdown",
|
|
48
|
+
"build": "tsdown && node scripts/build-native.mjs",
|
|
54
49
|
"build:native": "node scripts/build-native.mjs",
|
|
55
50
|
"prepare": "tsdown",
|
|
51
|
+
"test": "node test/simulate.ts && node test/scoring.ts && node test/jobs.ts && node test/pendulum-sim.ts",
|
|
56
52
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
57
53
|
},
|
|
58
54
|
"dsh": {
|