.ocdoc h2 { margin-top:2em; padding-bottom:.3em; border-bottom:2px solid #FF5A36; color:#FF5A36; }
.ocdoc h3 { margin-top:1.5em; color:#333; }
.ocdoc pre { background:#1e1e2e; color:#cdd6f4; padding:16px; border-radius:8px; overflow-x:auto; font-size:14px; line-height:1.6; }
.ocdoc code { font-family:'JetBrains Mono','Fira Code',Consolas,monospace; }
.ocdoc pre code { background:none; padding:0; color:inherit; }
.ocdoc :not(pre)>code { background:#f0f0f0; padding:2px 6px; border-radius:3px; font-size:.9em; color:#d63384; }
.ocdoc table { border-collapse:collapse; margin:1em 0; }
.ocdoc th,.ocdoc td { border:1px solid #ddd; padding:8px 12px; }
.ocdoc th { background:#f5f5f5; }
.ocdoc blockquote { border-left:4px solid #FF5A36; padding:.5em 1em; background:#fff7f4; color:#555; margin:1em 0; }
.ocdoc .page-sep { margin:2.5em 0; border:none; border-top:1px dashed #ccc; }
.ocdoc .page-title { color:#444; font-size:1.3em; margin-top:1em; padding:.4em .6em; background:#fafafa; border-left:4px solid #FF5A36; }
.ocdoc .src-link { font-size:.85em; color:#888; margin-top:2em; padding-top:1em; border-top:1px solid #e0e0e0; }
.ocdoc .toc-box { background:#f8f9fa; padding:1em 1.5em; border-radius:6px; margin:1em 0; }
![[OpenClaw 文档]参考--概念内部机制](https://minio.imgdata.cn/cnesa/cnesa/2026/05/29/765544625aa111cd7ec16c796667c69f.png)
本文档汇总了 OpenClaw 官方文档站 参考 > 概念内部机制 子模块下的全部 5 篇内容,源自 docs.openclaw.ai/zh-CN。
📄 TypeBox
原文:https://docs.openclaw.ai/zh-CN/concepts/typebox
TypeBox 是一个 TypeScript 优先的 schema 库。我们用它来定义 Gateway 网关
WebSocket 协议(握手、请求/响应、服务器事件)。这些 schema
驱动 运行时验证、JSON Schema 导出,以及面向
macOS 应用的 Swift 代码生成。单一事实来源;其他一切都由它生成。
如果你想了解更高层的协议上下文,请从
Gateway 网关架构开始。
心智模型(30 秒)
每条 Gateway 网关 WS 消息都是以下三种帧之一:
- 请求:
{ type: "req", id, method, params } - 响应:
{ type: "res", id, ok, payload | error } - 事件:
{ type: "event", event, payload, seq?, stateVersion? }
第一帧必须是 connect 请求。之后,客户端可以调用
方法(例如 health、send、chat.send)并订阅事件(例如
presence、tick、agent)。
连接流程(最小):
Client Gateway
|---- req:connect -------->|
|<---- res:hello-ok --------|
|<---- event:tick ----------|
|---- req:health ---------->|
|<---- res:health ----------|
常见方法 + 事件:
| 类别 | 示例 | 说明 |
|---|---|---|
| 核心 | connect、health、status |
connect 必须最先发送 |
| 消息传递 | send、agent、agent.wait、system-event、logs.tail |
副作用需要 idempotencyKey |
| 聊天 | chat.history、chat.send、chat.abort |
WebChat 使用这些 |
| 会话 | sessions.list、sessions.patch、sessions.delete |
会话管理 |
| 自动化 | wake、cron.list、cron.run、cron.runs |
唤醒 + cron 控制 |
| 节点 | node.list、node.invoke、node.pair.* |
Gateway 网关 WS + 节点操作 |
| 事件 | tick、presence、agent、chat、health、shutdown |
服务器推送 |
权威的已公布设备发现清单位于
src/gateway/server-methods-list.ts(listGatewayMethods、GATEWAY_EVENTS)。
schema 所在位置
- 源码:
src/gateway/protocol/schema.ts - 运行时验证器(AJV):
src/gateway/protocol/index.ts - 已公布功能/设备发现注册表:
src/gateway/server-methods-list.ts - 服务器握手 + 方法分发:
src/gateway/server.impl.ts - 节点客户端:
src/gateway/client.ts - 生成的 JSON Schema:
dist/protocol.schema.json - 生成的 Swift 模型:
apps/macos/Sources/OpenClawProtocol/GatewayModels.swift
当前流水线
pnpm protocol:gen- 将 JSON Schema(draft-07)写入
dist/protocol.schema.json pnpm protocol:gen:swift- 生成 Swift Gateway 网关模型
pnpm protocol:check- 运行两个生成器,并验证输出已提交
schema 在运行时的使用方式
- 服务器端:每个入站帧都会用 AJV 验证。握手只接受
params 匹配ConnectParams的connect请求。 - 客户端端:JS 客户端会在使用事件帧和响应帧之前验证它们。
- 功能发现:Gateway 网关会在
hello-ok中从listGatewayMethods()和
GATEWAY_EVENTS发送保守的features.methods
和features.events列表。 - 这个设备发现列表不是
coreGatewayHandlers中每个可调用 helper 的生成转储;
一些 helper RPC 实现在src/gateway/server-methods/*.ts中,
但并未枚举到公布的功能列表里。
示例帧
连接(第一条消息):
{
"type": "req",
"id": "c1",
"method": "connect",
"params": {
"minProtocol": 3,
"maxProtocol": 4,
"client": {
"id": "openclaw-macos",
"displayName": "macos",
"version": "1.0.0",
"platform": "macos 15.1",
"mode": "ui",
"instanceId": "A1B2"
}
}
}
Hello-ok 响应:
{
"type": "res",
"id": "c1",
"ok": true,
"payload": {
"type": "hello-ok",
"protocol": 4,
"server": { "version": "dev", "connId": "ws-1" },
"features": { "methods": ["health"], "events": ["tick"] },
"snapshot": {
"presence": [],
"health": {},
"stateVersion": { "presence": 0, "health": 0 },
"uptimeMs": 0
},
"policy": { "maxPayload": 1048576, "maxBufferedBytes": 1048576, "tickIntervalMs": 30000 }
}
}
请求 + 响应:
{ "type": "req", "id": "r1", "method": "health" }
{ "type": "res", "id": "r1", "ok": true, "payload": { "ok": true } }
事件:
{ "type": "event", "event": "tick", "payload": { "ts": 1730000000 }, "seq": 12 }
最小客户端(Node.js)
最小可用流程:连接 + health。
import { WebSocket } from "ws";
const ws = new WebSocket("ws://127.0.0.1:18789");
ws.on("open", () => {
ws.send(
JSON.stringify({
type: "req",
id: "c1",
method: "connect",
params: {
minProtocol: 4,
maxProtocol: 4,
client: {
id: "cli",
displayName: "example",
version: "dev",
platform: "node",
mode: "cli",
},
},
}),
);
});
ws.on("message", (data) => {
const msg = JSON.parse(String(data));
if (msg.type === "res" && msg.id === "c1" && msg.ok) {
ws.send(JSON.stringify({ type: "req", id: "h1", method: "health" }));
}
if (msg.type === "res" && msg.id === "h1") {
console.log("health:", msg.payload);
ws.close();
}
});
完整示例:端到端添加一个方法
示例:添加一个新的 system.echo 请求,返回 { ok: true, text }。
- Schema(事实来源)
添加到 src/gateway/protocol/schema.ts:
export const SystemEchoParamsSchema = Type.Object(
{ text: NonEmptyString },
{ additionalProperties: false },
);
export const SystemEchoResultSchema = Type.Object(
{ ok: Type.Boolean(), text: NonEmptyString },
{ additionalProperties: false },
);
将两者添加到 ProtocolSchemas 并导出类型:
SystemEchoParams: SystemEchoParamsSchema,
SystemEchoResult: SystemEchoResultSchema,
export type SystemEchoParams = Static<typeof SystemEchoParamsSchema>;
export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;
- 验证
在 src/gateway/protocol/index.ts 中导出一个 AJV 验证器:
export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);
- 服务器行为
在 src/gateway/server-methods/system.ts 中添加 handler:
export const systemHandlers: GatewayRequestHandlers = {
"system.echo": ({ params, respond }) => {
const text = String(params.text ?? "");
respond(true, { ok: true, text });
},
};
在 src/gateway/server-methods.ts 中注册它(已经合并 systemHandlers),
然后将 "system.echo" 添加到
src/gateway/server-methods-list.ts 中的 listGatewayMethods 输入。
如果该方法可由 operator 或节点客户端调用,还要在
src/gateway/method-scopes.ts 中对它分类,以便 scope 强制执行和
hello-ok 功能公布保持一致。
- 重新生成
pnpm protocol:check
- 测试 + 文档
在 src/gateway/server.*.test.ts 中添加服务器测试,并在文档中说明该方法。
Swift 代码生成行为
Swift 生成器会输出:
- 包含
req、res、event和unknowncase 的GatewayFrameenum - 强类型 payload struct/enum
ErrorCode值、GATEWAY_PROTOCOL_VERSION和GATEWAY_MIN_PROTOCOL_VERSION
未知帧类型会保留为原始 payload,以实现向前兼容。
版本控制 + 兼容性
PROTOCOL_VERSION位于src/gateway/protocol/version.ts。- 客户端发送
minProtocol+maxProtocol;服务器会拒绝不包含其当前协议版本的范围。 - Swift 模型会保留未知帧类型,以避免破坏较旧客户端。
Schema 模式和约定
- 大多数对象使用
additionalProperties: false来实现严格 payload。 NonEmptyString是 ID 和方法/事件名称的默认值。- 顶层
GatewayFrame在type上使用判别器。 - 带副作用的方法通常需要在 params 中提供
idempotencyKey
(示例:send、poll、agent、chat.send)。 agent接受可选的internalEvents,用于运行时生成的编排上下文
(例如子智能体/cron 任务完成交接);请将其视为内部 API 表面。
实时 schema JSON
生成的 JSON Schema 位于仓库中的 dist/protocol.schema.json。已发布的 raw 文件通常可在以下位置获取:
更改 schema 时
- 更新 TypeBox schema。
- 在
src/gateway/server-methods-list.ts中注册方法/事件。 - 当新的 RPC 需要 operator 或节点 scope 分类时,更新
src/gateway/method-scopes.ts。 - 运行
pnpm protocol:check。 - 提交重新生成的 schema + Swift 模型。
相关内容
📄 Markdown 格式
原文:https://docs.openclaw.ai/zh-CN/concepts/markdown-formatting
OpenClaw 通过将出站 Markdown 转换为共享的中间
表示(IR),再渲染为特定渠道的输出。IR 会保持
源文本不变,同时携带样式/链接范围,因此分块和渲染可以
在各渠道之间保持一致。
目标
- 一致性: 一次解析步骤,多个渲染器。
- 安全分块: 在渲染前拆分文本,确保内联格式永远不会
跨分块断裂。 - 适配渠道: 将同一份 IR 映射到 Slack mrkdwn、Telegram HTML 和 Signal
样式范围,而无需重新解析 Markdown。
流程
- 解析 Markdown -> IR
- IR 是纯文本加样式范围(粗体/斜体/删除线/代码/spoiler)和链接范围。
- 偏移量使用 UTF-16 代码单元,因此 Signal 样式范围能与其 API 对齐。
- 只有当渠道选择启用表格转换时,才会解析表格。 - 分块 IR(格式优先)
- 分块发生在渲染前的 IR 文本上。
- 内联格式不会跨分块拆分;范围会按分块切片。 - 按渠道渲染
- Slack: mrkdwn 标记(粗体/斜体/删除线/代码),链接为<url|label>。
- Telegram: HTML 标签(<b>、<i>、<s>、<code>、<pre><code>、<a href>)。
- Signal: 纯文本 +text-style范围;当标签不同时,链接会变成label (url)。
IR 示例
输入 Markdown:
Hello **world** - see [docs](https://docs.openclaw.ai).
IR(示意):
{
"text": "Hello world - see docs.",
"styles": [{ "start": 6, "end": 11, "style": "bold" }],
"links": [{ "start": 19, "end": 23, "href": "https://docs.openclaw.ai" }]
}
使用位置
- Slack、Telegram 和 Signal 出站适配器从 IR 渲染。
- 其他渠道(WhatsApp、iMessage、Microsoft Teams、Discord)仍使用纯文本或
它们自己的格式化规则;启用时会在
分块前应用 Markdown 表格转换。
表格处理
Markdown 表格在各类聊天客户端中的支持并不一致。使用
markdown.tables 按渠道(以及按账户)控制转换。
code:将表格渲染为代码块(大多数渠道的默认值)。bullets:将每一行转换为项目符号点(Matrix、Signal 和 WhatsApp 的默认值)。off:禁用表格解析和转换;原始表格文本会直接传递。
配置键:
channels:
discord:
markdown:
tables: code
accounts:
work:
markdown:
tables: off
分块规则
- 分块限制来自渠道适配器/配置,并应用于 IR 文本。
- 代码围栏会作为带尾随换行的单个块保留,以便渠道
正确渲染它们。 - 列表前缀和块引用前缀是 IR 文本的一部分,因此分块
不会在前缀中间拆分。 - 内联样式(粗体/斜体/删除线/行内代码/spoiler)永远不会跨
分块拆分;渲染器会在每个分块内重新打开样式。
如果你需要了解更多跨渠道分块行为,请参阅
流式传输和分块。
链接策略
- Slack:
[label](url)-><url|label>;裸 URL 保持裸露。解析期间会禁用 Autolink,
以避免重复链接。 - Telegram:
[label](url)-><a href="url">label</a>(HTML 解析模式)。 - Signal:
[label](url)->label (url),除非标签与 URL 匹配。
Spoilers
Spoiler 标记(||spoiler||)仅为 Signal 解析,在其中会映射到
SPOILER 样式范围。其他渠道会将它们视为纯文本。
如何添加或更新渠道格式化器
- 解析一次: 使用共享的
markdownToIR(...)辅助函数,并传入适合渠道的
选项(autolink、标题样式、块引用前缀)。 - 渲染: 使用
renderMarkdownWithMarkers(...)和
样式标记映射(或 Signal 样式范围)实现渲染器。 - 分块: 在渲染前调用
chunkMarkdownIR(...);渲染每个分块。 - 接入适配器: 更新渠道出站适配器,以使用新的分块器
和渲染器。 - 测试: 添加或更新格式测试;如果该
渠道使用分块,还要添加出站投递测试。
常见注意事项
- Slack 尖括号标记(
<@U123>、<#C123>、<https://...>)必须
保留;安全地转义原始 HTML。 - Telegram HTML 要求转义标签外的文本,以避免标记损坏。
- Signal 样式范围依赖 UTF-16 偏移量;不要使用码点偏移量。
- 为围栏代码块保留尾随换行,使结束标记落在
它自己的行上。
相关内容
出站流式传输行为、分块边界和特定渠道的投递。
模型在对话前看到的内容,包括注入的工作区文件。
📄 输入状态指示器
原文:https://docs.openclaw.ai/zh-CN/concepts/typing-indicators
运行处于活动状态时,会向聊天渠道发送输入指示器。使用
agents.defaults.typingMode 控制输入状态何时开始,使用 typingIntervalSeconds
控制它多久刷新一次。
默认值
当 agents.defaults.typingMode 未设置时,OpenClaw 会保持旧版行为:
- 直接聊天:模型循环一开始,输入状态就会立即开始。
- 带有提及的群聊:输入状态会立即开始。
- 不带提及的群聊:只有在消息文本开始流式传输时,输入状态才会开始。
- Heartbeat 运行:如果解析出的 Heartbeat 目标是支持输入状态的聊天,且输入状态未被禁用,则输入状态会在 Heartbeat 运行开始时启动。
模式
将 agents.defaults.typingMode 设置为以下之一:
never- 永不显示输入指示器。instant- 模型循环一开始就开始输入状态,即使该运行之后只返回静默回复 token。thinking- 在第一个推理增量时开始输入状态(该运行需要
reasoningLevel: "stream")。message- 在第一个非静默文本增量时开始输入状态(忽略
NO_REPLY静默 token)。
“触发早晚”的顺序:
never → message → thinking → instant
配置
设置智能体级别默认值:
{
agents: {
defaults: {
typingMode: "thinking",
typingIntervalSeconds: 6,
},
},
}
按会话覆盖模式或节奏:
{
session: {
typingMode: "message",
typingIntervalSeconds: 4,
},
}
说明
- 当整个载荷正好是静默 token(例如
NO_REPLY/no_reply,大小写不敏感匹配)时,message模式不会为仅静默回复显示输入状态。 thinking只有在运行流式传输推理(reasoningLevel: "stream")时才会触发。
如果模型没有发出推理增量,输入状态就不会开始。- Heartbeat 输入状态是针对解析出的投递目标的存活信号。它会在 Heartbeat 运行开始时启动,而不是遵循
message或thinking
的流式传输时机。设置typingMode: "never"可将其禁用。 - 当
target: "none"、目标无法解析、该 Heartbeat 的聊天投递被禁用,或渠道不支持输入状态时,Heartbeat 不会显示输入状态。 typingIntervalSeconds控制的是刷新节奏,不是开始时间。
默认值为 6 秒。
相关
Gateway 网关 如何跟踪已连接的客户端,并在 macOS Instances 标签页中显示它们。
出站流式传输行为、分块边界,以及特定于渠道的投递。
📄 使用情况跟踪
原文:https://docs.openclaw.ai/zh-CN/concepts/usage-tracking
它是什么
- 直接从各提供商的用量端点拉取提供商用量/配额。
- 不估算费用;只显示提供商报告的窗口。
- 面向人的状态输出会规范化为
X% left,即使上游 API 报告的是已消耗配额、剩余配额或仅原始计数。 - 会话级
/status和session_status可在实时会话快照稀疏时回退到最新的转录用量条目。该回退会补齐缺失的令牌/缓存计数器,可以恢复活跃运行时模型标签,并在会话元数据缺失或更小时优先使用更大的提示词导向总量。现有非零实时值仍然优先。
显示位置
- 聊天中的
/status:带有丰富表情符号的状态卡片,包含会话令牌 + 预估费用(仅 API key)。当可用时,会显示当前模型提供商的提供商用量,并规范化为X% left窗口。 - 聊天中的
/usage off|tokens|full:逐响应的用量页脚(OAuth 仅显示令牌)。 - 聊天中的
/usage cost:从 OpenClaw 会话日志聚合的本地费用摘要。 - CLI:
openclaw status --usage打印完整的逐提供商明细。 - CLI:
openclaw channels list在提供商配置旁打印相同的用量快照(使用--no-usage跳过)。 - macOS 菜单栏:Context 下的 “用量” 部分(仅在可用时)。
提供商 + 凭证
- Anthropic(Claude):凭证配置文件中的 OAuth 令牌。
- GitHub Copilot:凭证配置文件中的 OAuth 令牌。
- Gemini CLI:凭证配置文件中的 OAuth 令牌。
- JSON 用量会回退到
stats;stats.cached会规范化为cacheRead。 - OpenAI Codex:凭证配置文件中的 OAuth 令牌(存在 accountId 时使用)。
- MiniMax:API key 或 MiniMax OAuth 凭证配置文件。OpenClaw 将
minimax、minimax-cn和minimax-portal视为同一个 MiniMax 配额表面,存在已存储的 MiniMax OAuth 时优先使用,否则回退到MINIMAX_CODE_PLAN_KEY、MINIMAX_CODING_API_KEY或MINIMAX_API_KEY。配置后,用量轮询会从models.providers.minimax-portal.baseUrl或models.providers.minimax.baseUrl推导 Coding Plan 主机,否则使用 MiniMax CN 主机。MiniMax 的原始usage_percent/usagePercent字段表示剩余配额,因此 OpenClaw 会在显示前将其反转;存在基于计数的字段时,它们优先。 - Coding-plan 窗口标签优先来自提供商的小时/分钟字段,存在时使用;否则回退到
start_time/end_time时间跨度。 - 如果 coding-plan 端点返回
model_remains,OpenClaw 会优先使用聊天模型条目,在缺少显式window_hours/window_minutes字段时从时间戳推导窗口标签,并在方案标签中包含模型名称。 - Xiaomi MiMo:通过环境变量/配置/凭证存储提供的 API key(
XIAOMI_API_KEY)。 - z.ai:通过环境变量/配置/凭证存储提供的 API key。
当无法解析出可用的提供商用量认证时,会隐藏用量。提供商可以提供插件专用的用量认证逻辑;否则 OpenClaw 会回退到从凭证配置文件、环境变量或配置中匹配 OAuth/API-key 凭证。
相关
📄 时区
原文:https://docs.openclaw.ai/zh-CN/concepts/timezone
OpenClaw 会标准化时间戳,让模型看到的是单一参考时间,而不是混杂的提供商本地时钟。时区会出现在三个层面,每个层面都有自己的用途:
三个时区层面
| 层面 | 显示内容 | 默认值 | 配置方式 |
|---|---|---|---|
| 消息信封 | 包装传入的渠道消息:[Signal +1555 2026-01-18 00:19 PST] hello |
主机本地 | agents.defaults.envelopeTimezone |
| 工具载荷 | 渠道 readMessages 风格的工具返回原始提供商时间 + 标准化的 timestampMs / timestampUtc |
始终存在 UTC 字段 | 不可配置;保留提供商原生时间戳 |
| 系统提示词 | 一个小型 Current Date & Time 块,只包含时区(不含时钟值,以保持缓存稳定) |
未设置 userTimezone 时使用主机时区 |
agents.defaults.userTimezone |
系统提示词会有意省略实时时钟,以保持提示词缓存在多轮对话中的稳定性。当智能体需要当前时间时,它会调用 session_status。
设置用户时区
{
agents: {
defaults: {
userTimezone: "America/Chicago",
},
},
}
如果未设置 userTimezone,OpenClaw 会在运行时解析主机时区(不会写入配置)。agents.defaults.timeFormat(auto | 12 | 24)控制信封和下游层面的 12 小时制/24 小时制渲染,而不控制系统提示词部分。
何时覆盖
- 使用 UTC 信封(
envelopeTimezone: "utc"):当你希望不同区域的主机之间使用稳定时间戳,或者希望 UTC 对齐的日志匹配诊断输出时使用。 - 使用固定 IANA 时区(例如
"Europe/Vienna"):当 Gateway 网关主机位于一个时区,但用户位于另一个时区,并且你希望信封无论主机如何迁移都按用户时区显示时使用。 - 设置
envelopeTimestamp: "off":当时间戳上下文对对话没有帮助,并希望使用低 token 信封时使用。
如需完整行为参考、各提供商示例以及经过时间格式化,请参阅 日期和时间。
相关
📂 所属板块:参考 > 概念内部机制 | 🤖 翻译模型:volcengine-plan/ark-code-latest