@delta-infra/cli 1.0.41 → 1.0.42

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/checksums.txt CHANGED
@@ -1,5 +1,5 @@
1
- 88c2594af0fa0e800a22c84a104df746cf68db36208551e00af5a113329d355f delta-cli-darwin-amd64.tar.gz
2
- 2aec4ac96fb4bbc17aad0af625d00130cbeed69348373fa041f01f37fb6a7ef2 delta-cli-darwin-arm64.tar.gz
3
- 4a119af2d747e0f833a69ec18c3bb240c54ed7c566458ba198f7ed120fcb98e1 delta-cli-linux-amd64.tar.gz
4
- 6fa695bff9884698f831d01f91d3bc5b9456423eeec09bd7d3077e4cff247189 delta-cli-linux-arm64.tar.gz
5
- 2eec78a6462d116f97237f45892e79c29b149d0538cce4ea346e51ff979c5f97 delta-cli-windows-amd64.zip
1
+ 8f5decb10645898f55dc413650a369d561bf931ea743f183a326f8c12b345174 delta-cli-darwin-amd64.tar.gz
2
+ 679ac7745f8b37e77dd9857e35ce364150846321711f3cbaab0d6df11f8fe164 delta-cli-darwin-arm64.tar.gz
3
+ df5aaf2a470f23b7fe3501d757529872c2d9a5095e7cac82aee2f8820b24d535 delta-cli-linux-amd64.tar.gz
4
+ 391fad2bd8510bfa08bae19d60f40c1b9a1135cba7cc64a5b5a59e0a6c99adca delta-cli-linux-arm64.tar.gz
5
+ 04a9543eaa94ecf4f97861069e379510a9efb356bec7cee09910edfa0043f3ee delta-cli-windows-amd64.zip
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delta-infra/cli",
3
- "version": "1.0.41",
3
+ "version": "1.0.42",
4
4
  "description": "Delta Sandbox CLI",
5
5
  "bin": {
6
6
  "delta-cli": "scripts/run.js"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: delta-sandbox
3
- version: 1.1.0
4
- description: "通过 Delta Sandbox HTTP API 在 Linux 容器中运行任意计算任务。适用于训练、推理、编译、数据处理等场景。支持 Python / Node.js / Go / Java / Rust 等语言。认证/配置/权限错误转 delta-shared。"
3
+ version: 1.1.8
4
+ description: "在 Delta Sandbox Linux 容器中运行任意命令或脚本。适用于训练、推理、编译、数据处理等任意需要 sandbox 的计算任务,支持 Python / Node.js / Go / Java / Rust 等语言。所有任务通用同一套输出约定:命令在 stdout 末尾输出结构化 JSON,skill 提取为本地 result.json 的 summary,并生成一行 RESULT: 结论。Planner 调用本 skill 时,请在 plan step 的 required_outputs 中声明 [{kind: 'file', extensions: ['.json']}]。请求中用中性动词(运行/执行)描述命令,只有真的会落盘文件时,才使用创建/写入/保存等动词并带上扩展名。认证/配置/权限错误转 delta-shared。"
5
5
  metadata:
6
6
  requires:
7
7
  bins: ["delta-cli"]
@@ -62,6 +62,62 @@ metadata:
62
62
 
63
63
  9. **每个 `run-bg` 生成独立 `execution_id`**:每次调用 `sandbox run-bg` 都会返回一个唯一的 `execution_id`,多个后台任务之间通过它区分。务必保存每次返回的 `execution_id` 并与任务对应,后续通过 `sandbox logs <id> --execution-id <exec_id>` 分别查询各任务的结果。同步 `sandbox run` 无需 `execution_id`,结果直接返回。
64
64
 
65
+ 10. **执行 delta-cli 命令必须使用 `bash` 工具,禁止用 `python_repl` 包装 `subprocess`**
66
+ - `delta-cli` 返回的是结构化 JSON,用 `bash` 直接执行最清晰,也便于 `result_file` 提取。
67
+ - ❌ **禁止**:在 `python_repl` 里写 `subprocess.run(['delta-cli', ...])`。这会把输出混在 Python 代码块中,既难读又多走一步解析。
68
+ - ✅ **正确**:`bash` 工具直接执行 `delta-cli sandbox ...`。
69
+ - 只有在**解析 JSON**(例如从 `sandbox read` 的信封中提取 `summary` 并写入 `result.json`)时,才使用 `python3`/`python_repl`。
70
+
71
+ 11. **代码/数据必须经由 `delta-cli sandbox write` 进入 sandbox**
72
+ - 所有要送进 sandbox 执行的脚本、配置、数据文件,**必须**通过 `delta-cli sandbox write <id> --path /workspace/<文件名> --source <本地文件名>` 写入。
73
+ - 不要把脚本先写到宿主 workspace 再依赖同步;宿主 workspace 的文件对 sandbox 内部不可见。
74
+ - 本规则关注的是“入口统一为 `sandbox write`”,不针对任何特定宿主工具。无论宿主提供何种文件操作接口,最终都要把内容送到 sandbox 内部。
75
+
76
+ 12. **任务完成标准是执行结果,而不是脚本文件存在**
77
+ - 本 skill 的交付物是**命令在 sandbox 中执行后的结果摘要**(本地 `result.json` 及其 `result_summary`),而不是 `.py`、`.sh` 等脚本文件本身。
78
+ - 仅把脚本写入 disk 不代表任务完成;必须完成 `write → run → read result_file → create result.json → kill sandbox` 整个生命周期,才能调用 `step_finish`。
79
+ - 因此,`skill_request` 中不要用“写出/保存/创建某某文件并执行”这类把文件落盘当成里程碑的措辞,而是直接要求“运行某某命令并返回结果摘要”。
80
+
81
+ 13. **`result.json` 是完成前的必要条件**
82
+ - 在调用 `step_finish` 之前,必须确认:
83
+ 1. `delta-cli sandbox run` / `run-bg --wait` 已返回且 `finished=true`;
84
+ 2. 已从 `result_file` 生成本地 `result.json`(包含 `summary` 与 `result_summary`);
85
+ 3. 已执行 `sandbox kill <id>` 销毁 sandbox;
86
+ 4. `final_response` 只有一行 `RESULT: <result_summary>`。
87
+
88
+ ## 请求措辞约定
89
+
90
+ 为降低被 host 的 Phase-10B 文件扩展名校验误判的概率,构造 `skill_request` 时遵守:
91
+
92
+ 1. **运行/执行命令时,用中性动词**
93
+ 优先使用 `运行`、`执行`、`调用`。
94
+ - 正确:`在 GPU sandbox 中运行 PyTorch CUDA 自检脚本`
95
+ - 不推荐在请求里直接写代码并带“输出”动词,例如
96
+ `脚本需输出:1) torch.cuda.is_available();...`
97
+ 其中的 `torch.cuda` 会被正则误判为承诺输出 `.cuda` 文件。
98
+
99
+ 2. **只有真正会创建文件时,才用承诺动词 + 扩展名**
100
+ `创建`、`写入`、`保存`、`输出`、`生成` 这类词只在你确实会让 skill 落盘文件时使用,并显式写出扩展名。
101
+ - 正确:`创建 check_cuda.py 并运行`
102
+ - 正确:`训练完成后将指标写入 result.json`
103
+
104
+ 3. **不要把完整代码块写进 `skill_request`**
105
+ 用自然语言描述任务目标,具体代码由 skill 内部写入 sandbox。
106
+ - 正确:`运行标准 PyTorch CUDA 可用性检查`
107
+ - 不推荐:在 `skill_request` 里粘贴 `import torch; print(torch.cuda.is_available())`。
108
+
109
+ ### required_outputs 声明
110
+
111
+ 构造调用本 skill 的 plan step 时,**必须**在 `required_outputs` 中声明会落盘一个 `.json` 文件:
112
+
113
+ ```yaml
114
+ required_outputs:
115
+ - kind: file
116
+ extensions: [".json"]
117
+ ```
118
+
119
+ 原因:本 skill 运行命令后会从 sandbox 读取 `result_file` 并写入本地 `result.json`。host 的 Phase-10B deliverable 校验是“或”语义(任意一个 required 扩展名被真实文件满足即可);显式声明 `.json` 可以避免 `torch.cuda` 等代码 token 被误判为 `.cuda` 文件承诺,从而防止 `VERIFICATION_FAILED` 导致的重复执行。
120
+
65
121
  ## 快速路由
66
122
 
67
123
  > ⚠️ **`list` 与 `ls` 区分**:`sandbox list` 列出用户的 **沙箱实例**(与 `docker ps` 类似),`sandbox ls <id>` 列出 **沙箱内目录**(与 `ls` 命令类似)。Tab 补全时注意区分。
@@ -107,9 +163,10 @@ metadata:
107
163
  - `delta-cli sandbox providers` — 查看可用的计算后端(`opensandbox` / `autodl`)
108
164
  - `delta-cli sandbox images` — 查询服务端支持的镜像列表,根据用户需求的编程语言和工具链匹配镜像。例如 `deltarouter/python:latest`(Python)、`node:20`(Node.js)、`golang:1.23`(Go),镜像决定了容器内可用的语言/运行时环境。
109
165
  - `delta-cli sandbox recommend --cpu N --memory XGi [--gpu N]` — 获取资源配置推荐(自动选择 provider 和镜像)
110
- 2. **创建**:`delta-cli sandbox create --image <img> --cpu 4 --memory 16Gi --gpu 1 --gpu-mem 8000 --max-life 120`(创建后 sandbox 立即可用,无需额外连接)。**同一次任务若已有 `sandbox_id`,禁止再次 create,必须优先复用。**
111
- - --max-life 指定 sandbox 最大存活时间(分钟),默认 30。长任务请调高,确保 sandbox 在命令执行期间不被回收。
112
- - 这是 `sandbox create` 支持的完整资源参数集合,不存在其它“更正确”的资源 flag,不要发明不存在的参数。
166
+ 2. **创建**:`delta-cli sandbox create --image <img> --cpu 4 --memory 16Gi --gpu 1 --gpu-mem 8000 --max-life 120`。**返回的 JSON 信封中是 `data.sandbox_id`,不是 `data.id`;后续所有命令必须使用这个真实的 `sandbox_id`。**(创建后 sandbox 立即可用,无需额外连接)。**同一次任务若已有 `sandbox_id`,禁止再次 create,必须优先复用。**
167
+ - --max-life 指定 sandbox 最大存活时间(分钟),默认 30。长任务请调高,确保 sandbox 在命令执行期间不被回收。
168
+ - 这是 `sandbox create` 支持的完整资源参数集合,不存在其它“更正确”的资源 flag,不要发明不存在的参数。
169
+ - **禁止在 create 成功后反复调用 `sandbox status` 轮询**。`sandbox create` 返回时 sandbox 已经就绪,直接用它返回的 `data.sandbox_id` 执行 `write`/`run` 即可。多余的轮询会增加工具调用次数且没有任何收益。
113
170
  3. **写入代码/数据**:
114
171
  - **单个文件**:`delta-cli sandbox write <id> --path /workspace/<filename> --source <文件名>` — **必须**使用相对路径(如 `--source train.py`),**禁止**使用 `"$WORKSPACE_ROOT/train.py"` 或 `$(pwd)/train.py` 等 Shell 变量路径。`--source` 让 CLI 自行读取本地文件,不会经过 Shell 展开,是最安全的方式。写入后返回的 `size` 字段是实际磁盘字节数(来自 stat 验证),可对比确认写入完整性。少量配置(<20 行)可用 `--data "..."`。文件路径和扩展名由镜像中的运行时决定。
115
172
  - **批量写入**:`sandbox write-multiple <id> --entry <远程路径>=<本地路径> [--entry ...]`(远程路径在 `=` 左边,本地路径在右边,`--data` 批量写入不可用)
@@ -126,22 +183,131 @@ metadata:
126
183
  - **长任务(预计 > 60 秒,如下载模型、训练、编译、大规模数据处理)**:`delta-cli sandbox run-bg <id> --command "<命令>" --timeout <秒> [--result-file <路径>]` 提交后台任务,获得 `execution_id` 后通过以下命令轮询:
127
184
  - `delta-cli sandbox logs <id> --execution-id <execution_id>` — 返回 `cursor`、`running`、`finished`、`exit_code`、`result_file`(完成后)。当 `finished=true` 时认为完成,完整输出需读取 `result_file`。
128
185
  - `delta-cli sandbox status bg <id> --execution-id <execution_id>` — 返回 `running`、`finished`、`exit_code`。
129
- 禁止对长任务使用同步 `sandbox run`
130
- 5. **读取结果**:`delta-cli sandbox read <id> --path /workspace/result.json` — 返回 `content`(内容)、`size`(磁盘字节数,来自 stat 验证)、`content_length`(内存字符长度)。对比 `size` 与 `content_length` 可判断文件是否为纯文本。读不存在的文件会返回 error,不会静默返回空内容。
186
+ 禁止对长任务使用同步 `sandbox run`
187
+
188
+ **推荐实践**:让 sandbox 脚本在 `stdout` 末尾打印一个独立的结构化 JSON 对象(例如 `{"status":"ok", ...}`), SKILL 步骤 5 可直接把它提取为 `result.json` 的 `summary`。这样即使 `stdout` 前面是大量训练/下载日志,skill 也无需让大模型去“读整段日志再摘要”。
189
+ 5. **读取 result_file 并生成精简本地副本**:从 `sandbox run` / `sandbox run-bg --wait` / `sandbox logs` 返回数据中获得 `result_file` 路径。
190
+ - `sandbox read` 返回的是 CLI 信封 `{"ok":true,"data":{"content":"..."}}`,真实结果 JSON 在 `data.content` 字段里。
191
+ - **不要把 CLI 信封或完整长 `stdout` 原样写入本地 `result.json`**;应该解析后生成一份精简的结构化摘要。
192
+ - **推荐做法(避免 heredoc 引号失败)**:先用 `bash` 把信封写入临时文件,再用 `python3`(或 `python_repl`)读取该文件并生成 `result.json`。**不要**把 `delta-cli sandbox read` 的输出通过管道直接喂给内联 heredoc,管道+heredoc 的组合极易因 Shell 转义/引号问题失败。
193
+ 1. `bash` 保存信封:
194
+ ```bash
195
+ delta-cli sandbox read <sandbox_id> --path <result_file> > /tmp/_delta_result_envelope.json
196
+ ```
197
+ 2. `python3` / `python_repl` 生成 `result.json`:
198
+ ```python
199
+ import json, os
200
+
201
+ env = json.load(open("/tmp/_delta_result_envelope.json", encoding="utf-8"))
202
+ raw = json.loads(env["data"]["content"])
203
+
204
+ concise = {
205
+ "execution_id": raw.get("execution_id"),
206
+ "sandbox_id": raw.get("sandbox_id"),
207
+ "command": raw.get("command"),
208
+ "exit_code": raw.get("exit_code"),
209
+ "finished": raw.get("finished"),
210
+ "result_file": raw.get("result_file"),
211
+ "finished_at": raw.get("finished_at"),
212
+ "summary": {},
213
+ "error": raw.get("error"),
214
+ "stderr_preview": (raw.get("stderr") or "")[:500],
215
+ }
216
+
217
+ # 优先提取 stdout 末尾的独立 JSON 对象作为 summary
218
+ stdout = raw.get("stdout", "")
219
+ for line in reversed(stdout.strip().splitlines()):
220
+ s = line.strip()
221
+ if s.startswith("{") and s.endswith("}"):
222
+ try:
223
+ concise["summary"] = json.loads(s)
224
+ break
225
+ except Exception:
226
+ pass
227
+
228
+ # 构造 result_summary:一行字符串,最终回答的 RESULT: 行直接用它
229
+ parts = [f"exit_code={concise['exit_code']}", f"finished={concise['finished']}"]
230
+ for key, value in concise["summary"].items():
231
+ # 避免把长文本塞进 result_summary
232
+ if isinstance(value, (str, int, float, bool)) and len(str(value)) < 200:
233
+ parts.append(f"{key}={value}")
234
+ concise["result_summary"] = ", ".join(parts)
235
+
236
+ ws = os.environ.get("WORKSPACE_ROOT", ".")
237
+ with open(os.path.join(ws, "result.json"), "w", encoding="utf-8") as f:
238
+ json.dump(concise, f, indent=2, ensure_ascii=False)
239
+ print(concise["result_summary"])
240
+ ```
241
+ 3. 如果当前环境没有 `python3`,用 `jq`、`node` 或任何可解析 JSON 的工具实现**相同逻辑**:1)读取 `/tmp/_delta_result_envelope.json`;2)解开 CLI 信封取 `data.content`;3)解析内部 JSON;4)从 `stdout` 末尾提取 summary JSON;5)生成 `result_summary` 并写入 `result.json`。
242
+ - 如果 `stdout` 非常大(训练日志、下载日志等),不要把整段 `stdout` 写进 `result.json`;只保留关键指标和 preview。
243
+ - 写入本地副本的目的是让 host 的 deliverable 校验识别到真实的 `.json` 文件;由于校验是“或”语义,`.json` 文件会盖过 `torch.cuda` 等 token 被误判出的 `.cuda` 文件承诺。
244
+ - 完整原始输出仍保留在 sandbox 的 `result_file` 中,必要时可再次 `sandbox read` 获取。
131
245
  6. **销毁**:`delta-cli sandbox kill <id>`(如需保存结果,用 `sandbox finish --results '{...}'` 替代 kill,finish 会自动销毁 sandbox)
132
246
 
133
247
  详细步骤见 [lifecycle.md](references/lifecycle.md)。
134
248
 
249
+ ## 通用结构化输出约定
250
+
251
+ 本约定适用于**所有** `delta-sandbox` 任务(GPU/CPU、训练/推理/编译/数据处理等),目的是让 Runner 能直接从 `result.json` 读到结论,无需再次解析长日志。
252
+
253
+ ### sandbox 脚本/命令应该输出的内容
254
+
255
+ 命令执行完毕后,推荐在 `stdout` 末尾打印一行**独立的结构化 JSON**。例如:
256
+
257
+ - CUDA 检查:`{"status":"ok","torch_version":"2.5.1+cu121","cuda_available":true,"device_name":"NVIDIA H100 80GB HBM3"}`
258
+ - 训练任务:`{"status":"ok","epochs":10,"final_loss":0.12,"final_accuracy":0.94,"model_file":"/workspace/model.pt"}`
259
+ - 数据处理:`{"status":"ok","input_rows":10000,"output_rows":9876,"output_file":"/workspace/output.csv"}`
260
+
261
+ 这样 SKILL 可以用同一套代码把它提取到 `result.json` 的 `summary` 字段,再生成 `RESULT:` 行。
262
+
263
+ ### 本地 `result.json` 通用 Schema
264
+
265
+ ```json
266
+ {
267
+ "execution_id": "...",
268
+ "sandbox_id": "...",
269
+ "command": "...",
270
+ "exit_code": 0,
271
+ "finished": true,
272
+ "result_file": "/tmp/delta-result-xxx.json",
273
+ "finished_at": "...",
274
+ "summary": {},
275
+ "result_summary": "exit_code=0, status=ok, torch_version=..., ...",
276
+ "error": null,
277
+ "stderr_preview": ""
278
+ }
279
+ ```
280
+
281
+ 关键字段:
282
+ - `summary`: 命令输出的结构化结果对象。
283
+ - `result_summary`: **一行字符串**,与最终回答的 `RESULT:` 行内容一致,方便 Runner 直接读取。
284
+ - `stderr_preview`: stderr 的前 500 字符,用于快速排错。
285
+ - **不要把完整 `stdout` 塞进来**。完整日志仍保留在 sandbox 的 `result_file` 中。
286
+
135
287
  ## 输出阅读与最终回答格式
136
288
 
137
289
  1. **`sandbox run` / `sandbox run-bg --wait` / `sandbox logs` 返回的 JSON 中包含 `data.result_file`**(沙箱内结构化结果文件的路径)。
138
- 2. **只要 `data.result_file` 存在,必须优先使用 `delta-cli sandbox read <id> --path <result_file>` 读取该文件。**
290
+ 2. **只要 `data.result_file` 存在,必须优先使用 `delta-cli sandbox read <id> --path <result_file>` 读取该文件,并解析 CLI 信封得到真实结果 JSON。**
139
291
  - 结果文件包含完整 `stdout`、`stderr`、`exit_code`、`finished`、`command`、`error`。
140
- 3. **基于结果文件内容给出最终结论**,开头用 `RESULT:`,例如:
141
- ```
142
- RESULT: exit_code=0, CUDA available=True, GPU=NVIDIA H100 80GB HBM3, tensor addition on cuda:0 succeeded.
143
- ```
144
- 4. **不要依赖或被截断的 `stdout`/`stderr` 字段**,关键结论必须来自读取结果文件后的分析。
292
+ 3. **读取 result_file 后,生成本地精简 `result.json`**(见“完整生命周期”步骤 5 和“通用结构化输出约定”)。本地副本只应包含关键字段和摘要,**不应包含完整长 `stdout`**。
293
+ 4. **最终回答必须且只能是 `RESULT:` 开头的一行。**
294
+ - 优先直接复用 `result.json` 里的 `result_summary` 字段:
295
+ ```text
296
+ RESULT: <result.json 中的 result_summary>
297
+ ```
298
+ - 如果 `result_summary` 缺失,则从 `summary` 对象构造一行,例如:
299
+ ```text
300
+ RESULT: exit_code=0, status=ok, torch_version=2.7.0+cu128, cuda_available=True, device_name=NVIDIA GeForce RTX 3090.
301
+ ```
302
+ 5. **绝对禁止任何前缀、后缀、说明、过渡句或内心独白**
303
+ - 正确:`RESULT: exit_code=0, cuda_available=True, torch_version=2.5.1+cu121, device_name=NVIDIA H100 80GB HBM3`
304
+ - 错误:`Sandbox killed successfully. Final answer with result summary. RESULT: ...`
305
+ - 错误:`Sandbox killed. Task done. Need final answer exactly RESULT: line from result_summary. RESULT: ...`
306
+ - 错误:`The user wants me to verify CUDA... RESULT: ...`
307
+ - 错误:`Summary: ... RESULT: ...`
308
+ - 错误:在 `RESULT:` 后追加 `Let me know if you need anything else.` 等多余句子。
309
+ - **规则**:`final_response` 里出现的字符,必须是 `RESULT:` 及其后的内容,不允许其它任何自然语言。
310
+ 6. **不要依赖或被截断的 `stdout`/`stderr` 字段**,关键结论必须来自 `result.json` 的 `summary` / `result_summary`。
145
311
 
146
312
  ## 常见恢复
147
313
 
@@ -0,0 +1,127 @@
1
+ # 标准任务请求模式
2
+
3
+ 本文件提供 `delta-sandbox` 处理常见任务时的推荐请求写法。这些示例是语言无关的模板,实际代码由 skill 在 sandbox 内部生成或写入。
4
+
5
+ ## Planner 调用本 skill 时的 required_outputs
6
+
7
+ 所有直接调用 `delta-sandbox` 的 plan step 都应该声明会落盘一个 `.json` 文件。这样 skill 运行命令后把 sandbox `result_file` 写入本地 `result.json` 时,host 可以正确通过 Phase-10B deliverable 校验。
8
+
9
+ ```yaml
10
+ required_outputs:
11
+ - kind: file
12
+ extensions: [".json"]
13
+ ```
14
+
15
+ > 说明:这是声明 skill 会创建 `.json` 结果文件,不是要求用户请求中出现 `.json`。用户请求仍按下面的模板使用中性动词。
16
+
17
+ ## 通用脚本输出模板
18
+
19
+ 为了让 skill 用同一套流程生成 `RESULT:` 并避免大模型去摘要长日志,推荐任何 sandbox 脚本在**执行结束时**打印一行结构化 JSON:
20
+
21
+ ```json
22
+ {"status":"ok","key_metric_1":"value_1","key_metric_2":123}
23
+ ```
24
+
25
+ SKILL 会把它提取为 `result.json` 的 `summary`,并生成 `result_summary` 与最终 `RESULT:` 行。
26
+
27
+ 不同任务的关键字段示例:
28
+
29
+ - **CUDA 检查**:`status`, `torch_version`, `cuda_available`, `device_name`
30
+ - **训练任务**:`status`, `epochs`, `final_loss`, `final_accuracy`, `model_file`
31
+ - **推理任务**:`status`, `input_samples`, `output_file`, `avg_latency_ms`
32
+ - **数据处理**:`status`, `input_rows`, `output_rows`, `output_file`
33
+ - **编译/构建**:`status`, `build_time_s`, `output_binary`, `tests_passed`
34
+
35
+ ## 1. GPU / CUDA 可用性检查
36
+
37
+ 用户请求示例:
38
+
39
+ ```text
40
+ 在 GPU sandbox 中运行标准 PyTorch CUDA 自检脚本,返回 exit_code、torch 版本、CUDA 是否可用、CUDA/cuDNN 版本、GPU 名称与显存信息。
41
+ ```
42
+
43
+ 说明:
44
+
45
+ - 不要在请求里出现 `torch.cuda.is_available()` 等完整代码 token,避免被 host 误判为 `.cuda` 文件承诺。对应的 plan step 仍按上面模板声明 `.json` 输出。
46
+ - 推荐让脚本在 `stdout` 末尾输出一行结构化 JSON,例如:
47
+ ```json
48
+ {"torch_version":"2.7.0+cu128","cuda_available":true,"device_count":1,
49
+ "device_name":"NVIDIA GeForce RTX 3090","tensor_op":"[101.0]",
50
+ "memory_before_mb":{"allocated":0,"reserved":0,"max_allocated":0},
51
+ "memory_after_mb":{"allocated":0.0005,"reserved":2.0,"max_allocated":0.001}}
52
+ ```
53
+ - skill 会从 `result_file` 提取这个 JSON 作为本地 `result.json` 的 `summary`,最终只输出一行 `RESULT: ...`。
54
+ - 完整 `nvidia-smi` 原始输出保留在 sandbox 的 `result_file` 中。
55
+
56
+ ## 2. 运行用户已有的脚本
57
+
58
+ ```text
59
+ 在 sandbox <sandbox_id> 中运行 /workspace/train.py,参数为 --epochs 10 --batch-size 32。
60
+ ```
61
+
62
+ 说明:文件已存在,用中性动词 `运行`,不使用 `创建` 等承诺动词。
63
+
64
+ ## 3. 安装依赖并执行命令
65
+
66
+ ```text
67
+ 在 sandbox 中运行 pip install -r /workspace/requirements.txt,然后运行 python /workspace/app.py。
68
+ ```
69
+
70
+ 说明:依赖安装和命令执行都没有落盘新文件,使用中性动词描述。
71
+
72
+ ## 4. 训练并将指标落盘
73
+
74
+ ```text
75
+ 在 GPU sandbox 中运行训练脚本(例如基于 PyTorch 的 MNIST 训练),训练完成后在 stdout 末尾打印包含 epochs、final_loss、final_accuracy、model_file 的结构化 JSON。
76
+ ```
77
+
78
+ 说明:
79
+
80
+ - 训练日志可能很长,不要让 skill 去读整段日志再摘要;让脚本自己输出关键指标。
81
+ - 推荐脚本最终打印:`{"status":"ok","epochs":10,"final_loss":0.023,"final_accuracy":0.992,"model_file":"/workspace/model.pt"}`
82
+ - skill 会把它提取为 `result.json` 的 `summary`,最终输出 `RESULT: exit_code=0, status=ok, epochs=10, ...`。
83
+ - 如需保存完整模型文件,可再用 `sandbox read` 或 `sandbox upload` 处理,不属于 `result.json` 的摘要范围。
84
+
85
+ ## 5. 通用数据处理
86
+
87
+ ```text
88
+ 在 sandbox 中运行数据处理命令,读取 /workspace/input.csv,输出 /workspace/output.csv,并在 stdout 末尾打印包含 input_rows、output_rows、output_file 的结构化 JSON。
89
+ ```
90
+
91
+ 说明:
92
+
93
+ - 推荐脚本最终打印:`{"status":"ok","input_rows":10000,"output_rows":9876,"output_file":"/workspace/output.csv"}`
94
+ - skill 会把它提取为 `result.json` 的 `summary`,最终输出 `RESULT: exit_code=0, status=ok, input_rows=10000, output_rows=9876, output_file=/workspace/output.csv`。
95
+
96
+ ## 6. 模型推理(Qwen / LLM / 视觉等)
97
+
98
+ 用户请求示例:
99
+
100
+ ```text
101
+ 在 GPU sandbox 中用 ModelScope 上的 Qwen/Qwen2.5-0.5B-Instruct 运行一次推理,输入 "100+10",返回模型的输出结果及 CUDA 可用性摘要。
102
+ ```
103
+
104
+ 说明:
105
+
106
+ - 请求里不要贴完整 Python 代码,也不要指定宿主文件路径(如 `@ROOT/inference.py`、本地绝对路径等)。脚本内容、模型下载、执行路径都由 skill 内部通过 `delta-cli sandbox write` 写入 sandbox 后运行。
107
+ - 推荐让脚本在 `stdout` 末尾打印一行结构化 JSON,例如:
108
+ ```json
109
+ {"status":"ok","cuda_available":true,"device":"cuda","model":"Qwen/Qwen2.5-0.5B-Instruct","input":"100+10","output":"110"}
110
+ ```
111
+ - skill 会把它提取为 `result.json` 的 `summary`,最终输出 `RESULT: exit_code=0, status=ok, cuda_available=True, output=110, ...`。
112
+
113
+ ## 注意事项
114
+
115
+ - 尽量用自然语言描述任务,完整代码由 skill 内部处理。
116
+ - 只有在 skill 会真实创建文件时,才在请求中显式写出 `*.py` / `*.json` / `*.csv` 等扩展名。
117
+ - 不要使用 `脚本需输出...` 这类把代码片段直接跟在承诺动词后的句式。
118
+ - **任务完成的标准是执行结果,不是脚本文件存在**。Planner 和 skill 都要以本地 `result.json` 的生成作为完成标志;`required_outputs` 必须声明 `.json`,不要只声明 `{"kind": "file"}`。
119
+ - **`skill_request` 里不要出现完整代码块或宿主文件路径概念**(如 `@ROOT/...`、`/Users/...`)。脚本应通过 `delta-cli sandbox write` 进入 sandbox 内部路径 `/workspace/...`。
120
+
121
+ ## 本地 `result.json` 的内容约定
122
+
123
+ - 本地 `result.json` 是一份**精简摘要**,用于 host deliverable 校验,不是完整日志存档。
124
+ - 必须包含 `result_summary` 字段,内容与最终 `RESULT:` 行一致,方便 Runner 直接读取结论。
125
+ - 只写入关键字段(`execution_id`、`sandbox_id`、`exit_code`、`finished`、`summary`、`result_summary`、`error`、`stderr_preview` 等)。
126
+ - 不要把完整原始 `stdout` 塞进 `result.json`,否则 host 的 `read_file` 工具预览时会截断,Runner 可能误以为文件被截断。
127
+ - 完整原始输出保留在 sandbox 的 `result_file` 中,需要时再 `sandbox read`。