# 运行时与沙箱

沙箱生命周期、注入的环境、令牌系列，以及会话启动所基于的镜像。

Canonical page: https://beeuni.ai/docs/zh/work/runtime

每个会话都在独立的隔离环境中运行。 本页介绍沙箱生命周期、Beeuni 在启动时注入的环境、令牌类型，以及沙箱镜像本身。会话概念请参阅 [Sessions](/docs/zh/work/sessions)。

<a id="sandbox-lifecycle"></a>

## 沙箱生命周期

会话记录包含一个 `status`。该枚举定义了 `queued`、`branching`、`provisioning`、`running`、`stopped`、`failed`、`completed`，但 Beeuni 只会写入其中 4 种状态。

| 状态 | 设置时机 |
| --- | --- |
| `provisioning` | 创建会话时。Beeuni 创建会话分支并请求沙箱。 |
| `running` | 沙箱启动并可访问后。 |
| `stopped` | 显式停止时，或闲置清理任务休眠非活动沙箱时。 |
| `failed` | 配置失败时。 |

`queued`、`branching` 和 `completed` 虽然存在于枚举中，但在会话流程中不会使用。不要将它们视为有效状态。

沙箱本身在自己的记录中有单独的 `status`，并使用自己的枚举。

| 状态 | 设置时机 |
| --- | --- |
| `provisioning` | 提供商启动沙箱时。 |
| `active` | 提供商确认沙箱已启动时。 |
| `stopped` | 显式停止、闲置自动停止或重启过程中。 |
| `error` | 提供商报告启动或运行时故障时。 |
| `archived` | 终止状态。你删除了会话，提供商销毁了沙箱，而不是将其暂停。 |

Beeuni 不限制每个账户或项目同时运行的会话数量。运行中的会话会产生计算费用；账户余额不足时，创建会话会得到 `402`。

<a id="branch-model"></a>

### 分支模型

- 会话分支以会话 ID（UUID）命名。`BEEUNI_SESSION_ID` 和 `BEEUNI_BRANCH_NAME` 的值相同。
- Beeuni 在创建会话时从 `base_ref` 创建分支；该值默认为项目的默认分支。
- 触发器创建会话分支的方式与交互式会话相同。
- 默认分支不会被直接写入。只有合并后的[变更请求](/docs/zh/work/change-requests)会写入默认分支。

<a id="reconcile-a-session-branch"></a>

### 同步会话分支

当基分支发生变化时，从会话命令面板中选择 **Ask Agent: Sync Branch & Reload**。智能体会检查会话分支、保留本地工作、获取最新的 `base_ref`、解决冲突、运行相关测试，并提交同步结果。Beeuni 不会选择冲突的一方，也不会重置工作树。

智能体完成后会显示 `beeuni sessions reload "$BEEUNI_SESSION_ID" --project "$BEEUNI_PROJECT_ID" --no-repo --force --yes`。由于智能体已完成分支同步，因此必须执行 `--no-repo`。替换后的运行时通过健康检查后，重新加载会替换标准运行器运行时。重新加载会结束当前轮次，因此运行时恢复后，请发送 `continue`。

会话标题栏会实时显示服务器确认的每个重新加载阶段。网页重新加载会检查会话、编译智能体配置、应用并验证运行时替换，然后确认当前配置。它不会刷新代码库。CLI 可以刷新代码库，除非你传入 `--no-repo`。

<a id="config-convergence"></a>

### 配置趋同

<a id="where-a-box-gets-the-release"></a>

每个会话使用其基础分支上的配置。将修改推送到该分支后重新加载会话。配置更新会等待当前轮次结束，不再单独设置 Config Releases 功能开关。

使用 **Reload config** 或 `beeuni sessions reload <session id>` 应用最新配置。加载失败时，请查看会话错误详情并修正项目配置。

<a id="workspace-is-where-you-edit-the-base-branch-is-what-runs"></a>

#### `/workspace` 是你编辑配置的位置，基础分支决定运行什么

会话始终运行基础分支的当前配置。不存在按会话单独配置的模式。

`/workspace` 是你可编辑的检出目录。在那里查看配置、在那里修改配置——更改**推送到基础分支**后，就会应用到运行中的会话，并由常规收敛获取。仅存在于 `/workspace` 中的编辑不会改变会话行为，运行中的 agent 也会收到明确说明：其指令会指出配置来自哪个提交，并说明 `/workspace` 可能落后于该提交。

版本副本是只读的，因此误改错误副本时会出现权限错误，而不是悄无声息地不起作用。

<a id="when-the-configuration-no-longer-declares-a-sessions-agent"></a>

#### 配置不再声明会话的 agent 时

创建会话时会为其指定一个 agent。如果后续提交移除或重命名了该 agent，会话就会切换到项目的默认 agent——仅切换一次，并且只有会话所有者有权使用该 agent 时才会切换。Beeuni 会在审计日志中记录此次切换，并在运行中 agent 的指令中说明，让会话明确告知发生了什么。

如果所有者无权使用默认 agent，或者项目未声明默认 agent，会话就不会关联任何 agent，也不会拥有任何 agent 访问权限。会话仍会启动，并说明原因。请重新声明该 agent、为项目设置默认 agent，或向项目经理申请使用默认 agent 的权限。

<a id="what-the-session-header-shows"></a>

#### 会话标题显示内容

| 状态 | 条件 | 标题 |
| --- | --- | --- |
| 当前 | 未过时，无回退 | 无 |
| 有可用更新 | `stale: true` | 更新徽标，以及 **Reload config** |
| 回退 | 已设置 `fallback_reason` | 红色标记：**Config failed to load** |

如果重新加载后进入回退状态，操作会报告错误，而非成功。

#### Reload config

**Reload config**（以及 `beeuni sessions reload <session id>`）会一次性完成两件事，并分别说明各自的结果：

1. 将运行中的会话切换到基础分支当前的 agents、skills 和 tools。
2. 快进更新 `/workspace` 检出目录，使你在那里查看的文件与会话运行的配置一致。

检出目录只会在会话自己的分支上执行快进拉取，因此不会丢弃任何内容。在 CLI 中传入 `--no-repo` 可跳过此操作。若要将 `base_ref` 的代码带入会话分支，请使用 **Ask agent to sync**。

<a id="turning-it-off"></a>

#### 关闭此功能

<a id="injected-environment"></a>

## 注入的环境变量

Beeuni 会在启动时注入这些变量。只有明确配置为通过 `runtime` 传递的项目密钥才会进入沙盒。连接器和模型提供商凭据会留在 Beeuni 服务器上。

| 变量 | 说明 |
| --- | --- |
| `BEEUNI_PROJECT_ID` | 此项目的 UUID。 |
| `BEEUNI_SESSION_ID` | 此会话的 UUID，也是分支名称。 |
| `BEEUNI_BRANCH_NAME` | 与 `BEEUNI_SESSION_ID` 的值相同。 |
| `BEEUNI_REPO_URL` | 项目仓库的克隆 URL。 |
| `BEEUNI_DEFAULT_BRANCH` | 项目的默认分支。 |
| `BEEUNI_BASE_REF` | 此会话创建分支所基于的 ref。 |
| `BEEUNI_API_URL` | 平台 API 基础地址（`.../v1`）。 |
| `BEEUNI_AGENT_NAME` | 创建此会话时使用的 agent。 |
| `BEEUNI_MODEL` | 设置后要运行的模型。对于此名称出现之前构建的守护进程，`BEEUNI_OPENCODE_MODEL` 携带相同的值。 |
| `BEEUNI_LLM_BASE_URL` | Beeuni LLM 网关基础 URL。网关在服务器端解析提供商凭据。 |
| `BEEUNI_TOKEN` | 与会话绑定的 Beeuni 凭据。见下文。 |

Beeuni 不会注入 `BEEUNI_WORKSPACE`。镜像内置了 `/workspace`，并且没有任何按会话执行的步骤会设置它。Beeuni 也不会注入 git 令牌——守护进程需要时会获取短期克隆凭据；见下方的[从会话推送](#pushing-from-a-session)。Beeuni 拒绝名称带有 `BEEUNI_*` 前缀的用户机密，因为该前缀保留给平台变量。

<a id="session-credential"></a>

## 会话凭据

Beeuni 提供由你自行创建的外部令牌，以及每个沙箱内的一个凭据。

<a id="external-tokens"></a>

### 外部令牌

个人访问令牌（PAT，前缀为 `beeuni_pat_`）或服务账户（前缀为 `beeuni_sa_`）可从沙箱外对 Beeuni API、SDK 和 CLI 的调用进行身份验证。有关 PAT 作用域、服务账户设置以及如何在两者之间选择，请参阅 Authentication。

<a id="in-sandbox-token"></a>

### 沙箱内令牌

`BEEUNI_TOKEN` 在 Beeuni 启动会话环境时生成。它与启动用户、项目、会话和 agent 授权绑定。 每个 API 路由仍会执行自己的能力检查。

<a id="pushing-from-a-session"></a>

## 从会话推送

上游 Git 令牌不会进入沙箱。`git push origin HEAD` 将提交发送到会话分支。要落地到默认分支，必须合并[变更请求](/docs/zh/work/change-requests)。

<a id="the-sandbox-image"></a>

## 沙箱镜像

Dockerfile 定义基础环境。Beeuni 提供会话运行工具与仪表板连接。

<a id="declare-a-template"></a>

### 声明模板

在 `beeuni.yaml` 的 `sandbox.templates` 下，将 Dockerfile 引用为命名模板。

```yaml
sandbox:
  templates:
    - slug: dev
      name: Dev box
      dockerfile: Dockerfile.dev
  default: dev
```

在每个条目上准确设置 `dockerfile` 或 `image` 中的一个。Dockerfile 路径必须位于仓库内。将 `default` 设置为会话应使用的模板 slug；省略此项则使用平台默认镜像。使用 `beeuni.toml` 的旧项目遵循相同字段 — 请参阅 [旧版 `beeuni.toml`](/docs/zh/project/legacy-toml)。完整字段列表：[manifest reference](/docs/zh/project/manifest)。

<a id="constraints"></a>

### 限制

| 规则 | 原因 |
| --- | --- |
| 不要设置 `ENTRYPOINT` 或 `CMD`。 | Beeuni 会覆盖这两项以启动守护进程。 |
| 不要占用端口 `8000`。 | 该端口为守护进程的反向代理保留。请在其他端口上运行开发服务器。 |
| `FROM` Debian 或 Ubuntu 基础镜像。 | 运行时层运行 `apt-get`。Alpine、Fedora 和 Arch 会导致构建失败。 |
| 不要在没有 `rm -rf /var/lib/apt/lists/*` 的情况下运行 `apt-get clean`。 | 运行时层会重新运行 `apt-get update`；损坏的缓存会导致构建失败。 |
| 不要将凭据写入镜像。 | 在 `env:` 中声明名称，并将值设置为项目密钥。Beeuni 会在会话启动时注入该值。 |

<a id="hardware-spec"></a>

### 硬件规格

模板条目中的 `cpu`、`memory` 和 `disk` 用于设置沙箱大小。三者均为可选项；省略字段时使用平台默认值：2 个 vCPU、4 GiB 内存、20 GiB 磁盘。

```yaml
sandbox:
  templates:
    - slug: big
      image: ubuntu:24.04
      cpu: 4
      memory: 8
      disk: 50
```

`cpu` 接受 1–32 个核心，`memory` 接受 1–128 GiB，`disk` 接受 1–500 GiB。对于超过这些上限的值，Beeuni 会将其限制为对应上限。Beeuni 不支持 GPU；模板中的 `gpu` 键会产生警告，而不会产生错误。

该规格属于模板快照，而不是每个会话的设置。更改规格会重建快照，并应用于下一个会话。当前会话会继续使用已启动的规格。

<a id="docker-in-the-sandbox"></a>

### 沙箱中的 Docker

在模板上设置 `container_runtime: true`，即可在其沙箱中运行 Docker：桥接网络和用户定义网络、`overlayfs` 存储驱动程序，以及 NAT 出口。`supabase start` 和 `docker compose` 等本地堆栈的运行方式与在笔记本电脑上相同。

```yaml
sandbox:
  templates:
    - slug: dev
      dockerfile: .beeuni/Dockerfile.dev
      container_runtime: true
```

<a id="ports-and-preview-urls"></a>

### 端口和预览 URL

守护进程监听端口 `8000`，并代理应用在沙箱中使用的其他端口。只有端口 `8000` 本身会被代理阻止。

控制面板通过两种方式访问沙箱端口：

- **基于路径**：`https://<api-host>/v1/p/<sandbox-id>/<port>/...`。这是默认形式，也是唯一支持 WebSocket 升级的形式。
- **基于子域名**：`https://p<port>-<sandbox-id>.<api-host>/...`。对于需要根相对路径或 Cookie 的应用（例如 Next.js 或 Vite 开发服务器），请使用此形式。此形式目前不支持 WebSocket 升级。

预览代理会移除 `X-Frame-Options` 和任何 `frame-ancestors` 策略。会话无需进行任何配置，即可在 iframe 中嵌入应用预览。

会话预览也可以通过公开链接分享，并支持仅查看或交互模式。公开分享链接会阻止端口 `22`、`4096`、`8000` 以及静态文件分享端口。

<a id="snapshot-rebuilds"></a>

### 快照重建

镜像或环境配置变更后，Beeuni 会为后续会话重新构建环境；配置未变更时复用现有镜像。需要重建的首个会话会显示“正在准备镜像”，后续会话复用该构建结果。

在会话内编辑 Dockerfile 会在下一个会话中生效，而不会影响当前会话。只有在其[变更请求](/docs/zh/work/change-requests)合并后，该编辑才会进入 `main`。
