嵌入 OpenClaw
嵌入宿主应监管已安装的 openclaw 可执行文件,使用 Gateway WebSocket 协议作为其控制平面,并将子进程视为可替换的运行时。这样可以在不依赖 OpenClaw 私有状态布局的情况下,明确掌控进程所有权、就绪状态、故障恢复和升级。
有关客户端身份验证和重连状态,请参阅构建 Gateway 客户端。
使用嵌入预设启动子进程¶
使用真实的 node_modules 安装,并派生出该包的可执行文件。对于掌握发现、重启和频道生命周期的宿主来说,一个有用的基线示例如下:
import { spawn } from "node:child_process";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
// Supply an absolute path to a real Node runtime managed by the host application.
declare const hostNodeExecutable: string;
const packageEntry = fileURLToPath(import.meta.resolve("openclaw"));
const openclawEntry = resolve(dirname(packageEntry), "..", "openclaw.mjs");
const gateway = spawn(hostNodeExecutable, [openclawEntry, "gateway", "--allow-unconfigured"], {
env: {
...process.env,
OPENCLAW_DISABLE_BONJOUR: "1",
OPENCLAW_EXEC_SHELL_SNAPSHOT: "0",
OPENCLAW_NO_RESPAWN: "1",
OPENCLAW_SKIP_CHANNELS: "1",
},
stdio: ["ignore", "inherit", "inherit"],
});
如示例所示,通过已安装的包来解析 OpenClaw;不要假设项目本地的 openclaw 二进制文件位于宿主进程的 PATH 中。该示例继承了输出,因此子进程不会因 stdout 或 stderr 管道满而阻塞。如果宿主改为捕获这些流,则应在派生子进程后立即附加消费者。
| 设置 | 嵌入影响 |
|---|---|
OPENCLAW_DISABLE_BONJOUR=1 |
当宿主负责发现时,禁用 Gateway 拥有的局域网多播广播。 |
OPENCLAW_NO_RESPAWN=1 |
在非托管的嵌入子进程中,阻止 OpenClaw 将更新重启交给分离的子进程。常规重启仍在进程内进行,因此宿主保持对已跟踪 PID 的所有权。 |
OPENCLAW_EXEC_SHELL_SNAPSHOT=0 |
禁用宿主 exec 命令的登录 Shell 快照捕获。 |
OPENCLAW_SKIP_CHANNELS=1 |
跳过频道的启动和重新加载。仅当嵌入应用需要仅控制平面或仅 WebChat 的 Gateway 时,才设置此项。 |
--allow-unconfigured 仅绕过 gateway.mode=local 启动守卫。它不会写入配置或修复无效文件。当嵌入应用通过引导(onboarding)、配置 CLI 或 Gateway RPC 预置正常本地配置时,应省略此选项。
Electron Shell 快照警告¶
Shell 快照捕获会从登录 Shell 中运行 process.execPath -e <script>。在正常的 Node 进程中,process.execPath 是 Node 可执行文件。在 Electron 下,它是 Electron 二进制文件,可能会将此次调用解释为应用启动并弹出“无法找到 Electron 应用”的提示。请在 Gateway 子进程的环境中设置 OPENCLAW_EXEC_SHELL_SNAPSHOT=0,而不仅仅是在渲染进程中设置。出于同样的原因,hostNodeExecutable 必须指向真正的 Node 运行时,而不是 Electron 的 process.execPath。
根据退出码处理无效配置¶
Gateway 启动使用退出码 78(EX_CONFIG)表示配置类的启动失败,包括无效配置。请根据退出码进行分支判断,而不要解析人类可读的 stderr:
- 使用与 Gateway 子进程相同的配置和状态环境,运行
openclaw doctor --fix --yes --non-interactive。 - 在 doctor 成功退出后,重试一次 Gateway 启动。
- 如果子进程再次以
78退出,停止修复循环,并将配置失败呈现给用户。
保留 stderr 用于诊断,但不要根据其中的措辞做出生命周期决策。
成功启动后,对运行中配置进行无效编辑的破坏性较小。配置监视器会记录跳过重载,并继续提供最后一次被接受的内存配置。修复文件,然后让监视器接受下一个有效快照。
等待协议就绪¶
使用 WebSocket 信号,而不是日志子字符串:
- 打开 Gateway WebSocket。
- 等待
connect.challenge事件。该事件可证明监听器已接受 WebSocket,且质询握手可以开始。 - 发送带有绑定质询的设备签名的
connect。 - 将
hello-ok视为已通过身份验证的 RPC 的应用就绪信号。
质询故意早于完整初始化。如果启动 sidecar 仍在进行中,connect 会返回带有 details.reason: "startup-sidecars" 的可重试 UNAVAILABLE 错误,以及有界的 retryAfterMs,然后以代码 1013 和原因 gateway starting 关闭连接。请使用 @openclaw/gateway-protocol/startup-unavailable 中的 resolveGatewayStartupRetryAfterMs,或参考客户端的内置策略,然后重新连接。
解读重启与关闭¶
在有序关闭之前,Gateway 会广播一个包含 reason 和可选的 restartExpectedMs 的 shutdown 事件。数值型 restartExpectedMs 表示预期会发生进程内或受监管的重启;缺失或 null 值表示终止性关闭。
随后,WebSocket 关闭代码在两种情况下均为 1012。普通客户端关闭原因同样是 service restart,因此关闭代码和原因都无法区分重启与关闭。当 shutdown 负载到达时,请保留它,并将其与宿主自身的停止意图以及子进程退出状态结合起来。如果连接在未收到该事件的情况下消失,请使用常规的有界重连和子进程监管策略。
已接受的智能体响应会在其命令和清理完成之前确认请求。关闭操作会通过取消和最终清理来保留这些工作。如果关闭或启动失败的清理无法完成,子进程将以失败状态退出,而不是在同一进程中启动另一代 Gateway。在替换它之前,请等待子进程退出。
使用 RPC 而非状态文件¶
让 Gateway 成为 OpenClaw 状态的唯一拥有者。常见的嵌入操作已有 RPC 方法:
| 任务 | RPC 方法 |
|---|---|
| 会话目录与生命周期 | sessions.list, sessions.patch, sessions.delete |
| 会话记录显示 | chat.history |
| 成本与用量报告 | usage.cost, sessions.usage |
| 模型凭据状态 | models.authStatus |
| 配置 | config.get, config.patch |
config.get 在返回快照之前会脱敏敏感值和 SecretRef 标识符。写入方法同样返回脱敏后的配置。客户端必须将脱敏哨兵视为不透明数据,并遵循文档化的配置写入约定;绝不应期望 Gateway 返回明文机密。
不要为了实现应用功能而读取或修改 ~/.openclaw 下的文件、SQLite 表、会话记录文件或缓存目录。这些布局是私有运行时实现细节,可能会在没有协议兼容保证的情况下移动或更改。
安装;请勿扁平化¶
根目录的 openclaw 包不是单文件 vendoring 目标。dist/extensions 下的捆绑运行时文件保留了裸自导入,例如 openclaw/plugin-sdk/*,而 npm 包有意排除每个扩展各自的 node_modules 节点树。
请通过 npm、pnpm 或另一种常规 Node 包安装方式安装 OpenClaw,以便 Node 能解析包的导出和根依赖树。启动已安装的 openclaw 可执行文件。不要只复制 dist、将包扁平化到应用包中,或对选定的扩展文件进行 vendoring。
相关¶
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw