agent-hitch 0.2.15 → 0.2.17

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 (361) hide show
  1. package/README.md +7 -28
  2. package/README.zh-CN.md +6 -26
  3. package/dist/scripts/benchmark-dataset-verification.js +118 -0
  4. package/dist/scripts/benchmark-dataset-verification.js.map +1 -0
  5. package/dist/scripts/canary-external-endpoint.js +56 -0
  6. package/dist/scripts/canary-external-endpoint.js.map +1 -0
  7. package/dist/scripts/canary-native-training.js +8 -6
  8. package/dist/scripts/canary-native-training.js.map +1 -1
  9. package/dist/scripts/canary-remote-training.js +8 -6
  10. package/dist/scripts/canary-remote-training.js.map +1 -1
  11. package/dist/scripts/check-architecture.js +1 -1
  12. package/dist/scripts/check-architecture.js.map +1 -1
  13. package/dist/src/adapters/providers/codex.js +5 -2
  14. package/dist/src/adapters/providers/codex.js.map +1 -1
  15. package/dist/src/adapters/providers/model-call.js +1 -2
  16. package/dist/src/adapters/providers/model-call.js.map +1 -1
  17. package/dist/src/adapters/providers/training-tool.js +2 -0
  18. package/dist/src/adapters/providers/training-tool.js.map +1 -1
  19. package/dist/src/backends/harbor/artifact-pins.js +42 -0
  20. package/dist/src/backends/harbor/artifact-pins.js.map +1 -0
  21. package/dist/src/backends/harbor/backend.js +16 -8
  22. package/dist/src/backends/harbor/backend.js.map +1 -1
  23. package/dist/src/backends/harbor/bound-credential-helper.js +24 -0
  24. package/dist/src/backends/harbor/bound-credential-helper.js.map +1 -0
  25. package/dist/src/backends/harbor/credential-snapshot.js +71 -0
  26. package/dist/src/backends/harbor/credential-snapshot.js.map +1 -0
  27. package/dist/src/backends/harbor/environment-config.js +25 -2
  28. package/dist/src/backends/harbor/environment-config.js.map +1 -1
  29. package/dist/src/backends/harbor/environment-files.js +143 -0
  30. package/dist/src/backends/harbor/environment-files.js.map +1 -0
  31. package/dist/src/backends/harbor/evaluation-binding.js +160 -0
  32. package/dist/src/backends/harbor/evaluation-binding.js.map +1 -0
  33. package/dist/src/backends/harbor/host-credential-helper.js +5 -0
  34. package/dist/src/backends/harbor/host-credential-helper.js.map +1 -1
  35. package/dist/src/backends/harbor/index.js +2 -0
  36. package/dist/src/backends/harbor/index.js.map +1 -1
  37. package/dist/src/backends/harbor/model-proxy-config.js +3 -18
  38. package/dist/src/backends/harbor/model-proxy-config.js.map +1 -1
  39. package/dist/src/backends/harbor/portable-regrade.js +15 -3
  40. package/dist/src/backends/harbor/portable-regrade.js.map +1 -1
  41. package/dist/src/backends/harbor/python-runtime.js +71 -0
  42. package/dist/src/backends/harbor/python-runtime.js.map +1 -0
  43. package/dist/src/backends/harbor/tools.js +6 -4
  44. package/dist/src/backends/harbor/tools.js.map +1 -1
  45. package/dist/src/backends/index.js +3 -0
  46. package/dist/src/backends/index.js.map +1 -1
  47. package/dist/src/cli/arguments.js +30 -30
  48. package/dist/src/cli/arguments.js.map +1 -1
  49. package/dist/src/cli/commands/capabilities.js +7 -3
  50. package/dist/src/cli/commands/capabilities.js.map +1 -1
  51. package/dist/src/cli/commands/daemon.js +0 -17
  52. package/dist/src/cli/commands/daemon.js.map +1 -1
  53. package/dist/src/cli/commands/eval-binding.js +32 -0
  54. package/dist/src/cli/commands/eval-binding.js.map +1 -0
  55. package/dist/src/cli/commands/eval.js +21 -15
  56. package/dist/src/cli/commands/eval.js.map +1 -1
  57. package/dist/src/cli/commands/models.js +32 -45
  58. package/dist/src/cli/commands/models.js.map +1 -1
  59. package/dist/src/cli/commands/run.js +0 -35
  60. package/dist/src/cli/commands/run.js.map +1 -1
  61. package/dist/src/cli/main.js +0 -4
  62. package/dist/src/cli/main.js.map +1 -1
  63. package/dist/src/cli/output.js +5 -16
  64. package/dist/src/cli/output.js.map +1 -1
  65. package/dist/src/control-plane/eval-records.js +3 -1
  66. package/dist/src/control-plane/eval-records.js.map +1 -1
  67. package/dist/src/control-plane/eval-recovery.js +4 -1
  68. package/dist/src/control-plane/eval-recovery.js.map +1 -1
  69. package/dist/src/control-plane/eval-scheduler.js +16 -8
  70. package/dist/src/control-plane/eval-scheduler.js.map +1 -1
  71. package/dist/src/control-plane/index.js +0 -2
  72. package/dist/src/control-plane/index.js.map +1 -1
  73. package/dist/src/control-plane/model-capture-planning.js +3 -4
  74. package/dist/src/control-plane/model-capture-planning.js.map +1 -1
  75. package/dist/src/control-plane/remote-model-routes.js +4 -24
  76. package/dist/src/control-plane/remote-model-routes.js.map +1 -1
  77. package/dist/src/control-plane/remote-offer-contract.js +2 -2
  78. package/dist/src/control-plane/remote-offer-contract.js.map +1 -1
  79. package/dist/src/control-plane/remote-result-transport.js +7 -8
  80. package/dist/src/control-plane/remote-result-transport.js.map +1 -1
  81. package/dist/src/control-plane/remote-work-coordinator.js +2 -2
  82. package/dist/src/control-plane/remote-work-coordinator.js.map +1 -1
  83. package/dist/src/control-plane/remote-work-recovery.js +2 -2
  84. package/dist/src/control-plane/remote-work-recovery.js.map +1 -1
  85. package/dist/src/control-plane/remote-worker-protocol.js +1 -1
  86. package/dist/src/control-plane/remote-worker-protocol.js.map +1 -1
  87. package/dist/src/control-plane/remote-worker-runner.js +21 -6
  88. package/dist/src/control-plane/remote-worker-runner.js.map +1 -1
  89. package/dist/src/control-plane/remote-workers.js +2 -2
  90. package/dist/src/control-plane/remote-workers.js.map +1 -1
  91. package/dist/src/control-plane/rerun-recovery.js +1 -1
  92. package/dist/src/control-plane/rerun-recovery.js.map +1 -1
  93. package/dist/src/control-plane/rerun-scheduler.js +21 -14
  94. package/dist/src/control-plane/rerun-scheduler.js.map +1 -1
  95. package/dist/src/control-plane/rerun-source.js +5 -2
  96. package/dist/src/control-plane/rerun-source.js.map +1 -1
  97. package/dist/src/control-plane/rerun-submission.js +7 -5
  98. package/dist/src/control-plane/rerun-submission.js.map +1 -1
  99. package/dist/src/control-plane/synthetic-result.js +3 -2
  100. package/dist/src/control-plane/synthetic-result.js.map +1 -1
  101. package/dist/src/control-plane/worker-model-relay.js +1 -1
  102. package/dist/src/control-plane/worker-model-relay.js.map +1 -1
  103. package/dist/src/controller-runtime/hash.js +6 -0
  104. package/dist/src/controller-runtime/hash.js.map +1 -1
  105. package/dist/src/daemon/client.js +12 -35
  106. package/dist/src/daemon/client.js.map +1 -1
  107. package/dist/src/daemon/evaluation-binding.js +33 -0
  108. package/dist/src/daemon/evaluation-binding.js.map +1 -0
  109. package/dist/src/daemon/evaluation-submission.js +27 -0
  110. package/dist/src/daemon/evaluation-submission.js.map +1 -0
  111. package/dist/src/daemon/index.js +1 -0
  112. package/dist/src/daemon/index.js.map +1 -1
  113. package/dist/src/daemon/json-stream.js +98 -0
  114. package/dist/src/daemon/json-stream.js.map +1 -0
  115. package/dist/src/daemon/scheduler.js +1 -4
  116. package/dist/src/daemon/scheduler.js.map +1 -1
  117. package/dist/src/daemon/server.js +14 -54
  118. package/dist/src/daemon/server.js.map +1 -1
  119. package/dist/src/domain/endpoints.js +2 -0
  120. package/dist/src/domain/endpoints.js.map +1 -0
  121. package/dist/src/domain/evaluation-binding.js +5 -0
  122. package/dist/src/domain/evaluation-binding.js.map +1 -0
  123. package/dist/src/domain/index.js +2 -0
  124. package/dist/src/domain/index.js.map +1 -1
  125. package/dist/src/domain/runs.js.map +1 -1
  126. package/dist/src/evals/benchmark-adapter-manifest.js +95 -32
  127. package/dist/src/evals/benchmark-adapter-manifest.js.map +1 -1
  128. package/dist/src/evals/benchmark-verification.js +106 -0
  129. package/dist/src/evals/benchmark-verification.js.map +1 -0
  130. package/dist/src/evals/collect-only-rerun.js +3 -2
  131. package/dist/src/evals/collect-only-rerun.js.map +1 -1
  132. package/dist/src/evals/directory.js +9 -1
  133. package/dist/src/evals/directory.js.map +1 -1
  134. package/dist/src/evals/endpoint-attempts.js +112 -0
  135. package/dist/src/evals/endpoint-attempts.js.map +1 -0
  136. package/dist/src/evals/endpoint-usage.js +8 -0
  137. package/dist/src/evals/endpoint-usage.js.map +1 -0
  138. package/dist/src/evals/environment-binding.js +9 -0
  139. package/dist/src/evals/environment-binding.js.map +1 -0
  140. package/dist/src/evals/eval-artifact-planning.js +10 -1
  141. package/dist/src/evals/eval-artifact-planning.js.map +1 -1
  142. package/dist/src/evals/eval-finalization.js +2 -3
  143. package/dist/src/evals/eval-finalization.js.map +1 -1
  144. package/dist/src/evals/eval-logical-plan.js +2 -0
  145. package/dist/src/evals/eval-logical-plan.js.map +1 -1
  146. package/dist/src/evals/eval-result-builder.js +4 -0
  147. package/dist/src/evals/eval-result-builder.js.map +1 -1
  148. package/dist/src/evals/eval-state.js +22 -0
  149. package/dist/src/evals/eval-state.js.map +1 -0
  150. package/dist/src/evals/execution-plan.js +6 -2
  151. package/dist/src/evals/execution-plan.js.map +1 -1
  152. package/dist/src/evals/index.js +5 -1
  153. package/dist/src/evals/index.js.map +1 -1
  154. package/dist/src/evals/infrastructure-retry.js +2 -0
  155. package/dist/src/evals/infrastructure-retry.js.map +1 -1
  156. package/dist/src/evals/model-capture-runtime.js +9 -13
  157. package/dist/src/evals/model-capture-runtime.js.map +1 -1
  158. package/dist/src/evals/native-phase-evidence.js +8 -2
  159. package/dist/src/evals/native-phase-evidence.js.map +1 -1
  160. package/dist/src/evals/planned-execution.js +7 -2
  161. package/dist/src/evals/planned-execution.js.map +1 -1
  162. package/dist/src/evals/planned-progress-publisher.js +18 -5
  163. package/dist/src/evals/planned-progress-publisher.js.map +1 -1
  164. package/dist/src/evals/planned-retry-execution.js +1 -0
  165. package/dist/src/evals/planned-retry-execution.js.map +1 -1
  166. package/dist/src/evals/preparation-rerun.js +0 -1
  167. package/dist/src/evals/preparation-rerun.js.map +1 -1
  168. package/dist/src/evals/progress.js +92 -7
  169. package/dist/src/evals/progress.js.map +1 -1
  170. package/dist/src/evals/records.js +12 -2
  171. package/dist/src/evals/records.js.map +1 -1
  172. package/dist/src/evals/recovery.js +2 -0
  173. package/dist/src/evals/recovery.js.map +1 -1
  174. package/dist/src/evals/remote-rerun-execution.js +1 -3
  175. package/dist/src/evals/remote-rerun-execution.js.map +1 -1
  176. package/dist/src/evals/remote-verifier-rerun.js +1 -1
  177. package/dist/src/evals/remote-verifier-rerun.js.map +1 -1
  178. package/dist/src/evals/request.js +14 -45
  179. package/dist/src/evals/request.js.map +1 -1
  180. package/dist/src/evals/rerun-observation.js +31 -0
  181. package/dist/src/evals/rerun-observation.js.map +1 -0
  182. package/dist/src/evals/rerun.js +23 -28
  183. package/dist/src/evals/rerun.js.map +1 -1
  184. package/dist/src/evals/service.js +45 -42
  185. package/dist/src/evals/service.js.map +1 -1
  186. package/dist/src/evals/shared-runtime.js +125 -0
  187. package/dist/src/evals/shared-runtime.js.map +1 -0
  188. package/dist/src/evals/trial-import.js +10 -2
  189. package/dist/src/evals/trial-import.js.map +1 -1
  190. package/dist/src/evals/trial-publication-recovery.js +1 -1
  191. package/dist/src/evals/trial-publication-recovery.js.map +1 -1
  192. package/dist/src/evals/verifier-artifacts.js +1 -0
  193. package/dist/src/evals/verifier-artifacts.js.map +1 -1
  194. package/dist/src/evals/verifier-only-rerun.js +1 -1
  195. package/dist/src/evals/verifier-only-rerun.js.map +1 -1
  196. package/dist/src/evals/verifier-rerun-result.js +3 -2
  197. package/dist/src/evals/verifier-rerun-result.js.map +1 -1
  198. package/dist/src/evals/verifier-score-artifacts.js +9 -1
  199. package/dist/src/evals/verifier-score-artifacts.js.map +1 -1
  200. package/dist/src/foundation/config.js +0 -5
  201. package/dist/src/foundation/config.js.map +1 -1
  202. package/dist/src/inference/index.js +3 -22
  203. package/dist/src/inference/index.js.map +1 -1
  204. package/dist/src/inference/lock.js +44 -130
  205. package/dist/src/inference/lock.js.map +1 -1
  206. package/dist/src/model-access/endpoint-contract.js +127 -0
  207. package/dist/src/model-access/endpoint-contract.js.map +1 -0
  208. package/dist/src/model-access/endpoint-credentials.js +54 -0
  209. package/dist/src/model-access/endpoint-credentials.js.map +1 -0
  210. package/dist/src/model-access/endpoint-probe-stream.js +66 -0
  211. package/dist/src/model-access/endpoint-probe-stream.js.map +1 -0
  212. package/dist/src/model-access/endpoint-verification.js +76 -0
  213. package/dist/src/model-access/endpoint-verification.js.map +1 -0
  214. package/dist/src/model-access/endpoints.js +105 -0
  215. package/dist/src/model-access/endpoints.js.map +1 -0
  216. package/dist/src/model-access/index.js +5 -1
  217. package/dist/src/model-access/index.js.map +1 -1
  218. package/dist/src/model-access/proxy.js +57 -14
  219. package/dist/src/model-access/proxy.js.map +1 -1
  220. package/dist/src/model-access/remote-model.js +21 -29
  221. package/dist/src/model-access/remote-model.js.map +1 -1
  222. package/dist/src/model-access/usage.js +30 -0
  223. package/dist/src/model-access/usage.js.map +1 -0
  224. package/dist/src/runs/endpoint-runtime.js +40 -0
  225. package/dist/src/runs/endpoint-runtime.js.map +1 -0
  226. package/dist/src/runs/executor.js +28 -42
  227. package/dist/src/runs/executor.js.map +1 -1
  228. package/dist/src/runs/local-inference-environment.js +5 -53
  229. package/dist/src/runs/local-inference-environment.js.map +1 -1
  230. package/dist/src/runs/manifest.js +1 -0
  231. package/dist/src/runs/manifest.js.map +1 -1
  232. package/dist/src/runs/outcome.js +3 -10
  233. package/dist/src/runs/outcome.js.map +1 -1
  234. package/dist/src/runs/queued.js +3 -2
  235. package/dist/src/runs/queued.js.map +1 -1
  236. package/dist/src/runs/records.js +3 -0
  237. package/dist/src/runs/records.js.map +1 -1
  238. package/dist/src/runs/request.js +10 -38
  239. package/dist/src/runs/request.js.map +1 -1
  240. package/dist/src/workers/remote-harbor-work-spec.js +8 -10
  241. package/dist/src/workers/remote-harbor-work-spec.js.map +1 -1
  242. package/dist/src/workers/remote-harbor-worker.js +3 -0
  243. package/dist/src/workers/remote-harbor-worker.js.map +1 -1
  244. package/docs/evidence/eval-preparation-2026-10-09.json +393 -0
  245. package/docs/evidence/eval-preparation-2026-10-09.md +178 -0
  246. package/docs/local-model-inference-spec.zh-CN.md +4 -663
  247. package/docs/resource-storage.zh-CN.md +116 -0
  248. package/docs/schemas/endpoint-evaluation-attempt.schema.json +29 -0
  249. package/docs/schemas/eval-artifact-pin.schema.json +14 -0
  250. package/docs/schemas/eval-execution-plan.schema.json +486 -105
  251. package/docs/schemas/eval-progress.schema.json +1 -1
  252. package/docs/schemas/eval-request.schema.json +149 -18
  253. package/docs/schemas/eval-rerun-submission.schema.json +8 -1
  254. package/docs/schemas/eval-result.schema.json +310 -56
  255. package/docs/schemas/evaluation-binding.schema.json +15 -0
  256. package/docs/schemas/external-endpoint-binding.schema.json +153 -0
  257. package/docs/schemas/external-endpoint-config.schema.json +93 -0
  258. package/docs/schemas/inference-execution-evidence.schema.json +253 -3
  259. package/docs/schemas/inference-lock-v3.schema.json +6 -0
  260. package/docs/schemas/inference-lock.schema.json +842 -341
  261. package/docs/schemas/ordered-eval-control.schema.json +7 -1
  262. package/docs/schemas/ready-endpoint-binding.schema.json +201 -0
  263. package/docs/schemas/run-manifest.schema.json +6 -0
  264. package/docs/schemas/run-request.schema.json +122 -20
  265. package/examples/external-inference/.env.example +16 -0
  266. package/examples/external-inference/README.md +203 -0
  267. package/examples/external-inference/accept.mjs +297 -0
  268. package/examples/external-inference/compose.gateway.yaml +119 -0
  269. package/examples/external-inference/compose.single.yaml +64 -0
  270. package/examples/external-inference/compose.tp2.yaml +15 -0
  271. package/examples/external-inference/deployment.example.json +58 -0
  272. package/examples/external-inference/endpoint.chat-completions.example.json +13 -0
  273. package/examples/external-inference/endpoint.responses.example.json +13 -0
  274. package/integrations/harbor/hitch_build_inputs.py +213 -0
  275. package/integrations/harbor/hitch_build_process.py +126 -0
  276. package/integrations/harbor/hitch_compose_preparation.py +274 -0
  277. package/integrations/harbor/hitch_harbor_agent.py +25 -39
  278. package/integrations/harbor/hitch_harbor_environment.py +96 -3
  279. package/integrations/harbor/hitch_image_cache.py +357 -0
  280. package/integrations/harbor/hitch_python_runtime.py +303 -0
  281. package/integrations/harbor/hitch_shared_runtime.py +123 -0
  282. package/integrations/model-call/cli.js +11 -10
  283. package/integrations/training-tool/cli.js +56 -15
  284. package/node_modules/smol-toml/LICENSE +24 -0
  285. package/node_modules/smol-toml/README.md +418 -0
  286. package/node_modules/smol-toml/dist/date.d.ts +41 -0
  287. package/node_modules/smol-toml/dist/date.js +127 -0
  288. package/node_modules/smol-toml/dist/error.d.ts +38 -0
  289. package/node_modules/smol-toml/dist/error.js +63 -0
  290. package/node_modules/smol-toml/dist/extract.js +69 -0
  291. package/node_modules/smol-toml/dist/index.cjs +734 -0
  292. package/node_modules/smol-toml/dist/index.d.ts +43 -0
  293. package/node_modules/smol-toml/dist/index.js +33 -0
  294. package/node_modules/smol-toml/dist/parse.d.ts +36 -0
  295. package/node_modules/smol-toml/dist/parse.js +149 -0
  296. package/node_modules/smol-toml/dist/primitive.js +238 -0
  297. package/node_modules/smol-toml/dist/stringify.d.ts +31 -0
  298. package/node_modules/smol-toml/dist/stringify.js +181 -0
  299. package/node_modules/smol-toml/dist/struct.js +179 -0
  300. package/node_modules/smol-toml/dist/util.d.ts +38 -0
  301. package/node_modules/smol-toml/dist/util.js +89 -0
  302. package/node_modules/smol-toml/package.json +68 -0
  303. package/package.json +15 -4
  304. package/dist/src/cli/commands/local.js +0 -130
  305. package/dist/src/cli/commands/local.js.map +0 -1
  306. package/dist/src/cli/commands/model-node.js +0 -26
  307. package/dist/src/cli/commands/model-node.js.map +0 -1
  308. package/dist/src/control-plane/inference-manager.js +0 -357
  309. package/dist/src/control-plane/inference-manager.js.map +0 -1
  310. package/dist/src/control-plane/managed-gateway-receipt.js +0 -26
  311. package/dist/src/control-plane/managed-gateway-receipt.js.map +0 -1
  312. package/dist/src/control-plane/managed-service-recovery.js +0 -158
  313. package/dist/src/control-plane/managed-service-recovery.js.map +0 -1
  314. package/dist/src/daemon/inference-prepare.js +0 -47
  315. package/dist/src/daemon/inference-prepare.js.map +0 -1
  316. package/dist/src/inference/daemon-capacity.js +0 -41
  317. package/dist/src/inference/daemon-capacity.js.map +0 -1
  318. package/dist/src/inference/device-reservation.js +0 -58
  319. package/dist/src/inference/device-reservation.js.map +0 -1
  320. package/dist/src/inference/doctor.js +0 -95
  321. package/dist/src/inference/doctor.js.map +0 -1
  322. package/dist/src/inference/generation-recovery.js +0 -83
  323. package/dist/src/inference/generation-recovery.js.map +0 -1
  324. package/dist/src/inference/managed-launcher.js +0 -35
  325. package/dist/src/inference/managed-launcher.js.map +0 -1
  326. package/dist/src/inference/materialize.js +0 -66
  327. package/dist/src/inference/materialize.js.map +0 -1
  328. package/dist/src/inference/model-location.js +0 -34
  329. package/dist/src/inference/model-location.js.map +0 -1
  330. package/dist/src/inference/node-client.js +0 -167
  331. package/dist/src/inference/node-client.js.map +0 -1
  332. package/dist/src/inference/node-registry.js +0 -79
  333. package/dist/src/inference/node-registry.js.map +0 -1
  334. package/dist/src/inference/observation.js +0 -79
  335. package/dist/src/inference/observation.js.map +0 -1
  336. package/dist/src/inference/preflight.js +0 -132
  337. package/dist/src/inference/preflight.js.map +0 -1
  338. package/dist/src/inference/process-sglang.js +0 -169
  339. package/dist/src/inference/process-sglang.js.map +0 -1
  340. package/dist/src/inference/protocol-probe.js +0 -29
  341. package/dist/src/inference/protocol-probe.js.map +0 -1
  342. package/dist/src/inference/remote-model-store.js +0 -24
  343. package/dist/src/inference/remote-model-store.js.map +0 -1
  344. package/dist/src/inference/runtime-catalog.js +0 -41
  345. package/dist/src/inference/runtime-catalog.js.map +0 -1
  346. package/dist/src/inference/runtime-store.js +0 -93
  347. package/dist/src/inference/runtime-store.js.map +0 -1
  348. package/dist/src/inference/service-attachment.js +0 -46
  349. package/dist/src/inference/service-attachment.js.map +0 -1
  350. package/dist/src/inference/service-inspection.js +0 -38
  351. package/dist/src/inference/service-inspection.js.map +0 -1
  352. package/dist/src/inference/sglang.js +0 -279
  353. package/dist/src/inference/sglang.js.map +0 -1
  354. package/dist/src/inference/supervisor.js +0 -460
  355. package/dist/src/inference/supervisor.js.map +0 -1
  356. package/dist/src/model-access/local-gateway-request.js +0 -139
  357. package/dist/src/model-access/local-gateway-request.js.map +0 -1
  358. package/dist/src/model-access/local-gateway.js +0 -323
  359. package/dist/src/model-access/local-gateway.js.map +0 -1
  360. package/dist/src/runs/local-inference-run.js +0 -53
  361. package/dist/src/runs/local-inference-run.js.map +0 -1
@@ -0,0 +1,123 @@
1
+ """Read-only, evaluation-local installation snapshots for Harbor main services.
2
+
3
+ This changes transport, not content authentication. The bridge and in-container
4
+ Hitch keep their existing pinned manifest and payload checks.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import asyncio
9
+ import json
10
+ import posixpath
11
+ import re
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ CONTROLLER_TARGET = "/opt/hitch"
16
+ ARTIFACT_TARGET = "/opt/hitch-harness-artifact"
17
+ TARGETS = (CONTROLLER_TARGET, ARTIFACT_TARGET)
18
+
19
+
20
+ def configure(raw: Any, candidate: bool) -> dict[str, str] | None:
21
+ if raw is None:
22
+ return None
23
+ if not isinstance(raw, dict) or set(raw) != {"runtime_directory", "artifact_directory"}:
24
+ raise ValueError("shared runtime transport metadata is invalid")
25
+ for value in raw.values():
26
+ if not isinstance(value, str) or not Path(value).is_absolute() or any(ord(c) < 32 for c in value):
27
+ raise ValueError("shared runtime transport requires absolute host paths")
28
+ # Harbor also forwards environment kwargs to separate verifier containers.
29
+ # Only the candidate session receives harness code.
30
+ if not candidate:
31
+ return None
32
+ result = {
33
+ CONTROLLER_TARGET: str(Path(raw["runtime_directory"]) / "payload"),
34
+ ARTIFACT_TARGET: raw["artifact_directory"],
35
+ }
36
+ for source in result.values():
37
+ if not Path(source).is_dir() or Path(source).is_symlink():
38
+ raise ValueError("shared runtime snapshot must be an existing regular directory")
39
+ return result
40
+
41
+
42
+ def reject_conflicts(services: dict[str, Any]) -> None:
43
+ """Validate resolved services before exposing any shared installation."""
44
+ # Volume inheritance can copy main's mounts into sidecars transitively,
45
+ # or import unknown external mounts into main. A read-only declaration
46
+ # cannot protect a mount inherited by a privileged consumer. Require
47
+ # explicit mounts throughout this composition instead of guessing which
48
+ # container aliases or inheritance chains remain isolated.
49
+ if any(service.get("volumes_from") for service in services.values()):
50
+ raise ValueError("shared runtime does not support Compose volume inheritance")
51
+ # A sidecar can also join main's PID namespace and enter its mount
52
+ # namespace. Apply the privilege boundary to the entire composition.
53
+ for service in services.values():
54
+ if service.get("privileged") or any(str(cap).upper().removeprefix("CAP_") in {"ALL", "SYS_ADMIN"} for cap in (service.get("cap_add") or [])):
55
+ raise ValueError("shared runtime requires unprivileged services without CAP_SYS_ADMIN")
56
+ config = services["main"]
57
+ for mount in config.get("volumes") or []:
58
+ if isinstance(mount, dict):
59
+ target = mount.get("target")
60
+ elif isinstance(mount, str):
61
+ parts = mount.split(":")
62
+ target = parts[1] if len(parts) > 1 else parts[0]
63
+ else:
64
+ raise ValueError("shared runtime cannot validate candidate mounts")
65
+ if not isinstance(target, str):
66
+ raise ValueError("shared runtime cannot validate candidate mount target")
67
+ target = posixpath.normpath(target)
68
+ if any(target == reserved or target.startswith(reserved + "/") for reserved in TARGETS):
69
+ raise ValueError("task mount conflicts with a shared runtime installation")
70
+
71
+
72
+ def compose_mounts(sources: dict[str, str]) -> list[dict[str, Any]]:
73
+ return [{"type": "bind", "source": source.replace("$", "$$"), "target": target,
74
+ "read_only": True, "bind": {"create_host_path": False}}
75
+ for target, source in sources.items()]
76
+
77
+
78
+ def validate_mounts(inspected: Any, expected: dict[str, str]) -> None:
79
+ if not isinstance(inspected, dict) or not isinstance(inspected.get("mounts"), list):
80
+ raise RuntimeError("shared runtime Docker mount inspection is invalid")
81
+ if inspected.get("privileged") or any(str(c).upper().removeprefix("CAP_") in {"ALL", "SYS_ADMIN"} for c in (inspected.get("cap_add") or [])):
82
+ raise RuntimeError("shared runtime requires an unprivileged candidate without CAP_SYS_ADMIN")
83
+ found = {}
84
+ for mount in inspected["mounts"]:
85
+ target = mount.get("Destination", "")
86
+ if any(target.startswith(reserved + "/") for reserved in TARGETS):
87
+ raise RuntimeError("nested mount shadows a shared runtime installation")
88
+ if target in expected:
89
+ if target in found or mount.get("Type") != "bind" or mount.get("RW") is not False:
90
+ raise RuntimeError("shared runtime installation is not a unique read-only bind mount")
91
+ if mount.get("Source") != expected[target]:
92
+ raise RuntimeError("shared runtime bind source does not match its job")
93
+ found[target] = mount
94
+ if set(found) != set(expected):
95
+ raise RuntimeError("shared runtime installation mount is missing")
96
+
97
+
98
+ async def verify_environment(environment: Any, controller_payload: Path, artifact_directory: Path) -> bool:
99
+ expected = environment._hitch_shared_runtime
100
+ if expected is None:
101
+ return False
102
+ if expected != {CONTROLLER_TARGET: str(controller_payload), ARTIFACT_TARGET: str(artifact_directory)}:
103
+ raise RuntimeError("shared runtime environment and agent handoff disagree")
104
+ result = await environment._run_docker_compose_command(["ps", "--all", "--quiet", "main"])
105
+ identity = result.stdout.strip()
106
+ if not re.fullmatch(r"[a-f0-9]{64}", identity):
107
+ raise RuntimeError("shared runtime requires exactly one candidate container")
108
+ template = '{"mounts":{{json .Mounts}},"privileged":{{json .HostConfig.Privileged}},"cap_add":{{json .HostConfig.CapAdd}}}'
109
+ process = await asyncio.create_subprocess_exec(
110
+ "docker", "inspect", "--format", template, identity,
111
+ env=environment._compose_env_vars(),
112
+ stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL,
113
+ )
114
+ try:
115
+ stdout, _ = await asyncio.wait_for(process.communicate(), 30)
116
+ finally:
117
+ if process.returncode is None:
118
+ process.kill()
119
+ await process.wait()
120
+ if process.returncode != 0 or len(stdout) > 1024 * 1024:
121
+ raise RuntimeError("shared runtime Docker mount inspection failed")
122
+ validate_mounts(json.loads(stdout), expected)
123
+ return True
@@ -14,9 +14,9 @@ const key = process.env.HITCH_LOCAL_MODEL_TOKEN || process.env.OPENAI_API_KEY;
14
14
  if (!key) throw new Error('a model API credential is required for the model-call harness');
15
15
  const base = new URL(process.env.HITCH_LOCAL_MODEL_BASE_URL || process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1/');
16
16
  const loopback = base.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(base.hostname);
17
- const managedRunId = process.env.HITCH_MANAGED_RUN_ID || '';
18
- const managed = process.env.HITCH_MANAGED_LOCAL_INFERENCE === '1'
19
- && key === 'hitch-managed-local'
17
+ const managedRunId = process.env.HITCH_EXTERNAL_RUN_ID || '';
18
+ const managed = process.env.HITCH_EXTERNAL_ENDPOINT_BINDING
19
+ && key === 'hitch-external-endpoint'
20
20
  && /^run_[a-f0-9]{32}$/.test(managedRunId)
21
21
  && base.protocol === 'http:'
22
22
  && new RegExp(`^/[a-f0-9]{48}/${managedRunId}/openai/?$`).test(base.pathname);
@@ -27,7 +27,8 @@ for await (const chunk of process.stdin) {
27
27
  raw += chunk;
28
28
  if (Buffer.byteLength(raw) > 30 * 1024 * 1024) throw new Error('model input exceeds 30 MB');
29
29
  }
30
- const input = JSON.parse(raw);
30
+ let input;
31
+ try { input = JSON.parse(raw); } catch { input = { schema_version: '1', messages: [{ role: 'user', content: [{ type: 'input_text', text: raw }] }] }; }
31
32
  const allowed = new Set(['schema_version', 'messages', 'max_output_tokens', 'reasoning_effort']);
32
33
  if (input.schema_version !== '1' || Object.keys(input).some(k => !allowed.has(k)) || !Array.isArray(input.messages) || !input.messages.length) throw new Error('invalid model input');
33
34
  for (const message of input.messages) {
@@ -46,18 +47,18 @@ if (!Number.isSafeInteger(maxTokens) || maxTokens < 1 || maxTokens > 131072) thr
46
47
  if (input.reasoning_effort !== undefined && !['none', 'minimal', 'low', 'medium', 'high', 'xhigh'].includes(input.reasoning_effort)) throw new Error('invalid reasoning effort');
47
48
  const emit = event => console.log(JSON.stringify(event));
48
49
  emit({ type: 'session.created', session_id: randomUUID() });
49
- const response = await fetch(new URL('responses', base), {
50
+ const responses = process.env.HITCH_MODEL_API !== 'chat-completions';
51
+ const response = await fetch(new URL(responses ? 'responses' : 'chat/completions', base), {
50
52
  redirect: 'error',
51
53
  method: 'POST', headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' },
52
- body: JSON.stringify({ model, input: input.messages, tools: [], tool_choice: 'none', store: false,
53
- max_output_tokens: maxTokens, ...(input.reasoning_effort ? { reasoning: { effort: input.reasoning_effort } } : {}) }),
54
+ body: JSON.stringify(responses ? { model, input: input.messages, tools: [], tool_choice: 'none', store: false, max_output_tokens: maxTokens, ...(input.reasoning_effort ? { reasoning: { effort: input.reasoning_effort } } : {}) } : { model, messages: input.messages.map(m => ({ role: m.role, content: m.content.map(p => p.text || '').join('\n') })), max_tokens: maxTokens }),
54
55
  signal: AbortSignal.timeout(3600000),
55
56
  });
56
57
  if (!response.ok) throw new Error(`model API returned HTTP ${response.status}`);
57
58
  const body = await response.json();
58
- if (!['completed', 'incomplete'].includes(body.status) || !Array.isArray(body.output)) throw new Error('invalid model completion');
59
- if (body.output.some(item => !['message', 'reasoning'].includes(item.type))) throw new Error('model returned a prohibited tool/action item');
60
- const output = body.output.filter(item => item.type === 'message').flatMap(item => item.content || []).map(part => part.type === 'output_text' ? part.text : part.type === 'refusal' ? part.refusal : '').join('\n');
59
+ if (responses && (!['completed', 'incomplete'].includes(body.status) || !Array.isArray(body.output)) || !responses && !Array.isArray(body.choices)) throw new Error('invalid model completion');
60
+ if (responses && body.output.some(item => !['message', 'reasoning'].includes(item.type))) throw new Error('model returned a prohibited tool/action item');
61
+ const output = !responses ? body.choices.map(c => c.message?.content || '').join('\n') : body.output.filter(item => item.type === 'message').flatMap(item => item.content || []).map(part => part.type === 'output_text' ? part.text : part.type === 'refusal' ? part.refusal : '').join('\n');
61
62
  // An empty answer (including token exhaustion) remains a gradable model
62
63
  // outcome. Provider/transport failures above remain infrastructure errors.
63
64
  emit({ type: 'provider.response', response: body });
@@ -9,11 +9,13 @@ if (args.length !== 2 || args[0] !== '--model' || !args[1]) throw new Error('Usa
9
9
  if (process.env.HITCH_HARBOR_INTERNAL !== '1') throw new Error('training-tool requires a Harbor task container');
10
10
  const binding = JSON.parse(process.env.HITCH_TRAINING_BINDING || 'null');
11
11
  const training = process.env.HITCH_TRAINING_EXTERNAL === '1';
12
- if (!training && process.env.HITCH_MANAGED_LOCAL_INFERENCE !== '1') throw new Error('explicit Hitch model binding required');
13
- const runId = training ? process.env.HITCH_TRAINING_RUN_ID : process.env.HITCH_MANAGED_RUN_ID;
12
+ const external = JSON.parse(process.env.HITCH_EXTERNAL_ENDPOINT_BINDING || 'null');
13
+ if (!training && !external) throw new Error('explicit Hitch model binding required');
14
+ const runId = training ? process.env.HITCH_TRAINING_RUN_ID : process.env.HITCH_EXTERNAL_RUN_ID;
14
15
  const base = new URL(process.env.OPENAI_BASE_URL || '');
15
16
  if (!/^run_[a-f0-9]{32}$/.test(runId || '') || base.protocol !== 'http:' || base.username || base.password || base.search || base.hash
16
17
  || !new RegExp(`^/[a-f0-9]{48}/${runId}/openai/?$`).test(base.pathname)) throw new Error('invalid run-scoped endpoint');
18
+ if (!training && (external.api !== 'chat-completions' || args[1] !== external.endpoint_ref)) throw new Error('wrong ordinary endpoint binding');
17
19
  if (training && args[1] !== `training/${binding?.binding_id}`) throw new Error('wrong training binding');
18
20
  if (!base.pathname.endsWith('/')) base.pathname += '/';
19
21
  const maxTokens = training ? binding.max_output_tokens : Number(process.env.HITCH_LOCAL_MAX_OUTPUT_TOKENS || 2048);
@@ -21,8 +23,11 @@ const maxSteps = training ? binding.max_episode_steps : Number(process.env.HITCH
21
23
  if (![maxTokens, maxSteps].every(n => Number.isSafeInteger(n) && n > 0)) throw new Error('invalid harness budget');
22
24
  let prompt = '';
23
25
  for await (const chunk of process.stdin) { prompt += chunk; if (Buffer.byteLength(prompt) > 8 * 1024 * 1024) throw new Error('prompt exceeds 8 MiB'); }
24
- const messages = [{ role: 'user', content: prompt }];
25
- const tools = [{ type: 'function', function: { name: 'bash', description: 'Run a command in the task container.', parameters: { type: 'object', properties: { command: { type: 'string' } }, required: ['command'], additionalProperties: false } } }];
26
+ const messages = [
27
+ { role: 'system', content: `You are operating a live terminal in the task container. The current working directory is ${process.cwd()}. Use the bash tool to complete the user's task autonomously. Inspect the actual files and command output before choosing paths or actions. Keep commands and scripts short and focused. Run the commands needed to make the requested changes, check their results, and correct errors. Do not substitute instructions or placeholder commands for performing the work. Give your final response only after checking that the requested result exists.` },
28
+ { role: 'user', content: prompt },
29
+ ];
30
+ const tools = [{ type: 'function', function: { name: 'bash', description: 'Run a command in the task container, with a 120-second timeout and up to 4096 characters of output.', parameters: { type: 'object', properties: { command: { type: 'string' } }, required: ['command'], additionalProperties: false } } }];
26
31
  const emit = event => console.log(JSON.stringify(event));
27
32
  let child;
28
33
  const abort = new AbortController();
@@ -36,7 +41,7 @@ for (let step = 0; step < maxSteps; step++) {
36
41
  method: 'POST', redirect: 'error', headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': `${runId}-${step}` },
37
42
  body: JSON.stringify({ model: args[1], messages, tools, stream: false, max_tokens: maxTokens }), signal: abort.signal,
38
43
  });
39
- if (!response.ok) throw new Error(`training gateway returned HTTP ${response.status}`);
44
+ if (!response.ok) throw new Error(`model endpoint returned HTTP ${response.status}`);
40
45
  const body = await response.json(); abort.signal.throwIfAborted(); const choice = body.choices?.[0];
41
46
  if (!choice?.message || body.choices.length !== 1) throw new Error('invalid completion');
42
47
  emit({ type: 'provider.response', response: body, receipt_id: response.headers.get('x-gear-receipt-id') });
@@ -51,18 +56,54 @@ for (let step = 0; step < maxSteps; step++) {
51
56
  if (choice.finish_reason !== 'tool_calls') throw new Error('missing tool terminal state');
52
57
  for (const call of calls) {
53
58
  abort.signal.throwIfAborted();
54
- if (call.function?.name !== 'bash' || typeof call.id !== 'string') throw new Error('unsupported tool');
55
- const input = JSON.parse(call.function.arguments);
56
- if (typeof input.command !== 'string' || Object.keys(input).join(',') !== 'command') throw new Error('invalid bash arguments');
59
+ if (typeof call.id !== 'string') throw new Error('missing tool call identity');
60
+ let input; let toolError;
61
+ if (call.function?.name !== 'bash') toolError = 'Unknown tool. The available tool is bash, with arguments {"command":"shell command"}.';
62
+ else {
63
+ try { input = JSON.parse(call.function.arguments); }
64
+ catch { toolError = 'Invalid JSON arguments. bash expects {"command":"shell command"}.'; }
65
+ if (!toolError && (!input || typeof input !== 'object' || Array.isArray(input)
66
+ || typeof input.command !== 'string' || Object.keys(input).join(',') !== 'command'))
67
+ toolError = 'Invalid arguments. bash expects only a string command field.';
68
+ }
69
+ if (toolError) {
70
+ const result = `Tool error: ${toolError} No command was executed.`;
71
+ messages.push({ role: 'tool', tool_call_id: call.id, content: result });
72
+ emit({ type: 'tool.rejected', call_id: call.id, name: call.function?.name ?? null, error: toolError });
73
+ continue;
74
+ }
57
75
  emit({ type: 'tool.started', call_id: call.id, name: 'bash', arguments: input });
58
76
  const result = await new Promise((resolve, reject) => {
59
- let output = ''; let truncated = false;
60
- child = spawn('/bin/bash', ['-lc', input.command], { detached: true, stdio: ['ignore', 'pipe', 'pipe'] });
61
- const append = data => { const remaining = 32768 - output.length; if (remaining > 0) output += data.toString().slice(0, remaining); if (data.length > remaining) truncated = true; };
62
- child.stdout.on('data', append); child.stderr.on('data', append);
63
- const timer = setTimeout(killTool, 30000);
64
- child.once('error', error => { clearTimeout(timer); reject(error); });
65
- child.once('close', code => { clearTimeout(timer); child = undefined; resolve(`exit=${code}\n${output}${truncated ? '\n[tool output truncated]' : ''}`); });
77
+ let output = ''; let truncated = false; let timedOut = false;
78
+ const tool = spawn('/bin/bash', ['-lc', input.command], { detached: true, stdio: ['ignore', 'pipe', 'pipe'] });
79
+ child = tool;
80
+ let settled = false; let postExitTimer;
81
+ const append = data => { if (settled) return; const remaining = 4096 - output.length; if (remaining > 0) output += data.toString().slice(0, remaining); if (data.length > remaining) truncated = true; };
82
+ tool.stdout.on('data', append); tool.stderr.on('data', append);
83
+ const timer = setTimeout(() => { timedOut = true; killTool(); }, 120000);
84
+ const finish = (code, background = false) => {
85
+ if (settled) return;
86
+ settled = true; clearTimeout(timer); clearTimeout(postExitTimer);
87
+ if (child === tool) child = undefined;
88
+ resolve(`exit=${code}\n${output}${truncated ? '\n[tool output truncated]' : ''}${timedOut ? '\n[command timed out after 120 seconds]' : ''}${background ? '\n[command exited; background process kept output streams open]' : ''}`);
89
+ };
90
+ tool.once('error', error => {
91
+ if (settled) return;
92
+ settled = true; clearTimeout(timer); clearTimeout(postExitTimer);
93
+ if (child === tool) child = undefined;
94
+ reject(error);
95
+ });
96
+ tool.once('exit', code => {
97
+ clearTimeout(timer);
98
+ // Let ordinary output drain; daemons must not hold the command open.
99
+ postExitTimer = setTimeout(() => {
100
+ finish(code, true);
101
+ // Keep draining and discard later logs while the harness is alive.
102
+ // Unref lets it exit; Harbor owns cleanup of the task's processes.
103
+ tool.stdout.unref(); tool.stderr.unref(); tool.unref();
104
+ }, 1000);
105
+ });
106
+ tool.once('close', code => finish(code));
66
107
  });
67
108
  messages.push({ role: 'tool', tool_call_id: call.id, content: result });
68
109
  emit({ type: 'tool.completed', call_id: call.id, output: result });
@@ -0,0 +1,24 @@
1
+ Copyright (c) Squirrel Chat et al., All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this
7
+ list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ 3. Neither the name of the copyright holder nor the names of its contributors
12
+ may be used to endorse or promote products derived from this software without
13
+ specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.