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: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ The Runtime is not a sandbox; see
- Keep component boundaries explicit through shared interfaces and versioned
protocols. Register implementations behind those interfaces. Adding an
implementation must not require a new orchestration path selected by its name.
Sandbox registration, configuration adaptation and persistence boundaries follow
the [Sandbox Provider guide](docs/sandbox-provider.md#register-the-provider-kind).
- Core owns durable Session/Turn state and scheduling. Runtime owns local
execution resources. Harness adapters translate the common execution contract
into native operations; model and sandbox provider details stay behind their
Expand Down
60 changes: 43 additions & 17 deletions apps/docs/content/docs/sandbox-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ connectivity; see [Runtime and outer isolation](/concepts#runtime-and-outer-isol
(native SDK calls, ownership checks, identity translation, private config).
Assert `var _ sandbox.SandboxProvider = (*YourAdapter)(nil)` at compile time.
Out-of-process helpers live in `services/agents-api/tools/<kind>-provider`.
3. **Register the kind** in every file listed in
3. **Register the kind** once using
[Register the provider kind](#register-the-provider-kind). Registration is
explicit construction, not an init-time plugin registry.
4. **Label owned resources** with `io.oac.*` labels, or `oac_*` metadata keys
Expand Down Expand Up @@ -171,25 +171,51 @@ A provider must not implement a competing preparation path.

## Register the provider kind

Provider kinds are enumerated explicitly. Add a new kind to each surface
below; none accepts an arbitrary provider string.

| Surface | File | What it enumerates |
| --- | --- | --- |
| Node-local construction | [`sandbox/config/config.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/sandbox/config/config.go), [`specification.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/sandbox/config/specification.go) | Typed construction, readiness probe and node specification |
| Direct construction | [`cmd/server/managed_setup.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/cmd/server/managed_setup.go) (`managedSetup.provider`) | Direct adapters (E2B) and node-proxied kinds (Docker, microsandbox) |
| Resource validation | [`sandbox/deployment.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/sandbox/deployment.go) (`Resources.Validate`) | Per-kind resource limits |
| Node proxy and identity | [`sandbox/node/proxy.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/sandbox/node/proxy.go), [`node/identity.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/sandbox/node/identity.go) | Node-capable kinds and their checkpoint capability |
| Deployment persistence | [`sandbox_deployment_mutations.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/store/sandbox_deployment_mutations.go), [`sandbox_deployment_setup.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/store/sandbox_deployment_setup.go), [`sandbox_specification.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/store/sandbox_specification.go), [`runtime_node_deployment.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/internal/store/runtime_node_deployment.go) | Deployment admission and node-mode kinds |
| Database constraint | A new migration in [`migrations/`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/migrations) | `provider_kind` `CHECK` constraints, last set in `000081_sandbox_generations.sql`; never edit a landed migration |
| Node installation | [`node_installation.go`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/core-console/node_installation.go) | Node artifacts per kind |
| Installer | [`deploy/install/sandbox_setup.py`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/deploy/install/sandbox_setup.py) (`CHOICES`, used by `install.py --sandbox`) | Installer backend choices |
| Distribution | [`scripts/core-distribution-manifest.py`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/scripts/core-distribution-manifest.py) | Bundled provider helper binaries |
| Clients and Web | [`sandbox-client.ts`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/packages/agents-client/src/sandbox-client.ts) (`SandboxProvider`), [`features/sandbox`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/apps/web/src/features/sandbox) (`SandboxSetupWizard.tsx`, `console-config.ts`, `node-enrollment.ts`), [`sandbox-labels.ts`](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/apps/web/src/lib/sandbox-labels.ts) | Backend choices and labels shown to operators |
`sandbox/providers/registry.go` is the sole registration table. Each entry binds
an adapter's specification/resource validators, selection normalization, deployment
mode, defaults, optional checkpoint capability, and local or direct constructor.
`providers.Build` constructs node-local adapters; `providers.BuildDirect` constructs
direct adapters. Neither allocates compute. There is no init-time registration or
runtime plugin loading.

For a new implementation:

1. Implement `SandboxProvider` in its adapter package and add native contract tests.
2. Add its configuration validators and optional read-only `SelectionDiscoverer`
for native resource discovery. Normalization must copy input before changing it.
`RestoreSelection` must retain access to owned resources without requiring new
template validation. Put native credential verification behind
`CredentialVerifier` when needed.
3. Register its constructor, policies and defaults in `providers/registry.go`.
Node proxy identity and checkpoint advertisement consume this same entry.
The installer projection uses those registered policies and the common field
bounds in `sandbox/deployment_contract.go`; regenerate it with
`go run ./services/agents-api/cmd/specification-contract -write`.
4. If new configuration fields are necessary, extend the typed `sandbox.Selection`
envelope and its dedicated encrypted persistence fields, API DTO and operator
client. Do not replace typed configuration with unrestricted JSON. Field codecs
may map columns; Store must not parse native endpoints, templates or defaults.
5. Supply required installer/distribution artifacts and operator labels. A new
provider must not add a Session/Turn scheduling path or a Store vendor switch.

Preview and persistence use `providers.Normalize` and `providers.Describe`.
`SelectionDiscoverer` resolves omitted native resource values before commit; the
complete specification is validated again at persistence. Store owns transactions,
credential encryption, generation fencing, resource ownership and typed column
mapping. Database constraints validate structure, not the registration list.
`providers.ResolveChange` owns configuration inheritance and comparison uses
normalized selectors, so preview, retry and commit share the same defaults.

A direct adapter with credentials verifies all retained generations and allocation
references before replacing a key. The common `sandbox.CallFence` excludes native
calls and waits for helper completion, including calls whose callers timed out.
Execution invokes prepared verification/fencing callbacks without branching on a
vendor. A transport wrapper advertises only capabilities that its adapter supports;
new optional capabilities need forwarding and qualification before registration.

Keep vendor-specific deployment validation and SDK setup at the construction
boundary. Construction must not create an Environment. For node-local adapters
the `Built` result returns the provider, probe, installation identity, backend
the `providers.Built` result returns the provider, probe, installation identity, backend
fingerprint and specification digest; the factory also returns its close function.

Preserve the `execution.RuntimeProvider` deployment binding: `ProviderKind`,
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/content/guide-sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"contracts/agents-api/harness-onboarding.md": "18d3ccfe989e2caa57f220430157c6b73d87f5fc8e31aba8cada0b7ab9653a8c",
"docs/runtime-bootstrap.md": "0d49aed73b298039e04453e6f465b0e925fb2227fa35d4206820bb3acbd8df39",
"docs/runtime-protocol.md": "0e968e509236369dd4e840b94d9083372830c45b695ae3a71a56eba5bae01347",
"docs/sandbox-provider.md": "3def50dfeb69e5160124cb9c4577e107e6ca666b40e6da32843a1c33b2b3515b",
"docs/sandbox-provider.md": "4d47b234a457f874f3ff7e61a7f5da6fc8b75b0c6df0ce0ce9ead1c07afdfb3e",
"apps/docs/scripts/guides.json": "3c3768fb94fd3d42464d4ce8c55724b9ba8360133c7cc19d513d8ec83a8e034f"
},
"outputs": {
Expand Down Expand Up @@ -59,6 +59,6 @@
"content/docs/harness-onboarding.mdx": "e7a172793d81e0dee89398ea34351617c66435a13f511f7fb29df3b6a8967fbf",
"content/docs/runtime-bootstrap.mdx": "58982955811c9ad46a9fc04d8d2aef5a762fc9d25d5833f88aa75ee3fc46523f",
"content/docs/runtime-protocol.mdx": "75e7c85a2085cccedf453e8ee751316ba2ee22ed0559e4018ee82df1af805f48",
"content/docs/sandbox-provider.mdx": "5472ccc9dc965c48716b6d73ff74263b4373bab6b41a8ae30040b6181d2de5c0"
"content/docs/sandbox-provider.mdx": "9db833fe9ff3f30a65451f80d7251348695a08e7830f9e95871739a710529818"
}
}
2 changes: 1 addition & 1 deletion apps/web/src/features/sandbox/node-enrollment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface HostPrerequisite {
* - Docker: `provider_group` needs rootful Docker Engine running, its socket
* group-accessible (0660) and, through `device_group`, owned by the docker
* group, which the service user joins; and CPU and memory limits enforced (the
* node is ready only then: services/agents-api/internal/sandbox/config/probe.go).
* node is ready only then: services/agents-api/internal/sandbox/providers/probe.go).
* It installs nothing;
* - microsandbox: `provider_group` needs /dev/kvm, readable and writable by all or
* group-accessible in the kvm group, and `prepare_runtime` the libraries its
Expand Down
60 changes: 43 additions & 17 deletions docs/sandbox-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ connectivity; see [Runtime and outer isolation](design-principles.md#runtime-and
(native SDK calls, ownership checks, identity translation, private config).
Assert `var _ sandbox.SandboxProvider = (*YourAdapter)(nil)` at compile time.
Out-of-process helpers live in `services/agents-api/tools/<kind>-provider`.
3. **Register the kind** in every file listed in
3. **Register the kind** once using
[Register the provider kind](#register-the-provider-kind). Registration is
explicit construction, not an init-time plugin registry.
4. **Label owned resources** with `io.oac.*` labels, or `oac_*` metadata keys
Expand Down Expand Up @@ -168,25 +168,51 @@ A provider must not implement a competing preparation path.

## Register the provider kind

Provider kinds are enumerated explicitly. Add a new kind to each surface
below; none accepts an arbitrary provider string.

| Surface | File | What it enumerates |
| --- | --- | --- |
| Node-local construction | [`sandbox/config/config.go`](../services/agents-api/internal/sandbox/config/config.go), [`specification.go`](../services/agents-api/internal/sandbox/config/specification.go) | Typed construction, readiness probe and node specification |
| Direct construction | [`cmd/server/managed_setup.go`](../services/agents-api/cmd/server/managed_setup.go) (`managedSetup.provider`) | Direct adapters (E2B) and node-proxied kinds (Docker, microsandbox) |
| Resource validation | [`sandbox/deployment.go`](../services/agents-api/internal/sandbox/deployment.go) (`Resources.Validate`) | Per-kind resource limits |
| Node proxy and identity | [`sandbox/node/proxy.go`](../services/agents-api/internal/sandbox/node/proxy.go), [`node/identity.go`](../services/agents-api/internal/sandbox/node/identity.go) | Node-capable kinds and their checkpoint capability |
| Deployment persistence | [`sandbox_deployment_mutations.go`](../services/agents-api/internal/store/sandbox_deployment_mutations.go), [`sandbox_deployment_setup.go`](../services/agents-api/internal/store/sandbox_deployment_setup.go), [`sandbox_specification.go`](../services/agents-api/internal/store/sandbox_specification.go), [`runtime_node_deployment.go`](../services/agents-api/internal/store/runtime_node_deployment.go) | Deployment admission and node-mode kinds |
| Database constraint | A new migration in [`migrations/`](../services/agents-api/migrations) | `provider_kind` `CHECK` constraints, last set in `000081_sandbox_generations.sql`; never edit a landed migration |
| Node installation | [`node_installation.go`](../services/core-console/node_installation.go) | Node artifacts per kind |
| Installer | [`deploy/install/sandbox_setup.py`](../deploy/install/sandbox_setup.py) (`CHOICES`, used by `install.py --sandbox`) | Installer backend choices |
| Distribution | [`scripts/core-distribution-manifest.py`](../scripts/core-distribution-manifest.py) | Bundled provider helper binaries |
| Clients and Web | [`sandbox-client.ts`](../packages/agents-client/src/sandbox-client.ts) (`SandboxProvider`), [`features/sandbox`](../apps/web/src/features/sandbox) (`SandboxSetupWizard.tsx`, `console-config.ts`, `node-enrollment.ts`), [`sandbox-labels.ts`](../apps/web/src/lib/sandbox-labels.ts) | Backend choices and labels shown to operators |
`sandbox/providers/registry.go` is the sole registration table. Each entry binds
an adapter's specification/resource validators, selection normalization, deployment
mode, defaults, optional checkpoint capability, and local or direct constructor.
`providers.Build` constructs node-local adapters; `providers.BuildDirect` constructs
direct adapters. Neither allocates compute. There is no init-time registration or
runtime plugin loading.

For a new implementation:

1. Implement `SandboxProvider` in its adapter package and add native contract tests.
2. Add its configuration validators and optional read-only `SelectionDiscoverer`
for native resource discovery. Normalization must copy input before changing it.
`RestoreSelection` must retain access to owned resources without requiring new
template validation. Put native credential verification behind
`CredentialVerifier` when needed.
3. Register its constructor, policies and defaults in `providers/registry.go`.
Node proxy identity and checkpoint advertisement consume this same entry.
The installer projection uses those registered policies and the common field
bounds in `sandbox/deployment_contract.go`; regenerate it with
`go run ./services/agents-api/cmd/specification-contract -write`.
4. If new configuration fields are necessary, extend the typed `sandbox.Selection`
envelope and its dedicated encrypted persistence fields, API DTO and operator
client. Do not replace typed configuration with unrestricted JSON. Field codecs
may map columns; Store must not parse native endpoints, templates or defaults.
5. Supply required installer/distribution artifacts and operator labels. A new
provider must not add a Session/Turn scheduling path or a Store vendor switch.

Preview and persistence use `providers.Normalize` and `providers.Describe`.
`SelectionDiscoverer` resolves omitted native resource values before commit; the
complete specification is validated again at persistence. Store owns transactions,
credential encryption, generation fencing, resource ownership and typed column
mapping. Database constraints validate structure, not the registration list.
`providers.ResolveChange` owns configuration inheritance and comparison uses
normalized selectors, so preview, retry and commit share the same defaults.

A direct adapter with credentials verifies all retained generations and allocation
references before replacing a key. The common `sandbox.CallFence` excludes native
calls and waits for helper completion, including calls whose callers timed out.
Execution invokes prepared verification/fencing callbacks without branching on a
vendor. A transport wrapper advertises only capabilities that its adapter supports;
new optional capabilities need forwarding and qualification before registration.

Keep vendor-specific deployment validation and SDK setup at the construction
boundary. Construction must not create an Environment. For node-local adapters
the `Built` result returns the provider, probe, installation identity, backend
the `providers.Built` result returns the provider, probe, installation identity, backend
fingerprint and specification digest; the factory also returns its close function.

Preserve the `execution.RuntimeProvider` deployment binding: `ProviderKind`,
Expand Down
5 changes: 2 additions & 3 deletions services/agents-api/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -1445,9 +1445,8 @@ change guard. This boundary does not add cross-node Session
migration, Core multi-active, autoscaling, Kubernetes or harness residency.

The common
`services/agents-api/internal/sandbox` contract owns the four base operations
(Create, GetInfo, Renew, Kill) and the optional CheckpointProvider
capability. Core orchestration must not import an adapter or SDK. Exact compute
`services/agents-api/internal/sandbox` contract owns the five required operations and optional capabilities documented
in [the Provider guide](../../docs/sandbox-provider.md). Core orchestration must not import an adapter or SDK. Exact compute
identity, generation construction, inspection, full snapshot capture, restore,
thaw and owned artifact cleanup use that common capability. Initialization and
execution use the authenticated Runtime peer.
Expand Down
2 changes: 1 addition & 1 deletion services/agents-api/cmd/sandbox-node/generations.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import (
"time"

"github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox"
providerconfig "github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox/config"
"github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox/node"
providerconfig "github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox/providers"
)

func runGenerations(ctx context.Context, configFile, stateDir string) error {
Expand Down
4 changes: 2 additions & 2 deletions services/agents-api/cmd/sandbox-node/generations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import (
"context"
"encoding/json"
"errors"
"github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox"
"os"
"os/exec"
"path/filepath"
"syscall"
"testing"

providerconfig "github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox/config"
"github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox"
providerconfig "github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox/providers"
)

func TestGenerationJournalRestartIdentity(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion services/agents-api/cmd/sandbox-node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import (

"github.com/MiniMax-AI-Dev/parsar/internal/obs/log"
"github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox"
providerconfig "github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox/config"
"github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox/node"
providerconfig "github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox/providers"
)

func main() {
Expand Down
Loading
Loading