{"_id":"@bitkaio/langchain-kubernetes","_rev":"3-e307394a0be0c08ad855931f51ce1d6c","name":"@bitkaio/langchain-kubernetes","dist-tags":{"latest":"0.3.0"},"versions":{"0.0.1":{"name":"@bitkaio/langchain-kubernetes","version":"0.0.1","keywords":["langchain","deepagents","kubernetes","sandbox","agents"],"author":{"name":"bitkaio LLC"},"license":"MIT","_id":"@bitkaio/langchain-kubernetes@0.0.1","maintainers":[{"name":"bitkaio_team","email":"team@bitkaio.com"}],"homepage":"https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox#readme","bugs":{"url":"https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox/issues"},"dist":{"shasum":"52b2ee3b0c91cc0d8adb3fe56a1eb8e9dcb8836d","tarball":"https://registry.npmjs.org/@bitkaio/langchain-kubernetes/-/langchain-kubernetes-0.0.1.tgz","fileCount":57,"integrity":"sha512-8SdBh3nFNz6smT92XXj3yt0gLJO2nn4UyM0f3Gx8HQj93s8fTYzgu0T5cSoLZOQyfs23Y6wHKVtgAyKByh8VsA==","signatures":[{"sig":"MEYCIQCNt5H1aPykAgEbT3K2LJeb5YSVj0dkEEIHbcumtF3MLwIhAPv+tkqoajms6ICvAzcAKNE+iIt3j++RjKtoe0DKuQL4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":198954},"main":"./dist/cjs/index.js","type":"module","_from":"file:bitkaio-langchain-kubernetes-0.0.1.tgz","types":"./dist/types/index.d.ts","module":"./dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"}},"scripts":{"lint":"eslint src/","test":"vitest run tests/unit","build":"tsc -p tsconfig.build.json && tsc -p tsconfig.build.cjs.json","test:all":"vitest run","typecheck":"tsc --noEmit","test:integration":"K8S_INTEGRATION=1 vitest run tests/integration"},"_npmUser":{"name":"bitkaio_team","email":"team@bitkaio.com"},"_resolved":"/private/var/folders/r5/xf07fdqs66nb8vzm7vgtrkqm0000gn/T/2a882c2fdae58b303659bd48720bd164/bitkaio-langchain-kubernetes-0.0.1.tgz","_integrity":"sha512-8SdBh3nFNz6smT92XXj3yt0gLJO2nn4UyM0f3Gx8HQj93s8fTYzgu0T5cSoLZOQyfs23Y6wHKVtgAyKByh8VsA==","repository":{"url":"git+https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox.git","type":"git"},"_npmVersion":"10.9.3","description":"Kubernetes sandbox provider for the DeepAgents framework","directories":{},"_nodeVersion":"22.19.0","dependencies":{"deepagents":">=0.1.0","tar-stream":"^3.1.0","@kubernetes/client-node":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0","typescript":"^5.5.0","@types/node":"^22.0.0","@types/tar-stream":"^3.1.0"},"_npmOperationalInternal":{"tmp":"tmp/langchain-kubernetes_0.0.1_1772966707523_0.5566365487688294","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bitkaio/langchain-kubernetes","version":"0.2.0","keywords":["langchain","deepagents","kubernetes","sandbox","agents"],"author":{"name":"bitkaio LLC"},"license":"MIT","_id":"@bitkaio/langchain-kubernetes@0.2.0","maintainers":[{"name":"bitkaio_team","email":"team@bitkaio.com"}],"homepage":"https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox#readme","bugs":{"url":"https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox/issues"},"dist":{"shasum":"533f9db24512b796b0bfc87588403282396c1b92","tarball":"https://registry.npmjs.org/@bitkaio/langchain-kubernetes/-/langchain-kubernetes-0.2.0.tgz","fileCount":100,"integrity":"sha512-8PP4gmskHcBAE9ulo7RitiUaTd3J5WVxwyfXLn+EPwMfA7nMEJqIiPzjoEaC5uSd5ZNwIqMubh1Cfvk3zj32/w==","signatures":[{"sig":"MEUCIQCp9tQnAbRVm4sKzcLSZGdlLhPqKHLqvI94o9GBdz2ggAIgMgjYjYqE6gQ+fz3Qblpd3sxiMJaUeAtICFhSmtp8DVQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bitkaio%2flangchain-kubernetes@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":364869},"main":"./dist/cjs/index.js","type":"module","types":"./dist/types/index.d.ts","module":"./dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"}},"gitHead":"869eab0ff21fab3c49895d0275a40d449cf5f3d4","scripts":{"lint":"eslint src/","test":"vitest run tests/unit","build":"tsc -p tsconfig.build.json && tsc -p tsconfig.build.cjs.json","test:all":"vitest run","typecheck":"tsc --noEmit","test:integration":"K8S_INTEGRATION=1 vitest run tests/integration"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:ca5d45ed-98b6-470f-a666-f7b8fdc9645a"}},"repository":{"url":"git+https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox.git","type":"git"},"_npmVersion":"11.11.0","description":"Kubernetes sandbox provider for the DeepAgents framework","directories":{},"_nodeVersion":"22.22.1","dependencies":{"deepagents":">=0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0","tar-stream":"^3.1.0","typescript":"^5.5.0","@types/node":"^22.0.0","@types/tar-stream":"^3.1.0","@kubernetes/client-node":"^1.0.0"},"optionalDependencies":{"tar-stream":"^3.1.0","@kubernetes/client-node":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/langchain-kubernetes_0.2.0_1773089774219_0.7052649829972402","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bitkaio/langchain-kubernetes","version":"0.3.0","description":"Kubernetes sandbox provider for the DeepAgents framework","license":"MIT","author":{"name":"bitkaio LLC"},"keywords":["langchain","deepagents","kubernetes","sandbox","agents"],"type":"module","exports":{".":{"import":"./dist/esm/index.js","require":"./dist/cjs/index.js","types":"./dist/types/index.d.ts"}},"main":"./dist/cjs/index.js","module":"./dist/esm/index.js","types":"./dist/types/index.d.ts","scripts":{"build":"tsc -p tsconfig.build.json && tsc -p tsconfig.build.cjs.json","test":"vitest run tests/unit","test:integration":"K8S_INTEGRATION=1 vitest run tests/integration","test:all":"vitest run","lint":"eslint src/","typecheck":"tsc --noEmit"},"dependencies":{"deepagents":">=0.1.0"},"optionalDependencies":{"@kubernetes/client-node":"^1.0.0","tar-stream":"^3.1.0"},"devDependencies":{"@kubernetes/client-node":"^1.0.0","tar-stream":"^3.1.0","typescript":"^5.5.0","vitest":"^2.0.0","@types/node":"^22.0.0","@types/tar-stream":"^3.1.0"},"engines":{"node":">=18.0.0"},"repository":{"type":"git","url":"git+https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox.git"},"gitHead":"224512c76cb35d2f786106c5ba517c4de16fbdd5","_id":"@bitkaio/langchain-kubernetes@0.3.0","bugs":{"url":"https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox/issues"},"homepage":"https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox#readme","_nodeVersion":"22.22.1","_npmVersion":"11.12.0","dist":{"integrity":"sha512-Leen6kWmdL7wNizHOi+DabpTq30Z2BA0TskA2GFSEdciQnVN4bkdI1AP5miC8SBxLgM2J+Tuhed+pK/32Fnkkg==","shasum":"a68f566fd922b2bb8dd36e8ac72e0964bd70c8a8","tarball":"https://registry.npmjs.org/@bitkaio/langchain-kubernetes/-/langchain-kubernetes-0.3.0.tgz","fileCount":114,"unpackedSize":564950,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bitkaio%2flangchain-kubernetes@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIASURaFFRumezImZ7UqvRFE5g0TsZOqhrh/ALOzeK1aaAiBh0rNQrozQt2j05I12EHQgHdStNT64MwDJGNyHu5Scmg=="}]},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:ca5d45ed-98b6-470f-a666-f7b8fdc9645a"}},"directories":{},"maintainers":[{"name":"bitkaio_team","email":"team@bitkaio.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/langchain-kubernetes_0.3.0_1774102703010_0.8011552569546112"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-08T10:45:07.427Z","modified":"2026-03-21T14:18:23.591Z","0.0.1":"2026-03-08T10:45:07.668Z","0.2.0":"2026-03-09T20:56:14.365Z","0.3.0":"2026-03-21T14:18:23.232Z"},"bugs":{"url":"https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox/issues"},"author":{"name":"bitkaio LLC"},"license":"MIT","homepage":"https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox#readme","keywords":["langchain","deepagents","kubernetes","sandbox","agents"],"repository":{"type":"git","url":"git+https://gitlab.com/bitkaio/langchain/deepagents-kubernetes-sandbox.git"},"description":"Kubernetes sandbox provider for the DeepAgents framework","maintainers":[{"name":"bitkaio_team","email":"team@bitkaio.com"}],"readme":"# @bitkaio/langchain-kubernetes\n\nKubernetes sandbox provider for the [DeepAgents](https://github.com/langchain-ai/deepagents) framework (TypeScript).\n\nSupports two backend modes:\n\n| Mode | Requirements | Best for |\n| ---- | ------------ | -------- |\n| **`agent-sandbox`** (default) | [`kubernetes-sigs/agent-sandbox`](https://github.com/kubernetes-sigs/agent-sandbox) controller + CRDs | Production — warm pools, gVisor/Kata, sub-second startup |\n| **`raw`** | Any cluster, `@kubernetes/client-node` + `tar-stream` | Dev / clusters where you can't install CRDs |\n\n## Installation\n\n```bash\n# agent-sandbox mode — no extra deps (fetch is built in)\nnpm install @bitkaio/langchain-kubernetes\n\n# raw mode — additional deps required\nnpm install @bitkaio/langchain-kubernetes @kubernetes/client-node tar-stream\n```\n\n## Quick start\n\n### agent-sandbox mode\n\n```typescript\nimport { KubernetesProvider } from \"@bitkaio/langchain-kubernetes\";\n\nconst provider = new KubernetesProvider({\n  mode: \"agent-sandbox\",\n  routerUrl: \"http://sandbox-router-svc.default.svc.cluster.local:8080\",\n  templateName: \"python-sandbox-template\",\n});\n\nconst sandbox = await provider.getOrCreate();\n\nconst result = await sandbox.execute(\"python3 -c 'print(2 + 2)'\");\nconsole.log(result.output);   // \"4\\n\"\nconsole.log(result.exitCode); // 0\n\nawait provider.delete(sandbox.id);\n```\n\n### raw mode\n\n```typescript\nimport { KubernetesProvider } from \"@bitkaio/langchain-kubernetes\";\n\nconst provider = new KubernetesProvider({\n  mode: \"raw\",\n  image: \"python:3.12-slim\",\n});\n\nconst sandbox = await provider.getOrCreate();\nconst result  = await sandbox.execute(\"python3 -c 'print(42)'\");\nawait provider.delete(sandbox.id);\n```\n\n## Configuration reference\n\n### Shared options\n\n| Field | Type | Default | Description |\n| ----- | ---- | ------- | ----------- |\n| `mode` | `\"agent-sandbox\" \\| \"raw\"` | `\"agent-sandbox\"` | Backend mode |\n| `namespace` | `string` | `\"deepagents-sandboxes\"` | Kubernetes namespace |\n| `startupTimeoutMs` | `number` | `120_000` | Ms to wait for sandbox to be ready |\n| `executeTimeoutMs` | `number` | `300_000` | Default ms per `execute()` call |\n\n### agent-sandbox mode options\n\n| Field | Type | Required | Description |\n| ----- | ---- | -------- | ----------- |\n| `routerUrl` | `string` | Yes | URL of the sandbox-router service |\n| `templateName` | `string` | Yes | `SandboxTemplate` name to instantiate |\n| `serverPort` | `number` | No (8888) | Port the sandbox runtime listens on |\n| `kubeApiUrl` | `string` | No | Kubernetes API URL. Defaults to in-cluster URL. Use `http://localhost:8001` for `kubectl proxy`. |\n| `kubeToken` | `string` | No | Bearer token for k8s API. Auto-read from service account if omitted. |\n\n### raw mode options\n\n| Field | Type | Default | Description |\n| ----- | ---- | ------- | ----------- |\n| `image` | `string` | `\"python:3.12-slim\"` | Container image |\n| `imagePullPolicy` | `string` | `\"IfNotPresent\"` | Image pull policy |\n| `workdir` | `string` | `\"/workspace\"` | Working directory inside container |\n| `command` | `string[]` | `[\"sleep\", \"infinity\"]` | Container entrypoint |\n| `env` | `Record<string, string>` | — | Extra environment variables |\n| `cpuRequest` / `cpuLimit` | `string` | `\"100m\"` / `\"1000m\"` | CPU resources |\n| `memoryRequest` / `memoryLimit` | `string` | `\"256Mi\"` / `\"1Gi\"` | Memory resources |\n| `ephemeralStorageLimit` | `string` | `\"5Gi\"` | Ephemeral storage limit |\n| `blockNetwork` | `boolean` | `true` | Attach deny-all NetworkPolicy |\n| `runAsUser` / `runAsGroup` | `number` | `1000` / `1000` | UID/GID inside container |\n| `seccompProfile` | `string` | `\"RuntimeDefault\"` | seccomp profile type |\n| `namespacePerSandbox` | `boolean` | `false` | Give each sandbox its own namespace |\n| `kubeconfigPath` | `string` | — | Path to kubeconfig file |\n| `context` | `string` | — | Kubeconfig context to use |\n\n## Sandbox API\n\nEvery sandbox extends `BaseSandbox` from the `deepagents` package:\n\n```typescript\n// Execute a shell command\nconst result = await sandbox.execute(\"ls -la /workspace\");\n// result.output    — combined stdout + stderr\n// result.exitCode  — process exit code\n// result.truncated — true if output was capped at outputLimitBytes\n\n// Upload files\nconst results = await sandbox.uploadFiles([\n  [\"/workspace/script.py\", Buffer.from(\"print('hello')\")],\n  [\"/workspace/data.json\", Buffer.from('{\"key\": \"value\"}')],\n]);\n// results[0].error — null on success, \"file_not_found\" | \"permission_denied\" etc. on failure\n\n// Download files\nconst downloads = await sandbox.downloadFiles([\"/workspace/output.txt\"]);\n// downloads[0].content — Uint8Array | null\n// downloads[0].error   — null on success\n\n// BaseSandbox also provides higher-level helpers built on execute():\n// sandbox.ls(), sandbox.read(), sandbox.write(), sandbox.glob(), ...\n```\n\n## Usage with DeepAgents\n\n`KubernetesSandbox` plugs directly into\n[DeepAgents](https://github.com/langchain-ai/deepagents) via the `backend` parameter of\n`createDeepAgent`. When a sandbox backend is set, the agent automatically gains an\n`execute` tool for running shell commands in addition to the standard filesystem tools.\n\n### One-shot usage\n\n```typescript\nimport { ChatAnthropic } from \"@langchain/anthropic\";\nimport { createDeepAgent } from \"deepagents\";\nimport { KubernetesProvider } from \"@bitkaio/langchain-kubernetes\";\n\nconst provider = new KubernetesProvider({\n  routerUrl: \"http://sandbox-router-svc.default.svc.cluster.local:8080\",\n  templateName: \"python-sandbox-template\",\n  // mode: \"raw\", image: \"python:3.12-slim\",  // raw mode alternative\n});\n\nconst sandbox = await provider.getOrCreate();\nconst llm = new ChatAnthropic({ model: \"claude-opus-4-6\" });\nconst agent = createDeepAgent({ model: llm, backend: sandbox });\n\nconst result = await agent.invoke({\n  messages: [{ role: \"user\", content: \"Write and run a Python script that prints the Fibonacci sequence\" }],\n});\nconsole.log(result.messages.at(-1)?.content);\n\nawait provider.delete(sandbox.id);\n```\n\n### Multi-turn: persistent sandbox per conversation\n\nFor multi-turn applications you need the same sandbox to survive across turns — installed\npackages, written files, and shell state must all be retained between messages.\n\n`KubernetesSandboxManager.createAgent(llm)` returns a ready-to-use DeepAgents agent that\nhandles this automatically. Each turn it reconnects to the same sandbox using the\nconversation `thread_id`; if the sandbox has expired it provisions a new one\ntransparently.\n\n#### Behind Express / Hono\n\n```typescript\nimport express from \"express\";\nimport { MemorySaver } from \"@langchain/langgraph\";\nimport { ChatAnthropic } from \"@langchain/anthropic\";\nimport { KubernetesSandboxManager } from \"@bitkaio/langchain-kubernetes\";\n\nconst manager = new KubernetesSandboxManager(\n  {\n    routerUrl: \"http://sandbox-router-svc.default.svc.cluster.local:8080\",\n    templateName: \"python-sandbox-template\",\n  },\n  { ttlIdleSeconds: 1800 },\n);\nconst llm = new ChatAnthropic({ model: \"claude-opus-4-6\" });\n\n// MemorySaver keeps state in-process.\n// Replace with a persistent checkpointer for multi-process deployments.\nconst agent = await manager.createAgent(llm, { checkpointer: new MemorySaver() });\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/chat/:threadId\", async (req, res) => {\n  const result = await agent.invoke(\n    { messages: [{ role: \"user\", content: req.body.message }] },\n    { configurable: { thread_id: req.params.threadId } },\n  );\n  res.json({ reply: result.messages.at(-1)?.content });\n});\n\nprocess.on(\"SIGTERM\", () => manager.shutdown());\napp.listen(3000);\n```\n\nEach `thread_id` gets its own sandbox. The first request provisions a new one; every\nsubsequent request reconnects to the same one.\n\n#### With `langgraph dev` / LangGraph Platform\n\nYes — **each LangGraph thread automatically gets its own persistent sandbox.**\n`createAgent()` stores the `sandboxId` as a field in graph state. The LangGraph\nPlatform (and `langgraph dev`) checkpoint the entire graph state — including\n`sandboxId` — between runs for each thread. When the same thread sends its next\nmessage, the platform restores the state and the agent reconnects to the same sandbox\nautomatically. No extra configuration is needed.\n\nExport the compiled agent from `agent.ts` and point `langgraph.json` at it:\n\n**`agent.ts`:**\n\n```typescript\nimport { ChatAnthropic } from \"@langchain/anthropic\";\nimport { KubernetesSandboxManager } from \"@bitkaio/langchain-kubernetes\";\n\nconst manager = new KubernetesSandboxManager(\n  {\n    routerUrl: \"http://sandbox-router-svc.default.svc.cluster.local:8080\",\n    templateName: \"python-sandbox-template\",\n    warmPoolName: \"python-pool\",   // optional: sub-second startup\n  },\n  { ttlIdleSeconds: 1800, defaultLabels: { app: \"my-agent\" } },\n);\n\nconst llm = new ChatAnthropic({ model: \"claude-opus-4-6\" });\n\n// The platform provides the checkpointer — omit it here\nexport const graph = await manager.createAgent(llm);\n```\n\n**`langgraph.json`:**\n\n```json\n{\n    \"graphs\": {\n        \"agent\": \"./agent.ts:graph\"\n    }\n}\n```\n\n```bash\nnpx @langchain/langgraph-cli dev\n# → http://localhost:2024\n```\n\nInteract via the LangGraph SDK — threads and sandbox persistence are handled automatically:\n\n```typescript\nimport { Client } from \"@langchain/langgraph-sdk\";\n\nconst client = new Client({ apiUrl: \"http://localhost:2024\" });\nconst thread = await client.threads.create();\n\n// First run — provisions a sandbox for this thread\nawait client.runs.create(thread.thread_id, \"agent\", {\n  input: { messages: [{ role: \"user\", content: \"Install pandas and analyse the iris dataset\" }] },\n});\n\n// Second run — reconnects to the same sandbox automatically\nawait client.runs.create(thread.thread_id, \"agent\", {\n  input: { messages: [{ role: \"user\", content: \"Now plot a histogram of petal length\" }] },\n});\n```\n\n#### Custom `systemPrompt` and tools\n\nExtra options passed to `createAgent` are forwarded to `createDeepAgent`:\n\n```typescript\nconst agent = await manager.createAgent(llm, {\n  checkpointer: new MemorySaver(),\n  systemPrompt: \"You are a data analyst. Always save outputs to /workspace/output/.\",\n  // tools: [myCustomTool],\n});\n```\n\n**`KubernetesSandboxManagerOptions`:**\n\n| Field | Type | Default | Description |\n| ----- | ---- | ------- | ----------- |\n| `ttlSeconds` | `number \\| undefined` | — | Absolute TTL from creation (seconds) |\n| `ttlIdleSeconds` | `number \\| undefined` | — | Idle TTL from last `execute()` (seconds) |\n| `defaultLabels` | `Record<string, string> \\| undefined` | — | Labels applied to every sandbox (auto-prefixed) |\n\n**Methods:**\n\n| Method | Returns | Description |\n| ------ | ------- | ----------- |\n| `createAgent(model, options?)` | `Promise<CompiledGraph>` | Returns a compiled DeepAgents agent with sandbox persistence (primary integration point) |\n| `createAgentNode(model, options?)` | `AsyncNodeFn` | Returns a single LangGraph node; use when building a multi-node graph |\n| `getOrReconnect(sandboxId)` | `Promise<KubernetesSandbox>` | Reconnect or create; for custom node logic |\n| `cleanup(maxIdleSeconds?)` | `Promise<CleanupResult>` | Delete expired sandboxes |\n| `shutdown()` | `Promise<void>` | Delete all sandboxes |\n| `[Symbol.asyncDispose]()` | `Promise<void>` | Called by `await using` |\n\n## Sandbox lifecycle management\n\n### Provider API — getOrCreate and reconnect\n\nThe provider is stateless: it does not cache sandboxes in memory. Callers are responsible\nfor persisting `sandbox.id` between calls (LangGraph handles this via its checkpointer).\n\n```typescript\n// Create new sandbox\nconst sandbox = await provider.getOrCreate();\n\n// Reconnect to an existing sandbox, or create a new one if it no longer exists\nconst sandbox = await provider.getOrCreate({\n  sandboxId: \"existing-id\",             // from LangGraph state\n  labels: { customer: \"acme\" },         // auto-prefixed with langchain-kubernetes.bitkaio.com/\n  ttlSeconds: 3600,\n  ttlIdleSeconds: 600,\n});\n\n// List all managed sandboxes from the K8s API\nconst { sandboxes, cursor } = await provider.list();\nconst { sandboxes: running } = await provider.list({ status: \"running\" });\nconst { sandboxes: labelled } = await provider.list({ labels: { customer: \"acme\" } });\n// Pagination:\nconst page2 = await provider.list({ cursor });\n\n// Operational methods\nconst result = await provider.cleanup();               // CleanupResult\nconst result = await provider.cleanup(300);            // override idle threshold (seconds)\nconst status = await provider.poolStatus();            // WarmPoolStatus\n\n// Delete (idempotent)\nawait provider.delete(sandbox.id);\n```\n\n**`GetOrCreateOptions`:**\n\n| Field | Type | Description |\n| ----- | ---- | ----------- |\n| `sandboxId` | `string \\| undefined` | Existing sandbox ID to reconnect (from graph state) |\n| `labels` | `Record<string, string> \\| undefined` | Per-call labels (auto-prefixed) |\n| `ttlSeconds` | `number \\| undefined` | Absolute TTL override (seconds) |\n| `ttlIdleSeconds` | `number \\| undefined` | Idle TTL override (seconds) |\n\n**`SandboxListResponse`:**\n\n```typescript\ninterface SandboxListResponse {\n  sandboxes: SandboxInfo[];\n  cursor?: string;  // Kubernetes continue token for pagination\n}\n\ninterface SandboxInfo {\n  id: string;\n  namespace: string;\n  labels?: Record<string, string>;\n  annotations?: Record<string, string>;\n  createdAt?: string;    // ISO-8601\n  phase?: string;        // Kubernetes Pod phase\n  status?: string;       // \"running\" | \"warm\" | \"pending\" | \"terminated\"\n}\n```\n\n**`CleanupResult` / `WarmPoolStatus`:**\n\n```typescript\ninterface CleanupResult {\n  deleted: string[];  // sandbox IDs that were deleted\n  kept: number;       // sandboxes within their TTL / idle threshold\n}\n\ninterface WarmPoolStatus {\n  available: number;  // warm Pods ready to be claimed\n  active: number;     // Pods currently assigned\n  total: number;\n  target: number;     // configured warmPoolSize\n}\n```\n\n### Additional configuration options\n\n| Field | Type | Default | Description |\n| ----- | ---- | ------- | ----------- |\n| `defaultLabels` | `Record<string, string> \\| undefined` | — | Labels applied to every sandbox (auto-prefixed with `langchain-kubernetes.bitkaio.com/`) |\n| `ttlSeconds` | `number \\| undefined` | — | Default absolute TTL for `getOrCreate()` |\n| `ttlIdleSeconds` | `number \\| undefined` | — | Default idle TTL for `getOrCreate()` |\n| `warmPoolSize` | `number \\| undefined` | — | Pre-created warm Pods (raw mode only) |\n| `warmPoolName` | `string \\| undefined` | — | `SandboxWarmPool` resource name (agent-sandbox only) |\n\n### Warm pool configuration\n\n**agent-sandbox mode:**\n\n```typescript\nconst provider = new KubernetesProvider({\n  mode: \"agent-sandbox\",\n  routerUrl: \"http://sandbox-router-svc.default.svc.cluster.local:8080\",\n  templateName: \"python-sandbox-template\",\n  warmPoolName: \"python-pool\",   // name of a SandboxWarmPool CRD in the cluster\n});\n```\n\n**raw mode:**\n\n```typescript\nconst provider = new KubernetesProvider({\n  mode: \"raw\",\n  warmPoolSize: 3,   // pre-create 3 idle Pods, replenish after each delete\n});\n```\n\nSee [`docs/warm-pool.yaml`](../docs/warm-pool.yaml) for cluster YAML examples.\n\n## agent-sandbox mode — setup\n\n### 1. Install the controller\n\nFollow the [agent-sandbox installation guide](https://github.com/kubernetes-sigs/agent-sandbox).\n\n### 2. Create a SandboxTemplate\n\n```yaml\n# examples/k8s/sandbox-template.yaml\napiVersion: extensions.agents.x-k8s.io/v1alpha1\nkind: SandboxTemplate\nmetadata:\n  name: python-sandbox-template\n  namespace: default\nspec:\n  podTemplate:\n    spec:\n      containers:\n      - name: python-runtime\n        image: us-central1-docker.pkg.dev/k8s-staging-images/agent-sandbox/python-runtime-sandbox:latest-main\n        ports:\n        - containerPort: 8888\n        readinessProbe:\n          httpGet: { path: \"/\", port: 8888 }\n          periodSeconds: 1\n        resources:\n          requests: { cpu: \"250m\", memory: \"512Mi\" }\n      restartPolicy: \"OnFailure\"\n```\n\n```bash\nkubectl apply -f examples/k8s/sandbox-template.yaml\n```\n\n### 3. Apply RBAC\n\n```bash\nkubectl apply -f examples/k8s/sandbox-router-rbac.yaml\n```\n\n### 4. Connect\n\n**In-cluster** (the primary use case):\n\n```typescript\nconst provider = new KubernetesProvider({\n  routerUrl: \"http://sandbox-router-svc.default.svc.cluster.local:8080\",\n  templateName: \"python-sandbox-template\",\n});\n```\n\n**Local development** — forward the sandbox-router to localhost:\n\n```bash\nkubectl port-forward svc/sandbox-router-svc 8080:8080 -n default\n```\n\n```typescript\nconst provider = new KubernetesProvider({\n  routerUrl: \"http://localhost:8080\",\n  templateName: \"python-sandbox-template\",\n  // Optional: set kubeApiUrl for sandbox existence verification\n  // kubeApiUrl: \"http://localhost:8001\",  // kubectl proxy\n});\n```\n\n## raw mode — setup\n\n### 1. Create the namespace\n\n```bash\nkubectl create namespace deepagents-sandboxes\n```\n\n### 2. Apply RBAC\n\n```bash\nkubectl apply -f examples/k8s/raw-mode-rbac.yaml\n```\n\n### 3. Configure\n\n```typescript\nconst provider = new KubernetesProvider({\n  mode: \"raw\",\n  namespace: \"deepagents-sandboxes\",\n  image: \"python:3.12-slim\",\n  blockNetwork: true, // deny-all NetworkPolicy (requires NetworkPolicy-capable CNI)\n});\n```\n\nFor local kind clusters, `kindnet` does not support NetworkPolicy. Either use Calico or set `blockNetwork: false`.\n\n## Error handling\n\n```typescript\nimport {\n  SandboxNotFoundError,\n  SandboxStartupTimeoutError,\n  SandboxRouterError,\n  TemplateNotFoundError,\n  MissingDependencyError,\n} from \"@bitkaio/langchain-kubernetes\";\n\ntry {\n  const sandbox = await provider.getOrCreate();\n} catch (err) {\n  if (err instanceof TemplateNotFoundError) {\n    // SandboxTemplate doesn't exist in the cluster\n  } else if (err instanceof SandboxStartupTimeoutError) {\n    // Sandbox didn't become ready in time\n  } else if (err instanceof SandboxRouterError) {\n    // Router or Kubernetes API not reachable\n  } else if (err instanceof MissingDependencyError) {\n    // @kubernetes/client-node not installed (raw mode)\n  }\n}\n```\n\n## Integration tests\n\nIntegration tests require a running cluster:\n\n```bash\n# raw mode (any cluster)\nK8S_INTEGRATION=1 npm run test:integration\n\n# agent-sandbox mode (requires controller + CRDs)\nK8S_INTEGRATION=1 SANDBOX_TEMPLATE=python-sandbox-template \\\n  ROUTER_URL=http://localhost:8080 npm run test:integration\n```\n\n## Requirements\n\n- Node.js ≥ 18\n- Kubernetes cluster (kind, GKE, EKS, AKS, OpenShift, …)\n- For `agent-sandbox` mode: [`kubernetes-sigs/agent-sandbox`](https://github.com/kubernetes-sigs/agent-sandbox) controller\n- For `raw` mode: `@kubernetes/client-node` + `tar-stream`; NetworkPolicy-capable CNI if `blockNetwork: true`\n","readmeFilename":"README.md"}