Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions contracts/agents-api/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ The application owns the machine. It creates the Session with a clean absolute `
- Compute, workspace and files stay the application's. Deleting the Session or revoking the credential denies further access but does not stop native processes; the machine owner stops and cleans up.
- The workspace must survive a daemon restart. Losing it never authorizes silent replacement or replay.

**Application-managed E2B.** An application can run the Runtime in an E2B sandbox it creates, renews and destroys with the E2B SDK, then enroll that Runtime as a `self_hosted` Environment ([E2B Runtime guide](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/services/core/deploy/e2b/README.md)). Core keeps no E2B allocation for it and never renews or kills it.

### Ownership rules

- Keep Environment identity, ownership, configuration and lifecycle in Core, separate from Provider compute, device identity, daemon sockets and native sessions. Keep mutable connection state out of immutable configuration; a replacement owner fences stale observations.
Expand Down
1 change: 0 additions & 1 deletion contracts/agents-api/machine-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ The generated [`runtime.openapi.yaml`](./runtime.openapi.yaml) describes only th
| Node credential | The node itself: it generates a secret of 32 to 256 characters without whitespace and registers it at enrollment | `sandbox-node/configuration` with `X-OAC-Node-ID`, `sandbox-node/identity`, `sandbox-node/connect` |
| Installation grant | The `x_agents_core.installation` command of a `self_hosted` Session; short-lived | `agent-daemon/installation` and its `claim` |
| Executor credential | The installation claim, or the Core-key [executor credential routes](./environment-executor-credentials.md) | `agent-daemon/enroll` and `agent-daemon/connection`; after enrollment it is also the Serve credential of the Environment's enrollment on `sandbox-link` |
| Daemon credential of a hosted sandbox | Core, for each managed allocation, delivered in the [bootstrap file](../../docs/runtime-bootstrap.md) | `agent-daemon/bootstrap`, `device-status` and `ws` |
| Operator device profile | `oac-core-device`, run by an operator with database access | `agent-daemon/bootstrap`, `device-status` and `ws` |

Core keeps only a SHA-256 digest of each token and credential it stores; installation grants are signed and not stored. Credentials are not interchangeable: each works only on its own routes.
Expand Down
9 changes: 3 additions & 6 deletions contracts/agents-api/node-generation-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A sandbox node runs the Docker or microsandbox Provider on its host and connects

## Frames and version

Every frame is one JSON text message whose `version` equals `node.ProtocolVersion`; both peers reject any other version, and there is no fallback decoder. Member names are exact and unique: unknown members, case aliases, duplicates and unexpected nulls are rejected. Control frames (`hello`, `welcome`, `heartbeat`, `heartbeat_ack`, `retention`, `retention_ack`) are at most 32 KiB; `request` and `response` frames at most 72 MiB. An invalid frame closes the connection.
Every frame is one JSON text message whose `version` equals `node.ProtocolVersion`; both peers reject any other version, and there is no fallback decoder. Member names are exact and unique: unknown members, case aliases, duplicates and unexpected nulls are rejected. Control frames (`hello`, `welcome`, `heartbeat`, `heartbeat_ack`, `retention`, `retention_ack`) are at most 32 KiB; `request` and `response` frames at most 1 MiB. An invalid frame closes the connection.

## Connection

Expand Down Expand Up @@ -41,19 +41,17 @@ Each operation carries its own arguments and returns the following result on suc
| `info` | `GetInfo` | None | `info` |
| `renew` | `Renew` | None | `info` |
| `kill` | `Kill` | None | None |
| `command` | `RunCommand` | `command` | `command` |
| `observe` | `Observe` | `observation` | `sample` |
| `initial` | `Initial` | None | `compute` |
| `new_compute` | `NewCompute` | Positive compute `generation` and optional `snapshot` | `compute` |
| `compute` | `GetCompute` | `compute` | `state` |
| `kill_compute` | `KillCompute` | `compute` | None |
| `resume_compute` | `ResumeCompute` | `compute` | `state` |
| `command_compute` | `RunCommandCompute` | `compute` and `command` | `command` |
| `suspend` | `Suspend` | `suspend` | `state` |
| `resume` | `Resume` | `resume` | `state` |
| `delete_snapshot` | `DeleteSnapshot` | `snapshot` | None |

`bootstrap` is the Provider's `sandbox.Bootstrap`, including the [Sandbox bootstrap](../../docs/sandbox-bootstrap.md) input in `SandboxIO`; Core validates it before it sends `create`.
`bootstrap` is the Provider's `sandbox.Bootstrap`: the reference and the [Sandbox bootstrap](../../docs/sandbox-bootstrap.md) input in `SandboxIO`; Core validates it before it sends `create`.

A request whose `connection_id`, `owner_epoch` or `sequence` does not match closes the connection. A malformed request gets an `invalid` response. A node without generation management accepts only its enrolled `deployment_generation`; a generation-managing node runs the request on that generation's provider and answers `unconfirmed` when it cannot. Core sends `create` and a `resume` that is not observe-only only to a generation that is ready on that node, and keeps at most 32 requests pending per connection.

Expand All @@ -64,14 +62,13 @@ The `response` frame carries `id` and `connection_id`. A successful response car
| `error_code` | Meaning |
| --- | --- |
| `invalid`, `ownership`, `exists`, `not_found` | `ErrInvalid`, `ErrOwnership`, `ErrExists`, `ErrNotFound` |
| `command_unconfirmed` | `ErrCommandUnconfirmed` |
| `observation_unavailable`, `runtime_not_running` | The observation outcomes |
| `unsupported` | The operation is declared unsupported; see below |
| `unconfirmed`, or any other value | The outcome is unknown |

A failed response carries no result, except an `info` that is an exact-reference `CreateSettled` receipt: a confirmed native Create that failed a later check can still prove that the attempt settled. A timeout, a lost response or a disconnect is unavailable or uncertain, never evidence of absence, and Core never replays a mutation after one; it observes the original operation instead. The [Sandbox Provider guide](../../docs/sandbox-provider.md#operation-outcomes-and-retries) defines each outcome.

Node startup and generation loading validate complete Provider operation declarations before accepting work, and the Core proxy uses the same registered declaration, so an unsupported operation rejects before node resolution or native I/O. The [operation contract](../../docs/sandbox-provider.md#explicit-operation-contracts) owns the inventory. An `unsupported` response carries an `unsupported` object with the exact method `operation` and an authored safe `reason`; the proxy checks both against the request. Missing, malformed or mismatched evidence is an unconfirmed result, never proof that a mutation was rejected. Unsupported stays distinct from observation unavailability and unknown compute or command results, and it neither settles resource ownership nor authorizes a replay.
Node startup and generation loading validate complete Provider operation declarations before accepting work, and the Core proxy uses the same registered declaration, so an unsupported operation rejects before node resolution or native I/O. The [operation contract](../../docs/sandbox-provider.md#explicit-operation-contracts) owns the inventory. An `unsupported` response carries an `unsupported` object with the exact method `operation` and an authored safe `reason`; the proxy checks both against the request. Missing, malformed or mismatched evidence is an unconfirmed result, never proof that a mutation was rejected. Unsupported stays distinct from observation unavailability and unknown compute results, and it neither settles resource ownership nor authorizes a replay.

## Generation control

Expand Down
4 changes: 1 addition & 3 deletions contracts/agents-api/zh/environments.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "环境与模板"
source: contracts/agents-api/environments.md
source_hash: 91a4b01924b65e48003f3a66a76a840272b5f672d0e0b667e6afd3626b8e4564
source_hash: 2862ddcde357d25ab32c400dca1d7fa3812ea8967c2b40092941075034eb726d
---

Environment 是 Session 的执行资源,包括 Harness 运行所在的机器、工作区以及已完成准备的能力。Session 通过其 `environment` 配置创建 Environment;不存在独立的 create 调用。Environment Template 是 Session 创建时解析的可复用准备配置。本契约涵盖这两类资源、两种放置方式、输入接纳、能力准备、Skills、Plugins 和 MCP 连接来源。
Expand Down Expand Up @@ -77,8 +77,6 @@ Core 在 Session 创建事务中创建 Environment 记录;Session upsert 会
- 计算资源、工作区和文件仍归应用程序所有。删除 Session 或撤销凭据会拒绝后续访问,但不会停止原生进程;机器所有者负责停止和清理。
- 工作区必须能在 daemon 重启后继续存在。丢失它绝不授权进行静默替换或重播。

**应用管理的 E2B。** 应用程序可以在由其使用 E2B SDK 创建、续期和销毁的 E2B sandbox 中运行 Runtime,然后将该 Runtime 注册为 `self_hosted` Environment([E2B Runtime guide](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/services/core/deploy/e2b/README.md))。Core 不为其保留 E2B 分配,也绝不续期或终止它。

### 所有权规则 {#ownership-rules}

- 将 Environment 身份、所有权、配置和生命周期保留在 Core 中,并使其与 Provider 计算资源、设备身份、daemon 套接字和原生会话相分离。将可变连接状态排除在不可变配置之外;替换后的所有者会使过期观察值失效。
Expand Down
3 changes: 1 addition & 2 deletions contracts/agents-api/zh/machine-api.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "机器连接 API"
source: contracts/agents-api/machine-api.md
source_hash: 1540a3b84eb1cfa977654b46d407e1a4de7f502bab9c5264e21a8cc57e96d238
source_hash: 873d25773a865039ae1f1f8983d7b26e3bc772fad7301b36fc03a3ffd7084186
---

机器通过 `/api/v1` 调用 Core:包括沙箱节点、Runtime daemon、Sandbox I/O 服务和自托管安装器。各路由仅接受所列凭据,不接受 Core 密钥或 Project API 密钥;控制台登录也不授予此处权限。反向代理将 `/api/v1` 直接发送给 Core;Web 不提供这些路由。
Expand Down Expand Up @@ -35,7 +35,6 @@ source_hash: 1540a3b84eb1cfa977654b46d407e1a4de7f502bab9c5264e21a8cc57e96d238
| 节点凭据 | 节点自身:生成 32 至 256 个无空白字符的密钥,在登记时注册 | 带 `X-OAC-Node-ID` 的 `sandbox-node/configuration`、`sandbox-node/identity`、`sandbox-node/connect` |
| 安装授权 | `self_hosted` Session 的 `x_agents_core.installation` 命令;短期有效 | `agent-daemon/installation` 及其 `claim` |
| 执行器凭据 | 安装领取,或 Core 密钥[执行器凭据路由](environment-executor-credentials.md) | `agent-daemon/enroll` 和 `agent-daemon/connection`;登记后也作为该 Environment 的 enrollment 在 `sandbox-link` 上的 Serve 凭据 |
| 托管沙箱 daemon 凭据 | Core 为每个受管分配签发,通过[引导文件](../../../docs/zh/runtime-bootstrap.md)交付 | `agent-daemon/bootstrap`、`device-status` 和 `ws` |
| 操作者设备配置 | 具有数据库访问权限的操作者运行 `oac-core-device` | `agent-daemon/bootstrap`、`device-status` 和 `ws` |

Core 对存储的每个 token 和凭据仅保留 SHA-256 摘要;安装授权经签名但不存储。凭据不可互换:各自仅适用于自身路由。
Expand Down
11 changes: 4 additions & 7 deletions contracts/agents-api/zh/node-generation-protocol.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
title: "沙箱节点协议"
source: contracts/agents-api/node-generation-protocol.md
source_hash: e349ba887f9788e8f39990d33638182afcda553593e934788746fa0423cb4ee7
source_hash: 4c74de8583bc8f0b85b91a338357899a1bcc03d8b2bd7063e6c71dd0430e717b
---

沙箱节点在其主机上运行 Docker 或 microsandbox Provider,并通过一个 WebSocket 与 Core 相连。Core 通过该连接发送 Provider 操作;节点针对本地 Provider 执行这些操作,并报告就绪状态、主机测量值及其持有的部署代次。Core 始终是唯一的生命周期所有者:节点绝不重试变更操作或调度工作。帧和校验器位于 [`services/core/internal/sandbox/node`](https://github.com/MiniMax-AI/OpenAgentCore/tree/main/services/core/internal/sandbox/node)(`wire.go`、`generation_wire.go`);节点用于注册和读取配置的 HTTP 路由位于[机器连接 API](machine-api.md#node-routes)。

## 帧与版本 {#frames-and-version}

每个帧都是一个 JSON 文本消息,其 `version` 等于 `node.ProtocolVersion`;两端都会拒绝任何其他版本,并且没有回退解码器。成员名必须精确且唯一:未知成员、大小写别名、重复项和意外的空值都会被拒绝。控制帧(`hello`、`welcome`、`heartbeat`、`heartbeat_ack`、`retention`、`retention_ack`)最多为 32 KiB;`request` 和 `response` 帧最多为 72 MiB。无效帧会关闭连接。
每个帧都是一个 JSON 文本消息,其 `version` 等于 `node.ProtocolVersion`;两端都会拒绝任何其他版本,并且没有回退解码器。成员名必须精确且唯一:未知成员、大小写别名、重复项和意外的空值都会被拒绝。控制帧(`hello`、`welcome`、`heartbeat`、`heartbeat_ack`、`retention`、`retention_ack`)最多为 32 KiB;`request` 和 `response` 帧最多为 1 MiB。无效帧会关闭连接。

## 连接 {#connection}

Expand Down Expand Up @@ -43,19 +43,17 @@ Core 发送包含以下内容的 `request` 帧:
| `info` | `GetInfo` | 无 | `info` |
| `renew` | `Renew` | 无 | `info` |
| `kill` | `Kill` | 无 | 无 |
| `command` | `RunCommand` | `command` | `command` |
| `observe` | `Observe` | `observation` | `sample` |
| `initial` | `Initial` | 无 | `compute` |
| `new_compute` | `NewCompute` | 大于零的计算 `generation` 和可选的 `snapshot` | `compute` |
| `compute` | `GetCompute` | `compute` | `state` |
| `kill_compute` | `KillCompute` | `compute` | 无 |
| `resume_compute` | `ResumeCompute` | `compute` | `state` |
| `command_compute` | `RunCommandCompute` | `compute` 和 `command` | `command` |
| `suspend` | `Suspend` | `suspend` | `state` |
| `resume` | `Resume` | `resume` | `state` |
| `delete_snapshot` | `DeleteSnapshot` | `snapshot` | 无 |

`bootstrap` 是 Provider 的 `sandbox.Bootstrap`,其 `SandboxIO` 包含[沙箱引导](../../../docs/zh/sandbox-bootstrap.md)输入;Core 在发送 `create` 前完成校验。
`bootstrap` 是 Provider 的 `sandbox.Bootstrap`:reference 以及 `SandboxIO` 中的[沙箱引导](../../../docs/zh/sandbox-bootstrap.md)输入;Core 在发送 `create` 前完成校验。

只要 `connection_id`、`owner_epoch` 或 `sequence` 中任一值不匹配,请求就会关闭连接。格式错误的请求会得到 `invalid` 响应。未启用代次管理的节点仅接受其登记的 `deployment_generation`;支持代次管理的节点在对应代次的 Provider 上运行请求,无法运行时回复 `unconfirmed`。Core 仅向节点上已就绪的代次发送 `create` 和非 observe-only 的 `resume`,并且每条连接最多保留 32 个待处理请求。

Expand All @@ -66,14 +64,13 @@ Core 发送包含以下内容的 `request` 帧:
| `error_code` | 含义 |
| --- | --- |
| `invalid`、`ownership`、`exists`、`not_found` | `ErrInvalid`、`ErrOwnership`、`ErrExists`、`ErrNotFound` |
| `command_unconfirmed` | `ErrCommandUnconfirmed` |
| `observation_unavailable`、`runtime_not_running` | 对应的观察结果 |
| `unsupported` | 该操作被声明为不支持;见下文 |
| `unconfirmed` 或任何其他值 | 结果未知 |

失败响应不携带结果,唯一的例外是作为精确引用 `CreateSettled` 回执的 `info` 结果:即便已确认的原生 Create 在后续检查中失败,仍可证明该尝试已有确定结果。超时、响应丢失或断连属于不可用或不确定情况,绝不能证明资源不存在;发生这些情况后,Core 绝不重放变更操作,而是改为观察原始操作。[Sandbox Provider 指南](../../../docs/zh/sandbox-provider.md#operation-outcomes-and-retries) 定义了每种结果。

节点启动和代次加载会在接受工作前验证完整的 Provider 操作声明,Core 代理使用同一份已注册声明,因此不支持的操作会在节点解析或原生 I/O 之前被拒绝。操作清单由[操作契约](../../../docs/zh/sandbox-provider.md#explicit-operation-contracts)维护。`unsupported` 响应包含一个 `unsupported` 对象,其中有精确的方法 `operation` 和经作者编写且安全的 `reason`;代理会将两者与请求进行核对。证据缺失、格式错误或不匹配会得到 `unconfirmed` 结果,而绝不会证明变更操作被拒绝。`unsupported` 始终不同于观察不可用,也不同于计算或命令结果未知;它既不确定资源所有权,也不授权重放。
节点启动和代次加载会在接受工作前验证完整的 Provider 操作声明,Core 代理使用同一份已注册声明,因此不支持的操作会在节点解析或原生 I/O 之前被拒绝。操作清单由[操作契约](../../../docs/zh/sandbox-provider.md#explicit-operation-contracts)维护。`unsupported` 响应包含一个 `unsupported` 对象,其中有精确的方法 `operation` 和经作者编写且安全的 `reason`;代理会将两者与请求进行核对。证据缺失、格式错误或不匹配会得到 `unconfirmed` 结果,而绝不会证明变更操作被拒绝。`unsupported` 始终不同于观察不可用,也不同于计算结果未知;它既不确定资源所有权,也不授权重放。

## 代次控制 {#generation-control}

Expand Down
2 changes: 1 addition & 1 deletion deploy/node/node_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def provider_config(root, args, runtime_image):
if args.provider == "docker":
result["native"] = {"host": "unix:///var/run/docker.sock", "image": runtime_image,
"network": "oac-node-" + args.installation_id,
"seccomp_file": str(root / "runtime/seccomp.json"), "nested_sandbox": True}
"seccomp_file": str(root / "runtime/seccomp.json")}
else:
endpoint = urlsplit(args.core_url)
port = endpoint.port or (443 if endpoint.scheme == "https" else 80)
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Dashed arrows show provisioning and installation. Solid arrows show component in
| Component | Responsibility | Reference |
| --- | --- | --- |
| Core | Authenticate callers, resolve and freeze configuration, schedule Turns, handle cancellation and pending interactions, persist resources and execution facts in PostgreSQL | [Core service](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/services/core/README.md) |
| Sandbox Provider | Create, observe, renew and reclaim compute; supply Runtime startup input | [Sandbox Provider](./sandbox-provider.md), [Runtime bootstrap](./runtime-bootstrap.md) |
| Sandbox Provider | Create, observe, renew and reclaim compute; start the Sandbox I/O service in it | [Sandbox Provider](./sandbox-provider.md), [Sandbox bootstrap](./sandbox-bootstrap.md) |
| Sandbox node | Operate a Docker or microsandbox host and reconcile its assigned generation and allocations | [Sandbox node protocol](../contracts/agents-api/node-generation-protocol.md) |
| Runtime | Prepare the workspace and capabilities, manage Session Executors, execute Turns and report events and receipts | [Core–Runtime protocol](./runtime-protocol.md) |
| Harness adapter | Validate native configuration, invoke the upstream SDK or protocol, translate events and confirm native cleanup | [Harness onboarding](../contracts/agents-api/harness-onboarding.md) |
Expand Down
1 change: 0 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ The node installer writes Docker’s host settings into the `native` object of t
| `image` | The Runtime image’s local ID after loading | The release’s `image_id` or `image_manifest_digest`. The host’s image store decides which digest names the loaded image, so the value is node-local; the adapter accepts only these two |
| `network` | `oac-node-<installation-id>` | Runtime container network |
| `seccomp_file` | `<node-root>/runtime/seccomp.json` | Matched distribution’s seccomp profile |
| `nested_sandbox` | `true` | Enables the Docker adapter’s init process and proc-mask configuration |

The [Docker adapter](./sandbox-provider.md#docker-adapter) owns container isolation, volume layout and lifecycle behavior.

Expand Down
Loading