跳转到内容

输入关键词开始搜索文档。

Vercel Sandbox

最后更新 查看 Markdown 源文件

Vercel Sandbox 适配器将已初始化的 @vercel/sandbox Sandbox 适配为 Flue 的沙箱接口。当应用代码应在 Vercel 管理的沙箱中而非其主机文件系统上执行智能体工作时,可以使用它。

快速开始

使用 Vercel Sandbox 蓝图为现有 Flue 项目添加托管 Linux 沙箱能力。在终端或你选择的编码智能体中运行以下命令:

flue add sandbox vercel

概述

蓝图会在需要时安装 @vercel/sandbox,并在你的源码根目录下创建 sandboxes/vercel.ts。生成的适配器接受已初始化的 Vercel Sandbox;认证、运行时选择、保留和清理仍由应用管理。

<source-root>/sandboxes/vercel.ts (abridged)
// flue-blueprint: sandbox/vercel@1
import { sandboxFromDriver, useModel } from '@flue/runtime';
import type { SandboxDriver, SandboxFactory, Sandbox, FileStat } from '@flue/runtime';
import type { Sandbox as VercelSandbox } from '@vercel/sandbox';

class VercelSandboxDriver implements SandboxDriver {
  constructor(private sandbox: VercelSandbox) {}

  /* ... 使用 sandbox.fs 生成的文件系统操作 ... */

  async stat(path: string): Promise<FileStat> {
    const stat = await this.sandbox.fs.stat(path);
    return {
      isFile: stat.isFile(),
      isDirectory: stat.isDirectory(),
      isSymbolicLink: stat.isSymbolicLink(),
      size: stat.size,
      mtime: stat.mtime,
    };
  }

  async exec(
    command: string,
    options?: {
      cwd?: string;
      env?: Record<string, string>;
      timeoutMs?: number;
      signal?: AbortSignal;
    },
  ): Promise<{ stdout: string; stderr: string; exitCode: number }> {
    const timeoutSignal =
      typeof options?.timeoutMs === 'number' ? AbortSignal.timeout(options.timeoutMs) : undefined;
    const callerSignal = options?.signal;
    const signal =
      callerSignal && timeoutSignal
        ? AbortSignal.any([callerSignal, timeoutSignal])
        : (callerSignal ?? timeoutSignal);

    try {
      const response = await this.sandbox.runCommand({
        cmd: 'bash',
        args: ['-c', command],
        cwd: options?.cwd,
        env: options?.env,
        signal,
      });
      const [stdout, stderr] = await Promise.all([
        response.stdout({ signal }),
        response.stderr({ signal }),
      ]);
      return { stdout, stderr, exitCode: response.exitCode };
    } catch (err) {
      if (callerSignal?.aborted) throw err;
      const aborted =
        timeoutSignal?.aborted &&
        (err === timeoutSignal.reason ||
          (err instanceof Error && (err.name === 'AbortError' || err.name === 'TimeoutError')));
      if (aborted) {
        return {
          stdout: '',
          stderr: `[flue:vercel] 命令在 ${options?.timeoutMs} 毫秒后超时。`,
          exitCode: 124,
        };
      }
      throw err;
    }
  }
}

export function vercel(sandbox: VercelSandbox): SandboxFactory {
  return {
    async createSandbox(): Promise<Sandbox> {
      const sandboxCwd = '/vercel/sandbox';
      const driver = new VercelSandboxDriver(sandbox);
      return sandboxFromDriver(driver, sandboxCwd);
    },
  };
}

将已初始化的 Vercel Sandbox 传递给 vercel(...),并将返回的工厂传递给智能体的 useSandbox(...) 调用。适配器映射提供商完整的文件统计信息,从 /vercel/sandbox 解析相对路径,向命令执行和输出读取转发组合信号,传播调用方取消,仅将 timeoutMs 取消映射为退出码 124。

配置

变量用途
VERCEL_OIDC_TOKENOIDC 认证必需 — 在 Vercel 上自动注入;在本地使用 OIDC 时需显式设置。
覀求用途
Vercel 支持的认证必需 — 在 Vercel 上使用 OIDC,在 Vercel 外使用访问令牌或其他支持的认证流程。
@vercel/sandbox 包必需 — 创建由 Flue 适配的 Vercel Sandbox。
应用自有的生命周期必需 — 创建沙箱并决定其保留和清理策略。

典型用法

import { Sandbox } from '@vercel/sandbox';
import { useModel, useSandbox } from '@flue/runtime';
import { vercel } from '../sandboxes/vercel';

export function Assistant() {
  useModel('anthropic/claude-sonnet-4-6');
  useSandbox({
    // 按照 SandboxFactory 契约,延迟执行:构造此对象成本很低;
    // 昂贵的 Vercel 沙箱创建只在 createSandbox() 内部的初始化阶段
    // 执行一次 —— 永远不会在重新渲染时执行。
    async createSandbox(options) {
      const sandbox = await Sandbox.create({ runtime: 'node24' });
      return vercel(sandbox).createSandbox(options);
    },
  });
}

将 Vercel 认证值保存在可信的应用配置中,并确定沙箱应该是每次任务新建还是为稳定的智能体身份复用。

参见沙箱和沙箱适配器 API。