agent-hitch 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -256
- package/README.zh-CN.md +84 -235
- package/dist/src/artifacts/handoff.js +12 -0
- package/dist/src/artifacts/handoff.js.map +1 -0
- package/dist/src/artifacts/index.js +2 -0
- package/dist/src/artifacts/index.js.map +1 -1
- package/dist/src/artifacts/store.js +72 -2
- package/dist/src/artifacts/store.js.map +1 -1
- package/dist/src/backends/harbor/backend.js +22 -3
- package/dist/src/backends/harbor/backend.js.map +1 -1
- package/dist/src/cli/commands/run.js +65 -3
- package/dist/src/cli/commands/run.js.map +1 -1
- package/dist/src/evals/service.js +57 -1
- package/dist/src/evals/service.js.map +1 -1
- package/dist/src/runs/executor.js +10 -4
- package/dist/src/runs/executor.js.map +1 -1
- package/docs/schemas/eval-result.schema.json +14 -0
- package/integrations/harbor/hitch_harbor_agent.py +426 -13
- package/package.json +1 -1
package/README.zh-CN.md
CHANGED
|
@@ -6,171 +6,126 @@
|
|
|
6
6
|
|
|
7
7
|
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**让智能体 Harness 的每次运行都可复现。**
|
|
10
10
|
|
|
11
|
-
Hitch
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Git 可以标识发生变化的 Harness 源代码,而 Hitch 将这个身份贯穿构建与
|
|
16
|
-
执行的全过程:
|
|
11
|
+
Hitch 可以从确定的软件版本或 Git 提交运行 Codex、Claude Code、Pi、OpenCode
|
|
12
|
+
和 DeepSeek Harness。每次运行都会关联 Harness 版本、不可变制品、工作区、
|
|
13
|
+
轨迹、日志和评测证据。
|
|
17
14
|
|
|
18
15
|
```text
|
|
19
|
-
|
|
20
|
-
-> 已解析版本
|
|
21
|
-
-> 已准备制品
|
|
22
|
-
-> 运行 / 评测
|
|
23
|
-
-> 轨迹
|
|
24
|
-
-> 反馈与评测证据
|
|
25
|
-
|
|
26
|
-
Hitch 控制器
|
|
27
|
-
-> 内容寻址的运行时包
|
|
28
|
-
-> 由容器化评测引用
|
|
16
|
+
版本或提交 -> 不可变制品 -> 运行或评测 -> 可验证证据
|
|
29
17
|
```
|
|
30
18
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Hitch 的上层系统负责。
|
|
19
|
+
```bash
|
|
20
|
+
npm install --global agent-hitch
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
hitch run \
|
|
23
|
+
--harness codex@version:0.92.0 \
|
|
24
|
+
--prompt "Inspect this repository"
|
|
25
|
+
```
|
|
38
26
|
|
|
39
|
-
|
|
27
|
+
> **状态:** pre-alpha。核心运行、来源追踪、轨迹、反馈、守护进程和 Harbor
|
|
28
|
+
> 评测链路已经实现。
|
|
40
29
|
|
|
41
|
-
|
|
42
|
-
版本、构建产物、控制器代码、工作区模式、原生适配器,以及机器上可变的
|
|
43
|
-
已安装可执行文件。如果分数或记录没有关联这些身份,就很难审计,更难复现。
|
|
30
|
+
## 为什么使用 Hitch?
|
|
44
31
|
|
|
45
|
-
Hitch
|
|
32
|
+
Git 告诉你哪些源码发生了变化,Hitch 则告诉你究竟运行了什么,以及它产生了
|
|
33
|
+
哪些证据。
|
|
46
34
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
| 已准备制品 | 经过验证、采用内容寻址的可运行构建产物 |
|
|
52
|
-
| 控制器运行时 | 上传到容器化评测中的确切 Hitch 运行时 |
|
|
53
|
-
| 运行或评测记录 | 请求、工作区、生命周期、结果以及各身份之间的关联 |
|
|
54
|
-
| 规范化轨迹 | 采用稳定、兼容 DSH 格式记录的智能体消息与工具活动 |
|
|
55
|
-
| 反馈与评测证据 | 消息级反馈、验证器输出、奖励及后端记录 |
|
|
35
|
+
- **复现:** 从确定的软件包版本或源码提交重新运行。
|
|
36
|
+
- **比较:** 通过统一的执行契约比较不同 Harness 和模型。
|
|
37
|
+
- **审计:** 用不可变制品、原生事件、规范化轨迹、日志、反馈和评测记录验证
|
|
38
|
+
结果。
|
|
56
39
|
|
|
57
|
-
|
|
58
|
-
|
|
40
|
+
Hitch 适合构建智能体评测、Harness 实验、Coding Agent 基础设施和自动晋级
|
|
41
|
+
流水线的团队。
|
|
59
42
|
|
|
60
43
|
## 快速开始
|
|
61
44
|
|
|
62
|
-
Hitch 要求 Node.js 22
|
|
45
|
+
Hitch 要求 Node.js 22 或更高版本。
|
|
63
46
|
|
|
64
47
|
```bash
|
|
65
48
|
npm install --global agent-hitch
|
|
66
49
|
hitch --version
|
|
67
|
-
hitch list --json
|
|
68
50
|
```
|
|
69
51
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
hitch resolve codex@version:0.92.0 --json
|
|
74
|
-
hitch prepare codex@version:0.92.0 --json
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
在隔离的 Git worktree 中运行这个确定版本:
|
|
52
|
+
在隔离的 Git worktree 中运行一个确定的 Harness 版本:
|
|
78
53
|
|
|
79
54
|
```bash
|
|
80
55
|
hitch run \
|
|
81
56
|
--harness codex@version:0.92.0 \
|
|
82
|
-
--model gpt-5.6-terra \
|
|
83
|
-
--cwd /workspace/project \
|
|
84
57
|
--workspace-mode worktree \
|
|
85
|
-
--prompt
|
|
58
|
+
--prompt "Inspect this repository" \
|
|
86
59
|
--output jsonl
|
|
87
60
|
```
|
|
88
61
|
|
|
89
|
-
|
|
90
|
-
进程日志、规范化事件和规范化轨迹。可以通过 CLI 检查轨迹:
|
|
62
|
+
输出中包含 run ID,可以用它查看保存的轨迹:
|
|
91
63
|
|
|
92
64
|
```bash
|
|
93
|
-
hitch trajectory inspect RUN_ID
|
|
65
|
+
hitch trajectory inspect RUN_ID
|
|
94
66
|
```
|
|
95
67
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
npm install
|
|
100
|
-
npm run check
|
|
101
|
-
npm link
|
|
102
|
-
hitch list --json
|
|
103
|
-
```
|
|
68
|
+
每次运行的 manifest、结果、事件、日志和轨迹都会保存在
|
|
69
|
+
`~/.hitch/runs/RUN_ID` 下。
|
|
104
70
|
|
|
105
|
-
## Harness
|
|
71
|
+
## 固定任意 Harness 版本
|
|
106
72
|
|
|
107
|
-
|
|
108
|
-
不可变身份,并在 Hitch 的制品存储中完成准备。
|
|
73
|
+
每次运行都会显式选择 Harness:
|
|
109
74
|
|
|
110
75
|
```bash
|
|
111
|
-
#
|
|
76
|
+
# 对本机已经安装的可执行文件生成指纹并运行。
|
|
112
77
|
hitch run --harness codex@installed --prompt "Inspect this repository"
|
|
113
78
|
|
|
114
|
-
#
|
|
115
|
-
hitch resolve codex@version:0.92.0 --json
|
|
116
|
-
hitch prepare codex@version:0.92.0 --json
|
|
79
|
+
# 解析并运行一个确定的已发布版本。
|
|
117
80
|
hitch run --harness codex@version:0.92.0 --prompt "Inspect this repository"
|
|
118
81
|
|
|
119
|
-
#
|
|
82
|
+
# 从已注册的上游仓库构建并运行一个确定的提交。
|
|
120
83
|
hitch run --harness codex@commit:0123456789abcdef --prompt "Inspect this repository"
|
|
121
|
-
|
|
122
|
-
# 从本地 Harness 仓库构建一个干净的提交。
|
|
123
|
-
hitch run \
|
|
124
|
-
--harness 'pi@git+file:///workspace/pi#0123456789abcdef' \
|
|
125
|
-
--prompt "Inspect this repository"
|
|
126
84
|
```
|
|
127
85
|
|
|
128
|
-
|
|
129
|
-
|
|
86
|
+
| Harness | 已安装版本 | 确定的软件包版本 | 源码提交 |
|
|
87
|
+
| --- | :---: | :---: | :---: |
|
|
88
|
+
| Codex | ✓ | ✓ | ✓ |
|
|
89
|
+
| Claude Code | ✓ | ✓ | — |
|
|
90
|
+
| Pi | ✓ | ✓ | ✓ |
|
|
91
|
+
| OpenCode | ✓ | ✓ | — |
|
|
92
|
+
| DeepSeek Harness | ✓ | ✓ | ✓ |
|
|
130
93
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
与 OpenCode 目前支持已安装版本和确定的软件包版本。
|
|
94
|
+
确定的版本和提交会被准备为经过验证、采用内容寻址的制品,并从 Hitch 的本地
|
|
95
|
+
缓存中复用。已安装的可执行文件适合本地工作;需要可移植性时,应使用不可变
|
|
96
|
+
引用。
|
|
135
97
|
|
|
136
|
-
|
|
137
|
-
命令。内容寻址让制品可以审计和缓存,但不会让不可信的构建代码变得安全。
|
|
98
|
+
## 每次运行都会留下证据
|
|
138
99
|
|
|
139
|
-
|
|
100
|
+
Hitch 记录从请求到结果的完整链路:
|
|
140
101
|
|
|
141
|
-
|
|
102
|
+
- 请求的引用及解析后的不可变版本;
|
|
103
|
+
- 经过验证、采用内容寻址的可运行制品;
|
|
104
|
+
- 工作区、模型身份、生命周期与最终结果;
|
|
105
|
+
- 规范化控制面事件与原始进程日志;
|
|
106
|
+
- 支持场景下经过脱敏的 provider-native 事件;
|
|
107
|
+
- 采用 SHA-256 绑定文件、兼容 DSH 的规范化轨迹;
|
|
108
|
+
- 带版本的消息反馈与评测证据。
|
|
142
109
|
|
|
143
|
-
|
|
144
|
-
取消和最终状态;
|
|
145
|
-
- 支持结构化输出的 adapter 会先保存经过显式脱敏的 provider-native 事件,
|
|
146
|
-
兼容 DSH 的规范化轨迹则作为派生视图继续提供;
|
|
147
|
-
- `trajectory.ref.json` V2 通过相对路径、文件角色、字节数与 SHA-256 摘要
|
|
148
|
-
绑定完整轨迹文件集;
|
|
149
|
-
- 反馈 sidecar 可以为助手消息附加带版本的正向或负向评分与备注,而无需
|
|
150
|
-
改写不可变轨迹。
|
|
110
|
+
可以通过 CLI 查询运行,并在不改写轨迹的情况下附加反馈:
|
|
151
111
|
|
|
152
112
|
```bash
|
|
153
|
-
hitch
|
|
154
|
-
hitch runs list --context-kind benchmark_task --json
|
|
155
|
-
hitch compare model --benchmark BENCHMARK --task TASK --json
|
|
113
|
+
hitch runs list --json
|
|
156
114
|
hitch feedback list RUN_ID --json
|
|
157
115
|
hitch feedback put RUN_ID \
|
|
158
116
|
--message MESSAGE_ID \
|
|
159
117
|
--rating positive \
|
|
160
|
-
--note "修改保持了足够聚焦"
|
|
161
|
-
--json
|
|
118
|
+
--note "修改保持了足够聚焦"
|
|
162
119
|
```
|
|
163
120
|
|
|
164
|
-
带版本的机器接口 Schema 位于 [`docs/schemas`](docs/schemas)
|
|
165
|
-
拒绝未知的请求字段,并在守护进程 HTTP 边界两侧保留类型化错误。
|
|
121
|
+
带版本的机器接口 Schema 位于 [`docs/schemas`](docs/schemas)。
|
|
166
122
|
|
|
167
|
-
##
|
|
123
|
+
## 可复现的智能体评测
|
|
168
124
|
|
|
169
|
-
Hitch
|
|
170
|
-
|
|
125
|
+
Hitch 集成了 [Harbor](https://github.com/harbor-framework/harbor),可以在 Docker
|
|
126
|
+
中评测确定且可移植的 Harness 版本:
|
|
171
127
|
|
|
172
128
|
```bash
|
|
173
|
-
# 将固定版本的 Harbor 安装到 ~/.hitch/tools,不修改系统 Python。
|
|
174
129
|
hitch eval setup harbor
|
|
175
130
|
hitch eval doctor
|
|
176
131
|
|
|
@@ -178,157 +133,51 @@ hitch eval run \
|
|
|
178
133
|
--backend harbor \
|
|
179
134
|
--dataset terminal-bench@2.0 \
|
|
180
135
|
--harness codex@version:0.92.0 \
|
|
181
|
-
--model openai/gpt-5.6
|
|
182
|
-
--attempts 1 \
|
|
183
|
-
--max-concurrent 4
|
|
184
|
-
|
|
185
|
-
hitch eval list
|
|
186
|
-
hitch eval inspect EVAL_ID --json
|
|
136
|
+
--model openai/gpt-5.6
|
|
187
137
|
```
|
|
188
138
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
并在 `/app` 中执行选定的 Harness 版本。生成的评测记录会关联请求、已解析
|
|
192
|
-
版本、控制器运行时、后端配置与日志、规范化结果、奖励摘要和轨迹证据。
|
|
193
|
-
|
|
194
|
-
评测接受确定的 `version:`、已注册远端的 `commit:`,以及显式本地
|
|
195
|
-
`git+file:///绝对路径#<完整小写commit>` 引用。本地 Git 评测只会将该提交
|
|
196
|
-
所需并经过校验的 Git 对象包传入 Harbor trial;未提交文件、Git 配置、凭证
|
|
197
|
-
和无关历史不会被携带。仓库必须干净,缩写 commit、分支、tag、`HEAD` 和
|
|
198
|
-
已安装可执行文件会被拒绝。常用模型供应商凭证通过环境变量引用转发;使用
|
|
199
|
-
`--pass-env NAME` 可以额外传入一个环境变量。
|
|
200
|
-
|
|
201
|
-
有关安装、可移植性规则和执行边界,请参阅
|
|
139
|
+
每次评测都会关联已解析的 Harness 版本、采用内容寻址的 Hitch 控制器运行时、
|
|
140
|
+
后端配置、奖励、日志和轨迹证据。安装方法和可移植性规则参见
|
|
202
141
|
[Harbor 智能体评测](docs/evals.md)。
|
|
203
142
|
|
|
204
|
-
##
|
|
143
|
+
## 为自动化而设计
|
|
205
144
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
145
|
+
- 提供 JSON 和 JSONL 输出、带版本的 Schema 与类型化错误
|
|
146
|
+
- 支持直接执行或具有并发上限的持久化守护进程
|
|
147
|
+
- 支持共享、detached Git worktree 和独立副本工作区
|
|
148
|
+
- 支持超时、取消、进程树清理和中断运行恢复
|
|
149
|
+
- 通过 `--root <path>` 或 `HITCH_ROOT` 隔离本地状态
|
|
209
150
|
|
|
210
|
-
|
|
211
|
-
调用方 -> Hitch CLI / 守护进程 -> 共享运行引擎 -> Codex CLI
|
|
212
|
-
\----> Claude Code
|
|
213
|
-
\----> Pi
|
|
214
|
-
\----> OpenCode
|
|
215
|
-
\----> DeepSeek Harness
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
直接 CLI 与持久化守护进程使用同一个运行引擎,因此版本解析、记录、超时、
|
|
219
|
-
取消和事件行为不会发生偏移。当前运行时提供:
|
|
220
|
-
|
|
221
|
-
- 可执行文件发现、版本探测和可执行文件指纹;
|
|
222
|
-
- 确定的软件包版本与 Git 提交解析;
|
|
223
|
-
- 带完整性校验缓存的不可变制品;
|
|
224
|
-
- 输出规范化 JSONL 事件的直接执行;
|
|
225
|
-
- 具备并发上限的持久化本地守护进程;
|
|
226
|
-
- 队列中及运行中任务的取消、超时与完整进程树清理;
|
|
227
|
-
- 受管理的共享、Git worktree 和独立副本工作区模式;
|
|
228
|
-
- 原子的 manifest 与结果,以及原始 stdout 和 stderr 日志;
|
|
229
|
-
- 守护进程重启后对中断记录的保守恢复。
|
|
230
|
-
|
|
231
|
-
需要长期运行的队列时,可以通过守护进程执行:
|
|
151
|
+
需要长期执行队列时,可以启动守护进程:
|
|
232
152
|
|
|
233
153
|
```bash
|
|
234
154
|
hitch daemon start --max-concurrent 4
|
|
235
|
-
|
|
236
|
-
hitch run \
|
|
237
|
-
--daemon \
|
|
238
|
-
--harness codex@version:0.92.0 \
|
|
239
|
-
--cwd /workspace/project \
|
|
240
|
-
--prompt-file task.md \
|
|
241
|
-
--output jsonl
|
|
242
|
-
|
|
243
|
-
hitch daemon status --json
|
|
244
|
-
hitch daemon stop
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
也可以异步提交并取消:
|
|
248
|
-
|
|
249
|
-
```bash
|
|
250
|
-
hitch daemon submit \
|
|
251
|
-
--harness claude@version:EXACT_VERSION \
|
|
252
|
-
--cwd /workspace/project \
|
|
253
|
-
--prompt-file task.md
|
|
254
|
-
|
|
255
|
-
hitch daemon cancel RUN_ID
|
|
155
|
+
hitch run --daemon --harness codex@version:0.92.0 --prompt-file task.md
|
|
256
156
|
```
|
|
257
157
|
|
|
258
|
-
## 状态与隔离
|
|
259
|
-
|
|
260
|
-
状态默认存储在 `~/.hitch` 下。可以使用 `--root <path>` 或 `HITCH_ROOT`
|
|
261
|
-
修改位置。每个 root 都拥有独立的制品存储、控制器运行时存储、运行与评测
|
|
262
|
-
记录、守护进程令牌和队列。
|
|
263
|
-
|
|
264
|
-
可以通过 `HITCH_CODEX_PATH`、`HITCH_CLAUDE_PATH`、`HITCH_PI_PATH`、
|
|
265
|
-
`HITCH_OPENCODE_PATH` 和 `HITCH_DEEPSEEK_PATH` 覆盖原生可执行文件路径。
|
|
266
|
-
|
|
267
|
-
工作区模式会明确数据修改的边界:
|
|
268
|
-
|
|
269
|
-
- `shared` 直接在源码目录中运行;
|
|
270
|
-
- `worktree` 从干净的 `HEAD` 创建 detached Git worktree;
|
|
271
|
-
- `copy` 创建独立的文件系统副本。
|
|
272
|
-
|
|
273
|
-
工作区隔离并不等同于进程安全沙箱。
|
|
274
|
-
|
|
275
|
-
## 设计原则
|
|
276
|
-
|
|
277
|
-
- **默认可追溯:** 每次运行都会关联请求的引用、已解析版本、可运行制品、
|
|
278
|
-
执行记录与证据。
|
|
279
|
-
- **不可变解析:** 在准备或执行前将可变输入解析为不可变身份,并记录该
|
|
280
|
-
身份。
|
|
281
|
-
- **内容寻址复用:** 通过摘要复用经过验证的制品与控制器运行时,而不是为
|
|
282
|
-
每次运行重复复制。
|
|
283
|
-
- **不以有损抽象换取证据统一:** 稳定的规范化记录与原始 Harness 输出并存,
|
|
284
|
-
并明确记录轨迹保真度。
|
|
285
|
-
- **机器优先的接口:** 结构化输出、带版本的 Schema 和类型化错误构成公共
|
|
286
|
-
接口。
|
|
287
|
-
- **策略位于 Hitch 之上:** 变更、排序、晋级与回滚都是调用方系统的显式
|
|
288
|
-
决策。
|
|
289
|
-
- **安全中断:** 取消操作覆盖完整子进程树,涉及工作区修改的中断运行绝不
|
|
290
|
-
隐式重放。
|
|
291
|
-
|
|
292
|
-
## 计划中的工作
|
|
293
|
-
|
|
294
|
-
- [x] 基于 run 证据的严格模型/Harness 比较原语
|
|
295
|
-
- [ ] 命名的候选与 champion 引用
|
|
296
|
-
- [ ] 不内嵌晋级策略的晋级与回滚记录
|
|
297
|
-
- [ ] 远端制品与证据同步
|
|
298
|
-
- [ ] 更多 Harness 适配器
|
|
299
|
-
- [ ] 更多 API 供应商支持
|
|
300
|
-
- [ ] 本地模型推理支持
|
|
301
|
-
|
|
302
|
-
## 动态
|
|
303
|
-
|
|
304
|
-
- **2026-08-20:** Hitch 0.2 开发版将项目迁移到编译为 ESM 的严格
|
|
305
|
-
TypeScript,加入共享 SHA-256 控制器运行时缓存,为每次运行记录兼容 DSH
|
|
306
|
-
的规范化轨迹,并引入与生命周期绑定的消息反馈。
|
|
307
|
-
- **2026-08-13:** Hitch 加入对 DeepSeek Harness 的支持。
|
|
308
|
-
|
|
309
158
|
## 文档
|
|
310
159
|
|
|
311
|
-
- [
|
|
312
|
-
- [设计文档](docs/design.md)
|
|
313
|
-
- [智能体守护进程分析与移植](docs/daemon.md)
|
|
314
|
-
- [工作区隔离](docs/workspaces.md)
|
|
160
|
+
- [设计与架构](docs/design.md)
|
|
315
161
|
- [Harbor 评测](docs/evals.md)
|
|
162
|
+
- [工作区隔离](docs/workspaces.md)
|
|
163
|
+
- [守护进程设计](docs/daemon.md)
|
|
164
|
+
- [Hitch 0.2 开发规范](docs/hitch-0.2-development-spec.md)
|
|
316
165
|
- [发布流程](docs/releasing.md)
|
|
317
166
|
|
|
318
|
-
##
|
|
167
|
+
## 项目状态
|
|
319
168
|
|
|
320
|
-
|
|
321
|
-
|
|
169
|
+
Hitch 是 pre-alpha 阶段的本地版本与证据层。它是 Git 的补充,目前不提供远端
|
|
170
|
+
制品注册表、分支、标签、候选晋级或回滚策略。
|
|
322
171
|
|
|
323
|
-
|
|
172
|
+
远端制品同步、命名候选、晋级记录和更多 Harness 适配器已列入计划。
|
|
324
173
|
|
|
325
|
-
|
|
326
|
-
使用 [Harbor](https://github.com/harbor-framework/harbor) 作为评测后端。感谢
|
|
327
|
-
这两个项目提供的基础。
|
|
174
|
+
## 社区
|
|
328
175
|
|
|
329
|
-
|
|
176
|
+
加入 [Hitch Discord 社区](https://discord.gg/cZ4NBbHDk),提问、分享反馈,
|
|
177
|
+
并讨论智能体 Harness 基础设施。
|
|
330
178
|
|
|
331
|
-
|
|
179
|
+
Hitch 的设计受到 [Multica](https://github.com/multica-ai/multica) 启发,并使用
|
|
180
|
+
[Harbor](https://github.com/harbor-framework/harbor) 作为评测后端。
|
|
332
181
|
|
|
333
182
|
## 许可证
|
|
334
183
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HitchError } from "../foundation/index.js";
|
|
2
|
+
export function assertPreparedArtifactRevision(artifact, resolution) {
|
|
3
|
+
if (artifact.harness_id !== resolution.harness_id
|
|
4
|
+
|| artifact.revision_identity !== resolution.identity
|
|
5
|
+
|| artifact.resolved_revision?.identity !== resolution.identity) {
|
|
6
|
+
throw new HitchError("prepared artifact does not match the resolved harness revision", {
|
|
7
|
+
code: "artifact_integrity_mismatch",
|
|
8
|
+
exitCode: 5,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=handoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff.js","sourceRoot":"","sources":["../../../src/artifacts/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAIpD,MAAM,UAAU,8BAA8B,CAC5C,QAA0B,EAC1B,UAA4B;IAE5B,IACE,QAAQ,CAAC,UAAU,KAAK,UAAU,CAAC,UAAU;WAC1C,QAAQ,CAAC,iBAAiB,KAAK,UAAU,CAAC,QAAQ;WAClD,QAAQ,CAAC,iBAAiB,EAAE,QAAQ,KAAK,UAAU,CAAC,QAAQ,EAC/D,CAAC;QACD,MAAM,IAAI,UAAU,CAAC,gEAAgE,EAAE;YACrF,IAAI,EAAE,6BAA6B;YACnC,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { listPreparedArtifacts, prepareHarness } from "./preparer.js";
|
|
2
|
+
export { loadPreparedArtifact, preparedArtifactDirectory } from "./store.js";
|
|
3
|
+
export { assertPreparedArtifactRevision } from "./handoff.js";
|
|
2
4
|
export { resolveHarness } from "../revisions/index.js";
|
|
3
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
|
-
import { access, rename, rm } from "node:fs/promises";
|
|
3
|
+
import { access, lstat, rename, rm } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { SCHEMA_VERSION, atomicWriteJSON, ensureDir, readJSON, withFileLock } from "../foundation/index.js";
|
|
5
|
+
import { HitchError, SCHEMA_VERSION, atomicWriteJSON, ensureDir, readJSON, statePaths, withFileLock } from "../foundation/index.js";
|
|
6
6
|
import { artifactInvocation, artifactMatches } from "./integrity.js";
|
|
7
7
|
const RECIPE_VERSION = "1";
|
|
8
8
|
export function artifactManifest(resolved, adapter, artifactId, entrypoint, toolchain, extra = {}) {
|
|
@@ -81,6 +81,76 @@ export async function readCachedArtifact(paths, preparationKey, expectedRevision
|
|
|
81
81
|
}
|
|
82
82
|
return { ...manifest, ...artifactInvocation(manifest, directory), cache_hit: true };
|
|
83
83
|
}
|
|
84
|
+
export function preparedArtifactDirectory(root, artifactId) {
|
|
85
|
+
if (!/^sha256:[0-9a-f]{64}$/.test(artifactId)) {
|
|
86
|
+
throw new HitchError(`invalid artifact ID: ${artifactId}`, { code: "artifact_invalid", exitCode: 5 });
|
|
87
|
+
}
|
|
88
|
+
return path.join(statePaths(root).artifacts, artifactId.slice("sha256:".length));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Load an artifact handed across an isolation boundary. The caller supplies
|
|
92
|
+
* independently pinned identity and integrity values (from Harbor's job
|
|
93
|
+
* configuration); the uploaded manifest is never allowed to redefine them.
|
|
94
|
+
*/
|
|
95
|
+
export async function loadPreparedArtifact(directory, expected) {
|
|
96
|
+
const absolute = path.resolve(directory);
|
|
97
|
+
const info = await lstat(absolute).catch(() => null);
|
|
98
|
+
if (!info?.isDirectory() || info.isSymbolicLink()) {
|
|
99
|
+
throw new HitchError("prepared artifact handoff is not a regular directory", {
|
|
100
|
+
code: "artifact_integrity_mismatch",
|
|
101
|
+
exitCode: 5,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const manifestPath = path.join(absolute, "artifact.json");
|
|
105
|
+
const manifestInfo = await lstat(manifestPath).catch(() => null);
|
|
106
|
+
if (!manifestInfo?.isFile() || manifestInfo.isSymbolicLink()) {
|
|
107
|
+
throw new HitchError("prepared artifact handoff has no regular manifest", {
|
|
108
|
+
code: "artifact_integrity_mismatch",
|
|
109
|
+
exitCode: 5,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
let manifest;
|
|
113
|
+
try {
|
|
114
|
+
manifest = await readJSON(manifestPath, null);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
throw new HitchError("prepared artifact manifest is unreadable", {
|
|
118
|
+
code: "artifact_integrity_mismatch",
|
|
119
|
+
exitCode: 5,
|
|
120
|
+
cause: error,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (!manifest
|
|
124
|
+
|| manifest.artifact_id !== expected.artifact_id
|
|
125
|
+
|| manifest.artifact_integrity !== expected.artifact_integrity
|
|
126
|
+
|| manifest.entrypoint_integrity !== expected.entrypoint_integrity
|
|
127
|
+
|| manifest.harness_id !== expected.harness_id
|
|
128
|
+
|| manifest.revision_identity !== expected.revision_identity
|
|
129
|
+
|| manifest.platform !== expected.platform
|
|
130
|
+
|| manifest.resolved_revision?.harness_id !== expected.harness_id
|
|
131
|
+
|| manifest.resolved_revision?.identity !== expected.revision_identity) {
|
|
132
|
+
throw new HitchError("prepared artifact handoff does not match its job-pinned identity", {
|
|
133
|
+
code: "artifact_integrity_mismatch",
|
|
134
|
+
exitCode: 5,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const currentPlatform = `${process.platform}-${process.arch}`;
|
|
138
|
+
if (manifest.platform !== currentPlatform) {
|
|
139
|
+
throw new HitchError(`prepared artifact platform ${manifest.platform} is incompatible with ${currentPlatform}`, {
|
|
140
|
+
code: "artifact_platform_mismatch",
|
|
141
|
+
exitCode: 5,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (manifest.source_type === "installed" || !await artifactMatches(absolute, manifest)) {
|
|
145
|
+
throw new HitchError("prepared artifact handoff failed content verification", {
|
|
146
|
+
code: "artifact_integrity_mismatch",
|
|
147
|
+
exitCode: 5,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const invocation = artifactInvocation(manifest, absolute);
|
|
151
|
+
await access(invocation.entrypoint_args[0] || invocation.executable, manifest.launcher === "node" ? constants.R_OK : constants.X_OK);
|
|
152
|
+
return { ...manifest, ...invocation, cache_hit: true };
|
|
153
|
+
}
|
|
84
154
|
export async function withArtifactLock(paths, key, operation, options = {}) {
|
|
85
155
|
return withFileLock(paths.artifactLocks, key, operation, options);
|
|
86
156
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/artifacts/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/artifacts/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,11 +2,12 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { createWriteStream } from "node:fs";
|
|
3
3
|
import { readdir, stat } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { HitchError, atomicWriteJSON, consumeLines, detectVersion, ensureDir, fingerprintExecutable, invalidInput, packageRoot, readJSON, sha256JSON, terminateProcess } from "../../foundation/index.js";
|
|
5
|
+
import { HitchError, atomicWriteJSON, consumeLines, detectVersion, ensureDir, fingerprintExecutable, invalidInput, packageRoot, readJSON, sha256JSON, statePaths, terminateProcess } from "../../foundation/index.js";
|
|
6
6
|
import { HARBOR_CREDENTIAL_ENV, locateHarbor } from "./tools.js";
|
|
7
7
|
const BRIDGE_DIRECTORY = path.join(packageRoot(), "integrations", "harbor");
|
|
8
|
-
export async function runHarborBackend({ evalId, evalDirectory, request, root, resolvedRevision, runtimeDirectory, runtimeId, localTransport, env = process.env, harborExecutable, signal, emit = () => { }, }) {
|
|
8
|
+
export async function runHarborBackend({ evalId, evalDirectory, request, root, resolvedRevision, runtimeDirectory, runtimeId, preparedArtifact, localTransport, env = process.env, harborExecutable, signal, emit = () => { }, }) {
|
|
9
9
|
const backendDirectory = await ensureDir(path.join(evalDirectory, "harbor"));
|
|
10
|
+
const harnessArtifactCacheDirectory = await ensureDir(path.join(statePaths(root).store, "harbor-artifacts"));
|
|
10
11
|
const executable = await discoverHarbor(harborExecutable, root, env);
|
|
11
12
|
const version = await detectVersion(executable, ["--version"]);
|
|
12
13
|
const identity = await fingerprintExecutable(executable);
|
|
@@ -20,6 +21,8 @@ export async function runHarborBackend({ evalId, evalDirectory, request, root, r
|
|
|
20
21
|
resolvedRevision,
|
|
21
22
|
runtimeDirectory,
|
|
22
23
|
runtimeId,
|
|
24
|
+
preparedArtifact,
|
|
25
|
+
harnessArtifactCacheDirectory,
|
|
23
26
|
localTransport,
|
|
24
27
|
backendDirectory,
|
|
25
28
|
jobName,
|
|
@@ -84,7 +87,7 @@ async function attachTrialResults(jobDirectory, jobResult) {
|
|
|
84
87
|
}
|
|
85
88
|
return { ...jobResult, trial_results: trialResults };
|
|
86
89
|
}
|
|
87
|
-
export async function buildHarborJobConfig({ evalId, request, resolvedRevision, runtimeDirectory, runtimeId, localTransport, backendDirectory, jobName = "job", env = process.env, }) {
|
|
90
|
+
export async function buildHarborJobConfig({ evalId, request, resolvedRevision, runtimeDirectory, runtimeId, preparedArtifact, harnessArtifactCacheDirectory, localTransport, backendDirectory, jobName = "job", env = process.env, }) {
|
|
88
91
|
const timeoutSeconds = request.timeout_ms > 0 ? Math.ceil(request.timeout_ms / 1_000) : null;
|
|
89
92
|
const setupTimeoutSeconds = request.setup_timeout_ms > 0 ? Math.ceil(request.setup_timeout_ms / 1_000) : null;
|
|
90
93
|
const agent = {
|
|
@@ -110,6 +113,22 @@ export async function buildHarborJobConfig({ evalId, request, resolvedRevision,
|
|
|
110
113
|
// (spec §4.2); `runtime_id` records the exact execution payload.
|
|
111
114
|
hitch_runtime_dir: runtimeDirectory,
|
|
112
115
|
...(runtimeId ? { controller_runtime_id: runtimeId } : {}),
|
|
116
|
+
...(harnessArtifactCacheDirectory ? { harness_artifact_cache_dir: harnessArtifactCacheDirectory } : {}),
|
|
117
|
+
...(preparedArtifact ? {
|
|
118
|
+
harness_artifact: {
|
|
119
|
+
directory: preparedArtifact.directory,
|
|
120
|
+
artifact_id: preparedArtifact.artifact_id,
|
|
121
|
+
artifact_integrity: preparedArtifact.artifact_integrity,
|
|
122
|
+
entrypoint_integrity: preparedArtifact.entrypoint_integrity,
|
|
123
|
+
harness_id: preparedArtifact.harness_id,
|
|
124
|
+
revision_identity: preparedArtifact.revision_identity,
|
|
125
|
+
adapter_version: preparedArtifact.adapter_version,
|
|
126
|
+
recipe_version: preparedArtifact.recipe_version,
|
|
127
|
+
platform: preparedArtifact.platform,
|
|
128
|
+
node_version: preparedArtifact.node_version,
|
|
129
|
+
source_type: preparedArtifact.source_type,
|
|
130
|
+
},
|
|
131
|
+
} : {}),
|
|
113
132
|
...(localTransport ? {
|
|
114
133
|
local_source_transport: {
|
|
115
134
|
kind: localTransport.manifest.kind,
|