@deepseek-ai/dsh-subprocess-e2b 0.1.1-rc.2 → 0.1.2-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +146 -19
- package/README.zh.md +150 -23
- package/package.json +12 -12
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/e2b/subprocess-e2b/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 72f345aeddb632ef708c1e41795fb1307fc9dd6e
|
|
6
|
+
README.zh.md: 3770c060373507c06cc1c4851de997ea0ab1d5e3
|
package/README.md
CHANGED
|
@@ -1,43 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Shell commands and terminals inside the shared remote sandbox: what the agent can run there, how output is handled, and what to expect — for deployments and maintainers of the E2B family."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-subprocess-e2b
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-subprocess-e2b` runs the agent's shell commands and terminals inside the remote sandbox: the agent can execute Bash, open interactive terminals, and read their output exactly as with local execution, while nothing runs on the host machine. Existing command, terminal, and language-server features keep working unchanged — no E2B-specific tools are needed. Secrets and host environment variables never leak into the sandbox: only environment entries the agent explicitly requests are passed along. Use it together with `dsh-e2b` and `dsh-fs-e2b` so commands, terminals, and files share one remote world. The main cost is remote latency — each command starts with a short asynchronous setup instead of launching instantly.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Use this package when the agent's shell commands and terminals should run inside the remote sandbox rather than on your machine. It is the command half of the E2B family: commands, terminals, and files share one remote world.
|
|
29
|
+
|
|
30
|
+
### When to choose it
|
|
31
|
+
|
|
32
|
+
Choose it when a composition already uses the E2B sandbox and you want commands and terminals to run there. Choose the local subprocess package for host execution. Tooling that needs a process id immediately — for example the ACP child backend — cannot use this package.
|
|
33
|
+
|
|
34
|
+
### Configuration
|
|
35
|
+
|
|
36
|
+
The only setting is how often the package checks a running command's status; the default suits most deployments, and raising it reduces remote requests at the cost of slightly slower exit detection.
|
|
37
|
+
|
|
38
|
+
| Field | Default | Meaning |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `pollMs` | `20` | How often the package checks a running command's status, in milliseconds |
|
|
41
|
+
|
|
42
|
+
The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-subprocess-e2b) is the exhaustive source for every accepted field and its JSDoc.
|
|
43
|
+
|
|
44
|
+
### Running commands
|
|
45
|
+
|
|
46
|
+
The agent can run a command in the sandbox with a working directory and environment, choose how its output is delivered (streamed live, captured up to a size cap, or routed to the app's own output), and stop it if it hangs — a stop first asks the command to exit politely, then force-kills it after a short grace, so a stuck command cannot leak. Very large output can be saved to a file in the sandbox so the agent can read it later. The command's exit code is reported normally; if the sandbox vanishes while a command runs, the command is treated as ended rather than erroring.
|
|
47
|
+
|
|
48
|
+
### Using terminals
|
|
49
|
+
|
|
50
|
+
The agent can open an interactive terminal in the sandbox, send input, read output, and signal programs running in it — prompts, interactive tools, and full-screen programs behave as they do locally. Terminal features like scrollback and readiness detection are provided by the terminal tooling, which works unchanged.
|
|
51
|
+
|
|
52
|
+
### Keeping the environment clean
|
|
53
|
+
|
|
54
|
+
Commands run with a clean, sandbox-native environment: host variables and values that look like credentials are not passed in implicitly, and only entries the agent explicitly requests are set. This keeps secrets out of the sandbox.
|
|
55
|
+
|
|
56
|
+
### If the sandbox disappears
|
|
57
|
+
|
|
58
|
+
The sandbox is ephemeral: if it is deleted while commands or terminals are running — through expiry, shutdown, or removal elsewhere — the affected commands are treated as ended cleanly. Do not rely on work surviving the sandbox.
|
|
59
|
+
|
|
60
|
+
The default sandbox image ships with the runtime and utilities command work needs: `node`, `bash`, `setsid`, `ps`, `awk`, `tr`, `env`, `base64`, `chmod`, `tee`, `head`, `rm`, `kill`, `id`, and `getent`.
|
|
61
|
+
|
|
62
|
+
-----
|
|
63
|
+
|
|
64
|
+
<a id="understand-the-implementation"></a>
|
|
65
|
+
## Understand the implementation
|
|
66
|
+
|
|
67
|
+
<details>
|
|
68
|
+
<summary>Implementation internals — click to expand</summary>
|
|
69
|
+
|
|
70
|
+
This section explains the design decisions behind the provider and points at the code that realizes them; the observable behavior is fully covered in [Use this package](#use-this-package).
|
|
6
71
|
|
|
7
|
-
|
|
72
|
+
### Design philosophy
|
|
8
73
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
74
|
+
- **Deferred remote identity.** The synchronous seam never blocks on the network: the handle publishes its real process-group id asynchronously, and the wrapper's private files are the authority for pid, exit code, and spill validity.
|
|
75
|
+
- **One teardown ladder.** Termination, rollback, and disposal share one process-group signal path — `SIGTERM`, then `SIGKILL` plus the SDK kill fallback — and treat proven quiescence as final.
|
|
76
|
+
- **Environment is explicit.** Nothing from the host and nothing credential-shaped enters the sandbox implicitly; every ambient value is scrubbed and every `spec.env` entry is an explicit opt-in.
|
|
12
77
|
|
|
13
|
-
|
|
78
|
+
### Source map
|
|
14
79
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
80
|
+
| File | Role |
|
|
81
|
+
|---|---|
|
|
82
|
+
| [`src/index.ts`](src/index.ts) | Plugin entry: `E2BSubprocessRuntime`, `Config`, spawn and spawnTerminal, disposal |
|
|
83
|
+
| [`src/process.ts`](src/process.ts) | `E2BSubprocessHandle`: remote wrapper, publication, termination, output projection |
|
|
84
|
+
| [`src/terminal.ts`](src/terminal.ts) | `E2BTerminalHandle`: PTY allocation, session teardown |
|
|
85
|
+
| [`src/environment.ts`](src/environment.ts) | Remote environment probe, scrubbing, serialization |
|
|
86
|
+
| [`src/output.ts`](src/output.ts) | Base64 decoder and bounded output readers |
|
|
87
|
+
| [`src/remote.ts`](src/remote.ts) | Shared control-shell helpers: option shaping, poll ticks, group signalling |
|
|
88
|
+
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion (no runtime invariant; live remote handles are private teardown ownership) |
|
|
22
89
|
|
|
23
|
-
|
|
90
|
+
### Remote wrapper
|
|
24
91
|
|
|
92
|
+
The bootstrap resolves its own tools from the sandbox PATH, refuses any missing or non-executable path, execs through `env -i` and `setsid --wait`, publishes the process-group id and exit code to private files beneath `ctx.e2b.runtimeRoot/processes`, and redirects stdout and stderr through base64 encoders that emit a reserved completion frame; `tee` and `head -c` bound optional spill files.
|
|
93
|
+
|
|
94
|
+
### Process identity and publication
|
|
95
|
+
|
|
96
|
+
The synchronous seam returns a handle immediately while the command starts asynchronously; `pid` stays `-1` until the wrapper publishes its process-group id and the adapter validates it, and stdin plus ordinary observation wait for that publication. A startup signal aborts environment and private-state preparation before allocation; once allocation begins, cancellation waits for a provisional SDK handle it can clean.
|
|
97
|
+
|
|
98
|
+
### Environment boundary
|
|
99
|
+
|
|
100
|
+
One trusted control-shell probe resolves the sandbox user's login home from its passwd entry and transports the sandbox environment as base64 ASCII for one strict UTF-8 decode; the wrapper then removes ambient `DSH_*` and credential-shaped (`*KEY*`, `*SECRET*`, `*TOKEN*`) names and restores every valid `spec.env` entry as an explicit caller opt-in. Empty names, `=`, and NUL framing violations reject before launch; subsequent command and PTY login shells receive a fresh randomized root-level `HOME` plus empty overrides for every scrubbed ambient name before user profiles can run. Private environment files are removed after consumption.
|
|
101
|
+
|
|
102
|
+
### Output handling
|
|
103
|
+
|
|
104
|
+
The remote wrapper branches raw bytes into optional bounded spill files and frames each live chunk as newline-delimited base64 ASCII; the host restores bytes across arbitrary SDK callback boundaries. Pipe mode writes to host Node streams, inherit mode to the harness process streams, and collect mode retains a bounded host tail with offset reads. For collect or inherit output, an incomplete SDK stream is disconnected after `graceMs` with its partial spill withheld; natural raw-pipe completion awaits lossless transport and preserves backpressure. Batch and streaming stdin use the SDK handle.
|
|
105
|
+
|
|
106
|
+
### Termination ladder
|
|
107
|
+
|
|
108
|
+
Termination and rollback share one tolerant signal path (`signalRemoteGroups`), escalate `SIGTERM` to `SIGKILL` on grace expiry, use the SDK kill as a fallback, and prove quiescence with a bounded process-table probe before reporting success; zombie-only groups count as empty, and a `SandboxNotFoundError` is treated as quiescence.
|
|
109
|
+
|
|
110
|
+
</details>
|
|
111
|
+
|
|
112
|
+
-----
|
|
113
|
+
|
|
114
|
+
<a id="further-exploration"></a>
|
|
115
|
+
## Further Exploration
|
|
116
|
+
|
|
117
|
+
Read these pages when the package-level contract is not enough. They move from the family composition to the subprocess seam surface and the consumers that render it.
|
|
118
|
+
|
|
119
|
+
- [E2B provider family map](../README.md) — the sandbox owner and the three-package composition.
|
|
120
|
+
- [Subprocess subsystem](../../../docs/subsystems/subprocess.md) — the subprocess seam contract and the generated Cordis surface.
|
|
121
|
+
- [Subprocess seam package](../../subprocess/subprocess/README.md) — the abstract contract this provider implements.
|
|
122
|
+
- [Bash executor](../../shell/bash-local/README.md) — the consumer that renders spawned commands to the model.
|
|
123
|
+
- [PTY terminal backend](../../terminal/terminal-bash/README.md) — the consumer that renders terminal sessions.
|
|
124
|
+
- [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-subprocess-e2b) — every accepted config field and its source declaration.
|
|
125
|
+
|
|
126
|
+
-----
|
|
127
|
+
|
|
128
|
+
<a id="model-experience"></a>
|
|
25
129
|
## Model Experience
|
|
26
130
|
|
|
27
|
-
Indirectly, through
|
|
131
|
+
Indirectly, through consumer seams such as the bash executor family, which render remote output, exit facts, background deltas, and spill paths.
|
|
28
132
|
|
|
29
133
|
#### KV Cache effect
|
|
30
134
|
|
|
31
|
-
No direct invalidation
|
|
135
|
+
No direct invalidation: the consumer seams own any request-prefix changes; this backend's transport never reaches a request.
|
|
32
136
|
|
|
33
137
|
## Known Limitations and Deferred Work
|
|
34
138
|
|
|
139
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
These limits define when the provider is a poor fit or needs special operational care. They are current package constraints, not a task backlog.
|
|
143
|
+
|
|
35
144
|
- **The SDK still retains complete command output in host memory** — E2B `CommandHandle.stdout` and `.stderr` accumulate the base64 transport even when this adapter exposes bounded raw-byte tails, so the subprocess seam's normal host-memory bound is not achieved and transport retention is larger than the source stream.
|
|
36
145
|
- **Synchronous-PID consumers are unsupported** — `pid` remains `-1` during remote startup; consumers that require a positive PID immediately, including the ACP child backend, cannot use this provider unchanged.
|
|
37
146
|
- **Private state lives for the sandbox lifetime** — process directories and valid spill files remain under `.dsh-e2b` until the owner deletes the sandbox; this POC supplies no in-sandbox sweep.
|
|
38
|
-
- **Control state shares the sandbox user's UID** — E2B runs every command as the same default user, so `0700`/`0600` modes cannot isolate `.dsh-e2b` control files from concurrently running sandbox processes
|
|
39
|
-
- **Numeric process identities are not reuse-fenced** — E2B exposes numeric PID/PGID
|
|
40
|
-
- **The initial environment probe inherits sandbox defaults** — E2B merges command overrides with default environment entries, so the probe cannot blank unknown credential-shaped names before enumerating them
|
|
147
|
+
- **Control state shares the sandbox user's UID** — E2B runs every command as the same default user, so `0700`/`0600` modes cannot isolate `.dsh-e2b` control files from concurrently running sandbox processes; real isolation needs an E2B per-command user or an out-of-band control channel.
|
|
148
|
+
- **Numeric process identities are not reuse-fenced** — E2B exposes numeric PID/PGID input, signalling, and cleanup operations but no atomic identity-bound alternative; replacement is deferred until E2B adds an identity primitive or a failure demonstrates a narrower protocol.
|
|
149
|
+
- **The initial environment probe inherits sandbox defaults** — E2B merges command overrides with default environment entries, so the probe cannot blank unknown credential-shaped names before enumerating them; this POC therefore does not support secrets in sandbox-default environment variables.
|
|
41
150
|
- **E2B exposes no signal fact** — an adapter-requested `SIGTERM` or `SIGKILL` is reported only when no wrapper-published direct exit code wins; every unrequested SDK exit remains an exit code, including values equal to `128 + signal`.
|
|
42
151
|
- **Exact terminal stdin-wait inspection is unavailable** — E2B exposes the foreground process group but not the syscall evidence needed to prove it is waiting on fd 0, so the generic PTY backend falls back to controlled prompt markers and bounded silence.
|
|
43
152
|
- **Linux utility and E2B transport semantics are assumed** — there is no Windows, escaped-session recovery, or network-partition fidelity layer.
|
|
153
|
+
|
|
154
|
+
<a id="dev-note"></a>
|
|
155
|
+
### Dev Note
|
|
156
|
+
|
|
157
|
+
<details>
|
|
158
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
159
|
+
|
|
160
|
+
This Dev Note is working context for maintainers: open questions and directions that are not decided. It is explicitly non-authoritative — shipped behavior, limits, and accepted rationale live in the sections above and the package code.
|
|
161
|
+
|
|
162
|
+
#### Open: numeric process identities
|
|
163
|
+
|
|
164
|
+
E2B exposes numeric PID/PGID input, signalling, and cleanup operations without an atomic identity-bound alternative. The adapter minimizes host round trips and defers a replacement until E2B adds an identity primitive or a failure demonstrates a narrower protocol (TODO(e2b-pgid-identity)).
|
|
165
|
+
|
|
166
|
+
#### Open: replacement environments and status observation
|
|
167
|
+
|
|
168
|
+
The initial environment probe inherits sandbox defaults because E2B merges command overrides, and collect/inherit command status needs control-plane polling because E2B cannot observe direct-command exit independently of descendant-held output. Both close only with new E2B primitives (TODO(e2b-replace-environment), TODO(e2b-status-watch)).
|
|
169
|
+
|
|
170
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,43 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "共享远程沙箱内的 shell 命令与终端:agent 可以在那里运行什么、输出如何处理,以及可以期待什么——面向 E2B 家族的部署方与维护者。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-subprocess-e2b
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-subprocess-e2b` 让 agent(智能体)的 shell 命令与终端在远程沙箱内运行:agent 可以执行 Bash、打开交互式终端并读取其输出,体验与本地执行完全一致,而宿主机器上什么都不会运行。现有的命令、终端与语言服务器功能无需任何改动即可继续工作——不需要 E2B 专用工具。密钥与宿主环境变量绝不会泄漏进沙箱:只有 agent 显式请求的环境条目才会传入。请与 `dsh-e2b`、`dsh-fs-e2b` 一起使用,让命令、终端与文件共享同一个远程世界。主要代价是远程延迟——每条命令都要经过一段短暂异步初始化,而不是立即启动。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
当 agent 的 shell 命令与终端应在远程沙箱内而非你的机器上运行时,使用本包。它是 E2B 家族的命令半边:命令、终端与文件共享同一个远程世界。
|
|
29
|
+
|
|
30
|
+
### 何时选择
|
|
31
|
+
|
|
32
|
+
当组合已经使用 E2B 沙箱且希望命令与终端在其中运行时,选择本包。宿主执行请选择本地子进程包。需要立即获得进程 ID 的工具——例如 ACP(Agent Client Protocol)子进程后端——无法使用本包。
|
|
33
|
+
|
|
34
|
+
### 配置
|
|
35
|
+
|
|
36
|
+
唯一设置是包检查运行中命令状态的频率;默认值适合大多数部署,调大它可以减少远程请求,代价是退出检测略慢。
|
|
37
|
+
|
|
38
|
+
| 字段 | 默认值 | 含义 |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `pollMs` | `20` | 包检查运行中命令状态的频率(毫秒) |
|
|
41
|
+
|
|
42
|
+
生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-subprocess-e2b)是每个受支持字段及其 JSDoc 的穷尽式真源。
|
|
43
|
+
|
|
44
|
+
### 运行命令
|
|
45
|
+
|
|
46
|
+
agent 可以在沙箱中按指定的工作目录与环境运行命令,选择输出的交付方式(实时流式、在大小上限内捕获,或路由到应用自身的输出),并在命令卡住时停止它——停止会先礼貌地请求命令退出,短暂宽限期后再强制终止,因此卡住的命令不会残留。非常大的输出可以保存到沙箱中的文件里,供 agent 稍后读取。命令的退出码会正常报告;如果命令运行期间沙箱消失,该命令会被视为已结束而不是报错。
|
|
47
|
+
|
|
48
|
+
### 使用终端
|
|
49
|
+
|
|
50
|
+
agent 可以在沙箱中打开交互式终端、发送输入、读取输出,并向其中运行的程序发送信号——提示符、交互式工具与全屏程序的行为与本地完全一致。scrollback 与就绪检测等终端功能由终端工具提供,无需改动即可工作。
|
|
51
|
+
|
|
52
|
+
### 保持环境干净
|
|
53
|
+
|
|
54
|
+
命令在干净、沙箱原生的环境中运行:宿主变量与形似凭据的值不会被隐式传入,只有 agent 显式请求的条目才会被设置。这使密钥不会进入沙箱。
|
|
55
|
+
|
|
56
|
+
### 如果沙箱消失
|
|
57
|
+
|
|
58
|
+
沙箱是短暂的:如果命令或终端运行期间沙箱被删除——无论是到期、关闭还是被别处移除——受影响的命令会被视为干净地结束。请不要依赖能在沙箱中存续的工作。
|
|
59
|
+
|
|
60
|
+
默认沙箱镜像自带命令工作所需的运行时与工具:`node`、`bash`、`setsid`、`ps`、`awk`、`tr`、`env`、`base64`、`chmod`、`tee`、`head`、`rm`、`kill`、`id` 与 `getent`。
|
|
61
|
+
|
|
62
|
+
-----
|
|
63
|
+
|
|
64
|
+
<a id="understand-the-implementation"></a>
|
|
65
|
+
## 理解实现
|
|
66
|
+
|
|
67
|
+
<details>
|
|
68
|
+
<summary>实现细节——点击展开</summary>
|
|
69
|
+
|
|
70
|
+
本节解释提供方背后的设计决策,并指出实现它们的代码位置;可观察行为已在[使用本包](#use-this-package)中完整说明。
|
|
6
71
|
|
|
7
|
-
|
|
72
|
+
### 设计理念
|
|
8
73
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
74
|
+
- **延后的远程身份。** 同步 seam 从不阻塞在网络请求上:句柄异步发布真实进程组 ID,包装层的私有文件是 pid、退出码与 spill 有效性的权威来源。
|
|
75
|
+
- **单一终止阶梯。** 终止、回滚与资源释放共享同一条进程组信号路径——先 `SIGTERM`,再 `SIGKILL` 加 SDK kill 回退——并把已证明的完全停稳视为最终状态。
|
|
76
|
+
- **环境必须显式。** 宿主内容与形似凭据的内容都不会隐式进入沙箱;每个环境值都会被清理,每个 `spec.env` 条目都是显式选择。
|
|
12
77
|
|
|
13
|
-
|
|
78
|
+
### 源码地图
|
|
14
79
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
80
|
+
| 文件 | 职责 |
|
|
81
|
+
|---|---|
|
|
82
|
+
| [`src/index.ts`](src/index.ts) | 插件入口:`E2BSubprocessRuntime`、`Config`、spawn 与 spawnTerminal、资源释放 |
|
|
83
|
+
| [`src/process.ts`](src/process.ts) | `E2BSubprocessHandle`:远程包装层、发布、终止、输出投影 |
|
|
84
|
+
| [`src/terminal.ts`](src/terminal.ts) | `E2BTerminalHandle`:PTY 分配、会话拆除 |
|
|
85
|
+
| [`src/environment.ts`](src/environment.ts) | 远程环境探测、清理、序列化 |
|
|
86
|
+
| [`src/output.ts`](src/output.ts) | base64 解码器与有界输出读取器 |
|
|
87
|
+
| [`src/remote.ts`](src/remote.ts) | 共享控制 shell 辅助:选项构造、轮询 tick、进程组信号 |
|
|
88
|
+
| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件(无运行时不变式;存活远程句柄是私有的拆除所有权) |
|
|
22
89
|
|
|
23
|
-
|
|
90
|
+
### 远程包装层
|
|
24
91
|
|
|
92
|
+
引导脚本会从沙箱 PATH 解析自身所需的工具,拒绝任何缺失或不可执行的路径,通过 `env -i` 与 `setsid --wait` 执行 exec,把进程组 ID 与退出码发布到 `ctx.e2b.runtimeRoot/processes` 下的私有文件,并把 stdout 与 stderr 重定向到带保留完成帧的 base64 编码器;`tee` 与 `head -c` 约束可选 spill 文件的大小。
|
|
93
|
+
|
|
94
|
+
### 进程身份与发布
|
|
95
|
+
|
|
96
|
+
同步 seam 会立即返回句柄,同时命令异步启动;`pid` 在包装层发布进程组 ID 且适配器验证通过之前保持 `-1`,stdin 与常规观察都等待该发布。启动信号会在分配前中止环境与私有状态准备;分配开始后,取消会等待可清理的临时 SDK 句柄。
|
|
97
|
+
|
|
98
|
+
### 环境边界
|
|
99
|
+
|
|
100
|
+
一次受信任的控制 shell 探测会从 passwd 条目解析沙箱用户的登录主目录,以 base64 ASCII 传输沙箱环境,再进行一次严格 UTF-8 解码;随后包装层移除环境中的 `DSH_*` 与形似凭据的名称(`*KEY*`、`*SECRET*`、`*TOKEN*`),并把每个有效的 `spec.env` 条目恢复为调用方显式选择。空名称、`=` 与违反 NUL 分帧规则的条目会在启动前被拒绝;在用户 profile 脚本运行前,此后的命令与 PTY 登录 shell 会获得位于根目录下、全新随机生成的 `HOME`,并为每个被清理的环境变量名设置空值覆盖。私有环境文件在使用后会被删除。
|
|
101
|
+
|
|
102
|
+
### 输出处理
|
|
103
|
+
|
|
104
|
+
远程包装层先把原始字节分流到可选的有界 spill 文件,再把每个实时分片编码为换行分隔的 base64 ASCII 帧;宿主会跨任意 SDK 回调边界增量恢复字节。pipe 模式把字节写入宿主 Node 流,inherit 模式写入 harness 进程流,collect 模式保留有界的宿主尾部并支持偏移读取。对于 collect 或 inherit 输出,超过 `graceMs` 后适配器会断开未完成的 SDK 流并扣留其不完整的 spill;原始 pipe 自然完成时则会等待无损传输并保留背压。批量与流式 stdin 都使用 SDK 句柄。
|
|
105
|
+
|
|
106
|
+
### 终止阶梯
|
|
107
|
+
|
|
108
|
+
终止与回滚共享同一条容错信号路径(`signalRemoteGroups`),在宽限期满时从 `SIGTERM` 升级到 `SIGKILL`,以 SDK kill 作为回退,并在报告成功前用有界进程表探测证明完全停稳;仅含僵尸进程的进程组视为空,`SandboxNotFoundError` 视为完全停稳。
|
|
109
|
+
|
|
110
|
+
</details>
|
|
111
|
+
|
|
112
|
+
-----
|
|
113
|
+
|
|
114
|
+
<a id="further-exploration"></a>
|
|
115
|
+
## 进一步探索
|
|
116
|
+
|
|
117
|
+
当包级约定不够用时阅读以下页面。它们从家族组合逐步进入子进程 seam 表面,以及渲染它的消费方。
|
|
118
|
+
|
|
119
|
+
- [E2B 提供方家族地图](../README.zh.md)——沙箱所有者与三包组合。
|
|
120
|
+
- [子进程子系统](../../../docs/subsystems/subprocess.zh.md)——子进程 seam 约定与生成的 Cordis 表面。
|
|
121
|
+
- [子进程 seam 包](../../subprocess/subprocess/README.zh.md)——本提供方实现的抽象约定。
|
|
122
|
+
- [Bash 执行器](../../shell/bash-local/README.zh.md)——向模型渲染所启动命令的消费方。
|
|
123
|
+
- [PTY 终端后端](../../terminal/terminal-bash/README.zh.md)——渲染终端会话的消费方。
|
|
124
|
+
- [生成配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-subprocess-e2b)——每个受支持配置字段及其源声明。
|
|
125
|
+
|
|
126
|
+
-----
|
|
127
|
+
|
|
128
|
+
<a id="model-experience"></a>
|
|
25
129
|
## 模型体验
|
|
26
130
|
|
|
27
|
-
|
|
131
|
+
通过消费方 seam 间接影响模型,例如 bash 执行器家族;它们渲染远程输出、退出事实、后台增量与 spill 路径。
|
|
28
132
|
|
|
29
133
|
#### KV Cache 影响
|
|
30
134
|
|
|
31
|
-
|
|
135
|
+
不会直接失效:请求前缀变更由消费方 seam 负责;本后端的传输永远不会进入请求。
|
|
136
|
+
|
|
137
|
+
## 已知限制与延期工作
|
|
138
|
+
|
|
139
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
32
140
|
|
|
33
|
-
## 已知限制与延后工作
|
|
34
141
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
142
|
+
这些限制说明本提供方何时不合适,或何时需要特别的运维注意。它们是当前包约束,不是任务积压。
|
|
143
|
+
|
|
144
|
+
- **SDK 仍会在宿主内存中保留完整命令输出**:即使本适配器公开的是有界原始字节尾部,E2B `CommandHandle.stdout` 与 `.stderr` 仍会累积 base64 传输内容,因此无法达到子进程 seam 通常提供的宿主内存边界,而且传输保留量大于源数据流。
|
|
145
|
+
- **不支持需要同步 PID 的消费方**:远程启动期间 `pid` 保持 `-1`;包括 ACP 子进程后端在内,要求立即获得正 PID 的消费方无法原样使用本提供方。
|
|
146
|
+
- **私有状态随沙箱生命周期存在**:进程目录与有效的 spill 文件会留在 `.dsh-e2b` 下,直到所有者删除沙箱;本 POC 不提供沙箱内清理。
|
|
147
|
+
- **控制状态与沙箱用户同 UID**:E2B 以同一默认用户运行每条命令,因此 `0700`/`0600` 权限无法把 `.dsh-e2b` 控制文件与并发运行的沙箱进程隔离开;真正的隔离需要 E2B 提供按命令用户或带外控制通道。
|
|
148
|
+
- **数值进程身份没有复用围栏**:E2B 公开基于数值 PID/PGID 的输入、信号发送与清理操作,却没有与身份原子绑定的替代方案;在 E2B 新增身份原语,或实际故障证明需要更窄的协议之前,替代方案继续延后。
|
|
149
|
+
- **初始环境探测会继承沙箱默认值**:E2B 会把命令覆盖与默认环境条目合并,因此探测无法在枚举未知且形似凭据的名称之前将它们置空;因此,该 POC 不支持把 secret 放入沙箱默认环境变量。
|
|
41
150
|
- **E2B 不公开信号事实**:适配器请求的 `SIGTERM` 或 `SIGKILL` 只有在包装层发布的直接退出码没有胜出时才报告为信号;其他未请求的 SDK 退出始终保留为退出码,包括等于 `128 + signal` 的值。
|
|
42
151
|
- **无法精确检查终端 stdin 等待状态**:E2B 会公开前台进程组,但不提供证明其正在等待 fd 0 所需的 syscall 证据,因此通用 PTY 后端会回退到受控提示符标记与有界静默机制。
|
|
43
152
|
- **依赖 Linux 工具与 E2B 传输语义**:没有 Windows、逃逸会话恢复或网络分区的保真层。
|
|
153
|
+
|
|
154
|
+
<a id="dev-note"></a>
|
|
155
|
+
### 开发备注
|
|
156
|
+
|
|
157
|
+
<details>
|
|
158
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
159
|
+
|
|
160
|
+
本开发备注是维护者的工作上下文:开放问题与尚未决定的探索方向。它明确不具权威性——已交付的行为、限制与既定理由以上文和包代码为准。
|
|
161
|
+
|
|
162
|
+
#### 开放:数值进程身份
|
|
163
|
+
|
|
164
|
+
E2B 公开基于数值 PID/PGID 的输入、信号发送与清理操作,却没有与身份原子绑定的替代方案。适配器会尽量减少宿主往返,并在 E2B 新增身份原语或实际故障证明需要更窄的协议之前,继续延后替代方案(TODO(e2b-pgid-identity))。
|
|
165
|
+
|
|
166
|
+
#### 开放:替换环境与状态观察
|
|
167
|
+
|
|
168
|
+
由于 E2B 会合并命令覆盖,初始环境探测会继承沙箱默认值;又因为 E2B 无法独立于后代持有的输出观察直接命令的退出,collect/inherit 命令状态需要控制面轮询。两者都只能靠 E2B 的新原语来弥合(TODO(e2b-replace-environment)、TODO(e2b-status-watch))。
|
|
169
|
+
|
|
170
|
+
</details>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-subprocess-e2b",
|
|
3
3
|
"description": "E2B subprocess implementation for DeepSeek Harness",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2-alpha.3",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,20 +32,20 @@
|
|
|
32
32
|
],
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@deepseek-ai/dsh-
|
|
36
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
37
|
-
"@deepseek-ai/dsh-
|
|
38
|
-
"@deepseek-ai/
|
|
39
|
-
"@deepseek-ai/
|
|
35
|
+
"@deepseek-ai/dsh-e2b": "^0.1.2-alpha.3",
|
|
36
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.3",
|
|
37
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.2-alpha.3",
|
|
38
|
+
"@deepseek-ai/dsh-timeout": "^0.1.2-alpha.3",
|
|
39
|
+
"@deepseek-ai/cordis": "^4.0.2"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@deepseek-ai/schemastery": "^3.18.
|
|
42
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@deepseek-ai/dsh-
|
|
46
|
-
"@deepseek-ai/dsh-
|
|
47
|
-
"@deepseek-ai/dsh-
|
|
48
|
-
"@deepseek-ai/
|
|
49
|
-
"@deepseek-ai/
|
|
45
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.3",
|
|
46
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.2-alpha.3",
|
|
47
|
+
"@deepseek-ai/dsh-timeout": "^0.1.2-alpha.3",
|
|
48
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
49
|
+
"@deepseek-ai/dsh-e2b": "^0.1.2-alpha.3"
|
|
50
50
|
}
|
|
51
51
|
}
|