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
6 changes: 3 additions & 3 deletions apps/web/e2e/fixture-console.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ function unconfiguredDeployment(generation = 0, ownerEpoch = 3) {
}

function configuredDeployment() {
return { installation_id: INSTALLATION_ID, provider: "microsandbox", credential_configured: false, configuration: {}, metadata: {}, core_url: publicUrl(), reset: null, rollout: nodeRollout(), owner_epoch: 3, generation: 1, mode: "nodes", resources: { allocations: 0, running: 0, pending: 0 }, specification: { resources: { cpus: 2, memory_mib: 4096 } }, specification_digest: "fixture", suspension: { idle_seconds: 300, retention_seconds: 86400 } };
return { installation_id: INSTALLATION_ID, provider: "microsandbox", credential_configured: false, configuration: {}, metadata: {}, core_url: publicUrl(), reset: null, rollout: nodeRollout(), owner_epoch: 3, generation: 1, mode: "nodes", resources: { allocations: 0, running: 0, pending: 0 }, specification: { resources: { cpus: 2, memory_mib: 4096 }, network: { public: true, domains: [] } }, specification_digest: "fixture", suspension: { idle_seconds: 300, retention_seconds: 86400 } };
}
/** The E2B template build as Core read it when the selection was saved. */
const templateBuild = { status: "ready", resources: { cpus: 2, memory_mib: 2048, root_disk_mib: 10240 } };

// E2B runs sandboxes in its cloud: no nodes, only what Core holds there.
function e2bDeployment() {
return { ...configuredDeployment(), provider: "e2b", mode: "direct", rollout: noNodeRollout(), suspension: null, resources: { allocations: 3, running: 3, pending: 1 }, specification: { resources: { cpus: 2, memory_mib: 2048 } }, configuration: { template: "oac-runtime:0f1e2d3c-4b5a-6978-8a9b-0c1d2e3f4a5b", api_url: "https://api.e2b.app", domain: "e2b.app" } , credential_configured: true, metadata: { template_build: templateBuild } };
return { ...configuredDeployment(), provider: "e2b", mode: "direct", rollout: noNodeRollout(), suspension: null, resources: { allocations: 3, running: 3, pending: 1 }, specification: { resources: { cpus: 2, memory_mib: 2048 }, network: { public: true, domains: [] } }, configuration: { template: "oac-runtime:0f1e2d3c-4b5a-6978-8a9b-0c1d2e3f4a5b", api_url: "https://api.e2b.app", domain: "e2b.app" } , credential_configured: true, metadata: { template_build: templateBuild } };
}

function reset(mode = "login", fresh = false, sandbox = "configured", nodes = "demo", address = "public", installers = true, artifacts = "microsandbox") {
Expand Down Expand Up @@ -410,7 +410,7 @@ async function sandboxRoute(request, response, path, url) {
// As Core: E2B may omit resources and adopt its template build's CPU and memory; only microsandbox suspends.
const resources = input.resources ?? { cpus: templateBuild.resources.cpus, memory_mib: templateBuild.resources.memory_mib };
const previous = state.deployment;
const specification = { resources };
const specification = { resources, network: input.network ?? (initialize ? { public: true, domains: [] } : previous.specification.network) };
const explicitKey = e2b && Object.hasOwn(input, "credential");
const sameSelection = !initialize && JSON.stringify(specification) === JSON.stringify(previous.specification) && (!e2b || input.configuration.template === previous.configuration?.template);
// Omission can be a no-op; every explicit key, including identical bytes,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/e2e/nodes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ test("shows the retained E2B build while a replacement key is checked", async ({
});

test("edits only the saved backend, preserving a custom size", async ({ page, request }) => {
const current = { resources: { cpus: 7, memory_mib: 8192, root_disk_mib: 10240 }, workspace: { attachment: "host_directory", user_xattr: true, capacity_quota: false } };
const current = { resources: { cpus: 7, memory_mib: 8192, root_disk_mib: 10240 }, network: { public: true, domains: [] }, workspace: { attachment: "host_directory", user_xattr: true, capacity_quota: false } };
let deployment = { configuration: {}, metadata: {}, credential_configured: false, installation_id: "94be54a1-138c-4f30-bc87-b13686272dbe", provider: "microsandbox", core_url: "https://core.example", reset: null, rollout: { state: "settled", previous_generation_sandboxes: 0, nodes: { ready: 0, preparing: 0, failed: 0, unknown: 0 } },
owner_epoch: 1, generation: 1, mode: "nodes", resources: { allocations: 0, running: 0, pending: 0 }, specification: current, specification_digest: "e".repeat(64),
suspension: null };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { deploymentContract, type SandboxProvider, type SandboxSpecification } f

describe("deployment resources", () => {
it("preserves saved resources only for the same provider", () => {
const current: SandboxSpecification = { resources: { cpus: 7, memory_mib: 8192 } };
const current: SandboxSpecification = { resources: { cpus: 7, memory_mib: 8192 }, network: { public: true, domains: [] } };
expect(savedSpecification("microsandbox", "microsandbox", current)).toEqual(current);
expect(savedSpecification("microsandbox", "microsandbox", current)).not.toBe(current);
expect(savedSpecification("e2b", "microsandbox", current)).toBeNull();
expect(savedSpecification("microsandbox", "e2b", current)).toBeNull();
expect(savedSpecification("e2b", "e2b", { resources: current.resources })).toEqual({ resources: current.resources });
expect(savedSpecification("e2b", "e2b", { resources: current.resources, network: current.network })).toEqual({ resources: current.resources, network: current.network });
});
it("proposes a copy of each declared default size, which the declared bounds accept", () => {
for (const provider of Object.keys(deploymentContract.providers) as SandboxProvider[]) {
Expand Down
31 changes: 29 additions & 2 deletions contracts/agents-api/core.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,12 @@ definitions:
type: object
expected_generation:
type: integer
network:
allOf:
- $ref: '#/definitions/sandbox.Network'
description: |-
The network cap. Omitted, it is the public internet only on setup and the
current cap on a change.
provider:
type: string
resources:
Expand All @@ -763,6 +769,12 @@ definitions:
type: object
expected_generation:
type: integer
network:
allOf:
- $ref: '#/definitions/sandbox.Network'
description: |-
The network cap. Omitted, it is the public internet only on setup and the
current cap on a change.
provider:
type: string
resources:
Expand Down Expand Up @@ -1947,6 +1959,8 @@ definitions:
- DeploymentDirect
sandbox.DeploymentSpec:
properties:
network:
$ref: '#/definitions/sandbox.Network'
resources:
$ref: '#/definitions/sandbox.Resources'
workspace:
Expand All @@ -1955,8 +1969,21 @@ definitions:
description: Workspace is a derived immutable capability receipt, never filesystem configuration.
readOnly: true
required:
- network
- resources
type: object
sandbox.Network:
properties:
domains:
items:
type: string
type: array
public:
type: boolean
required:
- domains
- public
type: object
sandbox.NodeDiagnosticCode:
enum:
- provider_unavailable
Expand Down Expand Up @@ -7032,7 +7059,7 @@ paths:
post:
consumes:
- application/json
description: Selects a provider and its enforced resource limits. Core derives the deployment's core_url from the installation public URL and rejects a core_url member with 400. A Provider that requires a public origin returns 409 sandbox_configuration_error while the public URL is loopback. Credentials are write-only. A Provider without default resources may omit resources to adopt the validated configuration's CPU and memory, returned in specification.resources. Requires explicit expected_generation, including zero at first setup. Stale retries reject before provider validation. An identical selection at the current generation is a no-op; a differing selection rejects. This does not create compute or execute work.
description: Selects a provider, its enforced resource limits and the network cap. An omitted network is the public internet only. Core derives the deployment's core_url from the installation public URL and rejects a core_url member with 400. A Provider that requires a public origin returns 409 sandbox_configuration_error while the public URL is loopback. Credentials are write-only. A Provider without default resources may omit resources to adopt the validated configuration's CPU and memory, returned in specification.resources. Requires explicit expected_generation, including zero at first setup. Stale retries reject before provider validation. An identical selection at the current generation is a no-op; a differing selection rejects. This does not create compute or execute work.
parameters:
- description: Deployment selection
in: body
Expand Down Expand Up @@ -7075,7 +7102,7 @@ paths:
put:
consumes:
- application/json
description: 'Requires the observed generation, the same backend type and no active reset. Credential-holding Providers apply same-account changes online: allocations retain immutable generation and current credentials; an omitted credential preserves it, explicit submission including the same credential verifies and advances generation. Other accounts require explicit reset. Node providers retain the zero-resource guard and retire old nodes/tokens on change. Core rejects core_url input. Never automatically replay an uncertain write; rollout.state is the authoritative preparation polling signal.'
description: 'Requires the observed generation, the same backend type and no active reset. An omitted network keeps the current cap; a changed cap applies to new sandboxes only. Credential-holding Providers apply same-account changes online: allocations retain immutable generation and current credentials; an omitted credential preserves it, explicit submission including the same credential verifies and advances generation. Other accounts require explicit reset. Node providers retain the zero-resource guard and retire old nodes/tokens on change. Core rejects core_url input. Never automatically replay an uncertain write; rollout.state is the authoritative preparation polling signal.'
parameters:
- description: Replacement deployment selection
in: body
Expand Down
1 change: 1 addition & 0 deletions contracts/agents-api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Each item is Core's deliberate or native behavior where the official service beh

- Hosted workspace admission is limited by the [tenant capacity policy](../../docs/configuration.md#tenant-capacity) and the [input reservation deadline](./environments.md#reservations).
- MiniMax Code does not declare `retained_native_history`, so it cannot run on microsandbox, which keeps every Environment on workspace storage; Core rejects the Session ([Harness capabilities](./harness-capabilities.md)).
- The model provider stays reachable from the sandbox because the Harness runs there; MCP connections from the Environment follow the deployment's [network cap](./sandbox-deployment.md#network). E2B sandboxes cannot reach private networks, and `169.254.169.254` answers inside an E2B sandbox under every cap.
- Only `enabled` networking runs, so Sessions that need `disabled` or `restricted` are rejected ([restricted network policy](./environments.md#restricted-network)).
- `packages.system` other than null or an empty list is rejected; system packages must be preinstalled.
- `Environment.files` lists the files recorded at Session creation; files created later through the Environment files API do not appear.
Expand Down
15 changes: 15 additions & 0 deletions contracts/agents-api/runtime.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ definitions:
type: object
sandbox.DeploymentSpec:
properties:
network:
$ref: '#/definitions/sandbox.Network'
resources:
$ref: '#/definitions/sandbox.Resources'
workspace:
Expand All @@ -143,8 +145,21 @@ definitions:
description: Workspace is a derived immutable capability receipt, never filesystem configuration.
readOnly: true
required:
- network
- resources
type: object
sandbox.Network:
properties:
domains:
items:
type: string
type: array
public:
type: boolean
required:
- domains
- public
type: object
sandbox.Resources:
properties:
cpus:
Expand Down
15 changes: 15 additions & 0 deletions contracts/agents-api/sandbox-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ POST and PUT take the same complete selection and require `expected_generation`
| `expected_generation` | Required nonnegative integer from GET; never refresh and replay it automatically |
| `provider` | Exactly one of `microsandbox`, `e2b` |
| `resources` | Per-sandbox limits, below; required for microsandbox, optional for E2B |
| `network` | The egress cap, [below](#network). Omitted on POST means the default; omitted on PUT keeps the current cap |
| `configuration` | The provider's public selectors. E2B: the immutable `template` build and the optional paired `api_url` and `domain`. microsandbox accepts only `{}` or omission |
| `credential` | The provider's write-only credential. E2B: `{api_key}`, required at first setup and omitted on PUT to keep the current key; a null or empty key is invalid. microsandbox rejects it |

Expand All @@ -60,6 +61,19 @@ The optional response `specification.workspace` is an immutable capability recei

Select the filesystem configuration before the microsandbox deployment. Selecting the filesystem does not alter existing generations or allocations; the next sandbox update derives the receipt. A filesystem selection must support the provider's declared requirements. An existing deployment requires the same `attachment` and `user_xattr`; the selection may change `capacity_quota`, after which new workspaces are refused until a sandbox update sets a matching `environment_disk_mib`. Existing workspaces keep the capacity they were admitted with.

### Network

`network` caps what every sandbox of the deployment may reach when its Environment's `network.access` is `enabled` or omitted. The connection to Core and the host of the Session's model provider are always reachable, because the Harness runs inside the sandbox. MCP connections from the Environment follow the cap like any other traffic.

| Field | Accepted value |
| --- | --- |
| `public` | Boolean. `true` allows public addresses; `false` allows only Core, the model provider and `domains` |
| `domains` | At most 100 exact host names of at most 253 characters, in lowercase letters, digits, hyphens and dots, whose last label starts with a letter. Wildcards, IP literals, ports and URLs are rejected. Core stores them lowercase, deduplicated and sorted. Every address a name resolves to is allowed, private addresses included |

The default is `{"public": true, "domains": []}`. Under every cap, loopback, link-local and cloud-metadata addresses and all other private addresses stay blocked. Addresses are resolved when a sandbox starts and when it resumes, so a name whose answer changes in between is not followed. A sandbox keeps the cap of the generation that created it.

Each Provider declares what it enforces ([Sandbox Provider protocol](../../docs/sandbox-provider.md#network-egress)): microsandbox supports both fields, E2B supports `public: false` but not `domains` because E2B sandboxes cannot reach private networks. A cap the selected Provider does not declare returns 400 `invalid_sandbox_configuration` with `param` `network.public` or `network.domains`.

### E2B configuration

E2B uses `configuration.template` in `template-id:build-uuid` form; the build UUID must be canonical and nonzero, and a mutable template alias alone is refused. The API key is encrypted in PostgreSQL and never appears in a response, bootstrap configuration, command argument or log. By default Core uses `https://api.e2b.app` and `e2b.app`. For a compatible service, set both `configuration.api_url` (an HTTPS origin without path, port, query, fragment or credentials) and `configuration.domain` (the sandbox data-plane DNS suffix); the API host must equal the domain or be a subdomain of it. Core rejects a sandbox whose data-plane domain lies outside the selected suffix before sending daemon credentials or using envd.
Expand Down Expand Up @@ -218,6 +232,7 @@ Some fields keep one name across providers but differ in meaning, or do not appl
| Field | microsandbox | E2B |
| --- | --- | --- |
| Independent workspace filesystem | Required: [Kernel NFS adapter](../../docs/workspace-provider.md#kernel-nfs-adapter), configured separately from compute | Unsupported |
| Deployment `specification.network` | `public` and `domains` | `public` only; `domains` must be empty and private networks are unreachable |
| Deployment `specification.resources` | `cpus`, `memory_mib`, `root_disk_mib` and, as a quota request, `environment_disk_mib` | `cpus` and `memory_mib`, equal to the ready template build's and taken from it when omitted; no disk fields |
| Deployment `metadata.template_build` | Absent: `metadata` is empty | The build as Core read it when the selection was saved |
| Deployment `suspension` | `{idle_seconds, retention_seconds}` | `{idle_seconds, retention_seconds}`; Core pauses an idle E2B sandbox with the SDK's native pause |
Expand Down
3 changes: 2 additions & 1 deletion contracts/agents-api/zh/index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "OpenAI 兼容性"
source: contracts/agents-api/index.md
source_hash: 3e138165ee27672531124d2c156d24e087fb6904e60f828635990dd1d3eb8626
source_hash: ae9816c683a4f1bbfb09537e0c864767cfa7f376c19ad1c539e91a92bbea447c
---

Core 实现下方固定版本的 OpenAI Agents API。本台账列出各项资源的覆盖情况、相对于官方服务的所有差异以及已知缺口。
Expand Down Expand Up @@ -163,6 +163,7 @@ Core 自身字段位于 `x_agents_core` 中([Core extensions](../../../docs/zh

- Hosted 工作区准入受[租户容量策略](../../../docs/zh/configuration.md#tenant-capacity)及既有[输入预留截止时间](environments.md#reservations)限制。
- MiniMax Code 未声明 `retained_native_history`,因此无法在 microsandbox 上运行(其每个 Environment 都使用工作区存储);Core 会拒绝该 Session([Harness 能力](./harness-capabilities.md))。
- 模型提供商从沙箱内始终可达,因为 Harness 运行在那里;Environment 中的 MCP 连接遵循部署的[网络上限](sandbox-deployment.md#network)。E2B 沙箱无法访问私有网络,且在任何上限下 `169.254.169.254` 都会在 E2B 沙箱内应答。
- 只有 `enabled` 网络可以运行,因此需要 `disabled` 或 `restricted` 的 Session 会被拒绝([restricted network policy](environments.md#restricted-network))。
- 除 null 或空列表以外的 `packages.system` 都会被拒绝;系统软件包必须预先安装。
- `Environment.files` 列出 Session 创建时记录的文件;之后通过 Environment files API 创建的文件不会出现。
Expand Down
Loading
Loading