Skip to content

feat(containers): add Containers API with Docker/OpenShell providers and shell tool - #5853

Closed
zanetworker wants to merge 7 commits into
ogx-ai:mainfrom
zanetworker:feat/containers-api
Closed

zanetworker wants to merge 7 commits into
ogx-ai:mainfrom
zanetworker:feat/containers-api

Conversation

@zanetworker

@zanetworker zanetworker commented May 16, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a Containers API for managing sandboxed Docker execution environments, matching the OpenAI Containers API. This enables models to execute shell commands in isolated containers via the Responses API shell tool.

Only the Docker provider is implemented in this PR. Other providers (Podman, Kubernetes, Openshell, remote container services) can follow in separate PRs.

Closes #5852

API Surface

Method Endpoint Purpose
POST /v1/containers Create a sandboxed container
GET /v1/containers List containers with pagination
GET /v1/containers/{id} Retrieve a container
DELETE /v1/containers/{id} Delete a container and stop the Docker process
POST /v1/containers/{id}/exec Execute shell commands in a container

Shell Tool Integration

The Responses API now accepts {"type": "shell", "environment": {"type": "container_auto"}} as a tool. When a model emits a shell_call, the server:

  1. Creates a Docker container (python:3.12-slim)
  2. Executes the commands via docker exec
  3. Returns stdout/stderr/exit_code to the model
  4. Auto-deletes the container after execution

The containers API is registered as an optional dependency of the Responses provider, so servers without Docker continue to work normally.

Implementation

  • Protocol & models: src/ogx_api/containers/ — Pydantic models matching OpenAI's schema (Container, ExpiresAfter, NetworkPolicy, ExecInContainer)
  • Docker provider: src/ogx/providers/inline/containers/docker/ — manages lifecycle via Docker SDK, metadata persisted to AuthorizedSqlStore
  • Shell tool types: src/ogx_api/openai_responses.py — ShellContainerAutoEnvironment, ShellContainerReferenceEnvironment, ShellCallAction, ShellOutputContent, ShellExitOutcome, ShellTimeoutOutcome, OpenAIResponseOutputMessageShellCall, OpenAIResponseOutputMessageShellCallOutput
  • Responses wiring: ToolExecutor dispatches shell calls to the Containers API; _coordinate_tool_execution and convert_tool handle the new type; auto-cleanup via finally block

What is NOT in this PR

  • Container files (upload/download files to containers) — follow-up
  • Local shell tool (execute on host without Docker) — follow-up
  • Non-Docker providers (Podman, Kubernetes) — follow-up
  • Skills support (environment.skills) — follow-up

Test Plan

Unit tests (38 tests)

uv run pytest tests/unit/containers/ tests/unit/providers/containers/ -v
# 38 passed

OpenAI conformance (6 tests, requires OPENAI_API_KEY)

OPENAI_API_KEY=sk-... uv run pytest tests/integration/containers/test_openai_conformance.py -v
# 6 passed — validates response shapes match OpenAI's live API

End-to-end server test

# Terminal 1: start server
uv run ogx run starter

# Terminal 2: run demo
uv run python3 -c "
from openai import OpenAI
client = OpenAI(base_url='http://localhost:8321/v1', api_key='fake')

# CRUD
container = client.containers.create(name='test', memory_limit='1g')
print(f'Created: {container.id} status={container.status}')
client.containers.delete(container.id)
print('Deleted')

# Shell tool via Responses API
response = client.responses.create(
    model='openai/gpt-4o-mini',
    tools=[{'type': 'shell', 'environment': {'type': 'container_auto'}}],
    input='Use the shell tool to run: echo Hello from OGX containers',
)
for item in response.output:
    if item.type == 'shell_call':
        print(f'[shell] {item.action.commands}')
    elif item.type == 'message':
        print(item.content[0].text)
"

Output:

Created: cntr-e388f84718ed43ba85e6e5418439e553 status=running
Deleted
[shell] ['echo Hello from OGX containers!']
The output of the command is: **Hello from OGX containers!**

Full unit suite regression check

uv run pytest tests/unit/ --ignore=tests/unit/providers/vector_io -x --tb=short -q
# 2359 passed, 3 skipped, 3 xfailed

zanetworker and others added 6 commits May 16, 2026 19:36
Add model definitions for the Containers API: Container, CreateContainerRequest,
ListContainersRequest/Response, RetrieveContainerRequest, DeleteContainerRequest/Response,
network policies (disabled/allowlist), and expiration settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Adel Zaalouk <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Adel Zaalouk <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Adel Zaalouk <[email protected]>
Implements the Containers protocol using Docker SDK with metadata
persistence via AuthorizedSqlStore. Includes unit tests with mocked
Docker client and container logging category registration.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Adel Zaalouk <[email protected]>
Add shell tool input/output types to the Responses API models matching
OpenAI's schema (shell_call, shell_call_output, environment configs).
Add exec_in_container to the Containers protocol and Docker provider for
running commands in sandboxed containers. Fix containers registry to use
standard available_providers() pattern. Include unit tests for all new
types and conformance tests validated against OpenAI's live API.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Adel Zaalouk <[email protected]>
Add containers API as an optional dependency of the Responses provider.
Thread containers_api through the provider chain to the ToolExecutor,
which dispatches shell tool calls by executing commands in containers
via exec_in_container. Register shell as a server-side builtin tool so
the streaming orchestrator presents it to models as a callable function.
Auto-delete containers created by container_auto after execution.
Register Containers protocol in the resolver and add containers to
the starter distribution.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Adel Zaalouk <[email protected]>
@github-actions

github-actions Bot commented May 16, 2026 •

Copy link
Copy Markdown
Contributor

✱ Stainless preview builds

This PR will update the llama-stack-client SDKs with the following commit message.

feat(containers): add Containers API with Docker provider and shell tool

Edit this comment to update it. It will appear in the SDK's changelogs.

✅ llama-stack-client-openapi studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️

New diagnostics (10 note)
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCall`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellCallAction`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellContainerReferenceEnvironment`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCallOutput-Output`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellOutputContent`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellExitOutcome`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellTimeoutOutcome`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCallOutput`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseInputToolShell`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellContainerAutoEnvironment`
✅ llama-stack-client-node studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️ → build ✅ (prev: build ⏭️) → lint ✅ (prev: lint ⏭️) → test ✅

npm install https://pkg.stainless.com/s/llama-stack-client-node/c75541af4a0706e73d7e5ab571bba71f5a029db9/dist.tar.gz
New diagnostics (10 note)
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCall`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellCallAction`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellContainerReferenceEnvironment`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCallOutput-Output`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellOutputContent`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellExitOutcome`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellTimeoutOutcome`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCallOutput`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseInputToolShell`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellContainerAutoEnvironment`
✅ llama-stack-client-python studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️ → build ✅ (prev: build ⏭️) → lint ✅ (prev: lint ⏭️) → test ✅

pip install https://pkg.stainless.com/s/llama-stack-client-python/3bf026d21e625fbb0e9c60dfcd77fb50bdf588bd/ogx_client-0.8.0a2-py3-none-any.whl
New diagnostics (10 note)
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCall`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellCallAction`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellContainerReferenceEnvironment`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCallOutput-Output`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellOutputContent`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellExitOutcome`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellTimeoutOutcome`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCallOutput`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseInputToolShell`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellContainerAutoEnvironment`
✅ llama-stack-client-go studio · conflict

Your SDK build had at least one new note diagnostic, which is a regression from the base state.

New diagnostics (89 note)
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCall`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellCallAction`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellContainerReferenceEnvironment`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCallOutput-Output`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellOutputContent`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellExitOutcome`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellTimeoutOutcome`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseOutputMessageShellCallOutput`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/OpenAIResponseInputToolShell`
💡 Model/Recommended: We recommend you use a model for `#/components/schemas/ShellContainerAutoEnvironment`

This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-05-20 10:49:04 UTC

Add an OpenShell provider to the Containers API that manages sandboxed
environments via OpenShell's gRPC gateway instead of Docker. This gives
production deployments a security-hardened execution backend with
per-binary network policies, credential isolation, and L7 inspection.

The provider uses the openshell Python SDK (SandboxClient) with three
connection modes: explicit gateway endpoint, cluster name auto-discovery,
or active cluster fallback. Network policy mapping is deferred to a
follow-up; sandboxes use OpenShell's default policy.

Uses a separate SQLite table (openshell_containers) to avoid collisions
with the Docker provider's table schema.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Adel Zaalouk <[email protected]>
@zanetworker zanetworker changed the title feat(containers): add Containers API with Docker provider and shell tool feat(containers): add Containers API with Docker/OpenShell providers and shell tool May 26, 2026
@mergify

mergify Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale because it has not had activity within 60 days. It will be automatically closed if no further activity occurs within 30 days.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add Containers API and shell tool for sandboxed code execution

1 participant