@delta-infra/cli 1.0.85 → 1.0.87

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 CHANGED
@@ -170,13 +170,19 @@ delta-cli sandbox create \
170
170
  --cpu 4 --memory 16Gi --gpu 1 \
171
171
  --max-life 120
172
172
 
173
+ # 需要长期存活、不被自动清理的 sandbox:加 --no-auto-cleanup(仅显式 kill/finish 可销毁)
174
+ delta-cli sandbox create \
175
+ --image image.yangtzeailab.com/opensandbox/pytorch-cuda13:latest \
176
+ --cpu 4 --memory 16Gi --gpu 1 \
177
+ --no-auto-cleanup
178
+
173
179
  # 运行命令(短任务同步执行,长任务用 run-bg 替代 run)
174
180
  delta-cli sandbox run <sandbox_id> \
175
181
  --command "<命令>" \
176
182
  --timeout 3600
177
183
 
178
- # v1.0.55+ 默认带 --summary,返回 JSON 中 data.result_summary 字段已含 stdout 末尾 JSON 提取结果
179
- # 无需再手动读取 log_file 做二次解析(除非使用了 --no-summary)
184
+ # v1.0.85+ sandbox run 走 SSE 实时流:stdout 为原始 data: 帧(无末尾信封),exit_code/log_file 在 complete 帧中
185
+ # 需要 stdout 末尾 JSON 摘要时:读取 log_file 解析(sandbox read <id> --path <log_file>)
180
186
  delta-cli sandbox run <sandbox_id> --command "echo '{\"status\":\"ok\",\"result\":\"done\"}'" --timeout 60
181
187
 
182
188
  # 读取结果文件
@@ -214,13 +220,13 @@ delta-cli sandbox kill <sandbox_id>
214
220
  | `delta-cli sandbox providers` | 查看可用计算后端 |
215
221
  | `delta-cli sandbox images` | 查看可用镜像列表 |
216
222
  | `delta-cli sandbox recommend --cpu N --memory XGi` | 获取资源配置推荐 |
217
- | `delta-cli sandbox create --image <img>` | 创建 sandbox 容器 |
223
+ | `delta-cli sandbox create --image <img> [--no-auto-cleanup]` | 创建 sandbox 容器(`--no-auto-cleanup` 不被自动清理) |
218
224
  | `delta-cli sandbox connect <id>` | 连接 sandbox |
219
225
  | `delta-cli sandbox status <id>` | 查看 sandbox 状态 |
220
226
  | `delta-cli sandbox finish <id>` | 保存结果并销毁 |
221
227
  | `delta-cli sandbox kill <id>` | 销毁 sandbox |
222
- | `delta-cli sandbox run <id> --command "..." [--timeout <秒>] [--summary/--no-summary] [--artifacts]` | 同步运行命令;默认带 `--summary`,返回 JSON 中 `summary` 字段已含 stdout 末尾 JSON 提取结果;`--artifacts` 附带 workspace 产物清单 |
223
- | `delta-cli sandbox run-bg <id> --command "..." [--timeout <秒>] [--wait] [--summary/--no-summary] [--artifacts]` | 后台运行命令;不加 `--wait` 立即返回 `{execution_id, sandbox_id}`;加 `--wait` 等待完成返回含 `summary` 的完整结果 |
228
+ | `delta-cli sandbox run <id> --command "..." [--timeout <秒>] [--summary/--no-summary] [--artifacts]` | 同步运行命令(SSE 原始 `data:` 帧透传到 stdout,无末尾信封,`exit_code`/`log_file` 在 `complete` 帧);`--summary`/`--artifacts` 仅旧服务器回退路径生效 |
229
+ | `delta-cli sandbox run-bg <id> --command "..." [--timeout <秒>] [--wait] [--summary/--no-summary] [--artifacts]` | 后台运行命令;不加 `--wait` 立即返回 `{execution_id, sandbox_id}`;加 `--wait` 通过 SSE 实时流跟随(原始 `data:` 帧透传到 stdout,无末尾信封) |
224
230
  | `delta-cli sandbox logs <id> --execution-id <eid> [--tail N --grep <pattern> --context N --max-bytes N]` | 查看后台日志;默认返回 `stderr_size + stderr_tail`(避免上下文爆炸);可用 `--tail/--grep` 过滤 |
225
231
  | `delta-cli sandbox cancel <id> --execution-id <eid>` | 中断后台命令 |
226
232
  | `delta-cli sandbox read <id> --path <path> [--output <本地路径>] [--tail N] [--grep <pattern>] [--offset N] [--limit N] [--context N] [--max-bytes N] [--parse-json]` | 读取容器内文件;`--output <path>` 保存到本地;`--tail/--grep` 过滤;非 UTF-8 文件 CLI 自动走 base64 fallback |
package/checksums.txt CHANGED
@@ -1,5 +1,5 @@
1
- 598d6098c95178c336be2c69c1b8314341581c2b39bce5bd3d7a5b39d207ac04 delta-cli-darwin-amd64.tar.gz
2
- 815a88f48726354efc5e17dca5f54ed05784e0dfd2a525e05a2ab748114223e7 delta-cli-darwin-arm64.tar.gz
3
- 861f1e946c94311526b6802a85ebf9a7368b05631ee96822ed24b55facd5b5d2 delta-cli-linux-amd64.tar.gz
4
- e3bf8ed838c0cfc56d66ec9c663fc608217964599820c7c08ac34c227811f98d delta-cli-linux-arm64.tar.gz
5
- fbd669af1baa1d76d06d90e386350d20cda9c6569027ed4e00b4fe5bc796e578 delta-cli-windows-amd64.zip
1
+ 4f90fb1c489ac827e1be5aa0fbe9086518e0ae8b74e1c52254625f97b88cb699 delta-cli-darwin-amd64.tar.gz
2
+ e672888b452508b0721acb4c49a72202e7cd7010986bee8f5d806a0067fbdb2f delta-cli-darwin-arm64.tar.gz
3
+ 3d8174a44a868992815dfade0d5b8509fbf83099506b16cf240f9ff519e00849 delta-cli-linux-amd64.tar.gz
4
+ da0da161c54d1876b6b0d8a8dd2002d9ca0a8438e5f6b117f0da59135ddaa67d delta-cli-linux-arm64.tar.gz
5
+ 9773fabda94a779c6dec18f0486fe25e7ec7177a8ef490683e00b9dc2cf7ac04 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.85",
3
+ "version": "1.0.87",
4
4
  "description": "Delta Infra CLI for sandbox compute and science tools.",
5
5
  "bin": {
6
6
  "delta-cli": "scripts/run.js"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: delta-sandbox
3
- description: "在 Delta Sandbox Linux 容器中运行任意命令或脚本。适用于训练、推理、编译、数据处理等任意需要 sandbox 的计算任务,支持 Python / Node.js / Go / Java / Rust 等语言。所有任务通用同一套输出约定:命令在 stdout 末尾输出结构化 JSON,CLI 反向扫描 stdout 末尾 JSON 自动提取为 `data.result_summary` 字段。Planner 调用本 skill 时,请在 plan step 的 required_outputs 中声明 [{kind: 'file', extensions: ['.json']}]。请求中用中性动词(运行/执行)描述命令,只有真的会落盘文件时,才使用创建/写入/保存等动词并带上扩展名。认证/配置/权限错误转 delta-shared。"
3
+ description: "在 Delta Sandbox Linux 容器中运行任意命令或脚本。适用于训练、推理、编译、数据处理等任意需要 sandbox 的计算任务,支持 Python / Node.js / Go / Java / Rust 等语言。所有任务通用同一套输出约定:命令在 stdout 末尾输出结构化 JSON;SSE 路径下 CLI 检测 stdout 末尾 JSON 并直接在 complete 帧带出 `result_summary`,缺失时才需 skill 从 log_file 反向扫描提取(旧服务器回退路径由 CLI `--summary` 自动提取为 `data.result_summary`)。Planner 调用本 skill 时,请在 plan step 的 required_outputs 中声明 [{kind: 'file', extensions: ['.json']}]。请求中用中性动词(运行/执行)描述命令,只有真的会落盘文件时,才使用创建/写入/保存等动词并带上扩展名。认证/配置/权限错误转 delta-shared。"
4
4
  metadata:
5
5
  requires:
6
6
  bins: ["delta-cli"]
@@ -40,10 +40,10 @@ metadata:
40
40
  ```bash
41
41
  delta-cli sandbox run-bg <id> --command "<命令>" --timeout <秒> --wait
42
42
  ```
43
- CLI 在内部每 5 秒轮询一次 `logs`,直到 `finished=true` 或超时(`--timeout` 同时充当服务端命令超时和客户端轮询 deadline,默认 300s),然后一次性返回 `CommandResult` 信封:`{execution_id, sandbox_id, finished, exit_code, stderr_tail, stderr_size, log_file, result_summary, hints, error}`。**stdout 不直接暴露**——命令的 stdout 在 `finished=true` 时被写入沙箱内的 `log_file`,需要读全文时用 `sandbox read <id> --path <log_file>`;默认开启的 `--summary` 会自动 reverse-scan stdout 末尾 JSON 并填入 `data.result_summary`,常用场景无需手动读 `log_file`。返回的 `execution_id` 可在后续用于 `sandbox logs` / `cancel`。适合只关心最终结果、不需要查看中间进度的场景。
43
+ CLI 通过 SSE 实时流(`/logs/stream`)跟随输出,把原始 SSE 帧(`data: {...}`)**逐帧透传到 stdout**(curl -N 风格),帧类型见 JSON 的 `type` 字段:`init`(含 `execution_id`)/ `stdout` / `stderr` / `error` / `complete`。收到 `complete` 即命令结束。**CLI 会在 complete 帧里补全字段**:服务端给 `exit_code`/`execution_id`/`error`,CLI 注入流内累计的 `stdout`/`stderr`、兜底恢复的 `log_file`、以及检测到的末尾 JSON `result_summary`(stdout 末尾 50 行内有合法 JSON 对象时)。命令成败看 `complete` 帧里的 `exit_code`;**命令非零退出或报错时,CLI 追加一个 `error.type: command_failed` 信封并以非零码退出(进程退出码 8)**,信封 `message` 已附 stderr 尾部,便于 `&&` 链与按 `error.type` 分支、快速扫读失败原因;`type:"error"` 帧的 `message` 也会 best-effort 附上已流出的 stderr 尾部;成功则不追加信封。若在 `--timeout`(默认 300s,同时充当服务端命令超时和客户端等待 deadline)内未收到 `complete`,CLI 会在已透传的帧后**追加一个 `finished=false` 的快照信封**(`CommandLogsResult`),表示命令仍运行。完整 stdout 在 `finished` 后被写入沙箱内的 `log_file`(默认 `/workspace/{user_id}/{sandbox_id}/{execution_id}/delta-result-{execution_id}.json`,以服务端返回的 `log_file` 字段为准),需要读全文时用 `sandbox read <id> --path <log_file>`(末尾 JSON 摘要已在 complete 帧里,通常无需再读)。**`--summary`/`--artifacts` 富化(含 hints)仅在旧服务器回退路径生效**(服务端无 `/logs/stream` 端点时 CLI 自动回退到 5s 轮询并输出 `CommandResult` 信封)。`execution_id` 可用于后续 `sandbox logs` / `cancel`。
44
44
 
45
- **手动轮询(需要查看中间进度时)**:
46
- 如果不加 `--wait` 或需要查看实时输出,用 `sandbox logs <id> --execution-id <exec_id>` 手动轮询:
45
+ **实时跟随 / 手动轮询(需要查看中间进度时)**:
46
+ `sandbox logs <id> --execution-id <exec_id> --stream` 实时跟随(SSE):原始 `data:` 帧逐帧透传到 stdout,直到 `complete` 事件,无末尾信封。`sandbox logs <id> --execution-id <exec_id>`(不加 `--stream`)返回快照信封:
47
47
  - `finished=true` + `exit_code=0` → 完成
48
48
  - `finished=true` + `exit_code!=0` → 失败
49
49
  - `running=true` → 仍运行
@@ -79,7 +79,7 @@ metadata:
79
79
  13. **`result.json` 是完成前的必要条件**
80
80
  - 在调用 `step_finish` 之前,必须确认:
81
81
  1. `delta-cli sandbox run` / `run-bg --wait` 已返回且 `finished=true`;
82
- 2. (默认)直接复用 `sandbox run` / `run-bg --wait` 返回的 `summary` 字段写入 `result.json`;或(fallback)从 `log_file` 用 `sandbox read` + Python 解析
82
+ 2. (默认)直接复用 `sandbox run` / `run-bg --wait` 的 SSE `complete` 帧里的 `result_summary` 写入 `result.json`;缺失时(fallback)从 `log_file` 用 `sandbox read` + Python 解析
83
83
  3. 已执行 `sandbox kill <id>` 销毁 sandbox;
84
84
  4. `final_response` 只有一行 `RESULT: <result_summary>`。
85
85
 
@@ -131,9 +131,9 @@ required_outputs:
131
131
  | 查看可用镜像 | `sandbox images` |
132
132
  | 查看可用 provider | `sandbox providers` |
133
133
  | 获取资源推荐 | `sandbox recommend --cpu N --memory XGi [--gpu N] [--gpu-mem N]` |
134
- | 列出当前用户的 sandbox | `sandbox list` |
134
+ | 列出当前用户的 sandbox | `sandbox list [--status <running/finished/killed/error>] [--start-time <ISO8601>] [--end-time <ISO8601>] [--provider <opensandbox/autodl>] [--sandbox-id <id>] [--days N]` |
135
135
  | **生命周期** | |
136
- | 创建 sandbox | `sandbox create --image <image> [--cpu N --memory XGi --gpu N --gpu-mem N --max-life M]` |
136
+ | 创建 sandbox | `sandbox create --image <image> [--cpu N --memory XGi --gpu N --gpu-mem N --max-life M]`;不希望被自动清理时加 `--no-auto-cleanup`(仅显式 kill/finish 可销毁)|
137
137
  | 连接 sandbox | `sandbox connect <id>` |
138
138
  | 查看状态 | `sandbox status <id>` |
139
139
  | 完成 sandbox | `sandbox finish <id> [--results '{...}']` |
@@ -141,7 +141,7 @@ required_outputs:
141
141
  | **命令执行** | |
142
142
  | 同步运行命令(≤60s) | `sandbox run <id> --command "..." [--timeout <秒>] [--summary/--no-summary] [--artifacts]` |
143
143
  | 后台运行命令(>60s) | `sandbox run-bg <id> --command "..." [--timeout <秒>] [--wait] [--summary/--no-summary] [--artifacts]` |
144
- | 查看后台日志 | `sandbox logs <id> --execution-id <exec_id> [--tail N --grep <pattern> --context N]` |
144
+ | 查看后台日志 | `sandbox logs <id> --execution-id <exec_id> [--tail N --grep <pattern> --context N] [--stream]` |
145
145
  | 中断后台命令 | `sandbox cancel <id> --execution-id <exec_id>` |
146
146
  | **文件操作** | |
147
147
  | 读取文件 | `sandbox read <id> --path <path> [--output <本地路径> --tail N --grep <pattern> --offset N --limit N --context N --max-bytes N --parse-json]` |
@@ -168,9 +168,9 @@ required_outputs:
168
168
  - `delta-cli sandbox providers` — 可用的计算后端
169
169
  - `delta-cli sandbox images` — 服务端支持的镜像列表
170
170
  - `delta-cli sandbox recommend --cpu N --memory XGi [--gpu N]` — 资源配置推荐
171
- 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,必须优先复用。**
171
+ 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 立即可用,无需额外连接)。**响应会回显请求的 `image`/`provider`/`resource`(服务端未返回的字段由 CLI 用请求值补齐,服务端返回值优先),可直接核对一遍资源配置,无需额外调 status。**(`provider` 请求值为 `auto` 时不回显,避免冒充实际 provider)。**同一次任务若已有 `sandbox_id`,禁止再次 create,必须优先复用。**
172
172
  - --max-life 指定 sandbox 最大存活时间(分钟),默认 30。长任务请调高,确保 sandbox 在命令执行期间不被回收。
173
- - 这是 `sandbox create` 支持的完整资源参数集合,不存在其它“更正确”的资源 flag,不要发明不存在的参数。
173
+ - `--no-auto-cleanup`:加此 flag 后该 sandbox **不会被自动清理**(服务端超时回收 + 本地周期 cleanup_stale 均跳过),只能通过显式 `sandbox kill`/`finish` 销毁。仅当任务确实需要跨越周期清理长期存活时才使用,任务结束后必须主动销毁,避免资源泄漏。
174
174
  - **禁止在 create 成功后反复调用 `sandbox status` 轮询**。`sandbox create` 返回时 sandbox 已经就绪,直接用它返回的 `data.sandbox_id` 执行 `write`/`run` 即可。多余的轮询会增加工具调用次数且没有任何收益。
175
175
  3. **写入代码/数据**:
176
176
  - **单个文件**:`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 "..."`。文件路径和扩展名由镜像中的运行时决定。
@@ -180,43 +180,19 @@ required_outputs:
180
180
  - 支持嵌套目录,空目录也会被创建。
181
181
  - **写后验证(可选)**:`sandbox stat <id> --path <path>` 确认文件存在且 size 符合预期即可。**不要**用 `sandbox ls` + `sandbox read` 把刚写入的文件读回宿主再逐字对比;无异常时不需要读回。
182
182
  4. **运行命令**:
183
- - **短任务(预计 ≤ 60 秒)**:`delta-cli sandbox run <id> --command "<命令>" --timeout <秒>` 同步执行,返回 `stderr` / `exit_code` / `log_file`,完整 `stdout` 在 run envelope 日志文件中,**不要**再调用 `sandbox logs`。可通过 `--log-file <路径>` 自定义 run envelope 日志文件路径;默认值为 `/tmp/delta-result-{execution_id}.json`。根据镜像中的运行时构造命令,常见示例:
183
+ - **短任务(预计 ≤ 60 秒)**:`delta-cli sandbox run <id> --command "<命令>" --timeout <秒>` 同步执行,命令的 stdout/stderr 通过 SSE **以原始 `data:` 帧逐帧透传到 stdout**(无末尾信封),`exit_code` / `log_file` / `execution_id` 从 `complete` 帧读取。完整 `stdout` 在完成后写入 run envelope 日志文件(`log_file` 字段),需要读全文或提取末尾 JSON 时用 `sandbox read`,**不要**再调用 `sandbox logs`。可通过 `--log-file <路径>` 自定义 run envelope 日志文件路径;默认值为 `/workspace/{user_id}/{sandbox_id}/{execution_id}/delta-result-{execution_id}.json`(以服务端返回的 `log_file` 字段为准)。根据镜像中的运行时构造命令,常见示例:
184
184
  - Python:`python /workspace/train.py`
185
185
  - Node.js:`node /workspace/app.js`
186
186
  - Go:`go run /workspace/main.go`
187
187
  - Shell:`bash /workspace/run.sh`
188
- - **长任务(预计 > 60 秒,如下载模型、训练、编译、大规模数据处理)**:`delta-cli sandbox run-bg <id> --command "<命令>" --timeout <秒> [--log-file <路径>]` 提交后台任务,获得 `execution_id` 后通过以下命令轮询:
189
- - `delta-cli sandbox logs <id> --execution-id <execution_id>` — 返回 `stdout_tail`(末尾 800 字节)、`stderr_tail`(末尾 200 字节)、`stdout_size`、`stderr_size`、`cursor`、`running`、`finished`、`exit_code`、`log_file`(完成后)。当 `finished=true` 时认为完成,完整输出需读取 `log_file`。
188
+ - **长任务(预计 > 60 秒,如下载模型、训练、编译、大规模数据处理)**:`delta-cli sandbox run-bg <id> --command "<命令>" --timeout <秒> [--log-file <路径>]` 提交后台任务,获得 `execution_id` 后通过以下命令查询:
189
+ - `delta-cli sandbox logs <id> --execution-id <execution_id> --stream` — SSE 实时跟随,原始 `data:` 帧逐帧透传到 stdout,直到 `complete` 事件(含 `exit_code`/`log_file`),无末尾信封。
190
+ - `delta-cli sandbox logs <id> --execution-id <execution_id>` — 快照信封,返回 `stdout_tail`(末尾 800 字节)、`stderr_tail`(末尾 200 字节)、`stdout_size`、`stderr_size`、`cursor`、`running`、`finished`、`exit_code`、`log_file`(完成后)。当 `finished=true` 时认为完成,完整输出需读取 `log_file`。
190
191
  禁止对长任务使用同步 `sandbox run`
191
192
 
192
- **推荐实践**:让 sandbox 脚本在 `stdout` 末尾打印一个独立的结构化 JSON 对象(例如 `{"status":"ok", ...}`),CLI 的 `--summary` 默认会自动反向扫描 stdout 末尾 JSON 提取为 `data.result_summary` 字段。这样即使 `stdout` 前面是大量训练/下载日志,skill 也无需让大模型去“读整段日志再摘要”。
193
- 5. **生成 result.json**(默认路径使用 CLI 返回的 `summary` 字段;fallback 路径用 `sandbox read` + Python 解析):
194
- - **5a(默认路径,推荐)**:`run` / `run-bg --wait` 已返回 `result_summary` 字段(CLI 自动 reverse-scan stdout 末尾 JSON)。直接构造 `result.json`:
195
- ```bash
196
- delta-cli sandbox run <id> --command "..." --timeout 60 > /tmp/_run.json
197
- ```
198
- ```python
199
- import json, os
200
- r = json.load(open("/tmp/_run.json"))
201
- data = r.get("data", {})
202
- # CLI 字段名是 result_summary(不是 summary),是一个对象
203
- cli_summary = data.get("result_summary") or {}
204
- result = {
205
- "exit_code": data.get("exit_code"),
206
- "finished": data.get("finished", True),
207
- "summary": cli_summary,
208
- "result_summary": ", ".join(f"{k}={v}" for k,v in cli_summary.items()
209
- if isinstance(v, (str,int,float,bool)) and len(str(v))<200),
210
- "error": data.get("error"),
211
- }
212
- if not result["result_summary"]:
213
- result["result_summary"] = f"exit_code={result['exit_code']}, finished={result['finished']}"
214
- ws = os.environ.get("WORKSPACE_ROOT", ".")
215
- json.dump(result, open(os.path.join(ws, "result.json"), "w", encoding="utf-8"),
216
- indent=2, ensure_ascii=False)
217
- print(result["result_summary"])
218
- ```
219
- - **5b(fallback,仅当 `--no-summary` 或 `result_summary` 为 null)**:从 `sandbox run` / `sandbox run-bg --wait` / `sandbox logs` 返回数据中获得 `log_file` 路径,用 `sandbox read` + Python 解析。
193
+ **推荐实践**:让 sandbox 脚本在 `stdout` 末尾打印一个独立的结构化 JSON 对象(例如 `{"status":"ok", ...}`)。SSE 路径下 CLI 会检测该末尾 JSON 并直接在 `complete` 帧里带出 `result_summary`,**任务结束后直接复用 complete 帧的 `result_summary` 写入 result.json**,无需再 `sandbox read` log_file 反向扫描。仅当 complete 帧缺失 `result_summary`(末尾无合法 JSON)时,才用 `sandbox read <id> --path <log_file>` 读取并按步骤 5 反向扫描提取,避免让大模型“读整段日志再摘要”。
194
+ 5. **生成 result.json**(SSE 首选:直接复用 complete 帧的 `result_summary`;缺失时才从 `log_file` 读取解析):
195
+ - **获取 `log_file` 路径**:`run` / `run-bg --wait` 的 SSE `complete` 帧含 `log_file` 字段(CLI 已兜底补全);`sandbox logs <id> --execution-id <eid>` 快照在 `finished=true` 后同样返回 `log_file`。需要 read 时再按下面方式解析:
220
196
  - `sandbox read` 返回的是 CLI 信封 `{"ok":true,"data":{"content":"..."}}`,真实结果 JSON 在 `data.content` 字段里。
221
197
  - **不要把 CLI 信封或完整长 `stdout` 原样写入本地 `result.json`**;应该解析后生成一份精简的结构化摘要。
222
198
  - **推荐做法(避免 heredoc 引号失败)**:先用 `bash` 把信封写入临时文件,再用 `python3`(或 `python_repl`)读取该文件并生成 `result.json`。**不要**把 `delta-cli sandbox read` 的输出通过管道直接喂给内联 heredoc,管道+heredoc 的组合极易因 Shell 转义/引号问题失败。
@@ -308,8 +284,8 @@ required_outputs:
308
284
 
309
285
  ## 输出阅读与最终回答格式
310
286
 
311
- 1. **`sandbox run` / `run-bg --wait` 默认带 `--summary`,返回的 JSON 中 `data.result_summary` 字段已包含 stdout 末尾 JSON 提取结果(注意:这里是 `result_summary`,不是 `summary`)。也包含 `data.log_file`**(沙箱内 run envelope 日志文件的路径),作为 fallback 路径。
312
- 2. **默认优先用 `data.result_summary`**;仅当 `result_summary` 字段为 null(使用了 `--no-summary` 或 stdout 无 JSON)时,再用 `sandbox read <id> --path <log_file>` 读取 log_file 并解析 CLI 信封。
287
+ 1. **SSE 路径下 `sandbox run` / `run-bg --wait` 的 complete 帧直接带 `result_summary`**(CLI 检测 stdout 末尾 JSON 注入)以及 `stdout` / `stderr` / `log_file`(CLI 兜底补全)。`exit_code` / `log_file` / `execution_id` 从 complete 帧读取;命令失败时 complete 帧后追加 `error.type: command_failed` 信封(进程退出码 8)。`log_file` 路径也可从 `sandbox logs <id> --execution-id <eid>` 快照(`finished=true` 后)获得。
288
+ 2. **提取摘要**:首选直接复用 complete 帧的 `result_summary`;缺失时用 `sandbox read <id> --path <log_file>` 读取 run envelope 日志文件并解析,反向扫描 stdout 末尾 JSON 生成 `result_summary`(见“完整生命周期”步骤 5)。
313
289
  - run envelope 日志文件包含完整 `stdout`、`stderr`、`exit_code`、`finished`、`command`、`error`。
314
290
  3. **生成本地精简 `result.json`**(见“完整生命周期”步骤 5 和“通用结构化输出约定”)。本地副本只应包含关键字段和摘要,**不应包含完整长 `stdout`**。
315
291
  4. **最终回答必须且只能是 `RESULT:` 开头的一行。**
@@ -6,7 +6,7 @@
6
6
 
7
7
  | 命令 | 说明 |
8
8
  |------|------|
9
- | `sandbox list` | 列出当前用户创建的活跃 sandbox(与 `ls` 不同:这是列 **沙箱实例**) |
9
+ | `sandbox list [--status <running/finished/killed/error>] [--start-time <ISO8601>] [--end-time <ISO8601>] [--provider <opensandbox/autodl>] [--sandbox-id <id>] [--days N]` | 列出当前用户的 sandbox(与 `ls` 不同:这是列 **沙箱实例**);支持按状态/时间/Provider/sandbox_id 过滤;时间范围优先级 start_time/end_time > days > 默认 7 天 |
10
10
  | `sandbox providers` | 查看可用的计算后端(opensandbox / autodl) |
11
11
  | `sandbox images` | 查看可用镜像列表 |
12
12
  | `sandbox recommend --cpu N --memory XGi [--gpu N] [--gpu-mem N]` | 获取资源配置推荐 |
@@ -15,7 +15,7 @@
15
15
 
16
16
  | 命令 | 说明 |
17
17
  |------|------|
18
- | `sandbox create --image <img> [--cpu N --memory XGi --gpu N --gpu-mem N --max-life M --provider P]` | 创建 sandbox 容器 |
18
+ | `sandbox create --image <img> [--cpu N --memory XGi --gpu N --gpu-mem N --max-life M --no-auto-cleanup --provider P]` | 创建 sandbox 容器(`--no-auto-cleanup` 不被自动清理,仅显式 kill/finish 可销毁);**响应回显请求的 `image`/`provider`/`resource`**(服务端未返回字段用请求值补齐,服务端值优先;`provider=auto` 不回显) |
19
19
  | `sandbox connect <id>` | 连接已有 sandbox |
20
20
  | `sandbox status <id>` | 查看 sandbox 状态(running / done) |
21
21
  | `sandbox finish <id> [--results '{...}']` | 保存结果后自动销毁 |
@@ -25,9 +25,9 @@
25
25
 
26
26
  | 命令 | 说明 |
27
27
  |------|------|
28
- | `sandbox run <id> --command "..." [--timeout N] [--summary/--no-summary] [--artifacts]` | 同步运行命令;默认 `--summary` 开启,返回 JSON 中 `summary` 字段已含 stdout 末尾 JSON 提取结果;`--artifacts` 附带 workspace 产物清单 |
29
- | `sandbox run-bg <id> --command "..." [--timeout N] [--wait] [--summary/--no-summary] [--artifacts]` | 后台运行命令;不加 `--wait` 立即返回 `{execution_id, sandbox_id}`;加 `--wait` 等待完成返回含 `summary` 的完整结果 |
30
- | `sandbox logs <id> --execution-id <eid> [--tail N --grep <pattern> --context N]` | 获取后台命令日志;**默认返回 `stdout_tail`(末尾 800 字节)+ `stderr_tail`(末尾 200 字节)+ `stderr_size` + `cursor`**,总计约 1KB,避免上下文爆炸;`--tail N` 同时作用于 stdout 和 stderr(各取尾 N 行);`--grep <pattern>` 同时过滤 stdout 和 stderr(正则);`--context N` 提供 grep 匹配行前后 N 行上下文(同时用于 stdout 和 stderr);**`cursor` 字段无 `omitempty`,0 也常驻响应**。 |
28
+ | `sandbox run <id> --command "..." [--timeout N] [--summary/--no-summary] [--artifacts]` | 同步运行命令(SSE 实时流,原始 `data:` 帧逐帧透传到 stdout;**成功无末尾信封**;`complete` 帧由 CLI 补全 `exit_code`/`execution_id`/`log_file`/`stdout`/`stderr`/`result_summary`;**命令非零退出或报错时追加 `error.type: command_failed` 信封并以非零码退出**,信封 `message` 附 stderr 尾部,`type:"error"` 帧 message 亦附 best-effort stderr 尾部);`--summary`/`--artifacts` 仅在旧服务器回退路径(无 SSE 端点时输出 `CommandResult` 信封)生效 |
29
+ | `sandbox run-bg <id> --command "..." [--timeout N] [--wait] [--summary/--no-summary] [--artifacts]` | 后台运行命令;不加 `--wait` 立即返回 `{execution_id, sandbox_id}`;加 `--wait` 通过 SSE 实时流跟随到 `complete`(原始 `data:` 帧透传到 stdout;`complete` 帧由 CLI 补全 `log_file`/`stdout`/`stderr`/`result_summary`;**命令失败时追加 `command_failed` 信封并非零退出**,信封 `message` 附 stderr 尾部;超时则追加 `finished=false` 快照信封);`--summary`/`--artifacts` 仅在旧服务器回退路径生效 |
30
+ | `sandbox logs <id> --execution-id <eid> [--tail N --grep <pattern> --context N] [--stream]` | 获取后台命令日志;**默认返回 `stdout_tail`(末尾 800 字节)+ `stderr_tail`(末尾 200 字节)+ `stderr_size` + `cursor`**,总计约 1KB,避免上下文爆炸;`--stream` 走 `/logs/stream` SSE 实时跟随,原始 `data:` 帧透传到 stdout 直到 `complete`(complete 帧由 CLI 补全 `stdout`/`stderr`/`log_file`/`result_summary`,无末尾信封);`--tail N` 同时作用于 stdout 和 stderr(各取尾 N 行);`--grep <pattern>` 同时过滤 stdout 和 stderr(正则);`--context N` 提供 grep 匹配行前后 N 行上下文(同时用于 stdout 和 stderr);**`cursor` 字段无 `omitempty`,0 也常驻响应**;快照含 `last_updated`(SSE 路径由 CLI 填,服务端快照路径待服务端补齐)。 |
31
31
  | `sandbox cancel <id> --execution-id <eid>` | 中断正在运行的后台命令 |
32
32
 
33
33
  ## 文件操作
@@ -6,10 +6,10 @@
6
6
 
7
7
  1. **查看可用镜像** `delta-cli sandbox images` — 查询服务端支持的镜像列表。镜像决定了容器内的语言运行时(Python / Node.js / Go / Java / Rust 等),根据用户的技术栈和 GPU/CPU 需求匹配。
8
8
  2. **列出现有 sandbox(可选)** `delta-cli sandbox list` — 查看当前用户已创建的活跃 sandbox,避免重复创建
9
- 3. **创建** `delta-cli sandbox create --image <image> --cpu 4 --memory 16Gi --gpu 1 --gpu-mem 8000 --max-life 120`(创建后立即可用,无需连接;--max-life 指定 sandbox 最大存活时间(分钟),默认 30;这些是 `create` 全部资源参数,不要发明其它 flag。`--provider autodl` 可指定使用 AutoDL 后端。)
9
+ 3. **创建** `delta-cli sandbox create --image <image> --cpu 4 --memory 16Gi --gpu 1 --gpu-mem 8000 --max-life 120`(创建后立即可用,无需连接;--max-life 指定 sandbox 最大存活时间(分钟),默认 30。`--no-auto-cleanup` 可让 sandbox 不被自动清理,仅显式 kill/finish 可销毁。`--provider autodl` 可指定使用 AutoDL 后端。)
10
10
  4. **写入代码/数据** `delta-cli sandbox write <id> --path /workspace/<filename> --source <文件名>` — 将本地文件直接写入 sandbox。**必须**使用相对路径(如 `--source infer.py`),禁止使用 `"$WORKSPACE_ROOT/<filename>"`。也可用 `--data "..."` 写入少量内联内容,`--mode 755` 可设置文件权限。写入后返回的 `size` 字段是 stat 验证后的实际磁盘字节数,可确认写入完整。批量写入用 `write-multiple`。文件路径和扩展名由镜像中的运行时决定。
11
11
  5. **运行命令** — 根据镜像中的运行时构造命令,常见示例:`python /workspace/train.py`(Python)、`node /workspace/app.js`(Node.js)、`go run /workspace/main.go`(Go)、`bash /workspace/run.sh`(Shell)
12
- - **短任务 ≤60s**:`delta-cli sandbox run <id> --command "<命令>" --timeout <秒>` 同步执行,返回 `stdout`/`stderr`/`exit_code` (默认带 --summary,返回 JSON data.result_summary 已含 stdout 末尾 JSON 提取结果)
12
+ - **短任务 ≤60s**:`delta-cli sandbox run <id> --command "<命令>" --timeout <秒>` 同步执行,SSE 原始 `data:` 帧透传到 stdout(无末尾信封),`exit_code`/`log_file` 从 `complete` 帧读取,完整 stdout 写入 log_file
13
13
  - **长任务 >60s**:`delta-cli sandbox run-bg <id> --command "<命令>" --timeout <秒> --wait` 后台执行(推荐),或 `run-bg` + `logs` 手动轮询 (run-bg --wait 默认带 --summary;不加 --wait 立即返回 {execution_id, sandbox_id})
14
14
  6. **读取结果** `delta-cli sandbox read <id> --path /workspace/result.json` — 返回 `content`(内容)、`size`(磁盘字节,来自 stat)、`content_length`(字符数)。读不存在的文件返回 error 而非空内容。
15
15
  7. **销毁** `delta-cli sandbox kill <id>`(如需保存结果用 finish,finish 会自动销毁)
@@ -25,11 +25,11 @@
25
25
  ```bash
26
26
  delta-cli sandbox run-bg <id> --command "<命令>" --timeout 7200 --wait
27
27
  ```
28
- CLI 内部每 5 秒轮询一次,`finished=true` 时返回,结果中包含 `execution_id`。只消耗 **1 次 tool call**,适合不关心中间进度的场景。
28
+ CLI 通过 SSE 实时流(`/logs/stream`)跟随输出,把原始 SSE 帧(`data: {...}`)**逐帧透传到 stdout**,收到 `complete` 帧即命令结束。**CLI 会在 complete 帧里补全字段**:除服务端给的 `exit_code`/`execution_id`/`error` 外,还注入流内累计的 `stdout`/`stderr`、兜底恢复的 `log_file`,以及检测到的末尾 JSON `result_summary`(stdout 末尾 50 行内若有合法 JSON 对象)。命令非零退出或报错时,CLI **追加一个 `error.type: command_failed` 信封并以非零码退出**(进程退出码 8),便于 `&&` 链和 agent 分支;成功则不追加信封。只消耗 **1 次 tool call**,适合不关心中间进度的场景。
29
29
 
30
- > `--wait` 默认带 `--summary`,返回的 JSON `data.result_summary` 字段已包含 stdout 末尾结构化 JSON 的提取结果。常用场景无需再调 `sandbox read` 二次解析 log_file。
30
+ > `--wait` 的 SSE 路径 **complete 帧直接带 `result_summary`**(末尾 JSON 检测到即附上),无需再 `sandbox read <id> --path <log_file>` 反向扫描。仅当末尾没有合法 JSON 时才需手动读 log_file。`--summary`/`--artifacts` 富化(含 hints)仍仅旧服务器回退路径生效。
31
31
 
32
- > **结果信封统一为 `CommandResult`**:`run-bg --wait` 始终返回同一 `CommandResult` 信封:`{execution_id, sandbox_id, finished, exit_code, stderr_tail, stderr_size, log_file, result_summary, hints, error}`,`finished` 键**始终存在**。`finished=true` 表示执行结束并带富化摘要(`result_summary`/`hints`);`finished=false` 表示命令仍在运行(`exit_code` 与富化字段可能缺失),需用 `sandbox logs` 继续轮询或 `sandbox status` 查看。
32
+ > **输出契约(SSE 路径)**:`run-bg --wait` 命令成功时 stdout 只有原始 SSE 帧,**没有末尾信封**;命令失败时在 complete 帧后追加 `{"ok":false,"error":{"type":"command_failed",...}}` 信封;`--timeout` 内未结束则追加一个 `finished=false` 的 `CommandLogsResult` 快照信封;旧服务器(无 `/logs/stream` 端点)回退到 5s 轮询并输出 `CommandResult` 信封(`finished` 键始终存在,`finished=true` 时带 `result_summary`/`hints` 富化)。
33
33
 
34
34
  ### 方式二:手动轮询(需要看实时输出时)
35
35
 
@@ -38,7 +38,11 @@ CLI 内部每 5 秒轮询一次,`finished=true` 时返回,结果中包含 `e
38
38
  delta-cli sandbox run-bg <id> --command "<命令>" --timeout 7200
39
39
  # ↑ 返回 execution_id
40
40
 
41
- # 2. 手动轮询进度(可用 --tail N / --grep <pattern> 过滤大输出)
41
+ # 2a. 实时跟随(SSE,推荐):
42
+ delta-cli sandbox logs <id> --execution-id <exec_id> --stream
43
+ # ↑ 原始 data: 帧逐帧透传到 stdout,直到 complete 事件,无末尾信封
44
+
45
+ # 2b. 手动轮询快照(可用 --tail N / --grep <pattern> 过滤大输出)
42
46
  delta-cli sandbox logs <id> --execution-id <exec_id>
43
47
  # ↑ 返回 {sandbox_id, execution_id, stderr_tail, stderr_size, cursor, running, finished, exit_code, log_file?}
44
48
 
@@ -51,7 +55,7 @@ delta-cli sandbox kill <id>
51
55
  `sandbox logs` 返回的数据结构为:
52
56
 
53
57
  ```json
54
- {"ok":true,"data":{"sandbox_id":"...","execution_id":"...","stdout_tail":"...","stderr_tail":"...","stdout_size":1234,"stderr_size":1234,"cursor":5,"running":false,"finished":true,"exit_code":0,"log_file":"/tmp/delta-result-...json"}}
58
+ {"ok":true,"data":{"sandbox_id":"...","execution_id":"...","stdout_tail":"...","stderr_tail":"...","stdout_size":1234,"stderr_size":1234,"cursor":5,"running":false,"finished":true,"exit_code":0,"log_file":"/workspace/{user_id}/{sandbox_id}/{execution_id}/delta-result-{execution_id}.json"}}
55
59
  ```
56
60
 
57
61
  字段说明:
@@ -60,13 +64,14 @@ delta-cli sandbox kill <id>
60
64
  - `stderr_tail` — CLI 默认保留的 **最后 200 字节** stderr 片段(CLI 硬编码 `tailString(s, n)` 按字节截取;ASCII 等同 n 字符,多字节 UTF-8 可能被截断),避免上下文爆炸。不传任何 range flag 时,CLI 会把原始 `stdout`/`stderr` 字段清空,只暴露 `stdout_tail`/`stderr_tail` 和 `stdout_size`/`stderr_size`
61
65
  - `stdout_size` — 原始 stdout 字节数(CLI 端计算)
62
66
  - `stderr_size` — 原始 stderr 字节数(CLI 端计算)
63
- - `cursor` — 服务端 stderr 行计数器;**该字段无 `omitempty`,永远出现在响应中**(即使为 0)。`cursor=0` 通常意味着服务端从 provider 还没读到任何 stderr 行
67
+ - `cursor` — 服务端 stderr 行计数器;**该字段无 `omitempty`,永远出现在响应中**(即使为 0)。`cursor=0` 通常意味着服务端从 provider 还没读到任何 stderr 行;**仅凭 cursor 判断停滞不可靠**(纯 stdout 或静默任务 cursor 恒为 0),停滞检测应以 `last_updated` 为主
68
+ - `last_updated` — 最近活动时间(RFC3339)。SSE 流式路径由 CLI 填最后 data 帧到达时间;快照轮询路径由服务端填(当前服务端可能缺省),缺失时判断停滞退化用 `cursor`/`stdout_tail` 变化
64
69
  - `running` — 命令是否仍在运行
65
70
  - `finished` — 命令是否已完成(`finished = not running`)
66
71
  - `exit_code` — 退出码(完成后才有值,运行中字段省略)
67
- - `log_file` — 仅 `finished=true` 时出现,是 run envelope 日志文件路径(含完整 stdout + stderr + exit_code + finished + command + error),需读它用 `delta-cli sandbox read <id> --path <log_file>`
72
+ - `log_file` — 仅 `finished=true` 时出现,是 run envelope 日志文件路径(含完整 stdout + stderr + exit_code + finished + command + error),需读它用 `delta-cli sandbox read <id> --path <log_file>`;SSE 路径下 CLI 已在 complete 帧里兜底补全该字段
68
73
 
69
- **stdout 路径说明**:`sandbox logs` 默认返回 stdout 末尾 800 字节(`stdout_tail`)提供实时中间进度预览,完整 stdout 仍在命令结束时被写入沙箱内的 `log_file`,需全文时用 `sandbox read` 读。CLI `run-bg --wait` 完成后默认开启 `--summary`,会自动 reverse-scan stdout 末尾 JSON 填入 `data.result_summary`,常用场景无需手动读 `log_file`。
74
+ **stdout 路径说明**:`sandbox logs` 默认返回 stdout 末尾 800 字节(`stdout_tail`)提供实时中间进度预览,完整 stdout 仍在命令结束时被写入沙箱内的 `log_file`,需全文时用 `sandbox read` 读。SSE 路径下 CLI 已在 complete 帧里带 `stdout`(全文)与 `result_summary`(末尾 JSON 检测到即附上),`--summary` 富化(含 hints)仅旧服务器回退路径生效。
70
75
 
71
76
  要用 `--tail/--grep/--context` 自定义切片:传任意一个 flag 时,CLI 会把过滤后的 stdout 和 stderr 分别写回 `stdout`/`stderr` 字段并更新 `stdout_size`/`stderr_size`;不传则保持 `stdout=""` + `stdout_tail` 末尾 800 字节预览 + `stderr=""` + `stderr_tail` 末尾 200 字节预览(总计约 1KB)。
72
77
 
@@ -82,11 +87,11 @@ delta-cli sandbox logs <id> --execution-id <eid> --grep "ERROR|warning" --contex
82
87
  1. **`finished=true` + `exit_code=0`** → 正常完成,可以读取结果并销毁 sandbox
83
88
  2. **`finished=true` + `exit_code≠0`** → 命令执行失败,查看 stderr/error 信息
84
89
  3. **`running=true`** → 任务仍在运行,继续等待(建议每 15-30 秒查询一次)
85
- 4. **连续 3 次 `running=true` 且 `stderr_tail`/`cursor` 无变化且距离提交超过 60 秒** → 任务可能挂起或无输出,用 `sandbox status <id>` 检查 sandbox 是否存活
90
+ 4. **连续 3 次 `running=true` 且输出无变化且距离提交超过 60 秒** → 任务可能挂起或无输出,用 `sandbox status <id>` 检查 sandbox 是否存活。判断「输出无变化」:快照里有 `last_updated` 时,直接比较它与当前时间是否持续滞后;缺 `last_updated` 时才退化为 `stderr_tail`/`cursor` 无变化(注意 `cursor` 只反映 stderr 行数,纯 stdout 任务会恒为 0,勿据此误判挂起)
86
91
  5. **`sandbox status` 返回正常但 logs 仍然无变化** → 用 `sandbox run <id> --command "ps aux | grep <进程名>" --timeout 15` 在容器内检查命令是否还在运行
87
92
 
88
93
  **注意**:
89
94
  - `sandbox logs` 只应配合 `sandbox run-bg` 使用;同步 `sandbox run` 的结果直接返回,不能也不应该调用 `logs`。
90
95
  - `sandbox run-bg` 不加 `--wait` 时,HTTP 请求本身会快速返回 `{execution_id, sandbox_id}`;命令若超时会以非零退出码结束,需后续通过 `logs` 拿 `exit_code`。
91
- - `sandbox run-bg --wait` 模式下,`--timeout` **同时**充当服务端命令执行超时和客户端轮询 deadline(默认 300s);轮询间隔固定 5 秒;初始 `/run-background` POST 有独立的 60s HTTP timeout。
96
+ - `sandbox run-bg --wait` 模式下,`--timeout` **同时**充当服务端命令执行超时和客户端等待 deadline(默认 300s);CLI 通过 SSE 实时流(`/logs/stream`)跟随,原始 `data:` 帧透传到 stdout,收到 `complete` 即结束(无末尾信封),超时则追加 `finished=false` 快照信封;初始 `/run-background` POST 有独立的 60s HTTP timeout。
92
97
  - 后台命令可跨 tool call 轮次查询:保存 `sandbox_id` 和 `execution_id`,后续轮次通过 `sandbox status` / `sandbox logs` 获取结果。
@@ -22,7 +22,7 @@ required_outputs:
22
22
  {"status":"ok","key_metric_1":"value_1","key_metric_2":123}
23
23
  ```
24
24
 
25
- > `sandbox run` / `run-bg --wait` 默认带 `--summary`,CLI 会自动 reverse-scan stdout 末尾的 JSON 并填入响应 `data.result_summary` 字段。脚本作者只需保证 stdout 最后一行是合法 JSON,skill 端无需再做提取。
25
+ > SSE 路径下 `sandbox run` / `run-bg --wait` 的 **complete 帧已带 `result_summary`**(CLI 检测 stdout 末尾 50 行内的合法 JSON 对象并注入,无需手动 read+parse)。脚本作者保证 stdout 最后一行是合法 JSON 即可,skill 端直接从 complete 帧取 `result_summary`;仅当 complete 帧缺失该字段(末尾无合法 JSON)时才退化为 `sandbox read` 读取 `log_file` 反向扫描提取。`--summary` 富化(含 hints)仍仅旧服务器回退路径生效。
26
26
 
27
27
  SKILL 会把它提取为 `result.json` 的 `summary`,并生成 `result_summary` 与最终 `RESULT:` 行。
28
28
 
@@ -124,8 +124,9 @@ SKILL 会把它提取为 `result.json` 的 `summary`,并生成 `result_summary
124
124
 
125
125
  ## 本地 `result.json` 的内容约定
126
126
 
127
- - **默认路径**:`run` / `run-bg --wait` 返回 JSON 的 `data.result_summary` 字段已含 CLI 提取结果。写本地 `result.json` 时直接复用 `data.result_summary` 即可,无需再走 `sandbox read` 解析 `log_file`。
128
- - **fallback 路径**(用 `--no-summary` 时或 `summary` 为 null):保留 `delta-cli sandbox read <id> --path <log_file>` + Python 解析的旧路。
127
+ - **SSE 首选路径(推荐,一步到位)**:`sandbox run` / `run-bg --wait` 的 **complete 帧直接带 `result_summary`**(CLI 检测 stdout 末尾 JSON 注入),skill 从 complete 帧提取即可,无需 read+parse。
128
+ - **SSE 回退路径**:complete 帧缺失 `result_summary`(stdout 末尾无合法 JSON)时,`delta-cli sandbox read <id> --path <log_file>` 读取 run envelope 日志文件 + 反向扫描 stdout 末尾 JSON 提取。`log_file` 路径来自 SSE `complete` 帧(CLI 已兜底补全)或 `sandbox logs` 快照(`finished=true` 后)。
129
+ - **旧服务器回退路径**:`run` / `run-bg --wait` 走轮询回退时返回 `CommandResult` 信封,可直接复用 `data.result_summary` 字段。
129
130
  - 本地 `result.json` 是一份**精简摘要**,用于 host deliverable 校验,不是完整日志存档。
130
131
  - 必须包含 `result_summary` 字段,内容与最终 `RESULT:` 行一致,方便 Runner 直接读取结论。
131
132
  - 只写入关键字段(`exit_code`、`finished`、`summary`、`result_summary`、`error`)。**不要**额外添加 `final_answer` 等字段。
@@ -60,7 +60,7 @@ CLI 使用 `token` 发送请求头 `Authorization: Bearer <token>`,并自动
60
60
 
61
61
  AI Agent 解析规则:
62
62
  - 始终检查 `ok`,不要只看 exit code。
63
- - `error.type` 是稳定分支字段:`auth`, `permission`, `not_found`, `validation`, `network`, `api`, `internal`。
63
+ - `error.type` 是稳定分支字段:`auth`, `permission`, `not_found`, `validation`, `network`, `api`, `command_failed`, `internal`。
64
64
  - `error.hint` 可展示给用户。
65
65
 
66
66
  ## 退出码约定
@@ -73,6 +73,7 @@ AI Agent 解析规则:
73
73
  | not_found | 5 | sandbox/file 不存在 |
74
74
  | network | 6 | DNS、超时、连接失败 |
75
75
  | api | 7 | 服务端非 2xx |
76
+ | command_failed | 8 | sandbox 内命令执行失败(非零 exit_code 或报错);SSE 路径在 complete 帧后追加该 error 信封,**message 附 stderr 尾部**便于快速扫读 |
76
77
  | internal | 10 | 客户端内部错误 |
77
78
 
78
79
  ## 升级检查
@@ -92,4 +93,5 @@ delta-cli upgrade
92
93
  | `error.type: not_found` | 检查 `sandbox_id` / path |
93
94
  | `error.type: network` | 检查 `base_url` 和网络连通性 |
94
95
  | `error.type: validation` | 检查必填 flag 和参数格式 |
96
+ | `error.type: command_failed` | sandbox 内命令失败:信封 `message` 已带 stderr 尾部,可快速定位;完整 `stderr`/`result_summary` 在 complete 帧里,重试或修正命令 |
95
97
  | 配置文件解析失败 | 检查 `~/.delta-infra/config.json` 是否为有效 JSON |