vercel-open-agents

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Vercel Open Agents

Vercel Open Agents

Skill by ara.so — AI Agent Skills collection.
Open Agents is an open-source template for building cloud-based coding agents that run as durable workflows on Vercel. It provides web UI, agent runtime, sandbox orchestration, and GitHub integration to execute multi-step coding tasks without local execution.
ara.so提供的Skill——AI Agent技能合集。
Open Agents是一个开源模板,用于构建基于云的编码Agent,这些Agent在Vercel上作为持久化工作流运行。它提供Web UI、Agent运行时、沙箱编排和GitHub集成,无需本地执行即可完成多步编码任务。

Architecture

架构

Open Agents uses a three-layer architecture:
text
Web App (Next.js) → Agent Workflow (Vercel Workflow SDK) → Sandbox VM (isolated execution)
Key principle: The agent runs outside the sandbox and interacts with it through tools. This separation enables:
  • Durable execution beyond single request lifecycles
  • Independent sandbox hibernation and resume
  • Flexible model/provider swapping
  • Clean separation of concerns
Open Agents采用三层架构:
text
Web App (Next.js) → Agent Workflow (Vercel Workflow SDK) → Sandbox VM (isolated execution)
核心原则:Agent在沙箱外部运行,并通过工具与其交互。这种分离实现了:
  • 超越单次请求生命周期的持久化执行
  • 独立的沙箱休眠与恢复
  • 灵活的模型/提供商切换
  • 清晰的关注点分离

Installation

安装

Deploy to Vercel

部署到Vercel

  1. Fork and import the repository to Vercel
  2. Generate secrets:
    bash
    openssl rand -base64 32  # for BETTER_AUTH_SECRET
  3. Set required environment variables:
    env
    POSTGRES_URL=your_neon_postgres_url
    BETTER_AUTH_SECRET=your_generated_secret
  4. Deploy to get production URL
    • Callback:
      https://YOUR_DOMAIN/api/auth/callback/vercel
  5. Add OAuth credentials:
    env
    NEXT_PUBLIC_VERCEL_APP_CLIENT_ID=your_client_id
    VERCEL_APP_CLIENT_SECRET=your_client_secret
  6. Create GitHub App (optional, for repo access):
    • Homepage:
      https://YOUR_DOMAIN
    • Callback:
      https://YOUR_DOMAIN/api/auth/callback/github
    • Setup URL:
      https://YOUR_DOMAIN/api/github/app/callback
    • Make app public for org installs
  7. Add GitHub credentials:
    env
    NEXT_PUBLIC_GITHUB_CLIENT_ID=your_github_app_client_id
    GITHUB_CLIENT_SECRET=your_github_app_client_secret
    GITHUB_APP_ID=your_app_id
    GITHUB_APP_PRIVATE_KEY=your_pem_private_key
    NEXT_PUBLIC_GITHUB_APP_SLUG=your_app_slug
    GITHUB_WEBHOOK_SECRET=your_webhook_secret
  1. 复刻并导入仓库到Vercel
  2. 生成密钥:
    bash
    openssl rand -base64 32  # for BETTER_AUTH_SECRET
  3. 设置必要的环境变量:
    env
    POSTGRES_URL=your_neon_postgres_url
    BETTER_AUTH_SECRET=your_generated_secret
  4. 部署以获取生产环境URL
    • 回调地址:
      https://YOUR_DOMAIN/api/auth/callback/vercel
  5. 添加OAuth凭证:
    env
    NEXT_PUBLIC_VERCEL_APP_CLIENT_ID=your_client_id
    VERCEL_APP_CLIENT_SECRET=your_client_secret
  6. 创建GitHub应用(可选,用于仓库访问):
    • 主页:
      https://YOUR_DOMAIN
    • 回调地址:
      https://YOUR_DOMAIN/api/auth/callback/github
    • 设置URL:
      https://YOUR_DOMAIN/api/github/app/callback
    • 将应用设为公开,以便组织安装
  7. 添加GitHub凭证:
    env
    NEXT_PUBLIC_GITHUB_CLIENT_ID=your_github_app_client_id
    GITHUB_CLIENT_SECRET=your_github_app_client_secret
    GITHUB_APP_ID=your_app_id
    GITHUB_APP_PRIVATE_KEY=your_pem_private_key
    NEXT_PUBLIC_GITHUB_APP_SLUG=your_app_slug
    GITHUB_WEBHOOK_SECRET=your_webhook_secret

Local Development

本地开发

bash
undefined
bash
undefined

Install dependencies

安装依赖

bun install
bun install

Copy environment template

复制环境变量模板

cp apps/web/.env.example apps/web/.env
cp apps/web/.env.example apps/web/.env

Fill in required variables in apps/web/.env

在apps/web/.env中填写必要变量

Start dev server

启动开发服务器

bun run web

For existing Vercel projects:
```bash
vc env pull
bun run web

对于已有的Vercel项目:
```bash
vc env pull

Core Concepts

核心概念

Workflows

工作流

Agent runs execute as Vercel Workflow SDK workflows, enabling:
  • Durable execution: survives across steps and deployments
  • Streaming: real-time updates to the UI
  • Cancellation: user-initiated stop
  • Resume: reconnect to active runs
Example workflow structure:
typescript
// apps/web/app/api/workflows/agent/route.ts
import { createWorkflow } from '@vercel/workflow-sdk';

export const POST = createWorkflow(async (context, data) => {
  const { message, sessionId } = data;
  
  // Agent execution happens in workflow steps
  const result = await context.run('agent-step', async () => {
    return await runAgent(message, sessionId);
  });
  
  return result;
});
Agent运行以Vercel Workflow SDK工作流的形式执行,支持:
  • 持久化执行:在多步骤和部署中保持运行状态
  • 流式传输:向UI实时推送更新
  • 取消:用户主动终止运行
  • 恢复:重新连接到活跃的运行任务
示例工作流结构:
typescript
// apps/web/app/api/workflows/agent/route.ts
import { createWorkflow } from '@vercel/workflow-sdk';

export const POST = createWorkflow(async (context, data) => {
  const { message, sessionId } = data;
  
  // Agent执行在工作流步骤中进行
  const result = await context.run('agent-step', async () => {
    return await runAgent(message, sessionId);
  });
  
  return result;
});

Sandboxes

沙箱

Sandboxes provide isolated execution environments with:
  • Filesystem access: read, write, search files
  • Shell execution: run commands
  • Git operations: clone, branch, commit, push
  • Port exposure:
    3000
    ,
    5173
    ,
    4321
    ,
    8000
  • Snapshot-based resume: hibernate and restore state
typescript
// packages/sandbox/src/client.ts
import { createSandbox } from '@vercel-labs/open-agents/sandbox';

const sandbox = await createSandbox({
  baseSnapshotId: process.env.VERCEL_SANDBOX_BASE_SNAPSHOT_ID,
});

// Execute commands
const result = await sandbox.exec('npm install');

// Read files
const content = await sandbox.readFile('package.json');

// Write files
await sandbox.writeFile('src/config.ts', configContent);
沙箱提供隔离的执行环境,具备以下能力:
  • 文件系统访问:读取、写入、搜索文件
  • Shell执行:运行命令
  • Git操作:克隆、分支、提交、推送
  • 端口暴露
    3000
    ,
    5173
    ,
    4321
    ,
    8000
  • 基于快照的恢复:休眠与恢复状态
typescript
// packages/sandbox/src/client.ts
import { createSandbox } from '@vercel-labs/open-agents/sandbox';

const sandbox = await createSandbox({
  baseSnapshotId: process.env.VERCEL_SANDBOX_BASE_SNAPSHOT_ID,
});

// 执行命令
const result = await sandbox.exec('npm install');

// 读取文件
const content = await sandbox.readFile('package.json');

// 写入文件
await sandbox.writeFile('src/config.ts', configContent);

Tools

工具

Agents interact with sandboxes through tools:
typescript
// packages/agent/src/tools/file-edit.ts
export const fileEditTool = {
  name: 'file_edit',
  description: 'Edit a file with search-and-replace',
  parameters: z.object({
    path: z.string(),
    search: z.string(),
    replace: z.string(),
  }),
  execute: async ({ path, search, replace }, context) => {
    const content = await context.sandbox.readFile(path);
    const updated = content.replace(search, replace);
    await context.sandbox.writeFile(path, updated);
    return { success: true };
  },
};
Available tools:
  • file_read: Read file contents
  • file_write: Write entire file
  • file_edit: Search-and-replace edits
  • file_search: Search file contents
  • shell: Execute shell commands
  • task: Create subtasks for the agent
  • web: Fetch web content
  • skill: Access domain-specific skills
Agent通过工具与沙箱交互:
typescript
// packages/agent/src/tools/file-edit.ts
export const fileEditTool = {
  name: 'file_edit',
  description: 'Edit a file with search-and-replace',
  parameters: z.object({
    path: z.string(),
    search: z.string(),
    replace: z.string(),
  }),
  execute: async ({ path, search, replace }, context) => {
    const content = await context.sandbox.readFile(path);
    const updated = content.replace(search, replace);
    await context.sandbox.writeFile(path, updated);
    return { success: true };
  },
};
可用工具:
  • file_read: 读取文件内容
  • file_write: 写入整个文件
  • file_edit: 搜索替换编辑
  • file_search: 搜索文件内容
  • shell: 执行Shell命令
  • task: 为Agent创建子任务
  • web: 获取网页内容
  • skill: 访问领域特定技能

Creating Custom Tools

创建自定义工具

  1. Define the tool schema:
typescript
// packages/agent/src/tools/my-tool.ts
import { z } from 'zod';

export const myCustomTool = {
  name: 'my_tool',
  description: 'Does something specific',
  parameters: z.object({
    input: z.string().describe('The input parameter'),
  }),
  execute: async ({ input }, context) => {
    // Access sandbox
    const result = await context.sandbox.exec(`echo ${input}`);
    
    // Return structured data
    return {
      output: result.stdout,
      exitCode: result.exitCode,
    };
  },
};
  1. Register the tool:
typescript
// packages/agent/src/tools/index.ts
import { myCustomTool } from './my-tool';

export const tools = [
  fileReadTool,
  fileWriteTool,
  shellTool,
  myCustomTool, // Add your tool
  // ...
];
  1. 定义工具Schema:
typescript
// packages/agent/src/tools/my-tool.ts
import { z } from 'zod';

export const myCustomTool = {
  name: 'my_tool',
  description: 'Does something specific',
  parameters: z.object({
    input: z.string().describe('The input parameter'),
  }),
  execute: async ({ input }, context) => {
    // 访问沙箱
    const result = await context.sandbox.exec(`echo ${input}`);
    
    // 返回结构化数据
    return {
      output: result.stdout,
      exitCode: result.exitCode,
    };
  },
};
  1. 注册工具:
typescript
// packages/agent/src/tools/index.ts
import { myCustomTool } from './my-tool';

export const tools = [
  fileReadTool,
  fileWriteTool,
  shellTool,
  myCustomTool, // 添加你的工具
  // ...
];

Skills System

技能系统

Skills are domain-specific knowledge modules loaded into agent context:
typescript
// packages/agent/src/skills/registry.ts
export interface Skill {
  id: string;
  name: string;
  description: string;
  content: string; // Markdown content
  triggers: string[];
}

// Skills are cached in Redis/KV or in-memory
const skillsCache = new SkillsCache({
  redis: process.env.REDIS_URL,
});

// Retrieve skill by trigger
const skill = await skillsCache.findByTrigger('nextjs app router');
Create a custom skill:
typescript
// packages/agent/src/skills/custom-skill.ts
export const customSkill: Skill = {
  id: 'custom-framework',
  name: 'Custom Framework',
  description: 'Expertise in CustomFramework usage',
  content: `
技能是加载到Agent上下文的领域特定知识模块:
typescript
// packages/agent/src/skills/registry.ts
export interface Skill {
  id: string;
  name: string;
  description: string;
  content: string; // Markdown内容
  triggers: string[];
}

// 技能缓存于Redis/KV或内存中
const skillsCache = new SkillsCache({
  redis: process.env.REDIS_URL,
});

// 通过触发词检索技能
const skill = await skillsCache.findByTrigger('nextjs app router');
创建自定义技能:
typescript
// packages/agent/src/skills/custom-skill.ts
export const customSkill: Skill = {
  id: 'custom-framework',
  name: 'Custom Framework',
  description: 'Expertise in CustomFramework usage',
  content: `

Custom Framework Skill

Custom Framework Skill

Installation

Installation

```bash npm install custom-framework ```
```bash npm install custom-framework ```

Usage

Usage

```typescript import { Framework } from 'custom-framework';
const app = new Framework(); app.start(); ``` `, triggers: [ 'use custom framework', 'setup custom framework', 'configure custom framework', ], };
undefined
```typescript import { Framework } from 'custom-framework';
const app = new Framework(); app.start(); ``` `, triggers: [ 'use custom framework', 'setup custom framework', 'configure custom framework', ], };
undefined

GitHub Integration

GitHub集成

Auto-commit and PR Creation

自动提交与PR创建

Configure agent to automatically commit and create PRs:
typescript
// packages/agent/src/workflows/agent-workflow.ts
export async function runAgentWorkflow(
  message: string,
  options: {
    autoCommit?: boolean;
    autoPR?: boolean;
    repository?: string;
    branch?: string;
  }
) {
  const result = await agent.run(message);
  
  if (options.autoCommit && result.success) {
    await sandbox.exec('git add .');
    await sandbox.exec(`git commit -m "Agent: ${message}"`);
    
    if (options.autoPR) {
      await createPullRequest({
        repo: options.repository,
        branch: options.branch,
        title: `AI Agent: ${message}`,
        body: result.summary,
      });
    }
  }
}
配置Agent自动提交并创建PR:
typescript
// packages/agent/src/workflows/agent-workflow.ts
export async function runAgentWorkflow(
  message: string,
  options: {
    autoCommit?: boolean;
    autoPR?: boolean;
    repository?: string;
    branch?: string;
  }
) {
  const result = await agent.run(message);
  
  if (options.autoCommit && result.success) {
    await sandbox.exec('git add .');
    await sandbox.exec(`git commit -m "Agent: ${message}"`);
    
    if (options.autoPR) {
      await createPullRequest({
        repo: options.repository,
        branch: options.branch,
        title: `AI Agent: ${message}`,
        body: result.summary,
      });
    }
  }
}

GitHub App Installation

GitHub应用安装

typescript
// apps/web/lib/github/app.ts
import { App } from '@octokit/app';

const app = new App({
  appId: process.env.GITHUB_APP_ID,
  privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
});

// Get installation token
const installation = await app.octokit.request(
  'GET /users/{username}/installation',
  { username: 'user' }
);

const token = await app.octokit.auth({
  type: 'installation',
  installationId: installation.data.id,
});
typescript
// apps/web/lib/github/app.ts
import { App } from '@octokit/app';

const app = new App({
  appId: process.env.GITHUB_APP_ID,
  privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
});

// 获取安装令牌
const installation = await app.octokit.request(
  'GET /users/{username}/installation',
  { username: 'user' }
);

const token = await app.octokit.auth({
  type: 'installation',
  installationId: installation.data.id,
});

Configuration

配置

Resource Profiles

资源配置文件

For Hobby tier deployments:
env
OPEN_AGENTS_RESOURCE_PROFILE=hobby
This adjusts chat and sandbox resource limits to Hobby-compatible values.
对于Hobby层级部署:
env
OPEN_AGENTS_RESOURCE_PROFILE=hobby
这会调整聊天和沙箱的资源限制,使其适配Hobby层级的可用值。

Sandbox Base Snapshot

沙箱基础快照

Use a preconfigured sandbox image:
env
VERCEL_SANDBOX_BASE_SNAPSHOT_ID=your_snapshot_id
Create base snapshot:
bash
bun run sandbox:snapshot-base
使用预配置的沙箱镜像:
env
VERCEL_SANDBOX_BASE_SNAPSHOT_ID=your_snapshot_id
创建基础快照:
bash
bun run sandbox:snapshot-base

Voice Input

语音输入

Enable voice transcription with ElevenLabs:
env
ELEVENLABS_API_KEY=your_api_key
通过ElevenLabs启用语音转录:
env
ELEVENLABS_API_KEY=your_api_key

Optional Caching

可选缓存

Enable Redis/KV for skills metadata:
env
REDIS_URL=your_redis_url
KV_URL=your_kv_url
启用Redis/KV存储技能元数据:
env
REDIS_URL=your_redis_url
KV_URL=your_kv_url

Common Patterns

常见模式

Multi-step Agent Task

多步骤Agent任务

typescript
// packages/agent/src/agent.ts
export async function runMultiStepTask(goal: string) {
  const steps = await planSteps(goal);
  
  for (const step of steps) {
    const result = await executeStep(step, {
      tools: availableTools,
      sandbox: currentSandbox,
    });
    
    if (!result.success) {
      // Handle failure, retry, or replan
      return { success: false, error: result.error };
    }
  }
  
  return { success: true, steps };
}
typescript
// packages/agent/src/agent.ts
export async function runMultiStepTask(goal: string) {
  const steps = await planSteps(goal);
  
  for (const step of steps) {
    const result = await executeStep(step, {
      tools: availableTools,
      sandbox: currentSandbox,
    });
    
    if (!result.success) {
      // 处理失败、重试或重新规划
      return { success: false, error: result.error };
    }
  }
  
  return { success: true, steps };
}

Streaming Agent Response

流式Agent响应

typescript
// apps/web/app/api/chat/route.ts
import { streamText } from 'ai';

export async function POST(req: Request) {
  const { messages, sessionId } = await req.json();
  
  const result = await streamText({
    model: openai('gpt-4'),
    messages,
    tools: {
      file_read: fileReadTool,
      file_write: fileWriteTool,
      shell: shellTool,
    },
    onFinish: async ({ text, toolCalls }) => {
      // Save to session
      await saveMessage(sessionId, { text, toolCalls });
    },
  });
  
  return result.toDataStreamResponse();
}
typescript
// apps/web/app/api/chat/route.ts
import { streamText } from 'ai';

export async function POST(req: Request) {
  const { messages, sessionId } = await req.json();
  
  const result = await streamText({
    model: openai('gpt-4'),
    messages,
    tools: {
      file_read: fileReadTool,
      file_write: fileWriteTool,
      shell: shellTool,
    },
    onFinish: async ({ text, toolCalls }) => {
      // 保存到会话
      await saveMessage(sessionId, { text, toolCalls });
    },
  });
  
  return result.toDataStreamResponse();
}

Session Management

会话管理

typescript
// apps/web/lib/sessions.ts
import { db } from './db';

export async function createSession(userId: string, metadata: object) {
  const session = await db.session.create({
    data: {
      userId,
      metadata,
      createdAt: new Date(),
    },
  });
  
  return session;
}

export async function shareSession(sessionId: string) {
  const shareToken = await generateShareToken(sessionId);
  
  return {
    url: `${process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL}/share/${shareToken}`,
    token: shareToken,
  };
}
typescript
// apps/web/lib/sessions.ts
import { db } from './db';

export async function createSession(userId: string, metadata: object) {
  const session = await db.session.create({
    data: {
      userId,
      metadata,
      createdAt: new Date(),
    },
  });
  
  return session;
}

export async function shareSession(sessionId: string) {
  const shareToken = await generateShareToken(sessionId);
  
  return {
    url: `${process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL}/share/${shareToken}`,
    token: shareToken,
  };
}

Sandbox Lifecycle

沙箱生命周期

typescript
// packages/sandbox/src/lifecycle.ts
export class SandboxLifecycle {
  async create() {
    this.sandbox = await createSandbox({
      baseSnapshotId: this.baseSnapshotId,
    });
    return this.sandbox;
  }
  
  async hibernate() {
    const snapshot = await this.sandbox.createSnapshot();
    await this.sandbox.stop();
    return snapshot.id;
  }
  
  async resume(snapshotId: string) {
    this.sandbox = await createSandbox({
      baseSnapshotId: snapshotId,
    });
    return this.sandbox;
  }
  
  async destroy() {
    await this.sandbox.stop();
    this.sandbox = null;
  }
}
typescript
// packages/sandbox/src/lifecycle.ts
export class SandboxLifecycle {
  async create() {
    this.sandbox = await createSandbox({
      baseSnapshotId: this.baseSnapshotId,
    });
    return this.sandbox;
  }
  
  async hibernate() {
    const snapshot = await this.sandbox.createSnapshot();
    await this.sandbox.stop();
    return snapshot.id;
  }
  
  async resume(snapshotId: string) {
    this.sandbox = await createSandbox({
      baseSnapshotId: snapshotId,
    });
    return this.sandbox;
  }
  
  async destroy() {
    await this.sandbox.stop();
    this.sandbox = null;
  }
}

Troubleshooting

故障排查

Workflow Execution Fails

工作流执行失败

Problem: Workflow steps timeout or fail
typescript
// Check workflow logs
const logs = await getWorkflowLogs(workflowId);
console.log(logs);

// Increase timeout
export const POST = createWorkflow(
  async (context, data) => {
    // ...
  },
  { timeout: 300000 } // 5 minutes
);
问题: 工作流步骤超时或失败
typescript
// 查看工作流日志
const logs = await getWorkflowLogs(workflowId);
console.log(logs);

// 增加超时时间
export const POST = createWorkflow(
  async (context, data) => {
    // ...
  },
  { timeout: 300000 } // 5分钟
);

Sandbox Connection Issues

沙箱连接问题

Problem: Cannot connect to sandbox
typescript
// Verify sandbox is running
const status = await sandbox.status();
console.log('Sandbox status:', status);

// Recreate sandbox
await sandbox.stop();
const newSandbox = await createSandbox();
问题: 无法连接到沙箱
typescript
// 验证沙箱是否运行
const status = await sandbox.status();
console.log('Sandbox status:', status);

// 重新创建沙箱
await sandbox.stop();
const newSandbox = await createSandbox();

GitHub App Permissions

GitHub应用权限

Problem: Cannot access repositories
  • Verify app installation:
    https://github.com/settings/installations
  • Check app permissions include:
    • Repository contents: Read & write
    • Pull requests: Read & write
    • Metadata: Read-only
问题: 无法访问仓库
  • 验证应用安装状态:
    https://github.com/settings/installations
  • 检查应用权限是否包含:
    • 仓库内容: 读写
    • Pull请求: 读写
    • 元数据: 只读

Database Migrations

数据库迁移

Problem: Schema out of sync
bash
undefined
问题: 架构不同步
bash
undefined

Check migration status

检查迁移状态

bun run ci
bun run ci

Apply migrations manually if needed

必要时手动应用迁移

cd apps/web npx drizzle-kit push:pg
undefined
cd apps/web npx drizzle-kit push:pg
undefined

Authentication Issues

认证问题

Problem: OAuth callback fails
  • Verify callback URLs match exactly (including protocol)
  • Check
    BETTER_AUTH_SECRET
    is set and consistent across deployments
  • Confirm OAuth app credentials are correct
问题: OAuth回调失败
  • 验证回调URL完全匹配(包括协议)
  • 检查
    BETTER_AUTH_SECRET
    已设置且在所有部署中保持一致
  • 确认OAuth应用凭证正确

Port Conflicts in Sandbox

沙箱端口冲突

Problem: Preview port already in use
typescript
// Use alternative ports
const ports = [3000, 5173, 4321, 8000];
for (const port of ports) {
  try {
    await sandbox.exec(`lsof -ti:${port} | xargs kill -9`);
  } catch {
    // Port was free
  }
}
问题: 预览端口已被占用
typescript
// 使用备用端口
const ports = [3000, 5173, 4321, 8000];
for (const port of ports) {
  try {
    await sandbox.exec(`lsof -ti:${port} | xargs kill -9`);
  } catch {
    // 端口未被占用
  }
}

Development Commands

开发命令

bash
undefined
bash
undefined

Start development server

启动开发服务器

bun run web
bun run web

Lint and format check

检查代码规范与格式

bun run check
bun run check

Auto-fix linting and formatting

自动修复代码规范与格式问题

bun run fix
bun run fix

Type check all packages

类型检查所有包

bun run typecheck
bun run typecheck

Full CI suite

完整CI套件

bun run ci
bun run ci

Refresh sandbox base snapshot

刷新沙箱基础快照

bun run sandbox:snapshot-base
undefined
bun run sandbox:snapshot-base
undefined

API Reference

API参考

Core Types

核心类型

typescript
// Agent context passed to tools
interface AgentContext {
  sandbox: Sandbox;
  sessionId: string;
  userId: string;
  metadata: Record<string, unknown>;
}

// Tool definition
interface Tool<T = unknown> {
  name: string;
  description: string;
  parameters: z.ZodSchema<T>;
  execute: (params: T, context: AgentContext) => Promise<unknown>;
}

// Sandbox interface
interface Sandbox {
  exec(command: string): Promise<ExecResult>;
  readFile(path: string): Promise<string>;
  writeFile(path: string, content: string): Promise<void>;
  search(pattern: string): Promise<SearchResult[]>;
  createSnapshot(): Promise<Snapshot>;
  status(): Promise<SandboxStatus>;
  stop(): Promise<void>;
}
typescript
// 传递给工具的Agent上下文
interface AgentContext {
  sandbox: Sandbox;
  sessionId: string;
  userId: string;
  metadata: Record<string, unknown>;
}

// 工具定义
interface Tool<T = unknown> {
  name: string;
  description: string;
  parameters: z.ZodSchema<T>;
  execute: (params: T, context: AgentContext) => Promise<unknown>;
}

// 沙箱接口
interface Sandbox {
  exec(command: string): Promise<ExecResult>;
  readFile(path: string): Promise<string>;
  writeFile(path: string, content: string): Promise<void>;
  search(pattern: string): Promise<SearchResult[]>;
  createSnapshot(): Promise<Snapshot>;
  status(): Promise<SandboxStatus>;
  stop(): Promise<void>;
}

Resources

资源