Mastra × E2B Desktop:在云端 Linux 桌面沙箱中构建可操控桌面的 Agent Workspace
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
Mastra 的@mastra/e2b-desktop是一个基于 E2B Desktop 的 computer-use(桌面操作)沙箱 Provider,它在@mastra/e2b的 E2B 云沙箱之上叠加了一整套 Linux 桌面环境,并提供截图、鼠标、键盘控制能力。本文将带你掌握如何把它接入Workspace与Agent,如何用computer能力驱动桌面 Agent,以及如何深入底层理解其实现机制。
背景:为什么需要桌面沙箱
常规的代码执行沙箱只能跑命令、读写文件,无法“看见”和“操作”一个图形界面。而许多真实任务——操作浏览器、填写 GUI 表单、使用桌面应用——都需要 Agent 具备 computer-use 能力:截图观察屏幕、移动鼠标点击、键盘输入。
E2B Desktop 正是在 E2B 云沙箱中运行一个完整的 Linux 桌面环境,@mastra/e2b-desktop把这个桌面环境接入 Mastra Workspace 体系。它的定位非常清晰:继承@mastra/e2b的E2BSandbox的全部能力(命令执行、进程管理、文件上传、暂停/恢复重连),同时叠加桌面控制能力,@e2b/desktopSDK 之于e2bSDK 的扩展方式,与@mastra/e2b-desktop之于@mastra/e2b的扩展方式完全一致——基础 Provider 支持的一切能力,都作用在同一个桌面 VM 上。
安装
在 Mastra 项目中安装:
npm install @mastra/e2b-desktop从源码看,package.json 声明了以下依赖关系:
- 运行时依赖
@e2b/desktop(^2.3.1)与e2b(^2.36.0),以及 workspace 内的@mastra/e2b; @mastra/core作为 peer dependency,版本要求>=1.67.0-0 <2.0.0-0;- 要求 Node.js
>=22.13.0。
快速开始:把桌面沙箱挂进 Agent
以下是完整的接入示例(直接取自包的用法文档,并补充了可运行细节):
import { Agent } from '@mastra/core/agent'; import { Workspace } from '@mastra/core/workspace'; import { E2BDesktopSandbox } from '@mastra/e2b-desktop'; const sandbox = new E2BDesktopSandbox({ resolution: [1280, 720] }); const agent = new Agent({ name: 'desktop-agent', instructions: 'You can control a Linux desktop and run shell commands.', model: 'anthropic/claude-sonnet-4-6', // file + shell + computer 三类工具都会自动注入 workspace: new Workspace({ sandbox }), });关键点:
resolution: [1280, 720]指定桌面显示分辨率(像素宽高),也可用dpi指定显示 DPI;两者都只对新建的沙箱生效;- 由于沙箱实现了
computer能力,supportsComputer(sandbox)为true,Workspace 会自动向 Agent 注入mastra_workspace_computer_*系列工具(见下文"Computer 能力"一节),无需手动声明; - 与基础
E2BSandbox不同,桌面沙箱默认无需构建模板——未显式提供template时,使用 E2B 托管的desktop模板(源码中的DEFAULT_DESKTOP_TEMPLATE = 'desktop',见 sandbox/index.ts)。
环境变量与鉴权
与@mastra/e2b一致,凭据可通过构造参数或环境变量提供:
| 配置项 | 作用 | 回退环境变量 |
|---|---|---|
apiKey | E2B API 密钥 | E2B_API_KEY |
accessToken | E2B 访问令牌 | E2B_ACCESS_TOKEN |
domain | 自托管 E2B 域名 | E2B_DOMAIN |
apiUrl | 自托管 E2B API 地址 | E2B_API_URL |
构造选项(Options)全解
E2BDesktopSandboxOptions继承E2BSandboxOptions的全部字段,并新增两个桌面专属字段。下表综合了 sandbox/index.ts 与上游 workspaces/e2b/src/sandbox/index.ts 的完整定义:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
resolution | [number, number] | 无(SDK 默认) | 桌面分辨率[宽, 高],仅对新建沙箱生效 |
dpi | number | 无 | 桌面显示 DPI,仅对新建沙箱生效 |
id | string | 自动生成 | 沙箱逻辑 ID,用于元数据发现与重连 |
sandboxId | string | 无 | 优先按 E2B Provider 沙箱 ID 确定性重连(见下文) |
template | TemplateSpec | 'desktop' | 模板:字符串 ID / TemplateBuilder / 定制函数;不传则用 E2B 托管 desktop 模板,无需构建 |
timeout | number | 300_000(5 分钟) | 执行超时(毫秒) |
env | Record<string, string> | {} | 注入沙箱的环境变量 |
metadata | Record<string, unknown> | {} | 自定义元数据(会自动合并mastra-sandbox-id) |
network | SandboxNetworkOpts | 无 | 创建时的网络配置 |
lifecycle | SandboxLifecycle | { onTimeout: 'pause' } | 超时行为:pause快照暂停(下次start()恢复重连);kill则销毁重建,适合状态外置(如 S3 挂载)的沙箱 |
domain/apiUrl/apiKey/accessToken | string | 环境变量 | 鉴权与自托管配置 |
instructions | string \| (opts) => string | 默认说明 | 覆盖默认沙箱指令 |
关于 lifecycle 与 timeout 的行为
上游E2BSandbox源码注释说明(workspaces/e2b/src/sandbox/index.ts):默认onTimeout: 'pause'会把整个 VM(文件系统、内存、运行中的进程)冻结快照并停止计费,下次start()重连并恢复,后台进程依然存活;显式stop()无论该设置如何都会暂停。timeout会被写入创建参数timeoutMs,单位毫秒。
用 Workspace 执行代码
接入 Workspace 后,可直接执行代码与命令:
const sandbox = new E2BDesktopSandbox({ timeout: 60_000 }); const workspace = new Workspace({ sandbox }); // 在桌面 VM 中执行代码 const result = await workspace.executeCode('console.log("Hello from desktop VM!")');与基础 Provider 相同,桌面沙箱还支持executeCommand、文件上传(writeFiles)、后台进程管理等能力。集成测试中有一个非常直观的例子:通过 shell 写入文件,再用桌面 SDK 读回,验证 GUI 与 shell 两条通道作用在同一台机器上(见 index.integration.test.ts)。
Computer 能力:截屏、鼠标与键盘
E2BDesktopSandbox覆写了computer: SandboxComputer能力,其全部操作由withDesktop()统一编排:先ensureRunning()确保沙箱已启动,再通过retryOnDead()在检测到 VM 已死时自动重建并重试。因此所有 computer 操作都会在沙箱未运行时自动启动它。
屏幕观察
await sandbox.start(); const { data, mediaType } = await sandbox.computer.screenshot(); // mediaType === 'image/png',data 为 PNG 字节 const { width, height } = await sandbox.computer.getScreenSize(); const cursor = await sandbox.computer.getCursorPosition();getScreenSize()返回{ width, height },getCursorPosition()返回{ x, y }。单元测试验证了截图返回 PNG 魔数\x89PNG(见 index.test.ts)。
鼠标控制
await sandbox.computer.leftClick(100, 200); await sandbox.computer.rightClick(100, 200); await sandbox.computer.doubleClick(100, 200); await sandbox.computer.moveMouse(100, 200); await sandbox.computer.drag({ x: 1, y: 2 }, { x: 3, y: 4 }); await sandbox.computer.scroll('down', 3);所有坐标以像素计;drag接受起点/终点坐标对象,底层映射为desktop.drag([from.x, from.y], [to.x, to.y]);scroll接受方向(如'down')与步数。
键盘输入
await sandbox.computer.type('hello world'); // 映射为 desktop.write(text) await sandbox.computer.press('Enter'); // 单个按键 await sandbox.computer.press(['ctrl', 's']); // 组合键type底层调用desktop.write,press支持单个键名或键名数组(组合键)。测试用例覆盖了这三种调用形态(index.test.ts)。
实时桌面查看(noVNC 流)
const viewerUrl = await sandbox.computer.streamUrl();streamUrl()会做三件事:
- 通过
ensureStreamStarted()启动一个要求鉴权的 VNC 流(desktop.stream.start({ requireAuth: true })),并按沙箱 ID 记忆化——同一 VM 只启动一次,重启/重建的 VM 会重新启动; - 用
desktop.stream.getAuthKey()拼出带password=参数的 noVNC 查看器 URL; - 兼容外部已启动的流(拿不到 auth key 时返回普通 URL);任何失败都返回
null而非抛错。
单元测试验证了"重复调用只启动一次流""外部已启动的流被容忍""失败返回 null"等行为(index.test.ts)。集成测试确认返回 URL 形如https://...且包含password=(index.integration.test.ts)。
桌面专属逃生通道:sandbox.desktop
不是所有桌面 API 都值得抽象进统一接口,E2BDesktopSandbox提供了desktopgetter 直接暴露底层@e2b/desktopSDK 的Sandbox实例:
await sandbox.start(); await sandbox.desktop.launch('xfce4-terminal'); // 启动应用 await sandbox.desktop.open('https://mastra.ai'); // 打开 URL await sandbox.desktop.files.read('/tmp/x.txt'); // 文件操作注意:desktop在沙箱未启动时访问会抛出SandboxNotReadyError(源码 sandbox/index.ts,测试见 index.test.ts)。这是定制流、窗口管理、启动任意应用等高级操作的入口。
生命周期:启动、暂停、重连与销毁
E2BDesktopSandbox继承了E2BSandbox的生命周期管理,并针对桌面场景做了关键改造:
- 创建:重写
createSdkSandbox(),调用@e2b/desktop的Sandbox.create(templateId, opts),并把resolution、dpi透传给 SDK;创建参数包含timeoutMs、lifecycle 以及合并了mastra-sandbox-id的 metadata(测试验证了这些透传,index.test.ts); - 重连:重写
connectSdkSandbox()走@e2b/desktop的Sandbox.connect(sandboxId, opts)。start()时优先按sandboxId选项确定性重连,否则按mastra-sandbox-id元数据发现已有沙箱;只有"沙箱已消失"类错误才回退到新建,鉴权、配额、限流、超时、网络错误会直接抛出,避免创建重复 VM(workspaces/e2b/src/sandbox/index.ts); - 暂停/恢复:
stop()对 VM 做快照暂停(冻结文件系统、内存与进程并停止计费),下次start()重连恢复;FUSE 挂载会先卸载、启动时再对账恢复; - 销毁:
destroy()杀掉全部后台进程、卸载挂载并kill沙箱;对未在本进程附着的沙箱,按身份直接 pause/kill,无需唤醒它(workspaces/e2b/src/sandbox/index.ts); - 模板解析:重写
resolveTemplate(),未显式提供template时直接返回 E2B 托管的desktop模板 ID,并重写buildDefaultTemplate()为无操作——桌面模板由 E2B 托管,无需构建(sandbox/index.ts)。
集成测试对沙箱一致性(conformance)的声明也印证了能力边界(index.integration.test.ts):支持重连、并发、环境变量、工作目录与超时;不支持挂载(FUSE)——桌面模板没有 FUSE 工具链,这一点与基础 E2BSandbox 的云存储挂载能力不同。
在 MastraEditor 中作为可序列化 Provider 使用
@mastra/e2b-desktop还导出一个e2bDesktopSandboxProvider描述符(见 provider.ts),用于 MastraEditor:
import { e2bDesktopSandboxProvider } from '@mastra/e2b-desktop'; const editor = new MastraEditor({ sandboxes: [e2bDesktopSandboxProvider], });该描述符提供 JSON Schema 配置(configSchema),覆盖template、timeout(默认 300000ms)、env、metadata、resolution、dpi、domain、apiUrl、apiKey、accessToken等字段;不可序列化的回调(如 TemplateBuilder、运行时对象)被排除在外。编辑器据此渲染配置表单,并通过createSandbox(config)实例化真正的E2BDesktopSandbox。
自动注入的 computer 工具
当 Workspace 挂载支持 computer 能力的沙箱时,会向 Agent 注入一组mastra_workspace_computer_*工具(截图、点击、输入、滚动等),核心包的 tools/types.ts 提供了两个常用调优项:
screenshotAfterAction:动作类工具(click/type/scroll 等)完成后是否自动附一张新截图,让 computer-use 循环无需额外截图即可看到操作后的桌面状态,默认true;screenshotDelayMs:动作与操作后截图之间的延迟(默认 500ms),给 UI 菜单、动画留出反应时间。
示例配置:
const agent = new Agent({ // ... workspace: new Workspace({ sandbox }), tools: { // 点击后不附加截图,减少 token 消耗 mastra_workspace_computer_click: { screenshotAfterAction: false }, // 桌面输入需要人工审批 mastra_workspace_computer_type: { requireApproval: true }, }, });测试与验证方式
包内测试分两层:
- 单元测试(index.test.ts):mock 掉
e2b与@e2b/desktopSDK,验证模板解析、SDK 工厂钩子、computer 能力映射、流记忆化、workspace 工具注入、桌面逃生通道等,不消耗真实资源; - 集成测试(index.integration.test.ts):需要真实
E2B_API_KEY(未设置时自动跳过),针对真实桌面沙箱验证截图 PNG 魔数、鼠标移动→光标位置回读、shell 与 GUI 共享文件系统的跨通道回环、鉴权 noVNC URL 解析。
想在自己的项目里快速验证,可以运行:
const sandbox = new E2BDesktopSandbox({ id: `demo-${Date.now()}`, timeout: 120_000, }); await sandbox.start(); const shot = await sandbox.computer.screenshot(); // PNG 字节 const url = await sandbox.computer.streamUrl(); // noVNC 查看器 await sandbox.computer.type('echo desktop-ok > /tmp/x'); await sandbox.executeCommand('cat /tmp/x'); await sandbox.destroy();小结
@mastra/e2b-desktop让 Mastra Agent 第一次能够"看见并操作"一个云端 Linux 桌面:它完整继承@mastra/e2b的命令、进程、文件与暂停/恢复重连能力,叠加截图、鼠标、键盘与鉴权 noVNC 实时流,默认使用无需构建的 E2B 托管桌面模板,并通过mastra_workspace_computer_*工具把这一切自动暴露给 Agent。无论是构建 computer-use 自动化,还是需要一个同时支持 GUI 与 shell 的隔离执行环境,它都是一个开箱即用的选择。
相关代码入口:
- 包 README:安装、用法与能力概述
- 核心实现 sandbox/index.ts:
E2BDesktopSandbox与computer能力 - Provider 描述符 provider.ts:MastraEditor 可序列化配置
- 单元测试 index.test.ts 与 集成测试 index.integration.test.ts
- 上游基类 @mastra/e2b:选项、生命周期、挂载与重连语义
- computer 工具配置:
mastra_workspace_computer_*工具行为调优
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考