Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ tests/tmp/
tests/.tmp/
*.log
*.txt
.kode/
.kode/
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- **Long-Running & Resumable** - Seven-stage checkpoints with Safe-Fork-Point for crash recovery
- **Multi-Agent Collaboration** - AgentPool, Room messaging, and task delegation
- **Enterprise Persistence** - SQLite/PostgreSQL support with unified WAL
- **Cloud Sandbox** - [E2B](https://e2b.dev) integration for isolated remote code execution
- **Cloud Sandbox** - [E2B](https://e2b.dev) and OpenSandbox integration for isolated remote code execution
- **Extensible Ecosystem** - MCP tools, custom Providers, Skills system

## Quick Start
Expand Down Expand Up @@ -79,6 +79,15 @@ npm run example:getting-started # Minimal chat
npm run example:agent-inbox # Event-driven inbox
npm run example:approval # Tool approval workflow
npm run example:room # Multi-agent collaboration
npm run example:opensandbox # OpenSandbox basic usage
```

OpenSandbox quick config:

```bash
export OPEN_SANDBOX_API_KEY=... # optional (required only when auth is enabled)
export OPEN_SANDBOX_ENDPOINT=http://127.0.0.1:8080 # optional
export OPEN_SANDBOX_IMAGE=ubuntu # optional
```

## Architecture for Scale
Expand Down Expand Up @@ -142,6 +151,8 @@ See [docs/en/guides/architecture.md](./docs/en/guides/architecture.md) for detai
| **Guides** | |
| [Events](./docs/en/guides/events.md) | Three-channel event system |
| [Tools](./docs/en/guides/tools.md) | Built-in tools & custom tools |
| [E2B Sandbox](./docs/en/guides/e2b-sandbox.md) | E2B cloud sandbox integration |
| [OpenSandbox](./docs/en/guides/opensandbox-sandbox.md) | OpenSandbox self-hosted sandbox integration |
| [Skills](./docs/en/guides/skills.md) | Skills system for reusable prompts |
| [Providers](./docs/en/guides/providers.md) | Model provider configuration |
| [Database](./docs/en/guides/database.md) | SQLite/PostgreSQL persistence |
Expand Down
13 changes: 12 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- **长时运行与恢复** - 七段断点机制,支持 Safe-Fork-Point 崩溃恢复
- **多 Agent 协作** - AgentPool、Room 消息、任务委派
- **企业级持久化** - 支持 SQLite/PostgreSQL,统一 WAL 日志
- **云端沙箱** - 集成 [E2B](https://e2b.dev),提供隔离的远程代码执行环境
- **云端沙箱** - 集成 [E2B](https://e2b.dev) 与 OpenSandbox,提供隔离的远程代码执行环境
- **可扩展生态** - MCP 工具、自定义 Provider、Skills 系统

## 快速开始
Expand Down Expand Up @@ -79,6 +79,15 @@ npm run example:getting-started # 最简对话
npm run example:agent-inbox # 事件驱动收件箱
npm run example:approval # 工具审批流程
npm run example:room # 多Agent协作
npm run example:opensandbox # OpenSandbox 基础使用
```

OpenSandbox 快速配置:

```bash
export OPEN_SANDBOX_API_KEY=... # 可选(仅在服务开启鉴权时需要)
export OPEN_SANDBOX_ENDPOINT=http://127.0.0.1:8080 # 可选
export OPEN_SANDBOX_IMAGE=ubuntu # 可选
```

## 支持的 Provider
Expand All @@ -102,6 +111,8 @@ npm run example:room # 多Agent协作
| **使用指南** | |
| [事件系统](./docs/zh-CN/guides/events.md) | 三通道事件系统 |
| [工具系统](./docs/zh-CN/guides/tools.md) | 内置工具与自定义工具 |
| [E2B 沙箱](./docs/zh-CN/guides/e2b-sandbox.md) | E2B 云端沙箱接入 |
| [OpenSandbox 沙箱](./docs/zh-CN/guides/opensandbox-sandbox.md) | OpenSandbox 自托管沙箱接入 |
| [Skills 系统](./docs/zh-CN/guides/skills.md) | Skills 可复用提示词系统 |
| [Provider 配置](./docs/zh-CN/guides/providers.md) | 模型 Provider 配置 |
| [数据库存储](./docs/zh-CN/guides/database.md) | SQLite/PostgreSQL 持久化 |
Expand Down
185 changes: 185 additions & 0 deletions docs/en/guides/opensandbox-sandbox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# OpenSandbox Guide

KODE SDK supports OpenSandbox as a sandbox backend for isolated command execution and file operations.

---

## Overview

| Feature | Description |
|---------|-------------|
| **Deployment** | Self-hosted OpenSandbox server |
| **Runtime** | Container-based isolated execution environment |
| **Lifecycle** | Create/connect/dispose by `sandboxId` |
| **Compatibility** | Works with existing `bash_*` and `fs_*` tools |

### When to Use OpenSandbox vs E2B vs Local

| Scenario | Recommended |
|----------|-------------|
| You need self-hosted control in your own infra | OpenSandbox |
| You want fully managed cloud sandbox | E2B |
| Local development and offline debugging | Local Sandbox |

---

## Prerequisites

1. Docker daemon is running and can pull required images.
2. OpenSandbox server is running (for example on `http://127.0.0.1:8080`).
3. If your server enables auth, prepare an API key.

Optional environment variables:

```bash
export OPEN_SANDBOX_API_KEY=... # optional, only when auth is enabled
export OPEN_SANDBOX_ENDPOINT=http://127.0.0.1:8080 # optional
export OPEN_SANDBOX_IMAGE=ubuntu # optional
```

---

## Quick Start

### Create and Use a Sandbox

```typescript
import { OpenSandbox } from '@shareai-lab/kode-sdk';

const sandbox = new OpenSandbox({
kind: 'opensandbox',
apiKey: process.env.OPEN_SANDBOX_API_KEY,
endpoint: process.env.OPEN_SANDBOX_ENDPOINT,
image: process.env.OPEN_SANDBOX_IMAGE || 'ubuntu',
timeoutMs: 600_000,
execTimeoutMs: 120_000,
useServerProxy: false,
watch: { mode: 'polling', pollIntervalMs: 1000 },
lifecycle: { disposeAction: 'kill' },
});

await sandbox.init();
console.log('sandboxId:', sandbox.getSandboxId());

const result = await sandbox.exec('echo "hello opensandbox"');
console.log(result.code, result.stdout.trim());

await sandbox.fs.write('demo.txt', 'hello from opensandbox');
const content = await sandbox.fs.read('demo.txt');
console.log(content.trim());

await sandbox.dispose();
```

---

## Configuration

### OpenSandboxOptions

```typescript
interface OpenSandboxOptions {
kind: 'opensandbox';
apiKey?: string;
endpoint?: string;
domain?: string;
protocol?: 'http' | 'https';
sandboxId?: string;
image?: string;
template?: string; // alias of image in current implementation
workDir?: string; // default '/workspace'
timeoutMs?: number;
execTimeoutMs?: number;
requestTimeoutSeconds?: number;
useServerProxy?: boolean; // default false
env?: Record<string, string>;
metadata?: Record<string, string>;
resource?: Record<string, string>;
networkPolicy?: Record<string, any>;
skipHealthCheck?: boolean;
readyTimeoutSeconds?: number;
healthCheckPollingInterval?: number;
watch?: {
mode?: 'native' | 'polling' | 'off'; // default 'polling'
pollIntervalMs?: number; // default 1000
};
lifecycle?: {
disposeAction?: 'close' | 'kill'; // default 'kill'
};
}
```

### Environment Variables

| Variable | Description |
|----------|-------------|
| `OPEN_SANDBOX_API_KEY` | Optional API key (required only when server auth is enabled) |
| `OPEN_SANDBOX_ENDPOINT` | OpenSandbox server endpoint |
| `OPEN_SANDBOX_IMAGE` | Default image when creating a new sandbox |

---

## Agent Integration

### Use Sandbox Config (recommended)

```typescript
const agent = await Agent.create({
templateId: 'coder',
sandbox: {
kind: 'opensandbox',
endpoint: process.env.OPEN_SANDBOX_ENDPOINT,
apiKey: process.env.OPEN_SANDBOX_API_KEY,
image: 'debian:latest',
lifecycle: { disposeAction: 'kill' },
},
}, deps);
```

When you pass sandbox config, `SandboxFactory.createAsync()` initializes OpenSandbox automatically.

### Use Sandbox Instance

```typescript
const sandbox = new OpenSandbox({ kind: 'opensandbox', endpoint: 'http://127.0.0.1:8080' });
await sandbox.init();

const agent = await Agent.create({ templateId: 'coder', sandbox }, deps);
```

When you pass sandbox instance directly, call `sandbox.init()` yourself before `Agent.create()`.

### Resume with `sandboxId`

```typescript
const sandbox = new OpenSandbox({ kind: 'opensandbox', endpoint: 'http://127.0.0.1:8080' });
await sandbox.init();
const id = sandbox.getSandboxId();

const restored = new OpenSandbox({
kind: 'opensandbox',
endpoint: 'http://127.0.0.1:8080',
sandboxId: id,
});
await restored.init();
```

---

## Watch and Lifecycle Semantics

1. `watch.mode='native'` uses `inotifywait` in the sandbox container.
2. If `inotifywait` is unavailable or native stream exits unexpectedly, the SDK auto-falls back to polling mode.
3. `watch.mode='off'` disables file watch registration.
4. `disposeAction='kill'` performs `kill()` first, then `close()`.
5. `disposeAction='close'` only closes the connection.
6. Polling watch is level-triggered by mtime delta and may coalesce multiple writes within one polling interval.
7. Polling watch does not guarantee one callback per write operation; treat events as "file changed" hints.

---

## Troubleshooting

1. `DOCKER::SANDBOX_IMAGE_PULL_FAILED` or `DOCKER::SANDBOX_EXECD_START_FAILED`: Docker cannot pull required images (`image` and `opensandbox/execd`).
2. Verify OpenSandbox server endpoint is reachable from the SDK process.
3. If you use a proxy, verify Docker daemon proxy and OpenSandbox server network settings separately.
35 changes: 35 additions & 0 deletions docs/en/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,39 @@ new E2BSandbox(options?: E2BSandboxOptions)

---

## OpenSandbox

Self-hosted sandbox powered by [OpenSandbox](https://www.npmjs.com/package/@alibaba-group/opensandbox) for isolated code execution.

### Constructor

```typescript
new OpenSandbox(options: OpenSandboxOptions)
```

### Methods

| Method | Signature | Description |
|--------|-----------|-------------|
| `init()` | `async init(): Promise<void>` | Initialize (create or connect) sandbox |
| `exec(cmd, opts?)` | `async exec(cmd: string, opts?: { timeoutMs?: number }): Promise<SandboxExecResult>` | Execute a command |
| `dispose()` | `async dispose(): Promise<void>` | Dispose sandbox by lifecycle policy |
| `getSandboxId()` | `getSandboxId(): string \| undefined` | Get sandbox ID for persistence |
| `isRunning()` | `async isRunning(): Promise<boolean>` | Check if sandbox is alive |
| `watchFiles(paths, listener)` | `async watchFiles(...): Promise<string>` | Watch file changes (polling fallback supported) |
| `unwatchFiles(id)` | `unwatchFiles(id: string): void` | Stop watching |
| `getOpenSandbox()` | `getOpenSandbox(): OpenSandboxClient` | Access underlying OpenSandbox client |

### Properties

| Property | Type | Description |
|----------|------|-------------|
| `kind` | `'opensandbox'` | Sandbox type identifier |
| `workDir` | `string` | Working directory path |
| `fs` | `SandboxFS` | File system operations |

---

## E2BTemplateBuilder

Static utility for building custom E2B sandbox templates.
Expand Down Expand Up @@ -747,3 +780,5 @@ static async exists(alias: string, opts?: { apiKey?: string }): Promise<boolean>
- [Types Reference](./types.md)
- [Events Reference](./events-reference.md)
- [Guides](../guides/events.md)
- [E2B Sandbox Guide](../guides/e2b-sandbox.md)
- [OpenSandbox Guide](../guides/opensandbox-sandbox.md)
46 changes: 45 additions & 1 deletion docs/en/reference/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ interface SandboxConfig {
### SandboxKind

```typescript
type SandboxKind = 'local' | 'docker' | 'remote';
type SandboxKind = 'local' | 'docker' | 'k8s' | 'remote' | 'vfs' | 'e2b' | 'opensandbox';
```

---
Expand Down Expand Up @@ -516,6 +516,50 @@ interface E2BTemplateConfig {

---

## OpenSandbox Types

### OpenSandboxWatchMode

```typescript
type OpenSandboxWatchMode = 'native' | 'polling' | 'off';
```

### OpenSandboxOptions

```typescript
interface OpenSandboxOptions {
kind: 'opensandbox';
apiKey?: string;
endpoint?: string;
domain?: string;
protocol?: 'http' | 'https';
sandboxId?: string;
image?: string;
template?: string;
workDir?: string;
timeoutMs?: number;
execTimeoutMs?: number;
requestTimeoutSeconds?: number;
useServerProxy?: boolean;
env?: Record<string, string>;
metadata?: Record<string, string>;
resource?: Record<string, string>;
networkPolicy?: Record<string, any>;
skipHealthCheck?: boolean;
readyTimeoutSeconds?: number;
healthCheckPollingInterval?: number;
watch?: {
mode?: OpenSandboxWatchMode;
pollIntervalMs?: number;
};
lifecycle?: {
disposeAction?: 'close' | 'kill';
};
}
```

---

## References

- [API Reference](./api.md)
Expand Down
Loading