agent-hitch 0.2.6 → 0.2.7

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 (386) hide show
  1. package/README.md +14 -1
  2. package/dist/scripts/canary-buildkit-secrets.js +166 -0
  3. package/dist/scripts/canary-buildkit-secrets.js.map +1 -0
  4. package/dist/scripts/canary-collision-domains.js +77 -0
  5. package/dist/scripts/canary-collision-domains.js.map +1 -0
  6. package/dist/scripts/canary-docker-image-observation.js +181 -0
  7. package/dist/scripts/canary-docker-image-observation.js.map +1 -0
  8. package/dist/scripts/canary-gpu-hardware.js +95 -0
  9. package/dist/scripts/canary-gpu-hardware.js.map +1 -0
  10. package/dist/scripts/canary-harbor-load.js +365 -0
  11. package/dist/scripts/canary-harbor-load.js.map +1 -0
  12. package/dist/scripts/canary-packaged-harness.js +75 -0
  13. package/dist/scripts/canary-packaged-harness.js.map +1 -0
  14. package/dist/scripts/canary-resource-load.js +188 -0
  15. package/dist/scripts/canary-resource-load.js.map +1 -0
  16. package/dist/scripts/check-architecture.js +8 -4
  17. package/dist/scripts/check-architecture.js.map +1 -1
  18. package/dist/scripts/docker-reaper-crash-child.js +21 -0
  19. package/dist/scripts/docker-reaper-crash-child.js.map +1 -0
  20. package/dist/src/adapters/catalog.js +1 -0
  21. package/dist/src/adapters/catalog.js.map +1 -1
  22. package/dist/src/adapters/discovery.js +1 -1
  23. package/dist/src/adapters/discovery.js.map +1 -1
  24. package/dist/src/adapters/providers/claude.js +6 -0
  25. package/dist/src/adapters/providers/claude.js.map +1 -1
  26. package/dist/src/adapters/providers/codex.js +6 -0
  27. package/dist/src/adapters/providers/codex.js.map +1 -1
  28. package/dist/src/adapters/providers/deepseek.js +6 -0
  29. package/dist/src/adapters/providers/deepseek.js.map +1 -1
  30. package/dist/src/adapters/providers/opencode.js +6 -0
  31. package/dist/src/adapters/providers/opencode.js.map +1 -1
  32. package/dist/src/adapters/providers/pi.js +6 -0
  33. package/dist/src/adapters/providers/pi.js.map +1 -1
  34. package/dist/src/artifacts/index.js +1 -0
  35. package/dist/src/artifacts/index.js.map +1 -1
  36. package/dist/src/backends/harbor/backend.js +53 -103
  37. package/dist/src/backends/harbor/backend.js.map +1 -1
  38. package/dist/src/backends/harbor/environment-config.js +92 -0
  39. package/dist/src/backends/harbor/environment-config.js.map +1 -0
  40. package/dist/src/backends/harbor/index.js +5 -1
  41. package/dist/src/backends/harbor/index.js.map +1 -1
  42. package/dist/src/backends/harbor/model-proxy-config.js +23 -0
  43. package/dist/src/backends/harbor/model-proxy-config.js.map +1 -0
  44. package/dist/src/backends/harbor/process.js +177 -0
  45. package/dist/src/backends/harbor/process.js.map +1 -0
  46. package/dist/src/backends/harbor/runtime-toolchain.js +30 -0
  47. package/dist/src/backends/harbor/runtime-toolchain.js.map +1 -0
  48. package/dist/src/backends/harbor/supervisor.js +74 -0
  49. package/dist/src/backends/harbor/supervisor.js.map +1 -0
  50. package/dist/src/backends/harbor/task-resources.js +206 -0
  51. package/dist/src/backends/harbor/task-resources.js.map +1 -0
  52. package/dist/src/backends/harbor/tools.js +6 -29
  53. package/dist/src/backends/harbor/tools.js.map +1 -1
  54. package/dist/src/backends/index.js +4 -1
  55. package/dist/src/backends/index.js.map +1 -1
  56. package/dist/src/cli/commands/daemon.js +135 -8
  57. package/dist/src/cli/commands/daemon.js.map +1 -1
  58. package/dist/src/cli/commands/eval.js +214 -4
  59. package/dist/src/cli/commands/eval.js.map +1 -1
  60. package/dist/src/cli/commands/images.js +40 -0
  61. package/dist/src/cli/commands/images.js.map +1 -0
  62. package/dist/src/cli/commands/run.js +6 -3
  63. package/dist/src/cli/commands/run.js.map +1 -1
  64. package/dist/src/cli/commands/runs.js +25 -3
  65. package/dist/src/cli/commands/runs.js.map +1 -1
  66. package/dist/src/cli/commands/worker.js +79 -0
  67. package/dist/src/cli/commands/worker.js.map +1 -0
  68. package/dist/src/cli/main.js +4 -0
  69. package/dist/src/cli/main.js.map +1 -1
  70. package/dist/src/cli/output.js +71 -3
  71. package/dist/src/cli/output.js.map +1 -1
  72. package/dist/src/control-plane/build-admission.js +69 -0
  73. package/dist/src/control-plane/build-admission.js.map +1 -0
  74. package/dist/src/control-plane/build-records.js +6 -0
  75. package/dist/src/control-plane/build-records.js.map +1 -0
  76. package/dist/src/control-plane/collisions.js +40 -0
  77. package/dist/src/control-plane/collisions.js.map +1 -0
  78. package/dist/src/control-plane/eval-control-state.js +22 -0
  79. package/dist/src/control-plane/eval-control-state.js.map +1 -0
  80. package/dist/src/control-plane/eval-control-work.js +39 -0
  81. package/dist/src/control-plane/eval-control-work.js.map +1 -0
  82. package/dist/src/control-plane/eval-image-resolution.js +52 -0
  83. package/dist/src/control-plane/eval-image-resolution.js.map +1 -0
  84. package/dist/src/control-plane/eval-image-services.js +30 -0
  85. package/dist/src/control-plane/eval-image-services.js.map +1 -0
  86. package/dist/src/control-plane/eval-records.js +252 -0
  87. package/dist/src/control-plane/eval-records.js.map +1 -0
  88. package/dist/src/control-plane/eval-recovery.js +181 -0
  89. package/dist/src/control-plane/eval-recovery.js.map +1 -0
  90. package/dist/src/control-plane/eval-scheduler.js +447 -0
  91. package/dist/src/control-plane/eval-scheduler.js.map +1 -0
  92. package/dist/src/control-plane/index.js +20 -0
  93. package/dist/src/control-plane/index.js.map +1 -0
  94. package/dist/src/control-plane/local-worker.js +49 -0
  95. package/dist/src/control-plane/local-worker.js.map +1 -0
  96. package/dist/src/control-plane/model-capture-planning.js +12 -0
  97. package/dist/src/control-plane/model-capture-planning.js.map +1 -0
  98. package/dist/src/control-plane/remote-result-transport.js +172 -0
  99. package/dist/src/control-plane/remote-result-transport.js.map +1 -0
  100. package/dist/src/control-plane/remote-work-coordinator.js +332 -0
  101. package/dist/src/control-plane/remote-work-coordinator.js.map +1 -0
  102. package/dist/src/control-plane/remote-work-inputs.js +266 -0
  103. package/dist/src/control-plane/remote-work-inputs.js.map +1 -0
  104. package/dist/src/control-plane/remote-work-recovery.js +181 -0
  105. package/dist/src/control-plane/remote-work-recovery.js.map +1 -0
  106. package/dist/src/control-plane/remote-worker-artifacts.js +135 -0
  107. package/dist/src/control-plane/remote-worker-artifacts.js.map +1 -0
  108. package/dist/src/control-plane/remote-worker-client.js +202 -0
  109. package/dist/src/control-plane/remote-worker-client.js.map +1 -0
  110. package/dist/src/control-plane/remote-worker-configuration.js +34 -0
  111. package/dist/src/control-plane/remote-worker-configuration.js.map +1 -0
  112. package/dist/src/control-plane/remote-worker-credentials.js +58 -0
  113. package/dist/src/control-plane/remote-worker-credentials.js.map +1 -0
  114. package/dist/src/control-plane/remote-worker-protocol.js +510 -0
  115. package/dist/src/control-plane/remote-worker-protocol.js.map +1 -0
  116. package/dist/src/control-plane/remote-worker-runner.js +214 -0
  117. package/dist/src/control-plane/remote-worker-runner.js.map +1 -0
  118. package/dist/src/control-plane/remote-workers.js +377 -0
  119. package/dist/src/control-plane/remote-workers.js.map +1 -0
  120. package/dist/src/control-plane/rerun-scheduler.js +411 -0
  121. package/dist/src/control-plane/rerun-scheduler.js.map +1 -0
  122. package/dist/src/control-plane/rerun-submission.js +56 -0
  123. package/dist/src/control-plane/rerun-submission.js.map +1 -0
  124. package/dist/src/control-plane/resources.js +182 -0
  125. package/dist/src/control-plane/resources.js.map +1 -0
  126. package/dist/src/control-plane/scheduler-eval-entry.js +32 -0
  127. package/dist/src/control-plane/scheduler-eval-entry.js.map +1 -0
  128. package/dist/src/control-plane/synthetic-result.js +21 -0
  129. package/dist/src/control-plane/synthetic-result.js.map +1 -0
  130. package/dist/src/control-plane/work-admission.js +21 -0
  131. package/dist/src/control-plane/work-admission.js.map +1 -0
  132. package/dist/src/control-plane/work-dispatcher.js +229 -0
  133. package/dist/src/control-plane/work-dispatcher.js.map +1 -0
  134. package/dist/src/controller-runtime/hash.js +12 -1
  135. package/dist/src/controller-runtime/hash.js.map +1 -1
  136. package/dist/src/controller-runtime/index.js +1 -1
  137. package/dist/src/controller-runtime/index.js.map +1 -1
  138. package/dist/src/controller-runtime/store.js +15 -6
  139. package/dist/src/controller-runtime/store.js.map +1 -1
  140. package/dist/src/daemon/client.js.map +1 -1
  141. package/dist/src/daemon/event-stream.js +46 -0
  142. package/dist/src/daemon/event-stream.js.map +1 -0
  143. package/dist/src/daemon/health.js +66 -0
  144. package/dist/src/daemon/health.js.map +1 -0
  145. package/dist/src/daemon/launcher.js +28 -1
  146. package/dist/src/daemon/launcher.js.map +1 -1
  147. package/dist/src/daemon/logging.js +23 -0
  148. package/dist/src/daemon/logging.js.map +1 -0
  149. package/dist/src/daemon/scheduler.js +26 -5
  150. package/dist/src/daemon/scheduler.js.map +1 -1
  151. package/dist/src/daemon/server.js +255 -98
  152. package/dist/src/daemon/server.js.map +1 -1
  153. package/dist/src/daemon/telemetry.js +163 -0
  154. package/dist/src/daemon/telemetry.js.map +1 -0
  155. package/dist/src/daemon/worker-routes.js +219 -0
  156. package/dist/src/daemon/worker-routes.js.map +1 -0
  157. package/dist/src/domain/bundles.js +2 -0
  158. package/dist/src/domain/bundles.js.map +1 -0
  159. package/dist/src/domain/control-plane.js +2 -0
  160. package/dist/src/domain/control-plane.js.map +1 -0
  161. package/dist/src/domain/execution-evidence.js +2 -0
  162. package/dist/src/domain/execution-evidence.js.map +1 -0
  163. package/dist/src/domain/execution-plan.js +2 -0
  164. package/dist/src/domain/execution-plan.js.map +1 -0
  165. package/dist/src/domain/images.js +2 -0
  166. package/dist/src/domain/images.js.map +1 -0
  167. package/dist/src/domain/index.js +9 -0
  168. package/dist/src/domain/index.js.map +1 -1
  169. package/dist/src/domain/interactions.js +2 -0
  170. package/dist/src/domain/interactions.js.map +1 -0
  171. package/dist/src/domain/providers.js +2 -0
  172. package/dist/src/domain/providers.js.map +1 -0
  173. package/dist/src/domain/resources.js +2 -0
  174. package/dist/src/domain/resources.js.map +1 -0
  175. package/dist/src/domain/workers.js +2 -0
  176. package/dist/src/domain/workers.js.map +1 -0
  177. package/dist/src/evals/collect-only-rerun.js +182 -0
  178. package/dist/src/evals/collect-only-rerun.js.map +1 -0
  179. package/dist/src/evals/directory.js +30 -0
  180. package/dist/src/evals/directory.js.map +1 -0
  181. package/dist/src/evals/docker-engine-stats.js +89 -0
  182. package/dist/src/evals/docker-engine-stats.js.map +1 -0
  183. package/dist/src/evals/docker-ownership.js +51 -0
  184. package/dist/src/evals/docker-ownership.js.map +1 -0
  185. package/dist/src/evals/docker-reaper.js +144 -0
  186. package/dist/src/evals/docker-reaper.js.map +1 -0
  187. package/dist/src/evals/docker-resource-observer.js +207 -0
  188. package/dist/src/evals/docker-resource-observer.js.map +1 -0
  189. package/dist/src/evals/environment-image-planning.js +164 -0
  190. package/dist/src/evals/environment-image-planning.js.map +1 -0
  191. package/dist/src/evals/eval-artifact-planning.js +56 -0
  192. package/dist/src/evals/eval-artifact-planning.js.map +1 -0
  193. package/dist/src/evals/eval-finalization.js +10 -0
  194. package/dist/src/evals/eval-finalization.js.map +1 -0
  195. package/dist/src/evals/eval-lifecycle-events.js +16 -0
  196. package/dist/src/evals/eval-lifecycle-events.js.map +1 -0
  197. package/dist/src/evals/events.js +53 -5
  198. package/dist/src/evals/events.js.map +1 -1
  199. package/dist/src/evals/execution-evidence.js +116 -0
  200. package/dist/src/evals/execution-evidence.js.map +1 -0
  201. package/dist/src/evals/execution-leases.js +342 -0
  202. package/dist/src/evals/execution-leases.js.map +1 -0
  203. package/dist/src/evals/execution-plan-artifacts.js +72 -0
  204. package/dist/src/evals/execution-plan-artifacts.js.map +1 -0
  205. package/dist/src/evals/execution-plan-images.js +69 -0
  206. package/dist/src/evals/execution-plan-images.js.map +1 -0
  207. package/dist/src/evals/execution-plan-resources.js +174 -0
  208. package/dist/src/evals/execution-plan-resources.js.map +1 -0
  209. package/dist/src/evals/execution-plan.js +415 -0
  210. package/dist/src/evals/execution-plan.js.map +1 -0
  211. package/dist/src/evals/harbor-artifact-builder-image.js +99 -0
  212. package/dist/src/evals/harbor-artifact-builder-image.js.map +1 -0
  213. package/dist/src/evals/harbor-artifact-builder.js +354 -0
  214. package/dist/src/evals/harbor-artifact-builder.js.map +1 -0
  215. package/dist/src/evals/harbor-bridge-error.js +18 -3
  216. package/dist/src/evals/harbor-bridge-error.js.map +1 -1
  217. package/dist/src/evals/harbor-phase-timings.js +60 -0
  218. package/dist/src/evals/harbor-phase-timings.js.map +1 -0
  219. package/dist/src/evals/index.js +25 -2
  220. package/dist/src/evals/index.js.map +1 -1
  221. package/dist/src/evals/infrastructure-retry.js +100 -63
  222. package/dist/src/evals/infrastructure-retry.js.map +1 -1
  223. package/dist/src/evals/interaction-capture-import.js +49 -0
  224. package/dist/src/evals/interaction-capture-import.js.map +1 -0
  225. package/dist/src/evals/local-docker-provider.js +372 -0
  226. package/dist/src/evals/local-docker-provider.js.map +1 -0
  227. package/dist/src/evals/local-eval-planning.js +80 -0
  228. package/dist/src/evals/local-eval-planning.js.map +1 -0
  229. package/dist/src/evals/model-capture-plan.js +22 -0
  230. package/dist/src/evals/model-capture-plan.js.map +1 -0
  231. package/dist/src/evals/model-capture-runtime.js +114 -0
  232. package/dist/src/evals/model-capture-runtime.js.map +1 -0
  233. package/dist/src/evals/model-proxy-runtime-state.js +53 -0
  234. package/dist/src/evals/model-proxy-runtime-state.js.map +1 -0
  235. package/dist/src/evals/planned-execution-support.js +54 -0
  236. package/dist/src/evals/planned-execution-support.js.map +1 -0
  237. package/dist/src/evals/planned-execution.js +461 -0
  238. package/dist/src/evals/planned-execution.js.map +1 -0
  239. package/dist/src/evals/planned-remote-execution.js +40 -0
  240. package/dist/src/evals/planned-remote-execution.js.map +1 -0
  241. package/dist/src/evals/planned-retry-lifecycle.js +186 -0
  242. package/dist/src/evals/planned-retry-lifecycle.js.map +1 -0
  243. package/dist/src/evals/prepared-harness.js +76 -0
  244. package/dist/src/evals/prepared-harness.js.map +1 -0
  245. package/dist/src/evals/progress.js +4 -4
  246. package/dist/src/evals/progress.js.map +1 -1
  247. package/dist/src/evals/records.js +20 -3
  248. package/dist/src/evals/records.js.map +1 -1
  249. package/dist/src/evals/recovery.js +192 -0
  250. package/dist/src/evals/recovery.js.map +1 -0
  251. package/dist/src/evals/remote-infrastructure-retry.js +99 -0
  252. package/dist/src/evals/remote-infrastructure-retry.js.map +1 -0
  253. package/dist/src/evals/rerun-inputs.js +89 -0
  254. package/dist/src/evals/rerun-inputs.js.map +1 -0
  255. package/dist/src/evals/rerun-slots.js +4 -3
  256. package/dist/src/evals/rerun-slots.js.map +1 -1
  257. package/dist/src/evals/rerun-types.js +49 -0
  258. package/dist/src/evals/rerun-types.js.map +1 -0
  259. package/dist/src/evals/rerun.js +113 -75
  260. package/dist/src/evals/rerun.js.map +1 -1
  261. package/dist/src/evals/result-helpers.js +65 -0
  262. package/dist/src/evals/result-helpers.js.map +1 -0
  263. package/dist/src/evals/resume-state.js +36 -0
  264. package/dist/src/evals/resume-state.js.map +1 -0
  265. package/dist/src/evals/service-types.js +2 -0
  266. package/dist/src/evals/service-types.js.map +1 -0
  267. package/dist/src/evals/service.js +292 -257
  268. package/dist/src/evals/service.js.map +1 -1
  269. package/dist/src/evals/task-resources.js +209 -0
  270. package/dist/src/evals/task-resources.js.map +1 -0
  271. package/dist/src/evals/trial-environment-evidence.js +87 -0
  272. package/dist/src/evals/trial-environment-evidence.js.map +1 -0
  273. package/dist/src/evals/trial-execution-evidence.js +13 -0
  274. package/dist/src/evals/trial-execution-evidence.js.map +1 -0
  275. package/dist/src/evals/trial-import-identity.js +31 -0
  276. package/dist/src/evals/trial-import-identity.js.map +1 -0
  277. package/dist/src/evals/trial-import.js +143 -145
  278. package/dist/src/evals/trial-import.js.map +1 -1
  279. package/dist/src/evals/trial-publication-recovery.js +104 -0
  280. package/dist/src/evals/trial-publication-recovery.js.map +1 -0
  281. package/dist/src/evals/trial-publication.js +25 -0
  282. package/dist/src/evals/trial-publication.js.map +1 -0
  283. package/dist/src/evals/work-item-artifacts.js +23 -0
  284. package/dist/src/evals/work-item-artifacts.js.map +1 -0
  285. package/dist/src/foundation/config.js +17 -0
  286. package/dist/src/foundation/config.js.map +1 -1
  287. package/dist/src/foundation/credential-redaction.js +137 -0
  288. package/dist/src/foundation/credential-redaction.js.map +1 -0
  289. package/dist/src/foundation/environment-image-references.js +59 -0
  290. package/dist/src/foundation/environment-image-references.js.map +1 -0
  291. package/dist/src/foundation/executable.js +45 -5
  292. package/dist/src/foundation/executable.js.map +1 -1
  293. package/dist/src/foundation/index.js +5 -2
  294. package/dist/src/foundation/index.js.map +1 -1
  295. package/dist/src/foundation/process-identity.js +69 -0
  296. package/dist/src/foundation/process-identity.js.map +1 -0
  297. package/dist/src/images/context.js +47 -0
  298. package/dist/src/images/context.js.map +1 -0
  299. package/dist/src/images/docker-buildkit.js +137 -0
  300. package/dist/src/images/docker-buildkit.js.map +1 -0
  301. package/dist/src/images/dockerfile.js +67 -0
  302. package/dist/src/images/dockerfile.js.map +1 -0
  303. package/dist/src/images/gc.js +261 -0
  304. package/dist/src/images/gc.js.map +1 -0
  305. package/dist/src/images/index.js +10 -0
  306. package/dist/src/images/index.js.map +1 -0
  307. package/dist/src/images/manifest.js +109 -0
  308. package/dist/src/images/manifest.js.map +1 -0
  309. package/dist/src/images/ownership.js +5 -0
  310. package/dist/src/images/ownership.js.map +1 -0
  311. package/dist/src/images/records.js +32 -0
  312. package/dist/src/images/records.js.map +1 -0
  313. package/dist/src/images/registry.js +154 -0
  314. package/dist/src/images/registry.js.map +1 -0
  315. package/dist/src/images/service.js +224 -0
  316. package/dist/src/images/service.js.map +1 -0
  317. package/dist/src/model-access/capture.js +255 -0
  318. package/dist/src/model-access/capture.js.map +1 -0
  319. package/dist/src/model-access/index.js +5 -0
  320. package/dist/src/model-access/index.js.map +1 -0
  321. package/dist/src/model-access/policy.js +49 -0
  322. package/dist/src/model-access/policy.js.map +1 -0
  323. package/dist/src/model-access/proxy.js +336 -0
  324. package/dist/src/model-access/proxy.js.map +1 -0
  325. package/dist/src/model-access/records.js +167 -0
  326. package/dist/src/model-access/records.js.map +1 -0
  327. package/dist/src/runs/bundle.js +450 -0
  328. package/dist/src/runs/bundle.js.map +1 -0
  329. package/dist/src/runs/events.js +12 -1
  330. package/dist/src/runs/events.js.map +1 -1
  331. package/dist/src/runs/executor.js +24 -17
  332. package/dist/src/runs/executor.js.map +1 -1
  333. package/dist/src/runs/index.js +3 -1
  334. package/dist/src/runs/index.js.map +1 -1
  335. package/dist/src/runs/manifest.js +5 -5
  336. package/dist/src/runs/manifest.js.map +1 -1
  337. package/dist/src/runs/request.js +6 -1
  338. package/dist/src/runs/request.js.map +1 -1
  339. package/dist/src/runs/training-candidate.js +161 -0
  340. package/dist/src/runs/training-candidate.js.map +1 -0
  341. package/dist/src/trajectories/provider-capture.js +15 -24
  342. package/dist/src/trajectories/provider-capture.js.map +1 -1
  343. package/dist/src/trajectories/providers/deepseek.js +3 -3
  344. package/dist/src/trajectories/providers/deepseek.js.map +1 -1
  345. package/dist/src/workers/index.js +3 -0
  346. package/dist/src/workers/index.js.map +1 -0
  347. package/dist/src/workers/remote-harbor-work-spec.js +97 -0
  348. package/dist/src/workers/remote-harbor-work-spec.js.map +1 -0
  349. package/dist/src/workers/remote-harbor-worker.js +220 -0
  350. package/dist/src/workers/remote-harbor-worker.js.map +1 -0
  351. package/docs/schemas/environment-build-index.schema.json +13 -0
  352. package/docs/schemas/environment-build-record.schema.json +25 -0
  353. package/docs/schemas/environment-image-manifest.schema.json +62 -0
  354. package/docs/schemas/eval-control.schema.json +36 -0
  355. package/docs/schemas/eval-execution-plan.schema.json +216 -0
  356. package/docs/schemas/eval-rerun-result.schema.json +53 -0
  357. package/docs/schemas/eval-rerun-state.schema.json +61 -0
  358. package/docs/schemas/eval-rerun-submission.schema.json +58 -0
  359. package/docs/schemas/eval-result.schema.json +34 -1
  360. package/docs/schemas/eval-submission-input.schema.json +14 -0
  361. package/docs/schemas/eval-submission.schema.json +68 -0
  362. package/docs/schemas/eval-trial-publication.schema.json +39 -0
  363. package/docs/schemas/execution-evidence.schema.json +96 -0
  364. package/docs/schemas/execution-lease.schema.json +50 -0
  365. package/docs/schemas/execution-provider-status.schema.json +65 -0
  366. package/docs/schemas/execution-worker.schema.json +53 -0
  367. package/docs/schemas/harbor-process-exit.schema.json +14 -0
  368. package/docs/schemas/interaction-capture-ref.schema.json +45 -0
  369. package/docs/schemas/local-provider-execution.schema.json +33 -0
  370. package/docs/schemas/model-interaction.schema.json +41 -0
  371. package/docs/schemas/remote-result-envelope.schema.json +32 -0
  372. package/docs/schemas/remote-tree-envelope.schema.json +25 -0
  373. package/docs/schemas/remote-work-offer.schema.json +58 -0
  374. package/docs/schemas/remote-work-receipt.schema.json +50 -0
  375. package/docs/schemas/remote-worker-artifact.schema.json +17 -0
  376. package/docs/schemas/remote-worker-event.schema.json +18 -0
  377. package/docs/schemas/remote-worker-heartbeat.schema.json +37 -0
  378. package/docs/schemas/remote-worker-registration.schema.json +52 -0
  379. package/docs/schemas/result-bundle-index.schema.json +133 -0
  380. package/docs/schemas/run-environment-images.schema.json +39 -0
  381. package/docs/schemas/training-data-candidate.schema.json +46 -0
  382. package/integrations/harbor/hitch_harbor_agent.py +171 -539
  383. package/integrations/harbor/hitch_harbor_environment.py +331 -0
  384. package/integrations/harbor/hitch_harbor_task_resources.py +275 -0
  385. package/integrations/harbor/hitch_harbor_verifier.py +23 -0
  386. package/package.json +14 -1
@@ -1,7 +1,6 @@
1
1
  import path from "node:path";
2
- import { mkdir } from "node:fs/promises";
3
- import { prepareHarness, preparedArtifactDirectory, resolveHarness } from "../artifacts/index.js";
4
- import { HitchError, SCHEMA_VERSION, atomicWriteJSON, ensureDir, invalidInput, statePaths } from "../foundation/index.js";
2
+ import { resolveHarness } from "../artifacts/index.js";
3
+ import { HitchError, SCHEMA_VERSION, atomicWriteJSON, beginEvalEnvironmentImagePlanning, credentialValuesFromEnv, ensureDir, invalidInput, safeDiagnosticMessage, statePaths, withEnvironmentImageReferenceLock, writeEvalEnvironmentImageReferences } from "../foundation/index.js";
5
4
  import { parseHarnessReference } from "../revisions/index.js";
6
5
  import { buildLocalGitTransport, lockedHarnessRef, runHarborBackend, verifyLocalGitTransport } from "../backends/index.js";
7
6
  import { ensureControllerRuntime, writeRuntimeReference } from "../controller-runtime/index.js";
@@ -11,33 +10,47 @@ import { createEvalProgress, mergeEvalProgressTrial, writeEvalProgress } from ".
11
10
  import { infrastructureFailureTrials, runInfrastructureRetries } from "./infrastructure-retry.js";
12
11
  import { newEvalId, resolveLocalDatasetTaskIds, validateEvalId, validateEvalRequest } from "./request.js";
13
12
  import { invalidTrialSlots } from "./rerun-slots.js";
14
- export async function runEval({ evalId = newEvalId(), request, root, env = process.env, harborExecutable, signal, onEvent, trialBundleGraceMs }) {
13
+ import { prepareEvalDirectory } from "./directory.js";
14
+ import { buildEvalExecutionPlan, DEFAULT_EVAL_TRIAL_RESOURCES } from "./execution-plan.js";
15
+ import { planLocalEvalInputs } from "./local-eval-planning.js";
16
+ import { resolvedImageMapping } from "./environment-image-planning.js";
17
+ import { assertBackendTrialSet, attemptDirectoryName, localSourceBackendFailure, summarizeTrialRefs, transportSummary } from "./result-helpers.js";
18
+ import { executePlannedHarborTasks } from "./planned-execution.js";
19
+ import { assertEvalResumeState, executionPlanWorkState, loadEvalResumeState } from "./resume-state.js";
20
+ import { modelCaptureDegradationEvent, resolveEvalModelCapturePlan } from "./model-capture-plan.js";
21
+ import { finalizeEvalResult } from "./eval-finalization.js";
22
+ import { prepareHostHarborArtifactForTest } from "./prepared-harness.js";
23
+ import { prepareHarborArtifact } from "./harbor-artifact-builder.js";
24
+ import { prepareEvalArtifactAssignments, preparedArtifactPlanFields } from "./eval-artifact-planning.js";
25
+ import { startEvalModelCaptureRuntime } from "./model-capture-runtime.js";
26
+ import { recoverPromotedEvalTrialPublications } from "./trial-publication-recovery.js";
27
+ import { emitEvalPlanLifecycle } from "./eval-lifecycle-events.js";
28
+ export async function runEval({ evalId = newEvalId(), request, root, env = process.env, harborExecutable, signal, onEvent, trialBundleGraceMs, precreated = false, normalizedRequest, maxConcurrentOverride, executionResources, executionResourceSource = "operator-default", executionStrategy = "legacy-attempt-shards", executionWorker, modelCapturePlan, workItemAdmission, remoteWorkExecutor, resumeExisting = false, onControlPhase, onWorkItemState, dockerResourceReaper, environmentBuildMode = "backend", environmentImageResolver, environmentImageBuilder, environmentImageManifestLoader, harborArtifactBuilder }) {
15
29
  if (!root)
16
30
  throw invalidInput("a Hitch state root is required for eval");
17
31
  evalId = validateEvalId(evalId);
18
- const normalized = await validateEvalRequest(request);
19
- const evalsDirectory = await ensureDir(statePaths(root).evals);
20
- const evalDirectory = path.join(evalsDirectory, evalId);
21
- try {
22
- await mkdir(evalDirectory, { mode: 0o700 });
23
- }
24
- catch (error) {
25
- if (error.code === "EEXIST") {
26
- throw new HitchError(`eval ID already exists: ${evalId}`, { code: "eval_id_conflict", exitCode: 2 });
27
- }
28
- throw error;
32
+ const persistedRequest = normalizedRequest || await validateEvalRequest(request);
33
+ if (maxConcurrentOverride !== undefined && (!Number.isSafeInteger(maxConcurrentOverride) || maxConcurrentOverride < 1 || maxConcurrentOverride > persistedRequest.max_concurrent)) {
34
+ throw invalidInput("control-plane max concurrency override is invalid");
29
35
  }
30
- const startedAt = new Date();
36
+ const normalized = maxConcurrentOverride === undefined ? persistedRequest : { ...persistedRequest, max_concurrent: maxConcurrentOverride };
37
+ const evalsDirectory = await ensureDir(statePaths(root).evals);
38
+ const evalDirectory = await prepareEvalDirectory({ evalsDirectory, evalId, request: persistedRequest, precreated });
39
+ let startedAt = new Date();
31
40
  const sink = new EvalEventSink(evalDirectory, evalId, onEvent);
32
41
  await sink.open();
33
- await atomicWriteJSON(path.join(evalDirectory, "request.json"), normalized);
34
42
  let result;
35
43
  let trialRefs = [];
36
44
  let progress = null;
45
+ let captureRuntime;
37
46
  try {
47
+ const planningStartedAt = Date.now();
38
48
  sink.emit({ type: "eval.started", backend: normalized.backend, dataset: normalized.dataset });
49
+ sink.emit({ type: "eval.planning.started" });
50
+ await onControlPhase?.("planning");
39
51
  const requestedReference = parseHarnessReference(normalized.harness_ref);
40
52
  const resolvedRevision = await resolveHarness(normalized.harness_ref, { root, env });
53
+ await onControlPhase?.("preparing");
41
54
  let localTransport;
42
55
  if (resolvedRevision.source.type === "git" && resolvedRevision.source.registered !== true) {
43
56
  const selector = requestedReference.selector;
@@ -62,50 +75,6 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
62
75
  status: "verified",
63
76
  });
64
77
  }
65
- const selector = requestedReference.selector;
66
- const verifiedLocalGitSource = localTransport && selector.type === "commit" && selector.source?.explicit
67
- ? {
68
- directory: selector.source.local_path,
69
- commit: localTransport.manifest.commit,
70
- tree: localTransport.manifest.tree,
71
- resolutionIdentity: localTransport.manifest.resolution_identity,
72
- payloadSha256: localTransport.manifest.payload_sha256,
73
- }
74
- : undefined;
75
- const artifact = await prepareHarness(resolvedRevision, {
76
- root,
77
- env,
78
- ...(signal ? { signal } : {}),
79
- ...(verifiedLocalGitSource ? { verifiedLocalGitSource } : {}),
80
- });
81
- if (!artifact.artifact_integrity || !artifact.entrypoint_integrity) {
82
- throw new HitchError("host-prepared harness artifact has no complete integrity metadata", {
83
- code: "artifact_integrity_mismatch",
84
- exitCode: 5,
85
- });
86
- }
87
- const preparedArtifact = {
88
- directory: preparedArtifactDirectory(root, artifact.artifact_id),
89
- artifact_id: artifact.artifact_id,
90
- artifact_integrity: artifact.artifact_integrity,
91
- entrypoint_integrity: artifact.entrypoint_integrity,
92
- harness_id: artifact.harness_id,
93
- revision_identity: artifact.revision_identity,
94
- adapter_version: artifact.adapter_version,
95
- recipe_version: artifact.recipe_version,
96
- platform: artifact.platform,
97
- node_version: artifact.toolchain.node || process.version,
98
- source_type: artifact.source_type,
99
- };
100
- sink.emit({
101
- type: "eval.harness-artifact.prepared",
102
- harness: artifact.harness_id,
103
- artifact_id: artifact.artifact_id,
104
- platform: artifact.platform,
105
- cache_hit: artifact.cache_hit,
106
- });
107
- // Phase 2: the shared, read-only, SHA-256-addressed controller runtime
108
- // cache replaces the per-eval Hitch runtime copy (spec §4).
109
78
  const controllerRuntime = await ensureControllerRuntime({ root });
110
79
  const runtimeRefFile = await writeRuntimeReference(evalDirectory, controllerRuntime);
111
80
  sink.emit({
@@ -115,10 +84,27 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
115
84
  reference: runtimeRefFile,
116
85
  });
117
86
  const localTaskIds = await resolveLocalDatasetTaskIds(normalized.dataset);
87
+ const resume = resumeExisting ? await loadEvalResumeState(evalDirectory) : null;
88
+ await withEnvironmentImageReferenceLock(root, () => beginEvalEnvironmentImagePlanning(evalDirectory, evalId));
89
+ const localPlanning = await planLocalEvalInputs({ root, dataset: normalized.dataset, taskIds: localTaskIds, defaultResources: executionResources ?? DEFAULT_EVAL_TRIAL_RESOURCES, defaultSource: executionResourceSource, benchmarkId: normalized.benchmark_id, benchmarkRevision: normalized.benchmark_revision, buildMode: environmentBuildMode, harborTaskResourceInspector: path.join(controllerRuntime.directory, "payload", "integrations", "harbor", "hitch_harbor_task_resources.py"), ...(environmentImageResolver ? { resolver: environmentImageResolver } : {}), ...(environmentImageBuilder ? { builder: environmentImageBuilder } : {}), ...(resume ? { resumePlan: resume.executionPlan } : {}), ...(harborExecutable ? { harborExecutable } : {}), env, ...(signal ? { signal } : {}) });
90
+ await withEnvironmentImageReferenceLock(root, () => writeEvalEnvironmentImageReferences(evalDirectory, evalId, localPlanning.environmentImages));
91
+ const selectedArtifactBuilder = harborArtifactBuilder ?? (env.NODE_ENV === "test" && env.HITCH_TEST_HOST_ARTIFACT_BUILDER === "1" ? prepareHostHarborArtifactForTest : prepareHarborArtifact);
92
+ const prepared = await prepareEvalArtifactAssignments({ builder: selectedArtifactBuilder, root, resolvedRevision, requestedReference, controllerRuntime, ...(localTransport ? { localTransport } : {}), taskRuntimeContracts: localPlanning.taskRuntimeContracts, sink, env, ...(signal ? { signal } : {}) });
93
+ const preparedAssignments = prepared.assignments;
94
+ const preparedArtifact = prepared.primary;
95
+ const preparedArtifacts = prepared.artifactsById;
96
+ const multipleRuntimeContracts = preparedAssignments.length > 1;
97
+ const taskResources = localPlanning.taskResources;
118
98
  const plannedTasks = localTaskIds?.length ?? null;
119
99
  const plannedTrials = plannedTasks === null ? null : plannedTasks * normalized.attempts;
120
100
  if (plannedTrials !== null && !Number.isSafeInteger(plannedTrials))
121
101
  throw invalidInput("planned trial count exceeds the safe integer range");
102
+ if (resume)
103
+ startedAt = new Date(resume.progress.started_at);
104
+ const capture = resolveEvalModelCapturePlan({ requested: modelCapturePlan, resumed: resume?.executionPlan.model_capture, resuming: Boolean(resume) });
105
+ const activeCaptureRuntime = await startEvalModelCaptureRuntime({ plan: capture.plan, evalId, evalDirectory, env });
106
+ captureRuntime = activeCaptureRuntime;
107
+ capture.plan = activeCaptureRuntime.plan;
122
108
  const plan = {
123
109
  schema_version: SCHEMA_VERSION,
124
110
  eval_id: evalId,
@@ -135,8 +121,11 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
135
121
  benchmark_id: normalized.benchmark_id,
136
122
  benchmark_revision: normalized.benchmark_revision,
137
123
  attempts: normalized.attempts,
138
- attempt_execution: "harbor-attempt-shards-v1",
124
+ attempt_execution: (executionStrategy === "local-task-slots-v1" || multipleRuntimeContracts) && localTaskIds !== null
125
+ ? "harbor-task-slots-v1"
126
+ : "harbor-attempt-shards-v1",
139
127
  max_concurrent: normalized.max_concurrent,
128
+ ...(capture.persist ? { model_capture: capture.plan } : {}),
140
129
  infrastructure_retries: normalized.infrastructure_retries,
141
130
  infrastructure_retry_backoff_ms: normalized.infrastructure_retry_backoff_ms,
142
131
  ...(localTaskIds === null ? {} : { tasks: localTaskIds }),
@@ -144,13 +133,50 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
144
133
  runtime_id: controllerRuntime.runtime_id,
145
134
  manifest_digest: controllerRuntime.manifest_digest,
146
135
  },
147
- prepared_artifact: preparedArtifactSummary(preparedArtifact),
136
+ ...preparedArtifactPlanFields(preparedAssignments),
148
137
  ...(localTransport ? { local_source_transport: transportSummary(localTransport) } : {}),
149
- created_at: new Date().toISOString(),
138
+ created_at: typeof resume?.plan.created_at === "string" ? resume.plan.created_at : new Date().toISOString(),
150
139
  };
151
- await atomicWriteJSON(path.join(evalDirectory, "resolution.json"), resolvedRevision);
152
- await atomicWriteJSON(path.join(evalDirectory, "plan.json"), plan);
153
- progress = createEvalProgress({
140
+ const expectedExecutionPlan = buildEvalExecutionPlan({
141
+ evalId,
142
+ request: normalized,
143
+ candidate: {
144
+ revisionIdentity: resolvedRevision.identity,
145
+ artifactId: preparedArtifact.artifact_id,
146
+ artifactAssignments: preparedAssignments.map((entry) => ({
147
+ taskIds: entry.taskIds,
148
+ artifactId: entry.artifact.artifact_id,
149
+ runtimeContract: {
150
+ docker_platform: entry.runtimeContract.dockerPlatform,
151
+ artifact_platform: entry.runtimeContract.artifactPlatform,
152
+ node_version: entry.runtimeContract.nodeVersion,
153
+ },
154
+ })),
155
+ },
156
+ tasks: localTaskIds,
157
+ maxParallelism: normalized.max_concurrent,
158
+ ...(executionResources ? { trialResources: executionResources } : {}),
159
+ ...(taskResources ? { taskResources } : {}),
160
+ ...(localPlanning.environmentImages.length > 0 ? { environmentImages: localPlanning.environmentImages } : {}),
161
+ ...(localPlanning.environmentImageFallbacks.length > 0 ? { environmentImageFallbacks: localPlanning.environmentImageFallbacks } : {}),
162
+ ...(executionWorker ? { provider: executionWorker.provider } : {}),
163
+ modelCapture: capture.persist ? capture.plan : null,
164
+ ...((executionStrategy === "local-task-slots-v1" || multipleRuntimeContracts) && localTaskIds !== null ? { workItemMode: "task-slots" } : {}),
165
+ createdAt: plan.created_at,
166
+ });
167
+ if (resume)
168
+ assertEvalResumeState({ state: resume, expectedPlan: plan, expectedExecutionPlan, expectedResolutionIdentity: resolvedRevision.identity, plannedTasks, plannedTrials });
169
+ else
170
+ await Promise.all([
171
+ atomicWriteJSON(path.join(evalDirectory, "resolution.json"), resolvedRevision),
172
+ atomicWriteJSON(path.join(evalDirectory, "plan.json"), plan),
173
+ atomicWriteJSON(path.join(evalDirectory, "execution-plan.json"), expectedExecutionPlan),
174
+ ]);
175
+ const executionPlan = resume?.executionPlan ?? expectedExecutionPlan;
176
+ const captureDegradation = modelCaptureDegradationEvent(executionPlan.model_capture);
177
+ if (captureDegradation)
178
+ sink.emit(captureDegradation);
179
+ progress = resume?.progress ?? createEvalProgress({
154
180
  evalId,
155
181
  benchmarkId: normalized.benchmark_id,
156
182
  benchmarkRevision: normalized.benchmark_revision,
@@ -158,7 +184,10 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
158
184
  plannedTrials,
159
185
  startedAt: startedAt.toISOString(),
160
186
  });
161
- await writeEvalProgress(evalDirectory, progress);
187
+ if (!resume)
188
+ await writeEvalProgress(evalDirectory, progress);
189
+ else
190
+ progress = (await recoverPromotedEvalTrialPublications({ root, evalDirectory, plan: executionPlan, progress, sink })).progress;
162
191
  sink.emit({
163
192
  type: "eval.planned",
164
193
  harness: resolvedRevision.harness_id,
@@ -166,7 +195,11 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
166
195
  attempts: normalized.attempts,
167
196
  planned_tasks: plannedTasks,
168
197
  planned_trials: plannedTrials,
198
+ work_items: executionPlan.work_items.length,
199
+ membership: executionPlan.membership,
169
200
  });
201
+ emitEvalPlanLifecycle(sink, executionPlan, planningStartedAt);
202
+ await onControlPhase?.("running", executionPlanWorkState(executionPlan, progress));
170
203
  if (localTransport) {
171
204
  await verifyLocalGitTransport(localTransport, {
172
205
  expected: {
@@ -180,147 +213,203 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
180
213
  }
181
214
  const backendRuns = [];
182
215
  const infrastructureRetryRuns = [];
183
- for (let logicalAttempt = 1; logicalAttempt <= normalized.attempts; logicalAttempt += 1) {
184
- if (signal?.aborted)
185
- break;
186
- const backendDirectory = normalized.attempts === 1
187
- ? path.join(evalDirectory, "harbor")
188
- : path.join(evalDirectory, "harbor", attemptDirectoryName(logicalAttempt));
189
- const harborJobDirectory = path.join(backendDirectory, "job");
190
- const shardRefs = [];
191
- const publish = async (ref) => {
192
- if (ref.attempt !== logicalAttempt) {
193
- throw new HitchError(`Harbor returned attempt ${ref.attempt}, expected ${logicalAttempt}`, {
194
- code: "eval_trial_attempt_mismatch",
195
- exitCode: 12,
196
- });
197
- }
198
- if (!shardRefs.some((current) => current.trial_id === ref.trial_id))
199
- shardRefs.push(ref);
200
- if (progress === null)
201
- throw new Error("eval progress was not initialized");
202
- const previousGeneration = progress.generation;
203
- progress = mergeEvalProgressTrial(progress, ref);
204
- if (progress.generation === previousGeneration)
205
- return;
206
- await validateEvalTrialReferences(root, evalId, [ref], {
207
- benchmarkId: normalized.benchmark_id,
208
- benchmarkRevision: normalized.benchmark_revision,
209
- });
210
- await writeEvalProgress(evalDirectory, progress);
211
- sink.emit({
212
- type: "eval.trial.published",
213
- trial_id: ref.trial_id,
214
- task_id: ref.task_id,
215
- attempt: ref.attempt,
216
- run_id: ref.run_id,
217
- observation_status: ref.observation_status,
218
- settled_trials: progress.trials.length,
219
- generation: progress.generation,
220
- });
221
- };
222
- const backendRun = await runHarborBackend({
223
- evalId,
224
- evalDirectory,
225
- backendDirectory,
226
- logicalAttempt,
227
- request: { ...normalized, attempts: 1 },
228
- root,
229
- resolvedRevision,
230
- runtimeDirectory: controllerRuntime.directory,
231
- runtimeId: controllerRuntime.runtime_id,
232
- preparedArtifact,
233
- ...(localTransport ? { localTransport } : {}),
234
- env,
235
- ...(harborExecutable !== undefined ? { harborExecutable } : {}),
236
- ...(signal ? { signal } : {}),
237
- ...(trialBundleGraceMs === undefined ? {} : { trialBundleGraceMs }),
238
- emit: (event) => sink.emit(event),
239
- onTrialSettled: async (trial, context) => {
240
- try {
241
- const ref = await importEvalTrialRun({
242
- root,
243
- evalId,
244
- evalDirectory,
245
- harborJobDirectory,
246
- expectedAttempt: logicalAttempt,
247
- request: normalized,
248
- resolvedRevision,
249
- benchmarkId: normalized.benchmark_id,
250
- benchmarkRevision: normalized.benchmark_revision,
251
- runtimeId: controllerRuntime.runtime_id,
252
- requireCompleteMarker: true,
253
- allowMissingBundleDiagnostic: context.bundleWaitExpired,
254
- }, trial, shardRefs.length, shardRefs);
255
- await publish(ref);
256
- return true;
257
- }
258
- catch (error) {
259
- if (error instanceof TrialBundlePendingError)
260
- return false;
261
- throw error;
262
- }
263
- },
264
- });
265
- backendRuns.push({ attempt: logicalAttempt, run: backendRun });
266
- const terminalRefs = await importEvalTrialRuns({
267
- root,
268
- evalId,
269
- evalDirectory,
270
- harborJobDirectory,
271
- expectedAttempt: logicalAttempt,
272
- request: normalized,
273
- resolvedRevision,
274
- benchmarkId: normalized.benchmark_id,
275
- benchmarkRevision: normalized.benchmark_revision,
276
- runtimeId: controllerRuntime.runtime_id,
277
- rawResult: backendRun.rawResult,
278
- }, shardRefs);
279
- for (const ref of terminalRefs)
280
- await publish(ref);
281
- assertBackendTrialSet(backendRun.rawResult, shardRefs);
282
- await validateEvalTrialReferences(root, evalId, shardRefs, {
283
- benchmarkId: normalized.benchmark_id,
284
- benchmarkRevision: normalized.benchmark_revision,
285
- });
286
- if (backendRun.backend.process_exit_code !== 0 || backendRun.rawResult === null)
287
- break;
288
- if (localTransport && localSourceBackendFailure(backendRun.rawResult))
289
- break;
290
- if (progress === null)
291
- throw new Error("eval progress was not initialized");
292
- const retries = await runInfrastructureRetries({
216
+ const plannedTaskExecution = (executionStrategy === "local-task-slots-v1" || multipleRuntimeContracts) && localTaskIds !== null;
217
+ if (plannedTaskExecution) {
218
+ const execution = await executePlannedHarborTasks({
293
219
  evalId,
294
220
  evalDirectory,
295
- logicalAttempt,
296
- initialRefs: shardRefs,
221
+ plan: executionPlan,
297
222
  progress,
298
223
  request: normalized,
299
224
  root,
300
225
  resolvedRevision,
301
226
  controllerRuntime,
302
227
  preparedArtifact,
228
+ preparedArtifacts,
303
229
  ...(localTransport ? { localTransport } : {}),
304
230
  env,
305
231
  ...(harborExecutable !== undefined ? { harborExecutable } : {}),
306
232
  ...(signal ? { signal } : {}),
307
233
  ...(trialBundleGraceMs === undefined ? {} : { trialBundleGraceMs }),
308
234
  sink,
309
- ...(localTransport ? { stopAfterResult: localSourceBackendFailure } : {}),
235
+ worker: executionWorker || {
236
+ workerId: `worker_process_${process.pid}`,
237
+ provider: "local-docker",
238
+ collisionDomainId: `local-process:${process.pid}`,
239
+ },
240
+ ...(workItemAdmission ? { admission: workItemAdmission } : {}),
241
+ ...(onWorkItemState ? { onWorkItemState } : {}),
242
+ ...(dockerResourceReaper ? { dockerResourceReaper } : {}),
243
+ ...(environmentImageManifestLoader ? { environmentImageManifestLoader } : {}),
244
+ ...(activeCaptureRuntime.exporter ? { interactionCaptureExporter: activeCaptureRuntime.exporter } : {}),
245
+ ...(remoteWorkExecutor ? { remoteWorkExecutor } : {}),
310
246
  });
311
- progress = retries.progress;
312
- infrastructureRetryRuns.push(...retries.runs);
247
+ progress = execution.progress;
248
+ backendRuns.push(...execution.backendRuns.map((entry) => ({
249
+ attempt: entry.attempt,
250
+ run: entry.run,
251
+ workId: entry.workId,
252
+ tasks: entry.tasks,
253
+ leaseId: entry.leaseId,
254
+ })));
255
+ infrastructureRetryRuns.push(...execution.infrastructureRetryRuns);
313
256
  }
257
+ else
258
+ for (let logicalAttempt = 1; logicalAttempt <= normalized.attempts; logicalAttempt += 1) {
259
+ if (signal?.aborted)
260
+ break;
261
+ const backendDirectory = normalized.attempts === 1
262
+ ? path.join(evalDirectory, "harbor")
263
+ : path.join(evalDirectory, "harbor", attemptDirectoryName(logicalAttempt));
264
+ const harborJobDirectory = path.join(backendDirectory, "job");
265
+ const shardRefs = [];
266
+ const publish = async (ref) => {
267
+ if (ref.attempt !== logicalAttempt) {
268
+ throw new HitchError(`Harbor returned attempt ${ref.attempt}, expected ${logicalAttempt}`, {
269
+ code: "eval_trial_attempt_mismatch",
270
+ exitCode: 12,
271
+ });
272
+ }
273
+ if (!shardRefs.some((current) => current.trial_id === ref.trial_id))
274
+ shardRefs.push(ref);
275
+ if (progress === null)
276
+ throw new Error("eval progress was not initialized");
277
+ const previousGeneration = progress.generation;
278
+ progress = mergeEvalProgressTrial(progress, ref);
279
+ if (progress.generation === previousGeneration)
280
+ return;
281
+ await validateEvalTrialReferences(root, evalId, [ref], {
282
+ benchmarkId: normalized.benchmark_id,
283
+ benchmarkRevision: normalized.benchmark_revision,
284
+ });
285
+ await writeEvalProgress(evalDirectory, progress);
286
+ sink.emit({
287
+ type: "eval.trial.published",
288
+ trial_id: ref.trial_id,
289
+ task_id: ref.task_id,
290
+ attempt: ref.attempt,
291
+ run_id: ref.run_id,
292
+ observation_status: ref.observation_status,
293
+ settled_trials: progress.trials.length,
294
+ generation: progress.generation,
295
+ });
296
+ };
297
+ const backendRun = await runHarborBackend({
298
+ evalId,
299
+ evalDirectory,
300
+ backendDirectory,
301
+ logicalAttempt,
302
+ request: { ...normalized, attempts: 1 },
303
+ root,
304
+ resolvedRevision,
305
+ runtimeDirectory: controllerRuntime.directory,
306
+ runtimeId: controllerRuntime.runtime_id,
307
+ preparedArtifact,
308
+ ...(activeCaptureRuntime.exporter ? { modelProxy: activeCaptureRuntime.exporter.route } : {}),
309
+ resolvedImages: resolvedImageMapping(executionPlan.work_items.find((item) => item.logical_attempt === logicalAttempt)?.image_refs ?? []),
310
+ ...(executionResources ? { executionResources } : {}),
311
+ env,
312
+ ...(harborExecutable !== undefined ? { harborExecutable } : {}),
313
+ ...(signal ? { signal } : {}),
314
+ ...(trialBundleGraceMs === undefined ? {} : { trialBundleGraceMs }),
315
+ emit: (event) => sink.emit(event),
316
+ onTrialSettled: async (trial, context) => {
317
+ try {
318
+ const ref = await importEvalTrialRun({
319
+ root,
320
+ evalId,
321
+ evalDirectory,
322
+ harborJobDirectory,
323
+ expectedAttempt: logicalAttempt,
324
+ request: normalized,
325
+ resolvedRevision,
326
+ benchmarkId: normalized.benchmark_id,
327
+ benchmarkRevision: normalized.benchmark_revision,
328
+ runtimeId: controllerRuntime.runtime_id,
329
+ env,
330
+ modelCapturePlan: activeCaptureRuntime.plan,
331
+ ...(activeCaptureRuntime.exporter ? { interactionCaptureExporter: activeCaptureRuntime.exporter } : {}),
332
+ requireCompleteMarker: true,
333
+ allowMissingBundleDiagnostic: context.bundleWaitExpired,
334
+ }, trial, shardRefs.length, shardRefs);
335
+ await publish(ref);
336
+ return true;
337
+ }
338
+ catch (error) {
339
+ if (error instanceof TrialBundlePendingError)
340
+ return false;
341
+ throw error;
342
+ }
343
+ },
344
+ });
345
+ backendRuns.push({ attempt: logicalAttempt, run: backendRun });
346
+ const terminalRefs = await importEvalTrialRuns({
347
+ root,
348
+ evalId,
349
+ evalDirectory,
350
+ harborJobDirectory,
351
+ expectedAttempt: logicalAttempt,
352
+ request: normalized,
353
+ resolvedRevision,
354
+ benchmarkId: normalized.benchmark_id,
355
+ benchmarkRevision: normalized.benchmark_revision,
356
+ runtimeId: controllerRuntime.runtime_id,
357
+ env,
358
+ modelCapturePlan: activeCaptureRuntime.plan,
359
+ ...(activeCaptureRuntime.exporter ? { interactionCaptureExporter: activeCaptureRuntime.exporter } : {}),
360
+ rawResult: backendRun.rawResult,
361
+ }, shardRefs);
362
+ for (const ref of terminalRefs)
363
+ await publish(ref);
364
+ assertBackendTrialSet(backendRun.rawResult, shardRefs);
365
+ await validateEvalTrialReferences(root, evalId, shardRefs, {
366
+ benchmarkId: normalized.benchmark_id,
367
+ benchmarkRevision: normalized.benchmark_revision,
368
+ });
369
+ if (backendRun.backend.process_exit_code !== 0 || backendRun.rawResult === null)
370
+ break;
371
+ if (localTransport && localSourceBackendFailure(backendRun.rawResult))
372
+ break;
373
+ if (progress === null)
374
+ throw new Error("eval progress was not initialized");
375
+ const retries = await runInfrastructureRetries({
376
+ evalId,
377
+ evalDirectory,
378
+ logicalAttempt,
379
+ initialRefs: shardRefs,
380
+ progress,
381
+ request: normalized,
382
+ root,
383
+ resolvedRevision,
384
+ controllerRuntime,
385
+ preparedArtifact,
386
+ resolvedImages: resolvedImageMapping(executionPlan.work_items.find((item) => item.logical_attempt === logicalAttempt)?.image_refs ?? []),
387
+ ...(executionResources ? { executionResources } : {}),
388
+ modelCapturePlan: activeCaptureRuntime.plan,
389
+ ...(activeCaptureRuntime.exporter ? { interactionCaptureExporter: activeCaptureRuntime.exporter } : {}),
390
+ ...(localTransport ? { localTransport } : {}),
391
+ env,
392
+ ...(harborExecutable !== undefined ? { harborExecutable } : {}),
393
+ ...(signal ? { signal } : {}),
394
+ ...(trialBundleGraceMs === undefined ? {} : { trialBundleGraceMs }),
395
+ sink,
396
+ ...(localTransport ? { stopAfterResult: localSourceBackendFailure } : {}),
397
+ });
398
+ progress = retries.progress;
399
+ infrastructureRetryRuns.push(...retries.runs);
400
+ }
314
401
  if (progress === null)
315
402
  throw new Error("eval progress was not initialized");
403
+ await onControlPhase?.("finalizing");
316
404
  trialRefs = progress.trials;
317
405
  const cancelled = signal?.aborted === true;
318
406
  const localSourceFailure = localTransport
319
407
  ? backendRuns.some(({ run }) => localSourceBackendFailure(run.rawResult))
320
408
  || infrastructureRetryRuns.some(({ run }) => localSourceBackendFailure(run.rawResult))
321
409
  : false;
322
- const backendsSucceeded = backendRuns.length === normalized.attempts
323
- && backendRuns.every(({ run }) => run.backend.process_exit_code === 0 && run.rawResult !== null);
410
+ const expectedBackendRuns = plannedTaskExecution ? executionPlan.work_items.length : normalized.attempts;
411
+ const backendsSucceeded = backendRuns.every(({ run }) => run.backend.process_exit_code === 0 && run.rawResult !== null)
412
+ && (plannedTaskExecution ? progress.trials.length === plannedTrials : backendRuns.length === expectedBackendRuns);
324
413
  const invalidTrials = localTaskIds === null
325
414
  ? trialRefs.filter((trial) => trial.observation_status !== "valid").map((trial) => ({ task_id: trial.task_id, attempt: trial.attempt }))
326
415
  : invalidTrialSlots(localTaskIds, normalized.attempts, progress);
@@ -338,7 +427,16 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
338
427
  status: cancelled ? "cancelled" : succeeded ? "succeeded" : "failed",
339
428
  exit_code: cancelled ? 9 : succeeded ? 0 : 13,
340
429
  ...(singleBackend ? { backend: singleBackend.backend, backend_summary: singleBackend.summary } : {}),
341
- ...(normalized.attempts > 1 ? {
430
+ ...(plannedTaskExecution ? {
431
+ backend_work_items: backendRuns.map(({ attempt, workId, tasks, leaseId, run }) => ({
432
+ work_id: workId,
433
+ lease_id: leaseId,
434
+ attempt,
435
+ tasks,
436
+ backend: run.backend,
437
+ backend_summary: run.summary,
438
+ })),
439
+ } : normalized.attempts > 1 ? {
342
440
  backend_runs: backendRuns.map(({ attempt, run }) => ({
343
441
  attempt,
344
442
  backend: run.backend,
@@ -352,8 +450,8 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
352
450
  candidate_rerun_on_verifier_failure: false,
353
451
  },
354
452
  ...(infrastructureRetryRuns.length > 0 ? {
355
- infrastructure_retry_runs: infrastructureRetryRuns.map(({ attempt, retry, tasks, triggers, refs, run }) => ({
356
- attempt,
453
+ infrastructure_retry_runs: infrastructureRetryRuns.map(({ attempt, retry, tasks, triggers, refs, run, leaseId, workId }) => ({
454
+ execution_kind: "physical-infrastructure-retry", ...(leaseId ? { lease_id: leaseId } : {}), ...(workId ? { work_id: workId } : {}), attempt,
357
455
  retry,
358
456
  tasks,
359
457
  trigger_trials: triggers,
@@ -369,7 +467,7 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
369
467
  generation: progress.generation,
370
468
  trials: trialRefs,
371
469
  summary: summarizeTrialRefs(trialRefs),
372
- prepared_artifact: preparedArtifactSummary(preparedArtifact),
470
+ ...preparedArtifactPlanFields(preparedAssignments),
373
471
  ...(localTransport ? { local_source_transport: transportSummary(localTransport) } : {}),
374
472
  ...(succeeded ? {} : {
375
473
  error: {
@@ -387,7 +485,7 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
387
485
  : localSourceFailure
388
486
  ? "Harbor rejected the transported local Git source before candidate execution"
389
487
  : !backendsSucceeded
390
- ? `Harbor attempt shards completed ${backendRuns.length}/${normalized.attempts}`
488
+ ? `Harbor work items completed ${backendRuns.length}/${expectedBackendRuns}`
391
489
  : infrastructureFailures.length > 0
392
490
  ? `${infrastructureErrorCode === "eval_infrastructure_retries_exhausted" ? "infrastructure retries exhausted" : "verifier infrastructure failure"}: ${infrastructureFailureSlots.map(trial => `${trial.task_id}#${trial.attempt}`).join(", ")}`
393
491
  : `eval has invalid or missing trials: ${invalidTrials.map(trial => `${trial.task_id}#${trial.attempt}`).join(", ")}`,
@@ -407,7 +505,7 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
407
505
  exit_code: signal?.aborted ? 9 : typed ? error.exitCode : 12,
408
506
  error: {
409
507
  code: signal?.aborted ? "cancelled" : typed ? error.code : "internal_error",
410
- message: error?.message || String(error),
508
+ message: safeDiagnosticMessage(error, credentialValuesFromEnv(normalized.pass_env, env)),
411
509
  },
412
510
  benchmark_id: normalized.benchmark_id,
413
511
  benchmark_revision: normalized.benchmark_revision,
@@ -417,71 +515,8 @@ export async function runEval({ evalId = newEvalId(), request, root, env = proce
417
515
  completed_at: new Date().toISOString(),
418
516
  };
419
517
  }
420
- await atomicWriteJSON(path.join(evalDirectory, "result.json"), result);
421
- sink.emit({ type: result.status === "succeeded" ? "eval.completed" : "eval.failed", status: result.status, exit_code: result.exit_code, error: result.error });
422
- await sink.close();
423
- return result;
424
- }
425
- function assertBackendTrialSet(rawResult, refs) {
426
- const trials = Array.isArray(rawResult?.trial_results) ? rawResult.trial_results : [];
427
- const backendIds = new Set(trials.map((trial) => typeof trial.trial_name === "string" ? trial.trial_name : null).filter((value) => value !== null));
428
- const refIds = new Set(refs.map((ref) => ref.trial_id));
429
- if (backendIds.size !== trials.length || backendIds.size !== refIds.size || [...backendIds].some((id) => !refIds.has(id))) {
430
- throw new Error("Harbor terminal trial set does not match published eval progress");
431
- }
432
- }
433
- function attemptDirectoryName(attempt) {
434
- return `attempt-${String(attempt).padStart(4, "0")}`;
435
- }
436
- export function summarizeTrialRefs(trials) {
437
- const valid = trials.filter((trial) => trial.observation_status === "valid" && typeof trial.reward === "number");
438
- const rewards = valid.map((trial) => trial.reward);
439
- const aggregate = rewards.length
440
- ? {
441
- count: rewards.length,
442
- mean: rewards.reduce((sum, reward) => sum + reward, 0) / rewards.length,
443
- min: Math.min(...rewards),
444
- max: Math.max(...rewards),
445
- }
446
- : null;
447
- return {
448
- n_trials: trials.length,
449
- n_completed: valid.length,
450
- n_invalid: trials.length - valid.length,
451
- primary_reward: aggregate?.mean ?? null,
452
- rewards: aggregate ? { reward: aggregate } : {},
453
- };
454
- }
455
- function localSourceBackendFailure(rawResult) {
456
- if (!rawResult)
457
- return false;
458
- // The bridge uses this fixed, non-secret marker when setup cannot verify or
459
- // materialize the uploaded source. Do not surface provider exception text in
460
- // the durable Hitch error, because it may contain backend diagnostics.
461
- return JSON.stringify(rawResult).includes("hitch-local-source-materialize:");
462
- }
463
- function transportSummary(transport) {
464
- const manifest = transport.manifest;
465
- return {
466
- kind: manifest.kind,
467
- resolution_identity: manifest.resolution_identity,
468
- commit: manifest.commit,
469
- tree: manifest.tree,
470
- payload_sha256: manifest.payload_sha256,
471
- payload_bytes: manifest.payload_bytes,
472
- object_count: manifest.object_count,
473
- file_count: manifest.file_count,
474
- };
475
- }
476
- function preparedArtifactSummary(artifact) {
477
- return {
478
- artifact_id: artifact.artifact_id,
479
- artifact_integrity: artifact.artifact_integrity,
480
- entrypoint_integrity: artifact.entrypoint_integrity,
481
- harness_id: artifact.harness_id,
482
- revision_identity: artifact.revision_identity,
483
- platform: artifact.platform,
484
- source_type: artifact.source_type,
485
- };
518
+ if (captureRuntime)
519
+ await captureRuntime.close().catch((error) => sink.emit({ type: "interaction.capture.close-failed", code: error.code || "model_capture_close_failed" }));
520
+ return finalizeEvalResult(evalDirectory, sink, result);
486
521
  }
487
522
  //# sourceMappingURL=service.js.map