@delta-infra/cli 1.0.84 → 1.0.86
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 +11 -5
- package/checksums.txt +5 -5
- package/package.json +1 -1
- package/scripts/install-wizard.js +86 -16
- package/skills/delta-sandbox/SKILL.md +16 -40
- package/skills/delta-sandbox/references/commands.md +4 -4
- package/skills/delta-sandbox/references/lifecycle.md +13 -9
- package/skills/delta-sandbox/references/recipes.md +3 -3
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.
|
|
179
|
-
#
|
|
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
|
|
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]` |
|
|
223
|
-
| `delta-cli sandbox run-bg <id> --command "..." [--timeout <秒>] [--wait] [--summary/--no-summary] [--artifacts]` | 后台运行命令;不加 `--wait` 立即返回 `{execution_id, sandbox_id}`;加 `--wait`
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
eb73ffbfea1fdbdd770af7e1f6ee270b0ba53751c229521b0c15bae5768e7b2d delta-cli-darwin-amd64.tar.gz
|
|
2
|
+
ab05c3261cfae0f186dfa26d692ebc79724186ae1ad2e24ada3c725628489606 delta-cli-darwin-arm64.tar.gz
|
|
3
|
+
5ff9b72bd530a5d5974a1ca22735849332548fc785dd20d5619c8b30017a4673 delta-cli-linux-amd64.tar.gz
|
|
4
|
+
05922276dd519711d23aa9233b3bff560119f6803c9b9db1dcd9ee5d6070bd05 delta-cli-linux-arm64.tar.gz
|
|
5
|
+
b9ee55fe69a421b58f4706ae579b3db663d55625bb4990f444b984dee5ec73a2 delta-cli-windows-amd64.zip
|
package/package.json
CHANGED
|
@@ -45,7 +45,67 @@ const PLATFORM_LABELS = {
|
|
|
45
45
|
const skillManifest = require("../skills/manifest.json");
|
|
46
46
|
const SKILL_NAMES = skillManifest.skills;
|
|
47
47
|
const RETIRED_SKILL_NAMES = skillManifest.retired_skills || [];
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
// Language for interactive prompts and log text. Detection precedence:
|
|
50
|
+
// DELTA_CLI_LANG (explicit override) > OS locale env (LANG/LC_ALL/LANGUAGE/
|
|
51
|
+
// LC_MESSAGES) > platform probe (Windows UI culture via PowerShell) >
|
|
52
|
+
// Intl default locale. Only zh and en are supported; anything not Chinese
|
|
53
|
+
// falls back to English. Neutral locales (C / POSIX / und) carry no language
|
|
54
|
+
// signal and resolve to English instead of leaking the runtime's default.
|
|
55
|
+
//
|
|
56
|
+
// Windows does not set the POSIX LANG/LC_ALL vars and Node's Intl defaults to
|
|
57
|
+
// en-US there, so a Chinese Windows user would otherwise see English. We probe
|
|
58
|
+
// the real UI culture on that platform instead.
|
|
59
|
+
function detectLang() {
|
|
60
|
+
if (process.env.DELTA_CLI_LANG) {
|
|
61
|
+
return process.env.DELTA_CLI_LANG.toLowerCase().startsWith("zh") ? "zh" : "en";
|
|
62
|
+
}
|
|
63
|
+
const neutral = /^(c|posix|und)(\b|$)/i;
|
|
64
|
+
const candidates = [
|
|
65
|
+
process.env.LC_ALL,
|
|
66
|
+
process.env.LC_MESSAGES,
|
|
67
|
+
process.env.LANG,
|
|
68
|
+
process.env.LANGUAGE,
|
|
69
|
+
];
|
|
70
|
+
let sawLocale = false;
|
|
71
|
+
for (const value of candidates) {
|
|
72
|
+
if (!value) continue;
|
|
73
|
+
sawLocale = true;
|
|
74
|
+
const lower = value.toLowerCase();
|
|
75
|
+
if (neutral.test(value)) return "en";
|
|
76
|
+
if (lower.startsWith("zh")) return "zh";
|
|
77
|
+
return "en";
|
|
78
|
+
}
|
|
79
|
+
if (sawLocale) return "en";
|
|
80
|
+
if (isWindows) {
|
|
81
|
+
const win = windowsUiLanguage();
|
|
82
|
+
if (win) return win;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
if (String(Intl.DateTimeFormat().resolvedOptions().locale).toLowerCase().startsWith("zh")) {
|
|
86
|
+
return "zh";
|
|
87
|
+
}
|
|
88
|
+
} catch {}
|
|
89
|
+
return "en";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Returns "zh" or "en" from the Windows UI culture, or "" when it cannot be read.
|
|
93
|
+
function windowsUiLanguage() {
|
|
94
|
+
try {
|
|
95
|
+
const out = execFileSync(
|
|
96
|
+
"powershell.exe",
|
|
97
|
+
["-NoProfile", "-Command",
|
|
98
|
+
"[System.Globalization.CultureInfo]::CurrentUICulture.Name"],
|
|
99
|
+
{ stdio: ["ignore", "pipe", "ignore"], encoding: "utf8", timeout: 8000 }
|
|
100
|
+
);
|
|
101
|
+
const name = (out || "").trim().toLowerCase();
|
|
102
|
+
if (name.startsWith("zh")) return "zh";
|
|
103
|
+
if (name) return "en";
|
|
104
|
+
} catch {}
|
|
105
|
+
return "";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const LANG = detectLang();
|
|
49
109
|
|
|
50
110
|
function platformSkillDir(platform) {
|
|
51
111
|
return path.join(osHomedir(), ...PLATFORM_PATHS[platform]);
|
|
@@ -83,6 +143,10 @@ const messages = {
|
|
|
83
143
|
done: "安装完成!\n现在可以让你的 AI 工具使用 delta-cli 管理 Delta Sandbox 资源或调用 Science 工具。",
|
|
84
144
|
cancelled: "安装已取消",
|
|
85
145
|
nonTtyHint: "要完成配置,请在终端中运行:\n delta-cli config init\n delta-cli auth login",
|
|
146
|
+
uninstallConfirm: "将移除全局包、AI Skills 和配置文件。是否继续?",
|
|
147
|
+
uninstallCancelled: "卸载已取消",
|
|
148
|
+
uninstallDone: "卸载完成",
|
|
149
|
+
uninstallComplete: "卸载完成。",
|
|
86
150
|
},
|
|
87
151
|
en: {
|
|
88
152
|
setup: "Setting up Delta Infra CLI...",
|
|
@@ -113,6 +177,10 @@ const messages = {
|
|
|
113
177
|
done: "You are all set!\nYour AI tool can now use delta-cli to manage Delta Sandbox resources or invoke Science tools.",
|
|
114
178
|
cancelled: "Installation cancelled",
|
|
115
179
|
nonTtyHint: "To complete setup, run interactively:\n delta-cli config init\n delta-cli auth login",
|
|
180
|
+
uninstallConfirm: "This will remove the global package, AI Skills and config. Continue?",
|
|
181
|
+
uninstallCancelled: "Uninstall cancelled",
|
|
182
|
+
uninstallDone: "Uninstall complete",
|
|
183
|
+
uninstallComplete: "Uninstall complete.",
|
|
116
184
|
},
|
|
117
185
|
};
|
|
118
186
|
|
|
@@ -565,33 +633,35 @@ async function stepUninstallPackage(msg) {
|
|
|
565
633
|
|
|
566
634
|
async function doInstall() {
|
|
567
635
|
const isInteractive = isInteractiveEnv();
|
|
636
|
+
const msg = messages[LANG];
|
|
568
637
|
|
|
569
638
|
if (isInteractive) {
|
|
570
|
-
p.intro(
|
|
571
|
-
await stepInstallGlobally(
|
|
572
|
-
const platforms = await stepSelectPlatforms(
|
|
573
|
-
await stepInstallSkills(
|
|
574
|
-
await stepConfigInit(
|
|
575
|
-
await stepAuthLogin(
|
|
576
|
-
p.outro(
|
|
639
|
+
p.intro(msg.setup);
|
|
640
|
+
await stepInstallGlobally(msg);
|
|
641
|
+
const platforms = await stepSelectPlatforms(msg);
|
|
642
|
+
await stepInstallSkills(msg, platforms);
|
|
643
|
+
await stepConfigInit(msg);
|
|
644
|
+
await stepAuthLogin(msg);
|
|
645
|
+
p.outro(msg.done);
|
|
577
646
|
} else {
|
|
578
|
-
console.log(
|
|
579
|
-
await stepInstallGlobally(
|
|
647
|
+
console.log(msg.setup);
|
|
648
|
+
await stepInstallGlobally(msg);
|
|
580
649
|
const platforms = ["agents"];
|
|
581
|
-
await stepInstallSkills(
|
|
582
|
-
console.log(
|
|
650
|
+
await stepInstallSkills(msg, platforms);
|
|
651
|
+
console.log(msg.nonTtyHint);
|
|
583
652
|
}
|
|
584
653
|
}
|
|
585
654
|
|
|
586
655
|
async function doUninstall() {
|
|
587
656
|
const isInteractive = isInteractiveEnv();
|
|
657
|
+
const msg = messages[LANG];
|
|
588
658
|
|
|
589
659
|
if (isInteractive) {
|
|
590
660
|
const ok = await p.confirm({
|
|
591
|
-
message:
|
|
661
|
+
message: msg.uninstallConfirm,
|
|
592
662
|
});
|
|
593
663
|
if (p.isCancel(ok) || !ok) {
|
|
594
|
-
p.cancel(
|
|
664
|
+
p.cancel(msg.uninstallCancelled);
|
|
595
665
|
process.exit(0);
|
|
596
666
|
}
|
|
597
667
|
}
|
|
@@ -601,9 +671,9 @@ async function doUninstall() {
|
|
|
601
671
|
await stepUninstallPackage();
|
|
602
672
|
|
|
603
673
|
if (isInteractive) {
|
|
604
|
-
p.outro(
|
|
674
|
+
p.outro(msg.uninstallDone);
|
|
605
675
|
} else {
|
|
606
|
-
console.log("\
|
|
676
|
+
console.log("\n" + msg.uninstallComplete);
|
|
607
677
|
}
|
|
608
678
|
}
|
|
609
679
|
|
|
@@ -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,
|
|
3
|
+
description: "在 Delta Sandbox Linux 容器中运行任意命令或脚本。适用于训练、推理、编译、数据处理等任意需要 sandbox 的计算任务,支持 Python / Node.js / Go / Java / Rust 等语言。所有任务通用同一套输出约定:命令在 stdout 末尾输出结构化 JSON,skill 从 log_file 反向扫描提取为 `result_summary`(旧服务器回退路径由 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
|
|
43
|
+
CLI 通过 SSE 实时流(`/logs/stream`)跟随输出,把原始 SSE 帧(`data: {...}`)**逐帧透传到 stdout**(curl -N 风格),帧类型见 JSON 的 `type` 字段:`init`(含 `execution_id`)/ `stdout` / `stderr` / `error` / `complete`(含 `exit_code`、`log_file`)。收到 `complete` 即命令结束,CLI 直接退出,**不追加末尾信封**——命令成败看 `complete` 帧里的 `exit_code`,`execution_id` 从 `init`/`complete` 帧读取。若在 `--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` 字段为准),需要读全文或提取末尾 JSON 时用 `sandbox read <id> --path <log_file>`。**`--summary`/`--artifacts` 富化仅在旧服务器回退路径生效**(服务端无 `/logs/stream` 端点时 CLI 自动回退到 5s 轮询并输出 `CommandResult` 信封,此时才返回 `result_summary`/`hints`)。`execution_id` 可用于后续 `sandbox logs` / `cancel`。
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
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` → 仍运行
|
|
@@ -133,7 +133,7 @@ required_outputs:
|
|
|
133
133
|
| 获取资源推荐 | `sandbox recommend --cpu N --memory XGi [--gpu N] [--gpu-mem N]` |
|
|
134
134
|
| 列出当前用户的 sandbox | `sandbox list` |
|
|
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]` |
|
|
@@ -170,7 +170,7 @@ required_outputs:
|
|
|
170
170
|
- `delta-cli sandbox recommend --cpu N --memory XGi [--gpu N]` — 资源配置推荐
|
|
171
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,必须优先复用。**
|
|
172
172
|
- --max-life 指定 sandbox 最大存活时间(分钟),默认 30。长任务请调高,确保 sandbox 在命令执行期间不被回收。
|
|
173
|
-
-
|
|
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 <秒>`
|
|
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
|
|
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", ...}
|
|
193
|
-
5. **生成 result.json
|
|
194
|
-
-
|
|
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 不自动提取 `result_summary`(`--summary` 仅在旧服务器回退路径生效),因此任务结束后用 `sandbox read <id> --path <log_file>` 读取 log_file,再按步骤 5 反向扫描 stdout 末尾 JSON 提取摘要,避免让大模型“读整段日志再摘要”。
|
|
194
|
+
5. **生成 result.json**(从 `log_file` 读取解析:SSE 路径下 `run`/`run-bg --wait` 不透传 `result_summary` 信封,`--summary` 仅在旧服务器回退路径生效):
|
|
195
|
+
- **获取 `log_file` 路径**:`run` / `run-bg --wait` 的 SSE `complete` 帧中含 `log_file` 字段;`sandbox logs <id> --execution-id <eid>` 快照在 `finished=true` 后同样返回 `log_file`。然后从 log_file 读取解析:
|
|
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.
|
|
312
|
-
2.
|
|
287
|
+
1. **SSE 路径下 `sandbox run` / `run-bg --wait` 不透传 `result_summary` 信封**(`--summary` 富化仅在旧服务器回退路径生效)。`exit_code` / `log_file` / `execution_id` 从 SSE `complete` 帧读取;`log_file` 路径也可从 `sandbox logs <id> --execution-id <eid>` 快照(`finished=true` 后)获得。
|
|
288
|
+
2. **统一从 `log_file` 提取摘要**:用 `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:` 开头的一行。**
|
|
@@ -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 可销毁) |
|
|
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]` |
|
|
29
|
-
| `sandbox run-bg <id> --command "..." [--timeout N] [--wait] [--summary/--no-summary] [--artifacts]` | 后台运行命令;不加 `--wait` 立即返回 `{execution_id, sandbox_id}`;加 `--wait`
|
|
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,**无末尾信封**;`exit_code`/`log_file`/`execution_id` 从 `complete` 帧读取);`--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,无末尾信封;超时则追加 `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`(无末尾信封);`--tail N` 同时作用于 stdout 和 stderr(各取尾 N 行);`--grep <pattern>` 同时过滤 stdout 和 stderr(正则);`--context N` 提供 grep 匹配行前后 N 行上下文(同时用于 stdout 和 stderr);**`cursor` 字段无 `omitempty`,0 也常驻响应**。 |
|
|
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
|
|
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 <秒>`
|
|
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
|
|
28
|
+
CLI 通过 SSE 实时流(`/logs/stream`)跟随输出,把原始 SSE 帧(`data: {...}`)**逐帧透传到 stdout**,收到 `complete` 帧(含 `exit_code`/`log_file`/`execution_id`)即命令结束,CLI 直接退出、不追加末尾信封。只消耗 **1 次 tool call**,适合不关心中间进度的场景。
|
|
29
29
|
|
|
30
|
-
> `--wait`
|
|
30
|
+
> `--wait` 的 SSE 路径不返回 `result_summary` 信封(`--summary` 仅在旧服务器回退路径生效)。需要摘要时,用 `sandbox read <id> --path <log_file>` 读取 log_file,反向扫描 stdout 末尾 JSON 提取 `result_summary`。
|
|
31
31
|
|
|
32
|
-
>
|
|
32
|
+
> **输出契约(SSE 路径)**:`run-bg --wait` 成功时 stdout 只有原始 SSE 帧,**没有末尾信封**;`--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
|
-
#
|
|
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":"/
|
|
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
|
字段说明:
|
|
@@ -66,7 +70,7 @@ delta-cli sandbox kill <id>
|
|
|
66
70
|
- `exit_code` — 退出码(完成后才有值,运行中字段省略)
|
|
67
71
|
- `log_file` — 仅 `finished=true` 时出现,是 run envelope 日志文件路径(含完整 stdout + stderr + exit_code + finished + command + error),需读它用 `delta-cli sandbox read <id> --path <log_file>`
|
|
68
72
|
|
|
69
|
-
**stdout 路径说明**:`sandbox logs` 默认返回 stdout 末尾 800 字节(`stdout_tail`)提供实时中间进度预览,完整 stdout 仍在命令结束时被写入沙箱内的 `log_file`,需全文时用 `sandbox read` 读。CLI `
|
|
73
|
+
**stdout 路径说明**:`sandbox logs` 默认返回 stdout 末尾 800 字节(`stdout_tail`)提供实时中间进度预览,完整 stdout 仍在命令结束时被写入沙箱内的 `log_file`,需全文时用 `sandbox read` 读。CLI 的 `--summary` 富化仅在旧服务器回退路径生效(SSE 路径不透传 `result_summary`),SSE 路径下需手动 `sandbox read` log_file 反向扫描 stdout 末尾 JSON 提取摘要。
|
|
70
74
|
|
|
71
75
|
要用 `--tail/--grep/--context` 自定义切片:传任意一个 flag 时,CLI 会把过滤后的 stdout 和 stderr 分别写回 `stdout`/`stderr` 字段并更新 `stdout_size`/`stderr_size`;不传则保持 `stdout=""` + `stdout_tail` 末尾 800 字节预览 + `stderr=""` + `stderr_tail` 末尾 200 字节预览(总计约 1KB)。
|
|
72
76
|
|
|
@@ -88,5 +92,5 @@ delta-cli sandbox logs <id> --execution-id <eid> --grep "ERROR|warning" --contex
|
|
|
88
92
|
**注意**:
|
|
89
93
|
- `sandbox logs` 只应配合 `sandbox run-bg` 使用;同步 `sandbox run` 的结果直接返回,不能也不应该调用 `logs`。
|
|
90
94
|
- `sandbox run-bg` 不加 `--wait` 时,HTTP 请求本身会快速返回 `{execution_id, sandbox_id}`;命令若超时会以非零退出码结束,需后续通过 `logs` 拿 `exit_code`。
|
|
91
|
-
- `sandbox run-bg --wait` 模式下,`--timeout`
|
|
95
|
+
- `sandbox run-bg --wait` 模式下,`--timeout` **同时**充当服务端命令执行超时和客户端等待 deadline(默认 300s);CLI 通过 SSE 实时流(`/logs/stream`)跟随,原始 `data:` 帧透传到 stdout,收到 `complete` 即结束(无末尾信封),超时则追加 `finished=false` 快照信封;初始 `/run-background` POST 有独立的 60s HTTP timeout。
|
|
92
96
|
- 后台命令可跨 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`
|
|
25
|
+
> SSE 路径下 `sandbox run` / `run-bg --wait` 不透传 `data.result_summary`(`--summary` 富化仅在旧服务器回退路径生效)。脚本作者保证 stdout 最后一行是合法 JSON 即可,skill 端用 `sandbox read` 读取 `log_file` 后反向扫描提取。
|
|
26
26
|
|
|
27
27
|
SKILL 会把它提取为 `result.json` 的 `summary`,并生成 `result_summary` 与最终 `RESULT:` 行。
|
|
28
28
|
|
|
@@ -124,8 +124,8 @@ SKILL 会把它提取为 `result.json` 的 `summary`,并生成 `result_summary
|
|
|
124
124
|
|
|
125
125
|
## 本地 `result.json` 的内容约定
|
|
126
126
|
|
|
127
|
-
-
|
|
128
|
-
-
|
|
127
|
+
- **默认路径(SSE 下唯一可靠路径)**:`delta-cli sandbox read <id> --path <log_file>` 读取 run envelope 日志文件 + Python 反向扫描 stdout 末尾 JSON 提取 `result_summary`,再写入本地 `result.json`。`log_file` 路径来自 SSE `complete` 帧或 `sandbox logs` 快照(`finished=true` 后)。
|
|
128
|
+
- **旧服务器回退路径**:`run` / `run-bg --wait` 走轮询回退时返回 `CommandResult` 信封,可直接复用 `data.result_summary` 字段。
|
|
129
129
|
- 本地 `result.json` 是一份**精简摘要**,用于 host deliverable 校验,不是完整日志存档。
|
|
130
130
|
- 必须包含 `result_summary` 字段,内容与最终 `RESULT:` 行一致,方便 Runner 直接读取结论。
|
|
131
131
|
- 只写入关键字段(`exit_code`、`finished`、`summary`、`result_summary`、`error`)。**不要**额外添加 `final_answer` 等字段。
|