Skip to content

feat(sdk): Go SDK with oapi-codegen for Lifecycle, Execd, and Egress APIs#597

Open
AlexandrePh wants to merge 16 commits intoalibaba:mainfrom
AlexandrePh:feat/go-sdk
Open

feat(sdk): Go SDK with oapi-codegen for Lifecycle, Execd, and Egress APIs#597
AlexandrePh wants to merge 16 commits intoalibaba:mainfrom
AlexandrePh:feat/go-sdk

Conversation

@AlexandrePh
Copy link
Copy Markdown

@AlexandrePh AlexandrePh commented Mar 29, 2026

Summary

Go SDK with oapi-codegen for all 3 OpenSandbox APIs, plus a high-level Sandbox object matching the Python/JS/C#/Java SDKs.

  • Generated clients (opensandbox/api/) from OpenAPI specs via oapi-codegen
  • High-level API: CreateSandbox(), ConnectSandbox(), SandboxManager, CodeInterpreter
  • ConnectionConfig with env var fallbacks, WaitUntilReady() with custom health checks
  • Structured Execution model with stdout/stderr, exit codes, and event handlers
  • Spec-compliant nested error/results parsing with backward compat for legacy flat format
  • SSE/NDJSON hybrid streaming (with StreamEvent.Event populated from NDJSON type field), multipart upload, file download
  • 39 e2e tests across sandbox lifecycle, commands, filesystem, code interpreter, manager, volumes, concurrent creation, error handling
  • 3 real scenario tests using live LLM (Azure OpenAI via Bifrost): agent loop, multi-turn code interpreter, shell tool use
  • 2 runnable examples: examples/agent_loop/ and examples/code_interpreter_agent/

Closes #596

Testing

  • Unit tests (18 tests, httptest mocks)
  • Integration tests (staging, low-level client)
  • e2e / manual verification (39 tests against live K8s staging + Bifrost LLM gateway)
  • All 20 review comments addressed and resolved

Breaking Changes

  • None

Checklist

  • Linked Issue or clearly described motivation
  • Added/updated docs (README.md, examples/)
  • Added/updated tests (18 unit + 39 e2e + 3 scenario tests)
  • Security impact considered (env vars only, no hardcoded credentials, API key rotated)
  • Backward compatibility considered (new SDK, no existing consumers)

Architecture

sdks/sandbox/go/
  opensandbox/
    api/
      specs/                    # Patched OpenAPI specs (3.0.3 for codegen compat)
      lifecycle/gen.go          # Generated from sandbox-lifecycle.yml
      execd/gen.go              # Generated from execd-api.yaml
      egress/gen.go             # Generated from egress-api.yaml
    config.go                   # ConnectionConfig with env var fallbacks
    constants.go                # DefaultExecdPort, DefaultTimeout, etc.
    errors.go                   # SandboxReadyTimeoutError, etc.
    execution.go                # Structured Execution model + nested error/results parsing
    sandbox.go                  # High-level Sandbox object
    manager.go                  # SandboxManager for admin operations
    code_interpreter.go         # CodeInterpreter wrapper
    http.go                     # Base HTTP client with configurable timeout/headers
    streaming.go                # SSE/NDJSON hybrid parser (4MiB buffer, type extraction)
    types.go                    # Type definitions (spec-aligned)
    lifecycle.go, execd.go, egress.go  # Low-level clients
  examples/
    agent_loop/                 # LLM agent: task → code → execute → result
    code_interpreter_agent/     # Multi-turn agent with persistent Python state
tests/go/
  tests/
    sandbox_e2e_test.go         # 13 lifecycle tests
    command_e2e_test.go         # 7 command tests
    filesystem_e2e_test.go      # 6 filesystem tests
    code_interpreter_e2e_test.go # 6 code interpreter tests
    manager_e2e_test.go         # 3 manager tests
    volume_e2e_test.go          # 3 volume mount tests
    concurrent_e2e_test.go      # 1 concurrent creation test
    error_handling_e2e_test.go  # 1 x-request-id test
    scenario_agent_e2e_test.go  # 3 real LLM agent tests

Copilot AI review requested due to automatic review settings March 29, 2026 16:09
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 29, 2026

CLA assistant check
All committers have signed the CLA.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Go SDK (stdlib-only) for OpenSandbox’s Lifecycle, Execd, and Egress APIs, including an SSE streaming implementation and an httptest-based test suite.

Changes:

  • Introduce typed Go clients for Lifecycle, Execd, and Egress APIs plus shared HTTP/error helpers.
  • Implement SSE streaming support used by Execd streaming endpoints.
  • Add Go module scaffolding, README, Makefile, and a test suite covering core behaviors.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
sdks/sandbox/go/opensandbox/types.go Shared SDK types and error types used across clients
sdks/sandbox/go/opensandbox/http.go Base HTTP client, JSON helpers, and API error handling
sdks/sandbox/go/opensandbox/streaming.go SSE parsing + streaming request helper
sdks/sandbox/go/opensandbox/lifecycle.go Lifecycle API client methods (create/get/list/etc.)
sdks/sandbox/go/opensandbox/egress.go Egress policy client methods
sdks/sandbox/go/opensandbox/execd.go Execd client methods (SSE execution, files, dirs, metrics)
sdks/sandbox/go/opensandbox/opensandbox_test.go httptest-based unit tests for clients + SSE behavior
sdks/sandbox/go/go.mod New Go module definition for the SDK
sdks/sandbox/go/README.md Installation, examples, and API reference documentation
sdks/sandbox/go/Makefile Build/vet/test/lint targets for the SDK module

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@AlexandrePh AlexandrePh marked this pull request as draft March 29, 2026 18:57
@AlexandrePh AlexandrePh marked this pull request as ready for review March 30, 2026 04:05
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70f495e992

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@AlexandrePh AlexandrePh marked this pull request as draft March 30, 2026 04:50
…APIs

- oapi-codegen generates typed clients from all 3 OpenAPI specs
- Hand-written ergonomic wrapper for SSE/NDJSON streaming, multipart uploads, file downloads
- 18 unit tests + integration test (local) + staging test (remote K8s)
- `make generate` target + `go generate ./...` for spec-driven regeneration
- All review feedback addressed (streaming timeout, scanner buffer, type safety, FileMode encoding)
- No hardcoded credentials — staging tests require STAGING_URL and STAGING_API_KEY env vars

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@AlexandrePh AlexandrePh changed the title feat(sdk): Go SDK for Lifecycle, Execd, and Egress APIs feat(sdk): Go SDK with oapi-codegen for Lifecycle, Execd, and Egress APIs Mar 30, 2026
@Pangjiping
Copy link
Copy Markdown
Collaborator

Great Job! It's great to see the SDK for a new language. 🎉🎉

Perhaps you could refer to the e2e tests under the tests directory for the other languages and add some simple real e2e tests for Golang?

@AlexandrePh
Copy link
Copy Markdown
Author

All review feedback addressed

The branch was squashed into a single clean commit. All 10 Copilot and 2 Codex review comments from the previous revision are addressed:

# Issue Fix
1 Package doc missing Execd types.go:1 — "Lifecycle, Egress, and Execd APIs"
2 30s timeout kills SSE http.godefaultTimeout = 0
3 WithTimeout nil panic http.go — stores *time.Duration, applies after all options with nil guard
4 Silent cursor parse error execd.go — returns fmt.Errorf on invalid cursor header
5 go 1.24 vs 1.24.0 go.modgo 1.24.0
6 64K scanner buffer streaming.go — 4 MiB buffer via scanner.Buffer()
7 Missing JSON content-type on metadata execd.goCreatePart with Content-Type: application/json
8 Local path leaked in upload execd.gofilepath.Base(localPath)
9 Unused recursive param execd.go — removed from DeleteDirectory
10 Port as string, missing proxy param lifecycle.goport int, useServerProxy *bool
11 Codex P1: FileMode string execd.gofmt.Sprintf("%o", mode) sends octal string
12 Codex P1: FileMode decimal Same fix as #11

Additionally:

  • Switched to oapi-codegen — types and clients generated from OpenAPI specs
  • Removed hardcoded credentials — staging tests now require STAGING_URL and STAGING_API_KEY env vars
  • Added make generate target for spec-driven regeneration

@AlexandrePh
Copy link
Copy Markdown
Author

Thanks for the feedback! 🙏

We're actively working on this — the plan is:

  1. High-level Sandbox object — matching the Python/JS/C#/Java SDKs with Sandbox.Create(), WaitUntilReady(), .Commands, .Files, .Metrics accessors, and auto-endpoint resolution
  2. ConnectionConfig — shared config with env var fallbacks (OPEN_SANDBOX_DOMAIN, OPEN_SANDBOX_API_KEY)
  3. SandboxManager — list, filter, kill operations
  4. Structured Execution model — stdout/stderr logs, exit code, event handlers (replacing raw SSE callbacks)
  5. E2E tests in tests/go/ — following the same patterns and env vars as the other language test suites (sandbox lifecycle, command execution, filesystem ops, manager)

Will push an update soon.

High-level API matching Python/JS/C#/Java SDKs:
- ConnectionConfig: shared config with env var fallbacks (OPEN_SANDBOX_DOMAIN, OPEN_SANDBOX_API_KEY)
- Sandbox: high-level object with CreateSandbox(), ConnectSandbox(), auto-endpoint resolution, WaitUntilReady()
- SandboxManager: list, filter, kill, pause, resume, renew operations
- Execution model: structured stdout/stderr, exit codes, event handlers
- Error types: SandboxReadyTimeoutError, SandboxUnhealthyError, InvalidArgumentError
- Constants: DefaultExecdPort, DefaultTimeoutSeconds, DefaultResourceLimits, etc.

E2E tests in tests/go/ (12 tests, all passing against live staging):
- Sandbox lifecycle: create, info, metrics, renew, endpoint, kill
- Command execution: simple run, handlers, exit codes, multi-line
- Filesystem: file info, write + read via commands
- Manager: list, filter by state, get + kill

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@AlexandrePh
Copy link
Copy Markdown
Author

Done! Pushed the high-level API and e2e tests.

What's new

High-level API (matching Python/JS/C#/Java SDKs):

sb, err := opensandbox.CreateSandbox(ctx, config, opensandbox.SandboxCreateOptions{
    Image: "python:3.11-slim",
})
defer sb.Kill(ctx)

exec, err := sb.RunCommand(ctx, "echo hello", nil)
fmt.Println(exec.Text())     // "hello"
fmt.Println(*exec.ExitCode)  // 0
  • ConnectionConfig — shared config with env var fallbacks
  • Sandbox — wraps lifecycle + execd + egress with auto-endpoint resolution
  • CreateSandbox() / ConnectSandbox() — factory methods with WaitUntilReady
  • SandboxManager — list, filter, kill, pause, resume, renew
  • Execution model — structured stdout/stderr, exit codes, event handlers
  • Error types, constants, defaults

E2E tests in tests/go/ — 12 tests covering sandbox lifecycle, command execution, filesystem ops, and manager operations. All passing against live K8s staging.

…r, context-aware polling

- Extract clientOpts() helper to deduplicate option building in config.go
- Use strings.Builder in Execution.Text() instead of O(n²) string concat
- waitForRunning now respects context cancellation instead of hardcoded 120 iterations
- Remove SandboxFilter duplication — use ListOptions throughout
- Use SandboxState constants instead of string literals in tests
- Extract createTestSandbox() helper to reduce e2e test boilerplate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ninan-nn
Copy link
Copy Markdown
Collaborator

Once you're done with the development, please mark the PR as ready to review (convert it from draft) : >

AlexandrePh and others added 4 commits March 30, 2026 10:13
…directories

New e2e tests (19 total, up from 12):
- Filesystem: write/read/delete cycle, move files, create/delete directories,
  search files, download file
- Sandbox: connect to existing sandbox, bash sessions with state persistence
- Fix CreateDirectory to send mode as int per server spec

New Sandbox methods exposed:
- DeleteFiles, MoveFiles, SearchFiles, SetPermissions, ReplaceInFiles
- UploadFile, DownloadFile, CreateDirectory, DeleteDirectory
- ExecuteCode, CreateContext, ListContexts, DeleteContext
- CreateSession, RunInSession, DeleteSession

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CodeInterpreter type wrapping Sandbox with code execution capabilities
- CreateCodeInterpreter() factory with opensandbox/code-interpreter:latest image
- Execute() for quick language-based execution
- ExecuteInContext() for persistent state across executions

E2E tests (6 new, 25 total):
- Create and ping code-interpreter sandbox
- Python code execution
- Context persistence (variables survive across calls)
- Context management (create, list, delete)
- Context isolation (variables don't leak between contexts)
- Execution with handlers (streaming stdout)

All 25 e2e tests pass against live K8s staging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… policy, x-request-id

New e2e tests (35 total, up from 25):
- Command: env injection, background status/logs, interrupt
- Sandbox: manual cleanup, network policy create, egress get/patch, pause/resume
- Volumes: host mount (rw + readonly), PVC mount
- Error: x-request-id passthrough on API errors
- APIError now carries RequestID from X-Request-Id response header

Fix: CreateDirectory sends mode as octal-digits integer per server spec.
Tests that require egress sidecar, PVC, or pause support gracefully skip.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three scenario tests using live Bifrost (Azure OpenAI) + OpenSandbox:

1. SimpleAgentLoop: task → LLM generates Python → execute in sandbox → verify result
   (Fibonacci sequence via gpt-4o-mini generated code)

2. CodeInterpreterAgent: multi-turn agent with persistent Python context
   (Create dataset → LLM analyzes with stdlib → variables persist across turns)

3. SandboxToolUse: LLM as shell command planner
   (LLM decides what command → sandbox executes → LLM interprets output)

All 3 tests pass against live staging (Bifrost → Azure OpenAI gpt-4o-mini).

Also: configured Bifrost with Azure OpenAI provider (gpt-4o, gpt-4o-mini, o4-mini)
via azure-gpt-sharpi endpoint in Brazil South.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AlexandrePh and others added 4 commits March 30, 2026 13:09
Two runnable examples demonstrating real-world usage:

1. examples/agent_loop/ — Simple agent: task → LLM → Python code → sandbox → result
2. examples/code_interpreter_agent/ — Multi-turn agent with persistent Python state

Both use env vars for all config (OPEN_SANDBOX_DOMAIN, LLM_ENDPOINT, etc.)
No hardcoded credentials.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ccuracy

1. OctalMode: panic on invalid FileMode instead of silently returning 0
2. CodeInterpreter timeout: use named constant DefaultCodeInterpreterTimeoutSeconds
3. GetBaseURL doc: fix misleading comment that claimed /v1 suffix
4. resolveExecd/resolveEgress: use sync.Once for goroutine-safe initialization
5. execution.go: rename `init` variable to `initEvent` to avoid shadowing builtin
6. execd.go: remove duplicate doc comment on CreateDirectory
7. types.go: fix SandboxInfo doc comment that still said "Sandbox"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sync.Once captures the first caller's context permanently — if it fails,
subsequent retries are impossible. Replaced with mutex-guarded check-then-init
which respects each caller's context and retries on failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… passes

- TestConcurrent_CreateFiveSandboxes: creates 5 sandboxes in parallel,
  verifies each is healthy and responds independently (requires 3/5 minimum
  for resource-constrained staging clusters)
- TestVolume_PVCMount now passes after provisioning opensandbox-e2e-pvc-test
  PVC via local-path provisioner on staging

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 43 out of 45 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

AlexandrePh and others added 2 commits March 30, 2026 15:16
… assertions

8 fixes from Copilot's second review pass:

1. execution.go: Handle nested error/results JSON per execd spec
   ({"type":"error","error":{...}} and {"type":"result","results":{...}})
   with backward compat for flat fields from older servers
2. config.go: Wire RequestTimeout and Headers into clientOpts()
3. http.go: Add WithHeaders option for custom headers on requests
4. streaming.go: Populate StreamEvent.Event from NDJSON type field
5. sandbox.go: Fix doc comment — nil timeout uses client default, not server
6. README.md: Fix streaming example to parse NDJSON type field
7. volume_e2e_test.go: Assert read-only mount actually rejects writes
8. scenario_agent_e2e_test.go: Check error from write command before exec
9. config.go: Append /v1 to lifecycle client base URL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The execd spec defines error events with a nested `error` object
(`{ename, evalue, traceback}`) and result events with a MIME-keyed
`results` map (`{"text/plain": "4"}`). The SDK was parsing these as
flat top-level fields. Now supports both formats for backward compat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@AlexandrePh AlexandrePh marked this pull request as ready for review March 30, 2026 18:38
- Update streaming example to use event.Event (now populated from NDJSON type)
- Fix RenewExpiration signature: takes expiresAt, not duration
- Fix GetEndpoint signature: add useServerProxy parameter
- Fix DeleteDirectory signature: remove recursive parameter
- Update StreamEvent docs to reflect NDJSON type extraction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@AlexandrePh
Copy link
Copy Markdown
Author

@ninan-nn ready for review :)

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d83a932ae6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…ming

- resolveExecd/resolveEgress now forward all endpoint headers (e.g.
  routing headers like OPEN-SANDBOX-INGRESS) to the client, not just
  the auth token
- doStreamRequest now applies c.headers, matching doRequest behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@AlexandrePh
Copy link
Copy Markdown
Author

AlexandrePh commented Mar 30, 2026

Great Job! It's great to see the SDK for a new language. 🎉🎉

Perhaps you could refer to the e2e tests under the tests directory for the other languages and add some simple real e2e tests for Golang?

done! executed tests against live remote server

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Go SDK for OpenSandbox (Lifecycle, Execd, Egress)

5 participants