sandbox-agent
把 LLM agent CLI(opencode / codex / claude / pi / dsh)关进一次性 Docker 容器里跑,
用完即毁,产出安全地取回宿主机。零运行时依赖,宿主机只需要 docker。
from sandbox_agent import SandboxAgent, OpenCodeDriver
driver = OpenCodeDriver(provider="zhipuai-coding-plan", api_key=API_KEY)
with SandboxAgent(driver=driver, model="zhipuai-coding-plan/glm-5.3") as agent:
print(agent.ask("用 Python 写个快排, 存到 /tmp/qs.py"))
code, out = agent.container.exec(["python", "/tmp/qs.py"]) # 验收产出
agent.container.download("/tmp/qs.py", "./qs.py") # 取回宿主机
# 退出 with 块 -> 容器销毁
安装
uv add sandbox-agent # 或 pip install sandbox-agent
还需要装好了 agent CLI 的镜像,见 docker/ 与 .ci/build_docker.sh。
镜像 tag 由包内的 versions.json 唯一推导,格式
{repo}:{cli}-{cli版本}-{image_date},不用 latest。装好的包指向哪个镜像,直接问它:
python -c "from sandbox_agent import versions; print(versions.CLAUDE_IMAGE)"
镜像优先级:显式 image= > SANDBOX_AGENT_IMAGE_NAME(换私有 registry 用)>
driver.default_image > 内置默认值。
能干什么
| 对话 | chat() 拿可迭代的流式事件,推进主线;ask() 开旁支问一句,问完即扔 |
| 会话 | sessions.list() / .fork() / .dump() / .load() —— 会话能跨容器搬 |
| 容器操作 | container.upload() / .download() / .read() / .write() / .exec() —— 取回时只落普通文件和目录,链接不落地 |
| 能力注入 | skills.add() / .add_many() / .list(),rules.install() |
| 可观测 | token_usage、AgentEvent 流、按 tag 筛容器(list_containers) |
| 可审计 | 每次会话自动归档到 /tmp/sandbox-agent-<uid>/,默认开 |
扩展点
- 新 agent CLI:继承
BaseDriver,实现 11 个抽象成员。driver 只通过ContainerOps的三个原语(run/read_file/write_file)碰容器,单测伪造这三个方法即可。 - 新容器后端(podman、远程执行器):实现
ContainerRuntime协议,传给SandboxAgent(runtime_factory=...)。
完整 API 见 docs/sandbox_agent.md。
端到端冒烟
main.py 对真 CLI 跑一遍主要行为(容器 I/O、工具事件、ask、续接、fork 隔离、
skill / rules、delete / dump、审计、跨容器 load、假 key 抛 DriverError),多个 driver 并行:
uv run python main.py # 默认只跑 opencode
uv run python main.py claude codex # 指定若干个 (opencode|codex|claude|pi|dsh)
uv run python main.py all # 五个全跑
opencode 直连智谱,要 ZHIPUAI_CODING_TOKEN;其余四个走 runtime/litellm/
网关(GATEWAY_URL / GATEWAY_KEY 有默认值),网关怎么起见那边的 README。
会话审计
/tmp/sandbox-agent-<uid>/<YYYYMMDD>/<session_id>/
events.jsonl 归一后的 AgentEvent,一行一个;line 字段回指 session.jsonl 的行号
session.jsonl CLI 原始 stdout,逐字节照抄,不过滤
status.json 元数据 + 每一轮的结果
同一 session_id 的多轮落进同一目录,流式追加,可直接 tail -f。thinking 事件只在
后端返回推理正文时才有内容。归档失败只发 RuntimeWarning,不影响 chat。
jq -r '"\(.kind)\t\(.payload.command // .payload.path // .payload.text)"' events.jsonl
SandboxAgent(driver=driver, audit=False) # 关闭
from sandbox_agent import audit
audit.AUDIT_ROOT = "/data/sandbox-audit"
audit.RETENTION_DAYS = 30 # 默认 7; 0 = 永不清理, 按日期目录整个删
容器生命周期
close() / 退出 with 即销毁。兜底:容器闲置 keepalive_seconds(默认 3600s)后自杀,
有命令在跑就持续续期。
配置
优先级:环境变量 > ~/.config/sandbox-agent/config.json > 内置默认值。
| 环境变量 | JSON key | 默认值 |
|---|---|---|
SANDBOX_AGENT_IMAGE_NAME |
image |
driver 自己的 default_image |
SANDBOX_AGENT_RESOURCE_PREFIX |
prefix |
sandbox-agent |
SANDBOX_AGENT_CONTAINER_MEMORY |
memory |
1g |
SANDBOX_AGENT_CONTAINER_CPUS |
cpus |
1.0 |
SANDBOX_AGENT_KEEPALIVE_SECONDS |
keepalive_seconds |
3600(0 = 不自杀) |
SANDBOX_AGENT_MAX_CONTAINERS |
max_containers |
20 |
SANDBOX_AGENT_START_TIMEOUT |
start_timeout |
120 |
SANDBOX_AGENT_STOP_TIMEOUT |
stop_timeout |
30 |
SANDBOX_AGENT_EXEC_TIMEOUT |
exec_timeout |
60 |
SANDBOX_AGENT_CHAT_TIMEOUT |
chat_timeout |
300 |
SANDBOX_AGENT_SESSION_TIMEOUT |
session_timeout |
120 |
SANDBOX_AGENT_TRANSFER_TIMEOUT |
transfer_timeout |
300 |
方法参数 timeout=None 即用对应类别的配置值。
开发
uv sync --all-extras
uv run pytest # 单元测试, 全 mock, 不碰 docker
uv run pytest -m integration # 集成测试, 起真容器
docker pull debian:stable-slim # 集成测试用的镜像, 要事先拉好 (不会自动 pull, 没有则跳过)
集成测试镜像可用 SANDBOX_AGENT_TEST_IMAGE 替换,别用 alpine(busybox 的 timeout
超时不返回 124)。fixture 快照见 tests/fixtures/README.md。
已知限制见 TODO.md,变更历史见 CHANGELOG.md。
发布
先镜像后包:包里的 versions.json 指向镜像。改了 CLI 版本或 Dockerfile.base 时,
先手动 bump versions.json 的 image_date(YYYYMMDD,不会自动生成)。
./.ci/build_docker.sh --push # 1. 镜像; tag 已存在会拒绝, --force 覆盖
./.ci/build_pypi.sh --push # 2. 包; registry 上缺镜像会拒绝
License
GPL-3.0-or-later
Metadata
Release files for sandbox-agent 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sandbox_agent-0.2.2.tar.gz | 81.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sandbox_agent-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 183.8 kB
Release files / sandbox_agent-0.2.2.tar.gz
| Download URL | sandbox_agent-0.2.2.tar.gz |
|---|---|
| Size | 81.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8e9e0e7c9e55b182bc7f9c6b1d48b171ece0a5e11fd8c15ef579d5050a2f7031
|
|
BLAKE2b-256 checksum How to use checksums |
bf7dd092553651ca7e30bce43d6db76ce2d5beccbd4f24320ab93b97bb172bbd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / sandbox_agent-0.2.2-py3-none-any.whl
| Download URL | sandbox_agent-0.2.2-py3-none-any.whl |
|---|---|
| Size | 102.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dcfcaa3a8ef0a47603f8b82f1cd41eb124ae423d14e14360e22453fb03378ced
|
|
BLAKE2b-256 checksum How to use checksums |
1e95e573ceed8eadc72d6fa27345d063b6d5621eaf5feddcb223e6c5335902a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|