学习笔记 · Obsidian
Smith API:Sandbox 生命周期、快照、资源与网络边界
Sandbox 是 Workspace 隔离的可执行运行时。它的控制面包含三类资源:Sandbox 实例、可复用 Snapshot、拉取私有镜像的 Registry。创建成功、异步构建、运行状态、文件系统持久化和内存恢复是不同维度;只看一个 HTTP 2xx 不能推导整个运行时已经达到目标状态。
生命周期与状态
POST /api/v2/sandboxes/boxes 从 snapshot 创建 sandbox。snapshot_id 与 snapshot_name 最多传一个;两者都省略时使用默认 snapshot。成功为 201,但还可能出现 504“未在时限内 ready”、429 配额不足、409 名称冲突、400 snapshot 不存在、422 参数组合错误。
主要状态可从 list 的筛选枚举看出:provisioning、ready、failed、stopped、deleting。GET /boxes/{name} 会把长期停留在 provisioning 的 stale 资源自动标为 failed;高频轮询应使用轻量 /status,只取 status 与 status_message。
启动与停止不是幂等操作:
POST /boxes/{name}/start只适用于 stopped 或 failed,返回 202;重复 start 可能失败。POST /boxes/{name}/stop只适用于 ready,返回 204;文件系统保留,重复 stop 也不保证成功。DELETE /boxes/{name}可按名称或 UUID,拆除 runtime 并删除数据库记录,成功 204。- batch-delete 接收 names/UUIDs,响应分为
deleted[]与skipped[{name,reason}],HTTP 200 仍可能是部分完成。
可靠的 orchestration 先 GET/status 判断当前状态,再发状态转换;网络超时后回读,不能盲目重放非幂等 start/stop。删除前停止并不是 API 明示的必需步骤,但业务应先终止新任务、等待在途 command、保存需要的 snapshot,再删除。
CPU、内存、磁盘与自动回收
创建支持 vcpus 或 cpu_millicores,后者出现时优先;fractional CPU 并非所有 sandbox 都可用。默认内存按每 vCPU 4 GiB 推导。创建时显式内存必须位于该比例的 50%–150% 范围,例如 1 vCPU 接受 2–6 GiB;只给内存时会反推 CPU;上限 64 GiB。Update resize 的内存规则不同,只明确强制 64 GiB 上限,客户端不要把 create 的比例校验机械复制到 update。
其他资源字段:
fs_capacity_bytes:文件系统容量;idle_ttl_seconds:空闲多久后停止;delete_after_stop_seconds:停止后多久删除;preserve_memory_on_stop:主动 stop/idle stop 时是否保留内存;- labels 与 tag_value_ids:资源发现和治理标签。
idle stop 和 stop 后删除是两个计时器。前者影响运行态,后者影响资源存在性;业务不能把“停止后还能 restart”当永久保证。GET /sandboxes/usage 返回 CPU/memory 已用与上限、sandbox 总上限、running/stopped/direct/pool replicas 数量,以及 snapshots/registries/templates/pools 计数。创建前做 quota preflight,但仍要处理并发下的 429。
文件系统与内存快照
Snapshot 有两条创建路径:
POST /snapshots从 Docker image 异步构建,传 name、docker_image、fs_capacity_bytes,可带 registry_id 和 labels。201 返回的对象仍有 building/ready/failed/deleting 状态,需要轮询。POST /boxes/{name}/snapshot从现有 sandbox 捕获。可提供已有 checkpoint,或在运行 VM 中新建 checkpoint;也可指定 sandbox-local Docker image 导出。Docker 导出在 sandbox 没有容量信息时要求fs_capacity_bytes。
捕获时 include_memory=true 只有在 sandbox 正在运行且未传 checkpoint、即请求新鲜 in-VM checkpoint 时才生效。Snapshot 返回的 memory_snapshot_size_bytes 非空,是“可从内存 warm restore”的权威信号;空值只代表 rootfs。
创建 sandbox 时 restore_memory 是三态:
- 省略:snapshot 有内存就恢复,否则 cold boot;
- true:必须从内存恢复,snapshot 无内存则拒绝;
- false:始终 cold boot。
preserve_memory_on_stop 默认 false,主动 stop 后只保留文件系统;true 才在下次 start 继续内存状态。基础设施维护触发的 restart 无论该配置如何都会保留内存。两项含义不同:一个控制从 snapshot 首次创建,一个控制实例后续 stop/start。
删除 snapshot 成功 204,但底层存储异步回收。容量报表和账单下降可能滞后;删除完成不等于物理字节即时清零。
Registry 凭据
Registry CRUD 管理私有镜像源。Create 必填 name、url、username、password;Update 可替换名称、URL 与凭据;响应只返回 ID、name、URL、created/updated by/at,不回显 username/password。List 支持 limit、offset、name_contains,名称冲突为 409。
凭据只在 secret manager/受控输入中存在,不应写入 note、trace、日志或 Terraform plan 明文。轮换采用更新新凭据、构建 canary snapshot、验证拉取成功、再失效旧凭据。Registry 删除前检查仍引用它的 snapshot/build;这些页面没有声明级联语义,不能假设删除 registry 会安全迁移依赖。
Mount 模型
mount_config.mounts[] 是 discriminator union,每项必填 id(最多 64 字符)、mount_path 和 type,可设 read_only。支持:
| type | 专属配置 | 关键字段 |
|---|---|---|
| s3 | s3 | bucket、region 必填;prefix、endpoint_url、path_style 可选 |
| gcs | gcs | bucket 必填;prefix 可选 |
| git | git | remote_url 必填;ref=branch/tag+name;refresh interval 最少 1 秒 |
| contexthub | contexthub | repo=owner/repo,- 表示当前 workspace;可 initial_pull_only |
S3/GCS 可带 cache(max_size_bytes、writeback_seconds,均不小于 0);Git 与 Context Hub 的 variant 不带该 cache。各 union 只能出现对应配置,不能同时携带 s3/gcs/git/contexthub 多个块。
Mount auth 分 AWS access key/secret 与 GCP service account JSON,值使用 ProxySecretValue,type 为 plaintext、opaque 或 workspace_secret,并带 is_set。生产只使用 workspace_secret 或平台 opaque 形式;read_only mount 应是默认,只有明确需要写回且考虑并发/一致性时才开启写权限。
Git/Context Hub mount 会把外部内容引入可执行环境,仍需固定可信 repo/ref、验证内容来源,避免把自动刷新当代码供应链信任。Context Hub initial_pull_only=true 可在实例启动时固定一次内容,适合要求运行期间不漂移的任务。
出站 Proxy 与凭据注入
proxy_config 由 access_control、no_proxy、callbacks 和 rules 组成:
- allow_list/deny_list 控制出站 host;生产采用最小 allow list,deny list 不是替代品。
- Header injection rule 可用 match_hosts/match_paths;provider auth rule 使用内置 host 匹配,不接受自定义 match_hosts。
- Header/secret type 同样支持 plaintext、opaque、workspace_secret。
- AWS/GCP provider rule 使用受控 secret;GCP scopes 至少一个。
- callbacks 必填 URL、至少一个 match_host、TTL 60–3600 秒,可选择 full_request 与 request_headers。
Rule 的 env_vars 是每条命令都能看到的明文环境变量。文档说明它可为拒绝空 credential 的 CLI 提供 dummy 值,而真实 credential 由 wire injection 完成;显式 sandbox env_vars 优先于 rule env_vars,provider-managed AWS/GCP vars 又优先于两者。不要把真实长期密钥塞进 dummy env vars。
Callback 的 full_request 会扩大数据暴露面,默认应关闭;URL 必须 allowlist,回调请求需要签名、短 TTL、防重放与最小 headers。Proxy 更新属于 Sandbox PATCH 的整体嵌套配置,修改前应读回当前规则,避免遗漏字段导致现有 allow/deny 或 credential injection 消失。
临时 HTTP Service 访问
POST /boxes/{name}/service-url 为 sandbox 内指定 port 生成短期 JWT,返回:
browser_url:通过 redirect 设置认证 cookie;service_url:程序端地址,请求用X-Langsmith-Sandbox-Service-Token;- raw
token与expires_at。
这是临时凭据创建响应。完整 token 只应短暂进入调用方内存,不写日志、trace、URL 参数或 Obsidian。调用者应要求尽可能短的 expires_in_seconds,验证 port 白名单,并在浏览器路径防止 token 经 Referer、history 或第三方资源泄露。501 表示目标环境尚未实现该能力,不应自动降级为公开端口。
列表、标签与可运维性
Sandbox 与 Snapshot list 默认 limit 50、offset 0,支持 name substring、status、created_by=me、sort field/direction。Label query 可重复:所有条件都必须匹配;key 匹配存在,key=value 匹配相等。Registry list 也使用 offset pagination。
长时间任务应保存稳定 ID,而不是只保存可变 name;更新名称要求 tenant 内唯一。Offset 分页在并发增删时可能漂移,资产审计需按稳定排序、处理重复并最终按 ID 去重。状态机监控至少覆盖 provisioning/building 超时、failed reason、429 quota、504 ready timeout、stop 后未删除和异步 snapshot storage 回收。