@bitkaio/langchain-kubernetes
v0.2.0
Published
Kubernetes sandbox provider for the DeepAgents framework
Maintainers
Readme
@bitkaio/langchain-kubernetes
Kubernetes sandbox provider for the DeepAgents framework (TypeScript).
Supports two backend modes:
| Mode | Requirements | Best for |
|------|-------------|----------|
| agent-sandbox (default) | kubernetes-sigs/agent-sandbox controller + CRDs | Production — warm pools, gVisor/Kata, sub-second startup |
| raw | Any cluster, @kubernetes/client-node + tar-stream | Dev / clusters where you can't install CRDs |
Installation
# agent-sandbox mode — no extra deps (fetch is built in)
npm install @bitkaio/langchain-kubernetes
# raw mode — additional deps required
npm install @bitkaio/langchain-kubernetes @kubernetes/client-node tar-streamQuick start
agent-sandbox mode
import { KubernetesProvider } from "@bitkaio/langchain-kubernetes";
const provider = new KubernetesProvider({
mode: "agent-sandbox",
routerUrl: "http://sandbox-router-svc.default.svc.cluster.local:8080",
templateName: "python-sandbox-template",
});
const sandbox = await provider.getOrCreate();
const result = await sandbox.execute("python3 -c 'print(2 + 2)'");
console.log(result.output); // "4\n"
console.log(result.exitCode); // 0
await provider.delete(sandbox.id);raw mode
import { KubernetesProvider } from "@bitkaio/langchain-kubernetes";
const provider = new KubernetesProvider({
mode: "raw",
image: "python:3.12-slim",
});
const sandbox = await provider.getOrCreate();
const result = await sandbox.execute("python3 -c 'print(42)'");
await provider.delete(sandbox.id);Configuration reference
Shared options
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| mode | "agent-sandbox" \| "raw" | "agent-sandbox" | Backend mode |
| namespace | string | "deepagents-sandboxes" | Kubernetes namespace |
| startupTimeoutMs | number | 120_000 | Ms to wait for sandbox to be ready |
| executeTimeoutMs | number | 300_000 | Default ms per execute() call |
agent-sandbox mode options
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| routerUrl | string | Yes | URL of the sandbox-router service |
| templateName | string | Yes | SandboxTemplate name to instantiate |
| serverPort | number | No (8888) | Port the sandbox runtime listens on |
| kubeApiUrl | string | No | Kubernetes API URL. Defaults to in-cluster URL. Use http://localhost:8001 for kubectl proxy. |
| kubeToken | string | No | Bearer token for k8s API. Auto-read from service account if omitted. |
raw mode options
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| image | string | "python:3.12-slim" | Container image |
| imagePullPolicy | string | "IfNotPresent" | Image pull policy |
| workdir | string | "/workspace" | Working directory inside container |
| command | string[] | ["sleep", "infinity"] | Container entrypoint |
| env | Record<string, string> | — | Extra environment variables |
| cpuRequest / cpuLimit | string | "100m" / "1000m" | CPU resources |
| memoryRequest / memoryLimit | string | "256Mi" / "1Gi" | Memory resources |
| ephemeralStorageLimit | string | "5Gi" | Ephemeral storage limit |
| blockNetwork | boolean | true | Attach deny-all NetworkPolicy |
| runAsUser / runAsGroup | number | 1000 / 1000 | UID/GID inside container |
| seccompProfile | string | "RuntimeDefault" | seccomp profile type |
| namespacePerSandbox | boolean | false | Give each sandbox its own namespace |
| kubeconfigPath | string | — | Path to kubeconfig file |
| context | string | — | Kubeconfig context to use |
Sandbox API
Every sandbox extends BaseSandbox from the deepagents package:
// Execute a shell command
const result = await sandbox.execute("ls -la /workspace");
// result.output — combined stdout + stderr
// result.exitCode — process exit code
// result.truncated — true if output was capped at outputLimitBytes
// Upload files
const results = await sandbox.uploadFiles([
["/workspace/script.py", Buffer.from("print('hello')")],
["/workspace/data.json", Buffer.from('{"key": "value"}')],
]);
// results[0].error — null on success, "file_not_found" | "permission_denied" etc. on failure
// Download files
const downloads = await sandbox.downloadFiles(["/workspace/output.txt"]);
// downloads[0].content — Uint8Array | null
// downloads[0].error — null on success
// BaseSandbox also provides higher-level helpers built on execute():
// sandbox.ls(), sandbox.read(), sandbox.write(), sandbox.glob(), ...Provider API
// Create or reconnect to a sandbox
const sandbox = await provider.getOrCreate(); // create new
const sandbox = await provider.getOrCreate("existing-id"); // reconnect
// List active sandboxes
const { sandboxes } = await provider.list();
// sandboxes[0].id, .namespace, .phase
// Delete a sandbox (idempotent)
await provider.delete(sandbox.id);agent-sandbox mode — setup
1. Install the controller
Follow the agent-sandbox installation guide.
2. Create a SandboxTemplate
# examples/k8s/sandbox-template.yaml
apiVersion: extensions.agents.x-k8s.io/v1alpha1
kind: SandboxTemplate
metadata:
name: python-sandbox-template
namespace: default
spec:
podTemplate:
spec:
containers:
- name: python-runtime
image: us-central1-docker.pkg.dev/k8s-staging-images/agent-sandbox/python-runtime-sandbox:latest-main
ports:
- containerPort: 8888
readinessProbe:
httpGet: { path: "/", port: 8888 }
periodSeconds: 1
resources:
requests: { cpu: "250m", memory: "512Mi" }
restartPolicy: "OnFailure"kubectl apply -f examples/k8s/sandbox-template.yaml3. Apply RBAC
kubectl apply -f examples/k8s/sandbox-router-rbac.yaml4. Connect
In-cluster (the primary use case):
const provider = new KubernetesProvider({
routerUrl: "http://sandbox-router-svc.default.svc.cluster.local:8080",
templateName: "python-sandbox-template",
});Local development — the client needs access to both the sandbox-router and the Kubernetes API. Run two port-forwards:
# Forward the sandbox-router
kubectl port-forward svc/sandbox-router-svc 8080:8080 -n default
# Forward kubectl proxy for k8s API access
kubectl proxy --port=8001const provider = new KubernetesProvider({
routerUrl: "http://localhost:8080",
templateName: "python-sandbox-template",
kubeApiUrl: "http://localhost:8001", // kubectl proxy — no auth needed
});raw mode — setup
1. Create the namespace
kubectl create namespace deepagents-sandboxes2. Apply RBAC
kubectl apply -f examples/k8s/raw-mode-rbac.yaml3. Configure
const provider = new KubernetesProvider({
mode: "raw",
namespace: "deepagents-sandboxes",
image: "python:3.12-slim",
blockNetwork: true, // deny-all NetworkPolicy (requires NetworkPolicy-capable CNI)
});For local kind clusters, kindnet does not support NetworkPolicy. Either use Calico or set blockNetwork: false.
Error handling
import {
SandboxNotFoundError,
SandboxStartupTimeoutError,
SandboxRouterError,
TemplateNotFoundError,
MissingDependencyError,
} from "@bitkaio/langchain-kubernetes";
try {
const sandbox = await provider.getOrCreate();
} catch (err) {
if (err instanceof TemplateNotFoundError) {
// SandboxTemplate doesn't exist in the cluster
} else if (err instanceof SandboxStartupTimeoutError) {
// Sandbox didn't become ready in time
} else if (err instanceof SandboxRouterError) {
// Router or Kubernetes API not reachable
} else if (err instanceof MissingDependencyError) {
// @kubernetes/client-node not installed (raw mode)
}
}Integration tests
Integration tests require a running cluster:
# raw mode (any cluster)
K8S_INTEGRATION=1 npm run test:integration
# agent-sandbox mode (requires controller + CRDs)
K8S_INTEGRATION=1 SANDBOX_TEMPLATE=python-sandbox-template \
ROUTER_URL=http://localhost:8080 npm run test:integrationRequirements
- Node.js ≥ 18
- Kubernetes cluster (kind, GKE, EKS, AKS, OpenShift, …)
- For
agent-sandboxmode:kubernetes-sigs/agent-sandboxcontroller - For
rawmode:@kubernetes/client-node+tar-stream; NetworkPolicy-capable CNI ifblockNetwork: true
