Custom Sandbox Engine Integration Guide#
This document explains how to integrate a custom sandbox engine into your system using two supported approaches. Follow the instructions and code examples below based on your requirements.
Overview#
The system provides two integration paths for custom sandbox engines:
Option 1 (Standard): Adapt your existing sandbox API to the predefined
EnvInstanceClientinterface.Option 2 (Custom): Implement the
EnvInstanceServiceinterface directly in your own client, allowing full control over API interactions.
Both methods require implementing CRUD operations and lifecycle management for sandbox instances. The core interface is defined as:
type EnvInstanceService interface {
GetEnvInstance(id string) (*models.EnvInstance, error)
CreateEnvInstance(req *backend.Env) (*models.EnvInstance, error)
DeleteEnvInstance(id string) error
ListEnvInstances(envName string) ([]*models.EnvInstance, error)
Warmup(req *backend.Env) error
Cleanup() error
}
Configuration is controlled by the schedule_type flag in your main function:
schedule_type: standard→ UsesEnvInstanceClientschedule_type: custom→ Uses your implementation ofEnvInstanceService
Option 1: Adapt Existing API via EnvInstanceClient#
Use this approach if your sandbox API can be adapted to match the expected request/response format of
EnvInstanceClient.
Step 1: Configure Base URL#
Initialize the client with your sandbox engine’s base URL, which can be specified by schedule_addr flag in
api-service startup command:
client := service.NewEnvInstanceClient("https://your-sandbox-api.com")
Step 2: Ensure API Compatibility#
Your sandbox service must expose the following endpoints:
Method |
URI Pattern |
Description |
|---|---|---|
|
|
Create a new environment instance |
|
|
Get instance by ID |
|
|
Delete instance by ID |
|
|
List instances by environment name |
|
|
Warm up environment resources |
|
|
Cleanup unused resources |
API Details & Examples#
1. Create Environment Instance#
Endpoint: POST /aenvironment/instance
Request Body:
{
"id": "env-123",
"name": "Python3.9-RL",
"description": "Reinforcement Learning sandbox",
"version": "v1.2",
"tags": [
"ml",
"rl"
],
"code_url": "https://github.com/user/rl-env.git",
"build_config": {
"image": "python:3.9-rl",
"timeout": 600
},
"test_config": {
"command": "pytest tests/"
},
"deploy_config": {
"replicas": 1,
"resources": {
"cpu": "2",
"memory": "4Gi"
}
}
}
Success Response (200/201):
{
"success": true,
"code": 200,
"message": "Instance created",
"data": {
"id": "inst-789",
"env": {
/* same as request env */
},
"status": "Running",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z",
"ip": "10.244.1.10",
"ttl": "2h"
}
}
2. Get Environment Instance#
Endpoint: GET /aenvironment/instance/{id}
Response:
{
"success": true,
"code": 200,
"data": {
"id": "inst-789",
"env": {
/* env config */
},
"status": "Running",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:30:00Z",
"ip": "10.244.1.10",
"ttl": "2h"
}
}
3. Delete Environment Instance#
Endpoint: DELETE /aenvironment/instance/{id}
Response:
{
"success": true,
"code": 200,
"data": true
}
4. List Instances by Environment Name#
Endpoint: GET /aenvironment/instance?envName=Python3.9-RL
Response:
{
"success": true,
"code": 200,
"data": [
{
"id": "inst-789",
"env": {
"name": "Python3.9-RL"
},
"status": "Running",
"ip": "10.244.1.10",
"created_at": "2025-01-15T10:00:00Z"
}
]
}
5. Warmup (Prepare Resources)#
Endpoint: PUT /aenvironment/instance/action/warmup
Request: Same body format as CreateEnvInstance (sent in body or inferred by service).
Response: Same as GetEnvInstance (containing warmed-up instance).
6. Cleanup (Release Unused Resources)#
Endpoint: PUT /aenvironment/instance/action/cleanup
Response: Success or error message. Implementation may scan and delete expired instances.
Step 3: Initialize with Standard Mode#
In your main.go:
func main() {
// Load config where schedule_type is set
config := loadConfig()
var envSvc service.EnvInstanceService
if config.ScheduleType == "standard" {
envSvc = service.NewEnvInstanceClient(config.SandboxBaseURL)
} else if config.ScheduleType == "custom" {
envSvc = NewCustomSandboxClient(config) // See Option 2
}
// Pass envSvc to scheduler or manager
scheduler := NewScheduler(envSvc)
scheduler.Start()
}
✅ Pros: Quick integration if API matches.
⚠️ Cons: Requires adapting your API to expected URL, payload, and response formats.
Option 2: Implement Custom Client via EnvInstanceService#
Use this if your sandbox API differs significantly in endpoints, parameters, or response structure.
Step 1: Define Your Custom Client#
Implement all methods of EnvInstanceService:
type CustomSandboxClient struct {
baseURL string
httpClient *http.Client
apiKey string // Example: custom auth
}
func NewCustomSandboxClient(baseURL, apiKey string) *CustomSandboxClient {
return &CustomSandboxClient{
baseURL: baseURL,
apiKey: apiKey,
httpClient: &http.Client{
Timeout: 45 * time.Second,
},
}
}
Step 2: Implement Required Methods (Example: Create)#
func (c *CustomSandboxClient) CreateEnvInstance(req *backend.Env) (*models.EnvInstance, error) {
// Custom endpoint and payload
url := fmt.Sprintf("%s/v2/envs/launch", c.baseURL)
payload := map[string]interface{}{
"template": req.Name,
"git": req.CodeURL,
"resources": req.DeployConfig,
}
jsonData, _ := json.Marshal(payload)
httpReq, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
httpReq.Header.Set("X-API-Key", c.apiKey)
httpReq.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != 201 {
return nil, fmt.Errorf("custom create failed: %s", body)
}
// Parse custom response format
var result struct {
SandboxID string `json:"sandbox_id"`
IP string `json:"endpoint_ip"`
Status string `json:"state"`
}
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
}
return &models.EnvInstance{
ID: result.SandboxID,
Env: req,
Status: result.Status,
IP: result.IP,
}, nil
}
You must implement all 6 interface methods.
Step 3: Wire Custom Client in Main#
func main() {
var scheduleClient service.EnvInstanceService
if scheduleType == "k8s" {
scheduleClient = service.NewScheduleClient(scheduleAddr)
} else if scheduleType == "standard" {
scheduleClient = service.NewEnvInstanceClient(scheduleAddr)
} else if scheduleType == "custom" {
scheduleClient = service.NewCustomSandboxClient(scheduleAddr, "your-api-key")
} else {
log.Fatalf("unsupported schedule type: %v", scheduleType)
}
}
✅ Pros: Full flexibility in API design, headers, auth, and response parsing.
⚠️ Requirement: You must handle all error cases, timeouts, and data mapping.
Required Data Structures#
backend.Env (Input for Creation/Warmup)#
{
"id": "env-123",
"name": "Python3.9",
"description": "Standard Python env",
"version": "v1.0",
"tags": [
"ai",
"stable"
],
"code_url": "https://github.com/org/repo.git",
"build_config": {
"image": "python:3.9"
},
"test_config": {
"command": "make test"
},
"deploy_config": {
"cpu": "2",
"memory": "4Gi"
}
}
models.EnvInstance (Return Type)#
{
"id": "inst-abc123",
"env": {
/* Env object */
},
"status": "Running",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:05:00Z",
"ip": "192.168.1.100",
"ttl": "1h"
}
models.ClientResponse[T]#
All responses must follow this envelope format:
{
"success": true,
"code": 200,
"message": "OK",
"data": {
/* T payload */
}
}
If your API uses a different envelope, transform it in your custom client methods.
Recommendations & Best Practices#
Error Handling
Always return descriptive errors including HTTP status and response body (truncated if large).Timeout Configuration
Set reasonable timeouts (e.g., 30–60s) based on sandbox startup time.Idempotency
EnsureDeleteEnvInstanceis idempotent—returning success if resource is already gone is acceptable.Logging
Log key operations (e.g.,Creating sandbox for env=Python3.9), especially inCleanup.Health Checks
Consider adding/healthendpoint validation during client initialization.Testing
Provide a mock implementation ofEnvInstanceServicefor unit testing business logic.
Troubleshooting#
Symptom |
Likely Cause |
Solution |
|---|---|---|
|
Incorrect base URL or endpoint path |
Verify full URL construction in client |
|
Mismatched request payload |
Ensure |
|
Response format differs |
In custom client, map your response to |
|
|
Implement filtering logic or return mock data |
Summary#
Standard Integration: Fast path if your API matches expected routes/payloads.
Custom Integration: Implement
EnvInstanceServicefully for maximum control.Set
schedule_type: standardorcustomin config to select mode.All responses must conform to
ClientResponse[T]structure or be adapted.
For further details, refer to:
env_instance.go– Standard HTTP client implementationschedule_client.go– Adapter example (ScheduleClientwraps pod ops intoEnvInstanceService)models/– Shared data structures
Contact the platform team if you need assistance adapting your sandbox API.