@delta-infra/cli 1.1.16 → 1.1.18

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.
@@ -1,4 +1,4 @@
1
1
  interface:
2
- display_name: "Delta Sandbox 工作站"
3
- short_description: "通过 Delta CLI 安全创建、运行并销毁隔离计算工作站"
4
- default_prompt: "使用 $delta-sandbox 在隔离工作站中完成这项计算并返回结果。"
2
+ display_name: "Delta Sandbox workstation"
3
+ short_description: "Safely create, run and destroy isolated compute workstations using Delta CLI"
4
+ default_prompt: "Use $delta-sandbox to complete this computation in an isolated workstation and return the result."
@@ -1,58 +1,58 @@
1
- > **前置条件:** 先阅读 [`../delta-shared/SKILL.md`](../delta-shared/SKILL.md) 了解认证、配置和通用错误处理。
1
+ > **Prerequisite:** Read [`../../delta-shared/SKILL.md`](../../delta-shared/SKILL.md) first for authentication, configuration and general error handling.
2
2
 
3
- # 命令速查表
3
+ # Command reference
4
4
 
5
- ## 发现
5
+ ## Discovery
6
6
 
7
- | 命令 | 说明 |
7
+ | Command | Description |
8
8
  |------|------|
9
- | `sandbox list [--status <running/finished/killed/error>] [--start-time <ISO8601>] [--end-time <ISO8601>] [--sandbox-id <id>] [--days N]` | 列出当前用户的 sandbox(与 `ls` 不同:这是列 **沙箱实例**);支持按状态/时间/sandbox_id 过滤;时间范围优先级 start_time/end_time > days > 默认 7 天。**不再支持按算力后端(provider)过滤**——provider 为内部概念,自动选择 |
10
- | `sandbox resources` | 查看各算力分组的当前**剩余可申请**资源(GPU/显存/核心);响应 `compute_sources[].source` 为 `private`(私有算力)或 `third_party`(第三方算力);`gpu_types` 结构随分组不同——private 含 `vgpu`/`core`/`memory_mib` 的 `total/used/available`,third_party 含 `gpu_name`/`total_gpu_num`/`idle_gpu_num` |
11
- | `sandbox images` | 查看可用镜像列表(返回**镜像名**,底层镜像标识对用户隐藏);连"原逻辑"旧服务端时返回内部镜像名(URI),该值直接传给 `--image-name` 也能成功创建;连新逻辑服务端返回净化后的展示名 |
12
- | `sandbox recommend --cpu N --memory XGi [--gpu N] [--gpu-mem N]` | 获取资源配置推荐(`--memory`/`--gpu-mem` 支持 g/m/G/M 格式,如 `1G`/`512M`,CLI 自动转换为 Gi/Mi) |
9
+ | `sandbox list [--status <running/finished/killed/error>] [--start-time <ISO8601>] [--end-time <ISO8601>] [--sandbox-id <id>] [--days N]` | List the current user's sandboxes (unlike `ls`, this lists **sandbox instances**); filter by status, time or sandbox_id. Time-range precedence: start_time/end_time > days > the default of 7 days. **Filtering by compute backend (provider) is no longer supported**—provider selection is an internal detail and is automatic. |
10
+ | `sandbox resources` | Show the resources currently **available to request** in each compute group (GPU/VRAM/cores). In the response, `compute_sources[].source` is `private` or `third_party`; the `gpu_types` structure varies by group—`private` has `total/used/available` for `vgpu`/`core`/`memory_mib`, while `third_party` has `gpu_name`/`total_gpu_num`/`idle_gpu_num`. |
11
+ | `sandbox images` | List available images (returns the **image name**; the underlying image identifier is hidden from users). With an older server using the "original logic", the response contains the internal image name (URI), which can be passed directly to `--image-name` to create a sandbox successfully. A server using the new logic returns a sanitised display name. |
12
+ | `sandbox recommend --cpu N --memory XGi [--gpu N] [--gpu-mem N]` | Recommend a resource configuration (`--memory`/`--gpu-mem` accept g/m/G/M formats, such as `1G`/`512M`; the CLI converts these to Gi/Mi automatically). |
13
13
 
14
- ## 生命周期
14
+ ## Lifecycle
15
15
 
16
- | 命令 | 说明 |
16
+ | Command | Description |
17
17
  |------|------|
18
- | `sandbox create --image-name <镜像名> [--cpu N --memory XGi --gpu N --gpu-mem N --gpu-type <型号> --max-life M --no-auto-cleanup]` | 创建 sandbox 容器(`--image-name` 用镜像名,如 `"PyTorch CUDA13 (GPU)"`,底层镜像标识对用户隐藏;`--gpu-type` 指定 GPU 型号,如 `"RTX 4090"`、`H100`,服务端映射为 HAMi use-gputype 注解按型号调度,可选型号查 `sandbox resources`(`third_party` 分组 `gpu_types[].gpu_name`),不传则自动调度;`--no-auto-cleanup` 不被自动清理,仅显式 kill/finish 可销毁);`--memory`/`--gpu-mem` 支持 g/m/G/M 格式(如 `1G`/`512M`,小写亦可),CLI 自动转换为服务端接受的 `Gi`/`Mi` 单位;**响应回显请求的镜像名/resource**(服务端未返回字段用请求值补齐,服务端值优先);算力后端为内部概念,自动选择,不再支持 `--provider`。**单沙箱资源上限**:`--cpu` ≤ 512、`--memory` ≤ 1024Gi、`--gpu` ≤ 64、`--gpu-mem` ≤ 1024Gi,超出会在请求阶段**快速返回校验错误**(不会挂起),正常任务远低于这些上限 |
19
- | `sandbox connect <id>` | 连接已有 sandbox |
20
- | `sandbox status <id>` | 查看 sandbox 状态(running / done) |
21
- | `sandbox finish <id> [--results '{...}']` | 保存结果后自动销毁 |
22
- | `sandbox kill <id>` | 直接销毁 sandbox(不保存结果) |
18
+ | `sandbox create --image-name <image-name> [--cpu N --memory XGi --gpu N --gpu-mem N --gpu-type <model> --shm-size XGi --devices kvm --max-life M --no-auto-cleanup]` | Create a sandbox container (`--image-name` takes an image name, such as `"PyTorch CUDA13 (GPU)"`; the underlying image identifier is hidden from users. `--gpu-type` selects a GPU model, such as `"RTX 4090"` or `H100`; the server maps this to the HAMi use-gputype annotation for model-based scheduling. To see available models, check `sandbox resources` (the `third_party` group's `gpu_types[].gpu_name`); if omitted, scheduling is automatic. `--no-auto-cleanup` prevents automatic cleanup; the sandbox can then be destroyed only with an explicit kill/finish); `--memory`/`--gpu-mem` accept g/m/G/M formats (for example, `1G`/`512M`; lowercase is also accepted), which the CLI converts to the `Gi`/`Mi` units accepted by the server; `--shm-size` increases the container's `/dev/shm` (the **default is only 64Mi**; it must be increased if PyTorch `DataLoader(num_workers>0)`/`multiprocessing`, Chromium-based engines or similar report `No space left on device`/`Bus error` because shared memory is insufficient; **a Gi/Mi unit is required** (`4G`/`512M` are normalised by the CLI; the server rejects a bare number); it **must not exceed `--memory`** (it is a memory filesystem and filling it causes OOMKill; `--memory` defaults to only `1Gi`, so increasing shm usually requires increasing memory too); validation is backend-independent and rejects invalid values before creation, but this setting is applied only on private compute (third-party compute ignores it); `--devices` requests host-device passthrough using comma-separated tokens (for example, `kvm` makes `/dev/kvm` available inside the container for nested virtualisation; this raises privileges, and if the server allowlist is not enabled, creation is **explicitly rejected** rather than silently ignored; this setting is applied only on private compute); **resource limits per sandbox**: `--cpu` ≤ 512, `--memory` ≤ 1024Gi, `--gpu` ≤ 64, `--gpu-mem` ≤ 1024Gi, and `--shm-size` ≤ `--memory`. Exceeding a limit returns a **validation error promptly at request time** (it does not hang); normal tasks are well below these limits. The response echoes the requested image name/resource (request values fill fields not returned by the server; server values take precedence); compute backend is an internal detail and is selected automatically, so `--provider` is no longer supported. |
19
+ | `sandbox connect <id>` | Connect to an existing sandbox. |
20
+ | `sandbox status <id>` | Check sandbox status (running / done). |
21
+ | `sandbox finish <id> [--results '{...}']` | Save results and destroy the sandbox automatically. |
22
+ | `sandbox kill <id>` | Destroy the sandbox immediately without saving results. |
23
23
 
24
- ## 命令执行
24
+ ## Command execution
25
25
 
26
- | 命令 | 说明 |
26
+ | Command | Description |
27
27
  |------|------|
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 填,服务端快照路径待服务端补齐)。**省略 `--execution-id` 时按 sandbox 查询**(服务端走 ES),返回**数组**(按 execution_id 聚合,每项含 `execution_id`/`stdout`/`stderr`/`exit_code`/`command`/`finished`/`error`/`log_file`),CLI 对每个元素同样应用 tail/grep 裁剪。 |
31
- | `sandbox cancel <id> --execution-id <eid>` | 中断正在运行的后台命令 |
28
+ | `sandbox run <id> --command "..." [--timeout N] [--summary/--no-summary] [--artifacts]` | Run a command synchronously (live SSE stream; raw `data:` frames are passed through to stdout one by one; **there is no trailing envelope on success**; the CLI fills in `exit_code`/`execution_id`/`log_file`/`stdout`/`stderr`/`result_summary` in the `complete` frame; **if the command exits non-zero or errors, an `error.type: command_failed` envelope is appended and the process exits non-zero**; the envelope's `message` includes the stderr tail, as does the message in a `type:"error"` frame on a best-effort basis). `--summary`/`--artifacts` take effect only on the legacy-server fallback path (when there is no SSE endpoint and a `CommandResult` envelope is returned). |
29
+ | `sandbox run-bg <id> --command "..." [--timeout N] [--wait] [--summary/--no-summary] [--artifacts]` | Run a command in the background. Without `--wait`, return `{execution_id, sandbox_id}` immediately. With `--wait`, follow the live SSE stream until `complete` (raw `data:` frames are passed through to stdout; the CLI fills in `log_file`/`stdout`/`stderr`/`result_summary` in the `complete` frame; **on command failure, a `command_failed` envelope is appended and the process exits non-zero**; the envelope's `message` includes the stderr tail; on timeout, a `finished=false` snapshot envelope is appended). `--summary`/`--artifacts` take effect only on the legacy-server fallback path. |
30
+ | `sandbox logs <id> --execution-id <eid> [--tail N --grep <pattern> --context N] [--stream]` | Retrieve background-command logs. **By default, returns `stdout_tail` (last 800 bytes) + `stderr_tail` (last 200 bytes) + `stderr_size` + `cursor`**, about 1 KB in total, to keep context small. `--stream` follows the live `/logs/stream` SSE endpoint, passing raw `data:` frames through to stdout until `complete` (the CLI fills in `stdout`/`stderr`/`log_file`/`result_summary` in the complete frame; there is no trailing envelope). `--tail N` applies to both stdout and stderr (last N lines from each); `--grep <pattern>` filters both stdout and stderr (regular expression); `--context N` includes N lines before and after each grep match (for both stdout and stderr). The `cursor` field has no `omitempty` and is always present, even when 0. Snapshots include `last_updated` (filled by the CLI on the SSE path; the server snapshot path is awaiting a server-side update). **If `--execution-id` is omitted, query by sandbox** (the server uses ES); the response is an **array** grouped by execution_id (each item contains `execution_id`/`stdout`/`stderr`/`exit_code`/`command`/`finished`/`error`/`log_file`), and the CLI applies the same tail/grep trimming to each item. |
31
+ | `sandbox cancel <id> --execution-id <eid>` | Interrupt a background command that is running. |
32
32
 
33
- ## 文件操作
33
+ ## File operations
34
34
 
35
- | 命令 | 说明 |
35
+ | Command | Description |
36
36
  |------|------|
37
- | `sandbox read <id> --path <path> [--output <本地路径>] [--tail N] [--grep <pattern>] [--offset N] [--limit N] [--context N] [--max-bytes N] [--parse-json]` | 读取文件;返回 `content` + `size` + `content_length`;`--output <path>` 保存到本地;`--tail/--grep` 用于过滤;非 UTF-8 文件 CLI 自动走 base64 fallback |
38
- | `sandbox working-directory <id>` | 查询 sandbox 当前工作目录(绝对路径 `/workspace/{user_id}/{sandbox_id}`) |
39
- | `sandbox write <id> [--path <路径>] --source <文件名>` | 写入文件(推荐)。不传 `--path` 默认写到 working-directory(`<working-directory>/<文件名>`);相对 `--path` 也会拼到 working-directory 下;仅绝对 `--path` 原样使用(但 `/workspace/<文件名>` 根路径不在 OSS 同步范围内,不推荐) |
40
- | `sandbox write <id> --path <绝对路径> --data "..."` | 写入少量内联内容(`--data` 无源文件名,必须显式传 `--path`) |
41
- | `sandbox write-multiple <id> --entry <src=path> [--entry ...]` | 批量写入多个文件(目标 `path` 相对则同样拼到 working-directory) |
42
- | `sandbox pull <id> --source <沙箱路径> --target <本地路径> [--recursive] [--pattern <glob>]` | 拉取文件/目录到本地(mirror of `upload`,flag 方向相反:`--source`=远程沙箱路径,`--target`=本地路径);单文件自动识别;目录默认递归;CLI 端 + 服务端双向 sha1 完整性校验 |
43
- | `sandbox ls <id> --path <path>` | 列出目录内容(默认 `.`) |
44
- | `sandbox stat <id> --path <path>` | 获取文件元数据(size / mode / owner / group) |
45
- | `sandbox mv <id> --entry <source=dest> [--entry ...]` | 移动或重命名文件 |
46
- | `sandbox replace <id> --path <path> --old <文本> --new <文本> [--regex] [--ignore-case]` | 替换文件内容 |
47
- | `sandbox chmod <id> --path <path> --mode <八进制>` | 修改文件权限 |
48
- | `sandbox rm <id> --path <path> [--path ...]` | 删除文件 |
49
- | `sandbox mkdir <id> --path <路径> [--path ...]` | 创建目录(mkdir -p) |
50
- | `sandbox search <id> --path <根目录> --pattern <glob>` | 搜索文件 |
51
-
52
- ## 注意事项
53
-
54
- - `list` ≠ `ls`:`sandbox list` 列沙箱实例,`sandbox ls <id>` 列沙箱内目录
55
- - **算力后端(provider)为内部概念**:系统自动选择,各命令不再支持 `--provider`;`sandbox providers` 命令已随服务端 `/providers` 端点移除而废弃,调用会返回 404,不要使用
56
- - 写文件后返回的 `size` 是 stat 验证后的实际磁盘字节数
57
- - 读文件返回 `size`(磁盘字节,来自 stat)和 `content_length`(内存字符数),对比可判断编码偏差
58
- - 读不存在的文件会返回 error,不会静默返回空内容
37
+ | `sandbox read <id> --path <path> [--output <local-path>] [--tail N] [--grep <pattern>] [--offset N] [--limit N] [--context N] [--max-bytes N] [--parse-json]` | Read a file; returns `content` + `size` + `content_length`. `--output <path>` saves it locally; `--tail`/`--grep` filter the output. For non-UTF-8 files, the CLI automatically falls back to base64. |
38
+ | `sandbox working-directory <id>` | Get the sandbox's current working directory (absolute path `/workspace/{user_id}/{sandbox_id}`). |
39
+ | `sandbox write <id> [--path <path>] --source <filename>` | Write a file (recommended). If `--path` is omitted, write to the working directory (`<working-directory>/<filename>`); a relative `--path` is also resolved under the working directory. An absolute `--path` is used as-is (but the `/workspace/<filename>` root path is outside the OSS sync scope and is not recommended). |
40
+ | `sandbox write <id> --path <absolute-path> --data "..."` | Write a small amount of inline content (`--data` has no source filename, so `--path` must be specified explicitly). |
41
+ | `sandbox write-multiple <id> --entry <src=path> [--entry ...]` | Write multiple files in one operation (a relative target `path` is also resolved under the working directory). |
42
+ | `sandbox pull <id> --source <sandbox-path> --target <local-path> [--recursive] [--pattern <glob>]` | Pull files/directories to the local machine (the reverse of `upload`; flag directions are reversed: `--source`=remote sandbox path, `--target`=local path). Single files are detected automatically; directories are traversed recursively by default; SHA-1 integrity is checked by both the CLI and server. |
43
+ | `sandbox ls <id> --path <path>` | List directory contents (defaults to `.`). |
44
+ | `sandbox stat <id> --path <path>` | Get file metadata (size / mode / owner / group). |
45
+ | `sandbox mv <id> --entry <source=dest> [--entry ...]` | Move or rename files. |
46
+ | `sandbox replace <id> --path <path> --old <text> --new <text> [--regex] [--ignore-case]` | Replace file contents. |
47
+ | `sandbox chmod <id> --path <path> --mode <octal>` | Change file permissions. |
48
+ | `sandbox rm <id> --path <path> [--path ...]` | Delete files. |
49
+ | `sandbox mkdir <id> --path <path> [--path ...]` | Create directories (`mkdir -p`). |
50
+ | `sandbox search <id> --path <root-directory> --pattern <glob>` | Search for files. |
51
+
52
+ ## Notes
53
+
54
+ - `list` ≠ `ls`: `sandbox list` lists sandbox instances; `sandbox ls <id>` lists directories inside a sandbox.
55
+ - **Compute backend (provider) is an internal detail**: the system selects it automatically, and commands no longer support `--provider`. The `sandbox providers` command was retired when the server's `/providers` endpoint was removed; calling it returns 404. Do not use it.
56
+ - After writing a file, the returned `size` is the actual on-disk byte count verified with stat.
57
+ - Reading a file returns `size` (disk bytes, from stat) and `content_length` (characters in memory); comparing them can reveal encoding differences.
58
+ - Reading a non-existent file returns an error rather than silently returning empty content.
@@ -1,100 +1,100 @@
1
- > **前置条件:** 先阅读 [`../delta-shared/SKILL.md`](../delta-shared/SKILL.md) 了解认证、配置和通用错误处理。
1
+ > **Prerequisite:** Read [`../../delta-shared/SKILL.md`](../../delta-shared/SKILL.md) first for authentication, configuration and general error handling.
2
2
 
3
- # Delta Sandbox 生命周期
3
+ # Delta Sandbox lifecycle
4
4
 
5
- ## 完整流程
5
+ ## Complete workflow
6
6
 
7
- 1. **查看可用镜像** `delta-cli sandbox images` — 查询服务端支持的镜像列表。镜像决定了容器内的语言运行时(Python / Node.js / Go / Java / Rust 等),根据用户的技术栈和 GPU/CPU 需求匹配。
8
- 2. **列出现有 sandbox(可选)** `delta-cli sandbox list` — 查看当前用户已创建的活跃 sandbox,避免重复创建
9
- 3. **创建** `delta-cli sandbox create --image-name <镜像名> --cpu 4 --memory 16Gi --gpu 1 --gpu-mem 8000 --max-life 120 [--gpu-type <型号>]`(创建后立即可用,无需连接;--memory/--gpu-mem 支持 g/m/G/M 格式(如 1G/512M,小写亦可),CLI 自动转换为 Gi/Mi;--max-life 指定 sandbox 最大存活时间(分钟),默认 30。`--no-auto-cleanup` 可让 sandbox 不被自动清理,仅显式 kill/finish 可销毁。`--image-name` 用镜像名,如 `"PyTorch CUDA13 (GPU)"`;算力后端为内部概念,自动选择,无需指定。`--gpu-type`(可选)指定 GPU 型号,如 `"RTX 4090"`、`H100`,服务端映射为 HAMi use-gputype 注解按型号调度,可选型号查 `sandbox resources`(`third_party` 分组 `gpu_types[].gpu_name`),不传则自动调度。**单沙箱资源上限**:cpu ≤ 512、memory ≤ 1024Gi、gpu ≤ 64、gpuMem ≤ 1024Gi,超出会在请求阶段快速返回校验错误而非挂起。)
10
- 4. **写入代码/数据** `delta-cli sandbox write <id> --source <文件名>` — 将本地文件直接写入 sandbox,**不传 `--path` 默认写到该 sandbox 的 working-directory**(`/workspace/{user_id}/{sandbox_id}/<文件名>`,在 OSS 同步范围内,kill 后文件不会丢)。写前可用 `delta-cli sandbox working-directory <id>` 确认路径。**必须**使用相对源路径(如 `--source infer.py`),禁止使用 `"$WORKSPACE_ROOT/<filename>"` 或 `$(pwd)/...`。相对 `--path` 也会拼到 working-directory 下;仅绝对 `--path` 原样使用(`/workspace/<filename>` 根路径不在 OSS 同步范围,不推荐)。也可用 `--data "..."` 写入少量内联内容(需显式 `--path`),`--mode 755` 可设置文件权限。写入后返回的 `size` 字段是 stat 验证后的实际磁盘字节数,可确认写入完整。批量写入用 `write-multiple`。文件路径和扩展名由镜像中的运行时决定。
11
- 5. **运行命令** — 先 `delta-cli sandbox working-directory <id>` 查询 `<wd>`,再根据镜像中的运行时构造命令,常见示例:`python <wd>/train.py`(Python)、`node <wd>/app.js`(Node.js)、`go run <wd>/main.go`(Go)、`bash <wd>/run.sh`(Shell)
12
- - **短任务 ≤60s**:`delta-cli sandbox run <id> --command "<命令>" --timeout <秒>` 同步执行,SSE 原始 `data:` 帧透传到 stdout(无末尾信封),`exit_code`/`log_file` 从 `complete` 帧读取,完整 stdout 写入 log_file
13
- - **长任务 >60s**:`delta-cli sandbox run-bg <id> --command "<命令>" --timeout <秒> --wait` 后台执行(推荐),或 `run-bg` + `logs` 手动轮询 (run-bg --wait 默认带 --summary;不加 --wait 立即返回 {execution_id, sandbox_id})
14
- 6. **读取结果** `delta-cli sandbox read <id> --path <wd>/result.json`(`<wd>` 为 working-directory,可用 `delta-cli sandbox working-directory <id>` 查询) — 返回 `content`(内容)、`size`(磁盘字节,来自 stat)、`content_length`(字符数)。读不存在的文件返回 error 而非空内容。
15
- 7. **销毁** `delta-cli sandbox kill <id>`(如需保存结果用 finish,finish 会自动销毁)
7
+ 1. **Check available images** `delta-cli sandbox images` — list the images supported by the server. The image determines which language runtimes are available in the container (Python / Node.js / Go / Java / Rust, etc.); choose one that fits the user's technology stack and GPU/CPU requirements.
8
+ 2. **List existing sandboxes (optional)** `delta-cli sandbox list` — check the active sandboxes already created by the current user to avoid creating duplicates.
9
+ 3. **Create** `delta-cli sandbox create --image-name <image-name> --cpu 4 --memory 16Gi --gpu 1 --gpu-mem 8000 --max-life 120 [--gpu-type <model>] [--shm-size XGi] [--devices kvm]` (the sandbox is ready to use immediately; no connection step is needed. `--memory`/`--gpu-mem` accept g/m/G/M formats (for example, 1G/512M; lowercase is also accepted), which the CLI converts to Gi/Mi. `--max-life` sets the sandbox's maximum lifetime in minutes; the default is 30. `--no-auto-cleanup` prevents automatic cleanup; the sandbox can then be destroyed only with an explicit kill/finish. `--image-name` takes an image name, such as `"PyTorch CUDA13 (GPU)"`; compute backend selection is automatic and does not need to be specified. `--gpu-type` (optional) selects a GPU model, such as `"RTX 4090"` or `H100`; the server maps this to the HAMi use-gputype annotation for model-based scheduling. To see available models, check `sandbox resources` (the `third_party` group's `gpu_types[].gpu_name`); if omitted, scheduling is automatic. `--shm-size` (optional) increases the container's `/dev/shm` (the **default is only 64Mi**)—it must be increased when PyTorch `DataLoader(num_workers>0)`/`multiprocessing`, Chromium-based engines or similar report `No space left on device`/`Bus error`; **a Gi/Mi unit is required** (`4G`/`512M` are normalised by the CLI; the server rejects a bare number), and it **must not exceed `--memory`** (it is a memory filesystem and filling it causes OOMKill; `--memory` defaults to only 1Gi, so increasing shm usually requires increasing memory too, for example, `--memory 8Gi --shm-size 4Gi`). Only private compute (`private`) applies this setting (third-party compute ignores it), but unit/limit validation is backend-independent and rejects invalid values before creation. `--devices` (optional) requests host-device passthrough using comma-separated tokens (for example, `--devices kvm` makes `/dev/kvm` available inside the container for nested virtualisation); this raises privileges, and if the server allowlist is not enabled, creation is **explicitly rejected** (not silently ignored; validation is backend-independent). If this error occurs, do not retry; use an approach that does not depend on that device. Only private compute applies this setting. **Resource limits per sandbox**: cpu ≤ 512, memory ≤ 1024Gi, gpu ≤ 64, gpuMem ≤ 1024Gi, shmSize ≤ memory. Exceeding a limit returns a validation error promptly at request time rather than hanging.)
10
+ 4. **Write code/data** `delta-cli sandbox write <id> --source <filename>` — write a local file directly to the sandbox. If `--path` is omitted, the file is written to that sandbox's working directory by default (`/workspace/{user_id}/{sandbox_id}/<filename>`, which is within the OSS sync scope, so the file persists after kill). Before writing, use `delta-cli sandbox working-directory <id>` to confirm the path. **You must** use a relative source path (for example, `--source infer.py`); do not use `"$WORKSPACE_ROOT/<filename>"` or `$(pwd)/...`. A relative `--path` is also resolved under the working directory; an absolute `--path` is used as-is (`/workspace/<filename>` is outside the OSS sync scope and is not recommended). You can also use `--data "..."` to write a small amount of inline content (requires an explicit `--path`), and `--mode 755` to set file permissions. The returned `size` field is the actual on-disk byte count verified with stat, so it can confirm that the write completed. Use `write-multiple` to write several files at once. File paths and extensions depend on the runtimes in the image.
11
+ 5. **Run a command** — first use `delta-cli sandbox working-directory <id>` to get `<wd>`, then construct a command for a runtime in the image. Common examples: `python <wd>/train.py` (Python), `node <wd>/app.js` (Node.js), `go run <wd>/main.go` (Go), `bash <wd>/run.sh` (Shell).
12
+ - **Short tasks ≤60s**: `delta-cli sandbox run <id> --command "<command>" --timeout <seconds>` runs synchronously; raw SSE `data:` frames are passed through to stdout (with no trailing envelope), `exit_code`/`log_file` are read from the `complete` frame, and full stdout is written to the log_file.
13
+ - **Long tasks >60s**: run `delta-cli sandbox run-bg <id> --command "<command>" --timeout <seconds> --wait` in the background (recommended), or use `run-bg` + `logs` for manual polling (`run-bg --wait` includes `--summary` by default; without `--wait`, it returns `{execution_id, sandbox_id}` immediately).
14
+ 6. **Read the results** `delta-cli sandbox read <id> --path <wd>/result.json` (`<wd>` is the working directory; use `delta-cli sandbox working-directory <id>` to find it) — returns `content` (contents), `size` (disk bytes, from stat) and `content_length` (character count). Reading a non-existent file returns an error rather than empty content.
15
+ 7. **Destroy the sandbox** `delta-cli sandbox kill <id>` (if you need to save results, use finish; finish destroys the sandbox automatically).
16
16
 
17
- > **注意**:server 端没有 sandbox 的自动过期或 TTL 机制,不 kill 会永久占用 GPU 资源。请务必在任务结束后销毁。
17
+ > **Note:** The server has no automatic sandbox expiry or TTL mechanism. If you do not kill a sandbox, it will occupy GPU resources indefinitely. Always destroy it when the task is complete.
18
18
 
19
- ## 后台任务
19
+ ## Background tasks
20
20
 
21
- 对于长时间运行的任务(>60 秒,如训练、编译、数据处理),使用 `run-bg` 在后台异步执行:
21
+ For long-running tasks (>60 seconds, such as training, compilation or data processing), run `run-bg` asynchronously in the background:
22
22
 
23
- ### 方式一(推荐):`--wait` 一次性等待完成
23
+ ### Method 1 (recommended): wait for completion with `--wait`
24
24
 
25
25
  ```bash
26
- delta-cli sandbox run-bg <id> --command "<命令>" --timeout 7200 --wait
26
+ delta-cli sandbox run-bg <id> --command "<command>" --timeout 7200 --wait
27
27
  ```
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**,适合不关心中间进度的场景。
28
+ The CLI follows the live SSE stream (`/logs/stream`) and passes raw SSE frames (`data: {...}`) through to stdout one by one; the command ends when a `complete` frame arrives. **The CLI fills in fields in the complete frame**: in addition to the server-provided `exit_code`/`execution_id`/`error`, it adds the `stdout`/`stderr` accumulated from the stream, a recovered `log_file` if needed, and a detected trailing JSON `result_summary` (a valid JSON object found within the last 50 lines of stdout). If the command exits non-zero or errors, the CLI **appends an `error.type: command_failed` envelope and exits non-zero** (process exit code 8), which is useful for `&&` chains and agent branching; on success, no envelope is appended. This uses only **1 tool call**, making it suitable when intermediate progress is not needed.
29
29
 
30
- > `--wait` 的 SSE 路径 **complete 帧直接带 `result_summary`**(末尾 JSON 检测到即附上),无需再 `sandbox read <id> --path <log_file>` 反向扫描。仅当末尾没有合法 JSON 时才需手动读 log_file。`--summary`/`--artifacts` 富化(含 hints)仍仅旧服务器回退路径生效。
30
+ > On the SSE path, `--wait` puts `result_summary` directly in the **complete frame** (if trailing JSON is detected), so there is no need to scan backwards with `sandbox read <id> --path <log_file>`. Read the log_file manually only if no valid JSON is found at the end. `--summary`/`--artifacts` enrichment (including hints) still takes effect only on the legacy-server fallback path.
31
31
 
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` 富化)。
32
+ > **Output contract (SSE path):** On success, `run-bg --wait` writes only raw SSE frames to stdout, with **no trailing envelope**. On command failure, it appends an `{"ok":false,"error":{"type":"command_failed",...}}` envelope after the complete frame. If the command has not finished within `--timeout`, it appends a `finished=false` `CommandLogsResult` snapshot envelope. For an older server (without the `/logs/stream` endpoint), the CLI falls back to polling every 5s and outputs a `CommandResult` envelope (the `finished` key is always present; when `finished=true`, it includes `result_summary`/`hints` enrichment).
33
33
 
34
- ### 方式二:手动轮询(需要看实时输出时)
34
+ ### Method 2: poll manually (when you need to see live output)
35
35
 
36
36
  ```bash
37
- # 1. 启动后台命令
38
- delta-cli sandbox run-bg <id> --command "<命令>" --timeout 7200
39
- # ↑ 返回 execution_id
37
+ # 1. Start the background command
38
+ delta-cli sandbox run-bg <id> --command "<command>" --timeout 7200
39
+ # ↑ Returns execution_id
40
40
 
41
- # 2a. 实时跟随(SSE,推荐):
41
+ # 2a. Follow the live stream (SSE, recommended):
42
42
  delta-cli sandbox logs <id> --execution-id <exec_id> --stream
43
- # ↑ 原始 data: 帧逐帧透传到 stdout,直到 complete 事件,无末尾信封(--stream 必须传 --execution-id)
43
+ # ↑ Raw data: frames pass through to stdout one by one until the complete event, with no trailing envelope (--stream requires --execution-id)
44
44
 
45
- # 2b. 手动轮询快照(可用 --tail N / --grep <pattern> 过滤大输出)
45
+ # 2b. Poll a snapshot manually (use --tail N / --grep <pattern> to filter large output)
46
46
  delta-cli sandbox logs <id> --execution-id <exec_id>
47
- # ↑ 返回 {sandbox_id, execution_id, stderr_tail, stderr_size, cursor, running, finished, exit_code, log_file?}
48
- # --execution-id 可省略:省略时仅按 sandbox 查询,服务端因 sandbox_id/execution_id 未同时传递而自动走 ES;
49
- # 此时返回的是按 execution_id 聚合的**数组**(每项含 execution_id/stdout/stderr/exit_code/command/finished/error/log_file),
50
- # 而非单个快照对象,CLI 对每个元素同样做 800/200 字节 tail 裁剪与 --tail/--grep/--context 过滤
47
+ # ↑ Returns {sandbox_id, execution_id, stderr_tail, stderr_size, cursor, running, finished, exit_code, log_file?}
48
+ # --execution-id may be omitted: if omitted, the query is by sandbox only; because sandbox_id and execution_id are not both passed, the server automatically uses ES;
49
+ # the response is then an **array** grouped by execution_id (each item contains execution_id/stdout/stderr/exit_code/command/finished/error/log_file),
50
+ # rather than a single snapshot object; the CLI also applies 800/200-byte tail trimming and --tail/--grep/--context filters to each item
51
51
 
52
- # 3. 完成后销毁
52
+ # 3. Destroy after completion
53
53
  delta-cli sandbox kill <id>
54
54
  ```
55
55
 
56
- ### 轮询判断逻辑
56
+ ### How to interpret polling results
57
57
 
58
- `sandbox logs` 返回的数据结构为:
58
+ The data structure returned by `sandbox logs` looks like this:
59
59
 
60
60
  ```json
61
61
  {"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_logs/delta-result-{sandbox_id}-{execution_id}.json"}}
62
62
  ```
63
63
 
64
- 字段说明:
65
- - `sandbox_id` / `execution_id` — 与请求一致;省略 `--execution-id` 时走 ES 按 sandbox 查询,该字段为空
66
- - `stdout_tail` — CLI 默认保留的 **最后 800 字节** stdout 片段,避免上下文爆炸
67
- - `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`
68
- - `stdout_size` — 原始 stdout 字节数(CLI 端计算)
69
- - `stderr_size` — 原始 stderr 字节数(CLI 端计算)
70
- - `cursor` — 服务端 stderr 行计数器;**该字段无 `omitempty`,永远出现在响应中**(即使为 0)。`cursor=0` 通常意味着服务端从 provider 还没读到任何 stderr 行;**仅凭 cursor 判断停滞不可靠**(纯 stdout 或静默任务 cursor 恒为 0),停滞检测应以 `last_updated` 为主
71
- - `last_updated` — 最近活动时间(RFC3339)。SSE 流式路径由 CLI 填最后 data 帧到达时间;快照轮询路径由服务端填(当前服务端可能缺省),缺失时判断停滞退化用 `cursor`/`stdout_tail` 变化
72
- - `running` — 命令是否仍在运行
73
- - `finished` — 命令是否已完成(`finished = not running`)
74
- - `exit_code` — 退出码(完成后才有值,运行中字段省略)
75
- - `log_file` — 仅 `finished=true` 时出现,是 run envelope 日志文件路径(含完整 stdout + stderr + exit_code + finished + command + error),需读它用 `delta-cli sandbox read <id> --path <log_file>`;SSE 路径下 CLI 已在 complete 帧里兜底补全该字段
64
+ Field descriptions:
65
+ - `sandbox_id` / `execution_id` — match the request; if `--execution-id` is omitted, the server queries ES by sandbox and this field is empty.
66
+ - `stdout_tail` — the last **800 bytes** of stdout, retained by default by the CLI to keep context small.
67
+ - `stderr_tail` — the last **200 bytes** of stderr, retained by default by the CLI (the CLI hard-codes `tailString(s, n)` to slice by byte; for ASCII, this is n characters, while multibyte UTF-8 may be truncated). This keeps context small. If no range flag is passed, the CLI clears the raw `stdout`/`stderr` fields and exposes only `stdout_tail`/`stderr_tail` and `stdout_size`/`stderr_size`.
68
+ - `stdout_size` — number of bytes in the original stdout (calculated by the CLI).
69
+ - `stderr_size` — number of bytes in the original stderr (calculated by the CLI).
70
+ - `cursor` — server-side stderr line counter; **this field has no `omitempty` and is always present in the response**, even when 0. `cursor=0` usually means the server has not yet read any stderr lines from the provider. **A cursor alone is not a reliable way to detect a stall** (`cursor` stays at 0 for stdout-only or silent tasks); use `last_updated` as the primary signal when detecting stalls.
71
+ - `last_updated` — most recent activity time (RFC3339). On the SSE streaming path, the CLI sets this to the arrival time of the last data frame. On the snapshot polling path, it is supplied by the server (which may currently omit it); if missing, fall back to changes in `cursor`/`stdout_tail` when checking for a stall.
72
+ - `running` — whether the command is still running.
73
+ - `finished` — whether the command has completed (`finished = not running`).
74
+ - `exit_code` — exit code (available only after completion; omitted while running).
75
+ - `log_file` — present only when `finished=true`; path to the run-envelope log file (containing full stdout + stderr + exit_code + finished + command + error). Read it with `delta-cli sandbox read <id> --path <log_file>`. On the SSE path, the CLI fills in this field in the complete frame if needed.
76
76
 
77
- **stdout 路径说明**:`sandbox logs` 默认返回 stdout 末尾 800 字节(`stdout_tail`)提供实时中间进度预览,完整 stdout 仍在命令结束时被写入沙箱内的 `log_file`,需全文时用 `sandbox read` 读。SSE 路径下 CLI 已在 complete 帧里带 `stdout`(全文)与 `result_summary`(末尾 JSON 检测到即附上),`--summary` 富化(含 hints)仅旧服务器回退路径生效。
77
+ **stdout routing:** By default, `sandbox logs` returns the last 800 bytes of stdout (`stdout_tail`) as a preview of live progress. Full stdout is written to the sandbox's `log_file` when the command ends; use `sandbox read` to read it all. On the SSE path, the CLI includes full `stdout` and `result_summary` in the complete frame (the latter is included when trailing JSON is detected). `--summary` enrichment (including hints) takes effect only on the legacy-server fallback path.
78
78
 
79
- 要用 `--tail/--grep/--context` 自定义切片:传任意一个 flag 时,CLI 会把过滤后的 stdout 和 stderr 分别写回 `stdout`/`stderr` 字段并更新 `stdout_size`/`stderr_size`;不传则保持 `stdout=""` + `stdout_tail` 末尾 800 字节预览 + `stderr=""` + `stderr_tail` 末尾 200 字节预览(总计约 1KB)。
79
+ To customise the output slice with `--tail`/`--grep`/`--context`, pass any one of these flags. The CLI writes filtered stdout and stderr back to the `stdout`/`stderr` fields and updates `stdout_size`/`stderr_size`. Without these flags, it keeps `stdout=""` + the last 800 bytes in `stdout_tail` + `stderr=""` + the last 200 bytes in `stderr_tail` (about 1 KB total).
80
80
 
81
81
  ```bash
82
- # 看最后 50 行 stdout 和 stderr
82
+ # Show the last 50 lines of stdout and stderr
83
83
  delta-cli sandbox logs <id> --execution-id <eid> --tail 50
84
- # 过滤 ERROR/warning 行(同时作用于 stdout 和 stderr)
84
+ # Filter ERROR/warning lines (applies to both stdout and stderr)
85
85
  delta-cli sandbox logs <id> --execution-id <eid> --grep "ERROR|warning" --context 2
86
86
  ```
87
87
 
88
- 判断任务状态的规则(按优先顺序):
88
+ Interpret task status using these rules, in order:
89
89
 
90
- 1. **`finished=true` + `exit_code=0`** → 正常完成,可以读取结果并销毁 sandbox
91
- 2. **`finished=true` + `exit_code≠0`** → 命令执行失败,查看 stderr/error 信息
92
- 3. **`running=true`** → 任务仍在运行,继续等待(建议每 15-30 秒查询一次)
93
- 4. **连续 3 次 `running=true` 且输出无变化且距离提交超过 60 秒** → 任务可能挂起或无输出,用 `sandbox status <id>` 检查 sandbox 是否存活。判断「输出无变化」:快照里有 `last_updated` 时,直接比较它与当前时间是否持续滞后;缺 `last_updated` 时才退化为 `stderr_tail`/`cursor` 无变化(注意 `cursor` 只反映 stderr 行数,纯 stdout 任务会恒为 0,勿据此误判挂起)
94
- 5. **`sandbox status` 返回正常但 logs 仍然无变化** → 用 `sandbox run <id> --command "ps aux | grep <进程名>" --timeout 15` 在容器内检查命令是否还在运行
90
+ 1. **`finished=true` + `exit_code=0`** → completed successfully; read the results and destroy the sandbox.
91
+ 2. **`finished=true` + `exit_code≠0`** → command failed; check stderr/error details.
92
+ 3. **`running=true`** → the task is still running; keep waiting (poll every 15–30 seconds is recommended).
93
+ 4. **`running=true` for 3 consecutive polls, with no output changes and more than 60 seconds since submission** → the task may be stalled or producing no output; use `sandbox status <id>` to check whether the sandbox is alive. To judge whether output has changed: if the snapshot has `last_updated`, compare it directly with the current time and check whether it remains consistently stale. Only if `last_updated` is missing should you fall back to changes in `stderr_tail`/`cursor` (note that `cursor` reflects stderr lines only and stays at 0 for stdout-only tasks; do not use it alone to misdiagnose a hang).
94
+ 5. **`sandbox status` is normal but logs still have not changed** → use `sandbox run <id> --command "ps aux | grep <process-name>" --timeout 15` to check inside the container whether the command is still running.
95
95
 
96
- **注意**:
97
- - `sandbox logs` 只应配合 `sandbox run-bg` 使用;同步 `sandbox run` 的结果直接返回,不能也不应该调用 `logs`。
98
- - `sandbox run-bg` 不加 `--wait` 时,HTTP 请求本身会快速返回 `{execution_id, sandbox_id}`;命令若超时会以非零退出码结束,需后续通过 `logs` 拿 `exit_code`。
99
- - `sandbox run-bg --wait` 模式下,`--timeout` **同时**充当服务端命令执行超时和客户端等待 deadline(默认 300s);CLI 通过 SSE 实时流(`/logs/stream`)跟随,原始 `data:` 帧透传到 stdout,收到 `complete` 即结束(无末尾信封),超时则追加 `finished=false` 快照信封;初始 `/run-background` POST 有独立的 60s HTTP timeout。
100
- - 后台命令可跨 tool call 轮次查询:保存 `sandbox_id` 和 `execution_id`,后续轮次通过 `sandbox status` / `sandbox logs` 获取结果。
96
+ **Notes:**
97
+ - Use `sandbox logs` only with `sandbox run-bg`; synchronous `sandbox run` returns its result directly, so `logs` cannot and should not be called for it.
98
+ - Without `--wait`, the `sandbox run-bg` HTTP request itself returns quickly with `{execution_id, sandbox_id}`. If the command times out, it exits with a non-zero code; retrieve `exit_code` later with `logs`.
99
+ - In `sandbox run-bg --wait` mode, `--timeout` serves **both** as the server-side command timeout and the client-side waiting deadline (default 300s). The CLI follows the live SSE stream (`/logs/stream`), passes raw `data:` frames through to stdout and ends when `complete` arrives (with no trailing envelope); on timeout, it appends a `finished=false` snapshot envelope. The initial `/run-background` POST has its own 60s HTTP timeout.
100
+ - Background commands can be queried across tool-call turns: save `sandbox_id` and `execution_id`, then retrieve results in later turns with `sandbox status` / `sandbox logs`.
@@ -1,10 +1,10 @@
1
- # 标准任务请求模式
1
+ # Standard task request patterns
2
2
 
3
- 本文件提供 `delta-sandbox` 处理常见任务时的推荐请求写法。这些示例是语言无关的模板,实际代码由 skill 在 sandbox 内部生成或写入。
3
+ This file provides recommended request patterns for common tasks handled by `delta-sandbox`. The examples are language-agnostic templates; the actual code is generated or written by the skill inside the sandbox.
4
4
 
5
- ## Planner 调用本 skill 时的 required_outputs
5
+ ## `required_outputs` when the Planner calls this skill
6
6
 
7
- 所有直接调用 `delta-sandbox` 的 plan step 都应该声明会落盘一个 `.json` 文件。这样 skill 运行命令后把 sandbox `log_file` 写入本地 `result.json` 时,host 可以正确通过 Phase-10B deliverable 校验。
7
+ Every plan step that directly calls `delta-sandbox` should declare that it will write a `.json` file to disk. This allows the host to validate the deliverable in Phase-10B when the skill writes the sandbox `log_file` to the local `result.json` after running the command.
8
8
 
9
9
  ```yaml
10
10
  required_outputs:
@@ -12,127 +12,127 @@ required_outputs:
12
12
  extensions: [".json"]
13
13
  ```
14
14
 
15
- > 说明:这是声明 skill 会创建 `.json` 结果文件,不是要求用户请求中出现 `.json`。用户请求仍按下面的模板使用中性动词。
15
+ > This declares that the skill will create a `.json` result file; it does not require `.json` to appear in the user's request. Keep the user's request neutral in its wording, following the templates below.
16
16
 
17
- ## 通用脚本输出模板
17
+ ## General script output template
18
18
 
19
- 为了让 skill 用同一套流程生成 `RESULT:` 并避免大模型去摘要长日志,推荐任何 sandbox 脚本在**执行结束时**打印一行结构化 JSON:
19
+ To let the skill generate `RESULT:` consistently and avoid asking an LLM to summarise long logs, we recommend that every sandbox script print one line of structured JSON **at the end of execution**:
20
20
 
21
21
  ```json
22
22
  {"status":"ok","key_metric_1":"value_1","key_metric_2":123}
23
23
  ```
24
24
 
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)仍仅旧服务器回退路径生效。
25
+ > On the SSE path, the **complete frame for `sandbox run` / `run-bg --wait` already includes `result_summary`** (the CLI detects a valid JSON object in the last 50 lines of stdout and injects it, so there is no need to read and parse it manually). The script author only needs to ensure that the last line of stdout is valid JSON; the skill can then take `result_summary` directly from the complete frame. Only if the complete frame lacks this field (because there is no valid JSON at the end) should it fall back to `sandbox read` to read the `log_file` and scan backwards. `--summary` enrichment (including hints) still takes effect only on the legacy-server fallback path.
26
26
 
27
- SKILL 会把它提取为 `result.json` 的 `summary`,并生成 `result_summary` 与最终 `RESULT:` 行。
27
+ The skill extracts this as the `summary` in `result.json`, then generates `result_summary` and the final `RESULT:` line.
28
28
 
29
- **不要**再输出 `FINAL_ANSWER: ...` 这样的标记行,也不要在 JSON 里使用 `final_answer` 字段。summary 里的语义字段(如 `output`、`result`、`generated_text`、`final_accuracy`)已经足够表达结果。
29
+ **Do not** output marker lines such as `FINAL_ANSWER: ...` or use a `final_answer` field in the JSON. Semantic fields in the summary (such as `output`, `result`, `generated_text` and `final_accuracy`) are enough to express the result.
30
30
 
31
- 不同任务的关键字段示例:
31
+ Examples of key fields for different tasks:
32
32
 
33
- - **CUDA 检查**:`status`, `torch_version`, `cuda_available`, `device_name`
34
- - **训练任务**:`status`, `epochs`, `final_loss`, `final_accuracy`, `model_file`
35
- - **推理任务**:`status`, `input_samples`, `output_file`, `avg_latency_ms`
36
- - **数据处理**:`status`, `input_rows`, `output_rows`, `output_file`
37
- - **编译/构建**:`status`, `build_time_s`, `output_binary`, `tests_passed`
33
+ - **CUDA check**: `status`, `torch_version`, `cuda_available`, `device_name`
34
+ - **Training task**: `status`, `epochs`, `final_loss`, `final_accuracy`, `model_file`
35
+ - **Inference task**: `status`, `input_samples`, `output_file`, `avg_latency_ms`
36
+ - **Data processing**: `status`, `input_rows`, `output_rows`, `output_file`
37
+ - **Compilation/build**: `status`, `build_time_s`, `output_binary`, `tests_passed`
38
38
 
39
- ## 1. GPU / CUDA 可用性检查
39
+ ## 1. GPU / CUDA availability check
40
40
 
41
- 用户请求示例:
41
+ Example user request:
42
42
 
43
43
  ```text
44
- 在 GPU sandbox 中运行标准 PyTorch CUDA 自检脚本,返回 exit_code、torch 版本、CUDA 是否可用、CUDA/cuDNN 版本、GPU 名称与显存信息。
44
+ Run the standard PyTorch CUDA self-check script in a GPU sandbox; return exit_code, the torch version, whether CUDA is available, CUDA/cuDNN versions, the GPU name and memory information.
45
45
  ```
46
46
 
47
- 说明:
47
+ Notes:
48
48
 
49
- - 不要在请求里出现 `torch.cuda.is_available()` 等完整代码 token,避免被 host 误判为 `.cuda` 文件承诺。对应的 plan step 仍按上面模板声明 `.json` 输出。
50
- - 推荐让脚本在 `stdout` 末尾输出一行结构化 JSON,例如:
49
+ - Do not include full code expressions such as `torch.cuda.is_available()` in the request; the host may mistake them for a `.cuda` file commitment. The corresponding plan step should still declare `.json` output using the template above.
50
+ - We recommend that the script print one line of structured JSON at the end of `stdout`, for example:
51
51
  ```json
52
52
  {"torch_version":"2.7.0+cu128","cuda_available":true,"device_count":1,
53
53
  "device_name":"NVIDIA GeForce RTX 3090","tensor_op":"[101.0]",
54
54
  "memory_before_mb":{"allocated":0,"reserved":0,"max_allocated":0},
55
55
  "memory_after_mb":{"allocated":0.0005,"reserved":2.0,"max_allocated":0.001}}
56
56
  ```
57
- - skill 会从 `log_file` 提取这个 JSON 作为本地 `result.json` 的 `summary`,最终只输出一行 `RESULT: ...`。
58
- - 完整 `nvidia-smi` 原始输出保留在 sandbox 的 `log_file` 中。
57
+ - The skill extracts this JSON from `log_file` as the `summary` in the local `result.json`, then outputs only one `RESULT: ...` line.
58
+ - The full raw `nvidia-smi` output remains in the sandbox `log_file`.
59
59
 
60
- ## 2. 运行用户已有的脚本
60
+ ## 2. Run a script the user already has
61
61
 
62
62
  ```text
63
- 在 sandbox <sandbox_id> 中运行 <wd>/train.py,参数为 --epochs 10 --batch-size 32。
63
+ In sandbox <sandbox_id>, run <wd>/train.py with the arguments --epochs 10 --batch-size 32.
64
64
  ```
65
65
 
66
- > `<wd>` 为该 sandbox 的 working-directory(`/workspace/{user_id}/{sandbox_id}`,先 `delta-cli sandbox working-directory <id>` 查询)。
66
+ > `<wd>` is this sandbox's working directory (`/workspace/{user_id}/{sandbox_id}`; first check it with `delta-cli sandbox working-directory <id>`).
67
67
 
68
- 说明:文件已存在,用中性动词 `运行`,不使用 `创建` 等承诺动词。
68
+ Notes: the file already exists, so use the neutral verb `run` rather than a commitment verb such as `create`.
69
69
 
70
- ## 3. 安装依赖并执行命令
70
+ ## 3. Install dependencies and run a command
71
71
 
72
72
  ```text
73
- 在 sandbox 中运行 pip install -r <wd>/requirements.txt,然后运行 python <wd>/app.py。
73
+ In the sandbox, run pip install -r <wd>/requirements.txt, then run python <wd>/app.py.
74
74
  ```
75
75
 
76
- 说明:依赖安装和命令执行都没有落盘新文件,使用中性动词描述。
76
+ Notes: neither dependency installation nor command execution creates a new deliverable file, so describe them with neutral verbs.
77
77
 
78
- ## 4. 训练并将指标落盘
78
+ ## 4. Train and write metrics to disk
79
79
 
80
80
  ```text
81
- 在 GPU sandbox 中运行训练脚本(例如基于 PyTorch 的 MNIST 训练),训练完成后在 stdout 末尾打印包含 epochs、final_loss、final_accuracy、model_file 的结构化 JSON。
81
+ In a GPU sandbox, run a training script (for example, PyTorch-based MNIST training). When training finishes, print structured JSON at the end of stdout containing epochs, final_loss, final_accuracy and model_file.
82
82
  ```
83
83
 
84
- 说明:
84
+ Notes:
85
85
 
86
- - 训练日志可能很长,不要让 skill 去读整段日志再摘要;让脚本自己输出关键指标。
87
- - 推荐脚本最终打印:`{"status":"ok","epochs":10,"final_loss":0.023,"final_accuracy":0.992,"model_file":"<wd>/model.pt"}`
88
- - skill 会把它提取为 `result.json` 的 `summary`,最终输出 `RESULT: exit_code=0, status=ok, epochs=10, ...`。
89
- - 如需保存完整模型文件,可再用 `sandbox read` 或 `sandbox upload` 处理,不属于 `result.json` 的摘要范围。
86
+ - Training logs can be long; do not have the skill read the entire log and then summarise it. Have the script output the key metrics itself.
87
+ - We recommend that the script finish by printing: `{"status":"ok","epochs":10,"final_loss":0.023,"final_accuracy":0.992,"model_file":"<wd>/model.pt"}`
88
+ - The skill extracts this as the `summary` in `result.json`, then outputs `RESULT: exit_code=0, status=ok, epochs=10, ...`.
89
+ - To save the complete model file, use `sandbox read` or `sandbox upload` as needed; the model file is outside the scope of the `result.json` summary.
90
90
 
91
- ## 5. 通用数据处理
91
+ ## 5. General data processing
92
92
 
93
93
  ```text
94
- 在 sandbox 中运行数据处理命令,读取 <wd>/input.csv,输出 <wd>/output.csv,并在 stdout 末尾打印包含 input_rows、output_rows、output_file 的结构化 JSON。
94
+ In the sandbox, run a data-processing command that reads <wd>/input.csv and writes <wd>/output.csv, then prints structured JSON at the end of stdout containing input_rows, output_rows and output_file.
95
95
  ```
96
96
 
97
- 说明:
97
+ Notes:
98
98
 
99
- - 推荐脚本最终打印:`{"status":"ok","input_rows":10000,"output_rows":9876,"output_file":"<wd>/output.csv"}`
100
- - skill 会把它提取为 `result.json` 的 `summary`,最终输出 `RESULT: exit_code=0, status=ok, input_rows=10000, output_rows=9876, output_file=<wd>/output.csv`。
99
+ - We recommend that the script finish by printing: `{"status":"ok","input_rows":10000,"output_rows":9876,"output_file":"<wd>/output.csv"}`
100
+ - The skill extracts this as the `summary` in `result.json`, then outputs `RESULT: exit_code=0, status=ok, input_rows=10000, output_rows=9876, output_file=<wd>/output.csv`.
101
101
 
102
- ## 6. 模型推理(Qwen / LLM / 视觉等)
102
+ ## 6. Model inference (Qwen / LLM / vision, etc.)
103
103
 
104
- 用户请求示例:
104
+ Example user request:
105
105
 
106
106
  ```text
107
- 在 GPU sandbox 中用 ModelScope 上的 Qwen/Qwen2.5-0.5B-Instruct 运行一次推理,输入 "100+10",返回模型的输出结果及 CUDA 可用性摘要。
107
+ Run one inference in a GPU sandbox using Qwen/Qwen2.5-0.5B-Instruct from ModelScope, with "100+10" as input; return the model's output and a summary of CUDA availability.
108
108
  ```
109
109
 
110
- 说明:
110
+ Notes:
111
111
 
112
- - 请求里不要贴完整 Python 代码,也不要指定宿主文件路径(如 `@ROOT/inference.py`、本地绝对路径等),更不要要求脚本输出 `FINAL_ANSWER:` 标记行。脚本内容、模型下载、执行路径都由 skill 内部通过 `delta-cli sandbox write` 写入 sandbox 后运行。
113
- - 推荐让脚本在 `stdout` 末尾打印一行结构化 JSON,例如:
112
+ - Do not paste complete Python code into the request or specify a host file path (such as `@ROOT/inference.py` or a local absolute path), and do not ask the script to output a `FINAL_ANSWER:` marker line. The skill writes the script, downloads the model and sets the execution path inside the sandbox using `delta-cli sandbox write`.
113
+ - We recommend that the script print one line of structured JSON at the end of `stdout`, for example:
114
114
  ```json
115
115
  {"status":"ok","cuda_available":true,"device":"cuda","model":"Qwen/Qwen2.5-0.5B-Instruct","input":"100+10","generated_text":"110"}
116
116
  ```
117
- - skill 会把它提取为 `result.json` 的 `summary`,最终输出 `RESULT: exit_code=0, status=ok, cuda_available=True, generated_text=110, ...`。
117
+ - The skill extracts this as the `summary` in `result.json`, then outputs `RESULT: exit_code=0, status=ok, cuda_available=True, generated_text=110, ...`.
118
118
 
119
- > **GPU 显存与模型匹配**:创建 sandbox 时的 `--gpu-mem`(单位 MiB)必须匹配实际运行的模型。模型参数量/精度越大,所需显存越大;把大模型塞进过小的 `--gpu-mem` 会直接 OOM。上面的示例用的是 `Qwen2.5-0.5B`(0.5B 小模型),**不要把它当作更大模型(如 7B/9B/13B)的显存参考**。跑较大模型前先评估其显存需求、适当调大 `--gpu-mem`,并建议先用小模型验证流程是否跑通。
119
+ > **Match GPU memory to the model:** The `--gpu-mem` value (in MiB) used to create the sandbox must match the model being run. Larger models and higher precision require more memory; putting a large model in a sandbox with too little `--gpu-mem` will cause OOM directly. The example above uses `Qwen2.5-0.5B` (a small 0.5B model); **do not use it as a memory reference for larger models such as 7B/9B/13B**. Before running a larger model, assess its memory requirements, increase `--gpu-mem` as appropriate, and consider verifying the workflow with a smaller model first.
120
120
 
121
- ## 注意事项
121
+ ## Notes
122
122
 
123
- - 尽量用自然语言描述任务,完整代码由 skill 内部处理。
124
- - 只有在 skill 会真实创建文件时,才在请求中显式写出 `*.py` / `*.json` / `*.csv` 等扩展名。
125
- - 不要使用 `脚本需输出...` 这类把代码片段直接跟在承诺动词后的句式。
126
- - **任务完成的标准是执行结果,不是脚本文件存在**。Planner 和 skill 都要以本地 `result.json` 的生成作为完成标志;`required_outputs` 必须声明 `.json`,不要只声明 `{"kind": "file"}`。
127
- - **`skill_request` 里不要出现完整代码块或宿主文件路径概念**(如 `@ROOT/...`、`/Users/...`)。脚本应通过 `delta-cli sandbox write <id> --source <文件名>` 写入 sandbox 的 working-directory(`/workspace/{user_id}/{sandbox_id}/...`)。
123
+ - Describe tasks in natural language where possible; the skill handles the full code internally.
124
+ - Mention extensions such as `*.py` / `*.json` / `*.csv` explicitly in the request only when the skill will actually create a file.
125
+ - Do not use phrasing such as `The script should output...` that puts a code fragment immediately after a commitment verb.
126
+ - **Task completion is determined by the execution result, not by the presence of a script file.** The Planner and skill should both treat the creation of the local `result.json` as the completion criterion. `required_outputs` must declare `.json`; do not declare only `{"kind": "file"}`.
127
+ - **Do not include complete code blocks or host-file-path concepts in `skill_request`** (such as `@ROOT/...` or `/Users/...`). The script should be written to the sandbox working directory (`/workspace/{user_id}/{sandbox_id}/...`) with `delta-cli sandbox write <id> --source <filename>`.
128
128
 
129
- ## 本地 `result.json` 的内容约定
129
+ ## Local `result.json` content contract
130
130
 
131
- - **SSE 首选路径(推荐,一步到位)**:`sandbox run` / `run-bg --wait` 的 **complete 帧直接带 `result_summary`**(CLI 检测 stdout 末尾 JSON 注入),skill 从 complete 帧提取即可,无需 read+parse。
132
- - **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` 后)。
133
- - **旧服务器回退路径**:`run` / `run-bg --wait` 走轮询回退时返回 `CommandResult` 信封,可直接复用 `data.result_summary` 字段。
134
- - 本地 `result.json` 是一份**精简摘要**,用于 host deliverable 校验,不是完整日志存档。
135
- - 必须包含 `result_summary` 字段,内容与最终 `RESULT:` 行一致,方便 Runner 直接读取结论。
136
- - 只写入关键字段(`exit_code`、`finished`、`summary`、`result_summary`、`error`)。**不要**额外添加 `final_answer` 等字段。
137
- - 不要把完整原始 `stdout` 塞进 `result.json`,否则 host 的 `read_file` 工具预览时会截断,Runner 可能误以为文件被截断。
138
- - 完整原始输出保留在 sandbox 的 `log_file` 中,需要时再 `sandbox read`。
131
+ - **Preferred SSE path (recommended, one step):** The **complete frame for `sandbox run` / `run-bg --wait` includes `result_summary` directly** (the CLI injects detected trailing JSON from stdout), so the skill can extract it from the complete frame without reading and parsing the log.
132
+ - **SSE fallback path:** If the complete frame lacks `result_summary` (there is no valid JSON at the end of stdout), `delta-cli sandbox read <id> --path <log_file>` reads the run-envelope log file, then scans backwards through stdout to extract trailing JSON. The `log_file` path comes from the SSE `complete` frame (the CLI fills it in if needed) or the `sandbox logs` snapshot (after `finished=true`).
133
+ - **Legacy-server fallback path:** When `run` / `run-bg --wait` falls back to polling, it returns a `CommandResult` envelope whose `data.result_summary` field can be reused directly.
134
+ - The local `result.json` is a **concise summary** for host deliverable validation, not a complete log archive.
135
+ - It must include the `result_summary` field, with content matching the final `RESULT:` line, so the Runner can read the conclusion directly.
136
+ - Write only the key fields (`exit_code`, `finished`, `summary`, `result_summary`, `error`). **Do not** add fields such as `final_answer`.
137
+ - Do not put the full raw `stdout` in `result.json`; the host's `read_file` preview would be truncated, and the Runner might mistake this for a truncated file.
138
+ - Keep the full raw output in the sandbox `log_file` and use `sandbox read` to inspect it when needed.