openclaw 架构

openclaw gateway

基本

gateway整体架构

渠道

统一的 ChannelProvider 接口集成多个消息平台。

go 复制代码
interface ChannelProvider {

  name: string;

  // 启动通道连接

  start(): Promise<void>;

  stop(): Promise<void>;

  // 发送消息

  sendMessage(params: SendMessageParams): Promise<Result>;

  sendMedia(params: SendMediaParams): Promise<Result>;

  // 订阅事件(消息、状态等)

  on(event: string, handler: Function): void;

  // 查询通道能力

  capabilities(): ChannelCapabilities;

}

interface ChannelCapabilities {

  text: boolean;        // 📝 文本消息

  images: boolean;      // 🖼️ 图片

  videos: boolean;      // 🎥 视频

  audio: boolean;       // 🎵 音频

  documents: boolean;   // 📄 文档

  reactions: boolean;   // ❤️ 反应

  threads: boolean;     // 🧵 线程

  mentions: boolean;    // @ 提及

  formatting: boolean;  // 🎨 Markdown/富文本

}
  • 接口隔离原则: ChannelProvider 定义统一接口,各平台实现具体逻辑,确保代码的可维护性和可扩展性。
  • 能力查询机制: 通过 ChannelCapabilities 动态查询通道支持的功能,避免硬编码判断。
  • 事件驱动模式: 使用 on(event, handler) 订阅消息、媒体、在线状态等事件,解耦事件处理逻辑。
  • 异步操作模式: 所有核心方法返回 Promise,支持异步操作,不阻塞主线程。
  • 依赖注入: 各 Provider 依赖平台特定的库,通过构造函数注入。

规则解析

主流程

ts 复制代码
function startGatewayServer(){
	// 1. 读、校验修正配置
	// 2. 启用插件
	// 3. 鉴权相关
	// 4. 监听线程:管理gateway 的生命周期,监听终止/重启/升级命令和执行他们
	
	// 创建网络对象
	createGatewayRuntimeState()
	
	// 启动渠道管理模块
	// 广播服务
	// 保活程序
	startGatewayMaintenanceTimers()
	
	// 创建一些模块对象
	// 设置 skills 服务器
	// canvas服务器
	// 浏览器控制模块
	// cron 定时任务模块
	// log 对象
	// 配对加入/登录校验等
	
	// 将这些对象绑定到 websocket 接口,在请求到达时调用
	attachGatewayWsHandlers()
	// 配置热更新机制

	//注册安全退出函数
}
ts 复制代码
function startGatewayMaintenanceTimers(){
	// 向连接对象广播 tick 保活
	// 记录健康快照
	// 内存清理(清过期会话等)
	
}

openclaw 启动的守护进程Gateway,本质上是个 rpc 的网关,单一线程,不区分 server 和 agent,由事件驱动 agent 的执行,agent 所需的资源多为全局变量

消息

agent事件event

event 用于实时推流给控制界面

  1. 用于协调网关内部流程(waitForAgentJob、subagent 生命周期、run 清理)。
  2. 观测与调试(日志、监控可消费这些事件)。
ts 复制代码
// 单个事件结构
export type AgentEventStream = "lifecycle" | "tool" | "assistant" | "error" | (string & {});

export type AgentEventPayload = {
	runId: string;
	seq: number;
	stream: AgentEventStream;
	ts: number;
	data: Record<string, unknown>;
	sessionKey?: string;
};

事件运行机制:初始化时往全局对象里添加回调函数,agent 需要发送事件时遍历数组选择触发指定类型的回调

事件类型:

  • 把 agent 事件转成 agent/chat 推给 WS/会话客户端
  • subagent、agent job生命周期监听
  • 流式转发, 把 assistant + lifecycle(end/error) 组合成 chat delta/final 发给前端

rpc 服务

主要服务

初始阶段 连接鉴权
网关相关 健康检查/配置热更新
业务相关 会话管理/聊天/agent 执行/
接入 渠道/设备/浏览器代理/节点配对
工具 工具/插件

服务的注册逻辑

通过配置文件创建句柄对象

由 rpc 管理对象

请求时通过 rpc 路由到对应模块,调用相关的句柄的接口实现功能

对每个模块都注册了关闭接口

http

功能类到 gateway ws 的 rpc 请求

加载的插件合并注册到 rpc 里

探活就绪等走 http单独处理

心跳拷贝的数据:

  • Agent 维度信息:默认 agent、每个 agent 的 heartbeat 配置摘要、session 存储摘要(路径/数量/最近会话)
  • Channel 维度信息:每个 channel/account 的 configured/linked/probe 结果、最后探测时间
  • 统计字段:ts、durationMs、channelOrder、channelLabels 等

意义在于,多渠道请求心跳时,直接返回提前生成好的心跳快照

agent 循环

并发队列

每个会话一个队列,新建一个会话新建一个队列

上下文组装

如果是沙箱隔离运行,创建工作区

基础提示、Skills 提示、引导上下文和每次运行的覆盖构建

压缩

工具

会话管理

memory

gateway 启动时,初始化 memory 对象和环境,放在全局对象中,通过get 和 query 方法获取记忆

记忆写入文件系统,在会话结束时(例如/new)执行压缩

后台线程定期读取文件系统,构件 sqlite 对象,查询时查询 sqlite

hooks

可扩展的事件驱动系统,允许在会话的一些时机做一些事情:

  • 第一次创建时启动引导程序时
  • 用户的每次命令时

插件钩子

  • before_agent_start:在运行开始前注入上下文或覆盖系统提示。
  • agent_end:在完成后检查最终消息列表和运行元数据。
  • before_compaction / after_compaction:观察或注释压缩周期。
  • before_tool_call / after_tool_call:拦截工具参数/结果。
  • tool_result_persist:在工具结果写入会话记录之前同步转换它们。
  • message_received / message_sending / message_sent:入站 + 出站消息钩子。
  • session_start / session_end:会话生命周期边界。
  • gateway_start / gateway_stop:Gateway 网关生命周期事件。

大致分为:入口 → 会话 → Agent推理 → 工具执行 → 记录压缩 → 出站

Webhooks

在事件发生时主动发 HTTP 回调通知"的机制

一个典型场景是,用户传了个链接,数据在链接里

沙箱策略

浏览器、工具执行可以选择是否用沙箱执行

gateway 本身不会被沙箱隔离

插件系统

在 gateway 启动时候,调用每个插件的 run 函数,每个插件的运行、交互姿态都不一样

  • api.registerService({...}) 做常驻后台任务
  • api.registerHttpRoute({...}) 暴露 HTTP endpoint
  • api.registerGatewayMethod(...) 暴露 gateway 方法,hook
  • Tool 插件

famou webagent VS openclaw gateway

我们和 openclaw 的不同在于,我们是在服务端上跑,面向公网服务足量的用户,openclaw 是个人电脑轻量级部署,服务个人,细化差异

openclaw webagent
语言 ts openclaw 起源个人项目,前后端用 ts 统一便于快速开发, 服务端为支持并发和资源利用,使用go
渠道 简化这部分
鉴权 少量少频 高频多量 单独的登录系统
并发 消息队列移到 server 层、高频调用组件解耦
用户自定义 简化这部分
持久化 agent 内写入文件 一个 agent 在 sandbox 里,不能持久化 agent 通过 rpc 上传记忆,server 存储记忆

openclaw 代码质量低的原因

  • 函数是功能的堆叠,没有最小功能原则,主函数 700 行代码,
  • Composition Root 与运行时 Service 边界不清,缺少明确模块协议。
  • 生命周期状态机没有显式建模
  • 没有组织数据,函数入参出参都是一堆变量
  • 变量、函数的定义和使用类似 c 风格,不方便追踪
  • 使用了大量的匿名函数,代码耦合度极高

openclaw gateway

基本

gateway整体架构

Pasted image 20260304111834.png

渠道

统一的 ChannelProvider 接口集成多个消息平台。

go 复制代码
interface ChannelProvider {

name: string;


// 启动通道连接


start(): Promise<void>;


stop(): Promise<void>;


// 发送消息


sendMessage(params: SendMessageParams): Promise<Result>;


sendMedia(params: SendMediaParams): Promise<Result>;


// 订阅事件(消息、状态等)


on(event: string, handler: Function): void;


// 查询通道能力


capabilities(): ChannelCapabilities;


}


interface ChannelCapabilities {


text: boolean;        // 📝 文本消息


images: boolean;      // 🖼️ 图片


videos: boolean;      // 🎥 视频


audio: boolean;       // 🎵 音频


documents: boolean;   // 📄 文档


reactions: boolean;   // ❤️ 反应


threads: boolean;     // 🧵 线程


mentions: boolean;    // @ 提及


formatting: boolean;  // 🎨 Markdown/富文本

`}`
`
`
  • **接口隔离原则**: ChannelProvider 定义统一接口,各平台实现具体逻辑,确保代码的可维护性和可扩展性。
  • **能力查询机制**: 通过 ChannelCapabilities 动态查询通道支持的功能,避免硬编码判断。
  • **事件驱动模式**: 使用 on(event, handler) 订阅消息、媒体、在线状态等事件,解耦事件处理逻辑。
  • **异步操作模式**: 所有核心方法返回 Promise,支持异步操作,不阻塞主线程。
  • **依赖注入**: 各 Provider 依赖平台特定的库,通过构造函数注入。

规则解析

Pasted image 20260304112030.png

主流程

ts 复制代码
function startGatewayServer(){
	// 1. 读、校验修正配置
	// 2. 启用插件
	// 3. 鉴权相关
	// 4. 监听线程:管理gateway 的生命周期,监听终止/重启/升级命令和执行他们

    // 创建网络对象
    createGatewayRuntimeState()

    // 启动渠道管理模块
    // 广播服务
    // 保活程序
    startGatewayMaintenanceTimers()

    // 创建一些模块对象
    // 设置 skills 服务器
    // canvas服务器
    // 浏览器控制模块
    // cron 定时任务模块
    // log 对象
    // 配对加入/登录校验等

    // 将这些对象绑定到 websocket 接口,在请求到达时调用
    attachGatewayWsHandlers()
    // 配置热更新机制

    //注册安全退出函数




}
ts 复制代码
function startGatewayMaintenanceTimers(){
	// 向连接对象广播 tick 保活
	// 记录健康快照
	// 内存清理(清过期会话等)
	
}

openclaw 启动的守护进程Gateway,本质上是个 rpc 的网关,单一线程,不区分 server 和 agent,由事件驱动 agent 的执行,agent 所需的资源多为全局变量

消息

agent事件event

event 用于实时推流给控制界面

  1. 用于协调网关内部流程(waitForAgentJob、subagent 生命周期、run 清理)。
  2. 观测与调试(日志、监控可消费这些事件)。
ts 复制代码
// 单个事件结构
export type AgentEventStream = "lifecycle" | "tool" | "assistant" | "error" | (string & {});
`export type AgentEventPayload = {`
`
runId: string;`
`
seq: number;`
`
stream: AgentEventStream;`
`
ts: number;`
`
data: Record<string, unknown>;`
`
sessionKey?: string;`
`
};`
`
`

事件运行机制:初始化时往全局对象里添加回调函数,agent 需要发送事件时遍历数组选择触发指定类型的回调

事件类型:

  • 把 agent 事件转成 agent/chat 推给 WS/会话客户端
  • subagent、agent job生命周期监听
  • 流式转发, 把 assistant + lifecycle(end/error) 组合成 chat delta/final 发给前端

rpc 服务

主要服务

初始阶段 连接鉴权
网关相关 健康检查/配置热更新
业务相关 会话管理/聊天/agent 执行/
接入 渠道/设备/浏览器代理/节点配对
工具 工具/插件

服务的注册逻辑

通过配置文件创建句柄对象

由 rpc 管理对象

请求时通过 rpc 路由到对应模块,调用相关的句柄的接口实现功能

对每个模块都注册了关闭接口

http

功能类到 gateway ws 的 rpc 请求

加载的插件合并注册到 rpc 里

探活就绪等走 http单独处理

心跳拷贝的数据:

  • Agent 维度信息:默认 agent、每个 agent 的 heartbeat 配置摘要、session 存储摘要(路径/数量/最近会话)
  • Channel 维度信息:每个 channel/account 的 configured/linked/probe 结果、最后探测时间
  • 统计字段:ts、durationMs、channelOrder、channelLabels 等

意义在于,多渠道请求心跳时,直接返回提前生成好的心跳快照

agent 循环

并发队列

每个会话一个队列,新建一个会话新建一个队列
Pasted image 20260305165657.png

上下文组装

如果是沙箱隔离运行,创建工作区

基础提示、Skills 提示、引导上下文和每次运行的覆盖构建

压缩

工具

会话管理

Pasted image 20260305201537.png

memory

gateway 启动时,初始化 memory 对象和环境,放在全局对象中,通过get 和 query 方法获取记忆

记忆写入文件系统,在会话结束时(例如/new)执行压缩

后台线程定期读取文件系统,构件 sqlite 对象,查询时查询 sqlite

hooks

可扩展的事件驱动系统,允许在会话的一些时机做一些事情:

  • 第一次创建时启动引导程序时
  • 用户的每次命令时

插件钩子

  • before_agent_start:在运行开始前注入上下文或覆盖系统提示。
  • agent_end:在完成后检查最终消息列表和运行元数据。
  • before_compaction / after_compaction:观察或注释压缩周期。
  • before_tool_call / after_tool_call:拦截工具参数/结果。
  • tool_result_persist:在工具结果写入会话记录之前同步转换它们。
  • message_received / message_sending / message_sent:入站 + 出站消息钩子。
  • session_start / session_end:会话生命周期边界。
  • gateway_start / gateway_stop:Gateway 网关生命周期事件。

大致分为:入口 → 会话 → Agent推理 → 工具执行 → 记录压缩 → 出站

Webhooks

在事件发生时主动发 HTTP 回调通知"的机制

一个典型场景是,用户传了个链接,数据在链接里

沙箱策略

浏览器、工具执行可以选择是否用沙箱执行

gateway 本身不会被沙箱隔离

插件系统

在 gateway 启动时候,调用每个插件的 run 函数,每个插件的运行、交互姿态都不一样

  • api.registerService({...}) 做常驻后台任务
  • api.registerHttpRoute({...}) 暴露 HTTP endpoint
  • api.registerGatewayMethod(...) 暴露 gateway 方法,hook
  • Tool 插件

famou webagent VS openclaw gateway

我们和 openclaw 的不同在于,我们是在服务端上跑,面向公网服务足量的用户,openclaw 是个人电脑轻量级部署,服务个人,细化差异

openclaw webagent
语言 ts openclaw 起源个人项目,前后端用 ts 统一便于快速开发, 服务端为支持并发和资源利用,使用go
渠道 简化这部分
鉴权 少量少频 高频多量 单独的登录系统
并发 消息队列移到 server 层、高频调用组件解耦
用户自定义 简化这部分
持久化 agent 内写入文件 一个 agent 在 sandbox 里,不能持久化 agent 通过 rpc 上传记忆,server 存储记忆

openclaw 代码质量低的原因

  • 函数是功能的堆叠,没有最小功能原则,主函数 700 行代码,
  • Composition Root 与运行时 Service 边界不清,缺少明确模块协议。
  • 生命周期状态机没有显式建模
  • 没有组织数据,函数入参出参都是一堆变量
  • 变量、函数的定义和使用类似 c 风格,不方便追踪
  • 使用了大量的匿名函数,代码耦合度极高