[OpenClaw 文档]参考--概念内部机制

.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 文档]参考--概念内部机制

本文档汇总了 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 请求。之后,客户端可以调用
方法(例如 healthsendchat.send)并订阅事件(例如
presencetickagent)。

连接流程(最小):

Client                    Gateway
  |---- req:connect -------->|
  |<---- res:hello-ok --------|
  |<---- event:tick ----------|
  |---- req:health ---------->|
  |<---- res:health ----------|

常见方法 + 事件:

类别 示例 说明
核心 connecthealthstatus connect 必须最先发送
消息传递 sendagentagent.waitsystem-eventlogs.tail 副作用需要 idempotencyKey
聊天 chat.historychat.sendchat.abort WebChat 使用这些
会话 sessions.listsessions.patchsessions.delete 会话管理
自动化 wakecron.listcron.runcron.runs 唤醒 + cron 控制
节点 node.listnode.invokenode.pair.* Gateway 网关 WS + 节点操作
事件 tickpresenceagentchathealthshutdown 服务器推送

权威的已公布设备发现清单位于
src/gateway/server-methods-list.tslistGatewayMethodsGATEWAY_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 匹配 ConnectParamsconnect 请求。
  • 客户端端: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 }

  1. 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>;
  1. 验证

src/gateway/protocol/index.ts 中导出一个 AJV 验证器:

export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);
  1. 服务器行为

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 功能公布保持一致。

  1. 重新生成
pnpm protocol:check
  1. 测试 + 文档

src/gateway/server.*.test.ts 中添加服务器测试,并在文档中说明该方法。

Swift 代码生成行为

Swift 生成器会输出:

  • 包含 reqreseventunknown case 的 GatewayFrame enum
  • 强类型 payload struct/enum
  • ErrorCode 值、GATEWAY_PROTOCOL_VERSIONGATEWAY_MIN_PROTOCOL_VERSION

未知帧类型会保留为原始 payload,以实现向前兼容。

版本控制 + 兼容性

  • PROTOCOL_VERSION 位于 src/gateway/protocol/version.ts
  • 客户端发送 minProtocol + maxProtocol;服务器会拒绝不包含其当前协议版本的范围。
  • Swift 模型会保留未知帧类型,以避免破坏较旧客户端。

Schema 模式和约定

  • 大多数对象使用 additionalProperties: false 来实现严格 payload。
  • NonEmptyString 是 ID 和方法/事件名称的默认值。
  • 顶层 GatewayFrametype 上使用判别器
  • 带副作用的方法通常需要在 params 中提供 idempotencyKey
    (示例:sendpollagentchat.send)。
  • agent 接受可选的 internalEvents,用于运行时生成的编排上下文
    (例如子智能体/cron 任务完成交接);请将其视为内部 API 表面。

实时 schema JSON

生成的 JSON Schema 位于仓库中的 dist/protocol.schema.json。已发布的 raw 文件通常可在以下位置获取:

更改 schema 时

  1. 更新 TypeBox schema。
  2. src/gateway/server-methods-list.ts 中注册方法/事件。
  3. 当新的 RPC 需要 operator 或节点 scope 分类时,更新 src/gateway/method-scopes.ts
  4. 运行 pnpm protocol:check
  5. 提交重新生成的 schema + Swift 模型。

相关内容


📄 Markdown 格式

原文:https://docs.openclaw.ai/zh-CN/concepts/markdown-formatting

OpenClaw 通过将出站 Markdown 转换为共享的中间
表示(IR),再渲染为特定渠道的输出。IR 会保持
源文本不变,同时携带样式/链接范围,因此分块和渲染可以
在各渠道之间保持一致。

目标

  • 一致性: 一次解析步骤,多个渲染器。
  • 安全分块: 在渲染前拆分文本,确保内联格式永远不会
    跨分块断裂。
  • 适配渠道: 将同一份 IR 映射到 Slack mrkdwn、Telegram HTML 和 Signal
    样式范围,而无需重新解析 Markdown。

流程

  1. 解析 Markdown -> IR
    - IR 是纯文本加样式范围(粗体/斜体/删除线/代码/spoiler)和链接范围。
    - 偏移量使用 UTF-16 代码单元,因此 Signal 样式范围能与其 API 对齐。
    - 只有当渠道选择启用表格转换时,才会解析表格。
  2. 分块 IR(格式优先)
    - 分块发生在渲染前的 IR 文本上。
    - 内联格式不会跨分块拆分;范围会按分块切片。
  3. 按渠道渲染
    - 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 样式范围。其他渠道会将它们视为纯文本。

如何添加或更新渠道格式化器

  1. 解析一次: 使用共享的 markdownToIR(...) 辅助函数,并传入适合渠道的
    选项(autolink、标题样式、块引用前缀)。
  2. 渲染: 使用 renderMarkdownWithMarkers(...)
    样式标记映射(或 Signal 样式范围)实现渲染器。
  3. 分块: 在渲染前调用 chunkMarkdownIR(...);渲染每个分块。
  4. 接入适配器: 更新渠道出站适配器,以使用新的分块器
    和渲染器。
  5. 测试: 添加或更新格式测试;如果该
    渠道使用分块,还要添加出站投递测试。

常见注意事项

  • 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)。

“触发早晚”的顺序:
nevermessagethinkinginstant

配置

设置智能体级别默认值:

{
  agents: {
    defaults: {
      typingMode: "thinking",
      typingIntervalSeconds: 6,
    },
  },
}

按会话覆盖模式或节奏:

{
  session: {
    typingMode: "message",
    typingIntervalSeconds: 4,
  },
}

说明

  • 当整个载荷正好是静默 token(例如 NO_REPLY / no_reply,大小写不敏感匹配)时,message 模式不会为仅静默回复显示输入状态。
  • thinking 只有在运行流式传输推理(reasoningLevel: "stream")时才会触发。
    如果模型没有发出推理增量,输入状态就不会开始。
  • Heartbeat 输入状态是针对解析出的投递目标的存活信号。它会在 Heartbeat 运行开始时启动,而不是遵循 messagethinking
    的流式传输时机。设置 typingMode: "never" 可将其禁用。
  • target: "none"、目标无法解析、该 Heartbeat 的聊天投递被禁用,或渠道不支持输入状态时,Heartbeat 不会显示输入状态。
  • typingIntervalSeconds 控制的是刷新节奏,不是开始时间。
    默认值为 6 秒。

相关

Gateway 网关 如何跟踪已连接的客户端,并在 macOS Instances 标签页中显示它们。

出站流式传输行为、分块边界,以及特定于渠道的投递。


📄 使用情况跟踪

原文:https://docs.openclaw.ai/zh-CN/concepts/usage-tracking

它是什么

  • 直接从各提供商的用量端点拉取提供商用量/配额。
  • 不估算费用;只显示提供商报告的窗口。
  • 面向人的状态输出会规范化为 X% left,即使上游 API 报告的是已消耗配额、剩余配额或仅原始计数。
  • 会话级 /statussession_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 用量会回退到 statsstats.cached 会规范化为 cacheRead
  • OpenAI Codex:凭证配置文件中的 OAuth 令牌(存在 accountId 时使用)。
  • MiniMax:API key 或 MiniMax OAuth 凭证配置文件。OpenClaw 将 minimaxminimax-cnminimax-portal 视为同一个 MiniMax 配额表面,存在已存储的 MiniMax OAuth 时优先使用,否则回退到 MINIMAX_CODE_PLAN_KEYMINIMAX_CODING_API_KEYMINIMAX_API_KEY。配置后,用量轮询会从 models.providers.minimax-portal.baseUrlmodels.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.timeFormatauto | 12 | 24)控制信封和下游层面的 12 小时制/24 小时制渲染,而不控制系统提示词部分。

何时覆盖

  • 使用 UTC 信封envelopeTimezone: "utc"):当你希望不同区域的主机之间使用稳定时间戳,或者希望 UTC 对齐的日志匹配诊断输出时使用。
  • 使用固定 IANA 时区(例如 "Europe/Vienna"):当 Gateway 网关主机位于一个时区,但用户位于另一个时区,并且你希望信封无论主机如何迁移都按用户时区显示时使用。
  • 设置 envelopeTimestamp: "off":当时间戳上下文对对话没有帮助,并希望使用低 token 信封时使用。

如需完整行为参考、各提供商示例以及经过时间格式化,请参阅 日期和时间

相关

  • 日期和时间 — 完整的信封/工具/提示词行为和示例。
  • Heartbeat — 活跃时段使用时区进行调度。
  • Cron 任务 — cron 表达式使用时区进行调度。
上一篇 静态路由、默认路由、动态路由到底怎么选?
下一篇 运维、网工们!别再只知道XShell了,Electerm真的更香