跳转至

通道辅助

通道特定运行时辅助函数,在通道插件加载时可用。是 插件运行时辅助函数 参考的一部分;通道插件 是分步指南。

通道命名空间

api.runtime.channel

通道特定运行时辅助函数(在通道插件加载时可用)。按关注点分组:

分组 用途
text 分块(chunkText、chunkMarkdownText、resolveChunkMode)、控制命令检测、Markdown 表格转换。
reply 缓冲块回复分发、信封格式化、有效消息/人工延迟配置解析。
routing buildAgentSessionKey、resolveAgentRoute。
pairing buildPairingReply、允许列表读取/移除、配对请求插入或更新,以及由请求派生的审批条目。
media 远程媒体下载/保存(见下文)。
activity 记录/读取最近通道活动。
session 来自入站事件的会话元数据、最后路由更新。
mentions 提及策略辅助函数(见下文)。
reactions 用于处理中指示的确认反应句柄。
groups 群组策略和需要提及解析。
debounce 入站消息防抖。
commands 命令授权和文本命令门控。
outbound 加载通道的出站适配器。
inbound 使用主机绑定的 ingress 辅助函数解析入口,构建入站事件上下文,并运行共享的入站事件/回复内核。
threadBindings 调整已绑定会话线程的空闲超时/最大存活时间。
runtimeContexts 注册、读取和监视进程本地的按通道/账户/能力上下文。

api.runtime.channel.media 是通道媒体下载和存储的首选接口:

const saved = await api.runtime.channel.media.saveRemoteMedia({
  url,
  subdir: "inbound",
  maxBytes,
  filePathHint: fileName,
});

当远程 URL 应成为 OpenClaw 媒体时,使用 saveRemoteMedia(...)。当插件已经获取了带有插件自有的身份验证、重定向或允许列表处理的 Response 时,使用 saveResponseMedia(...)。仅当插件需要原始字节用于检查、转换、解密或重新上传时,才使用 readRemoteMediaBuffer(...)。fetchRemoteMedia(...) 仍然是 readRemoteMediaBuffer(...) 的已弃用兼容别名,在 兼容性注册表 中作为 plugin-runtime-api-compat-aliases 跟踪,removeAfter 日期为 2026-10-01。

对于不成功的 HTTP 响应,媒体错误会报告状态码,并在可用时包含有界的响应体摘录。被丢弃的错误响应体不会被报告为空的上游响应。没有响应体的成功响应仍会被拒绝为空媒体。

远程媒体选项和来自 openclaw/plugin-sdk/ssrf-runtime 的 fetchWithSsrFGuard(...) 接受同步的 beforeRequest 回调,用于最终分发授权检查。它在代理、DNS 和分发器准备之后、每个物理请求之前立即运行。重定向会每跳调用一次;媒体重试会为每次尝试和每跳再次调用它。如果它抛出异常,则不会发送该请求,并且相同错误会传播。Promise 或 thenable 结果会在传输分发前被拒绝。

对于 saveRemoteMedia(...),当读取权限可能在响应体下载期间丢失时,请传入同步的 assertCurrent 回调。媒体所有者会将其与任何外层读取范围组合,并在请求、流式传输和本地文件发布过程中重新检查,失败时清理未接受的文件。同时通过 requestInit.signal 转发取消。省略 assertCurrent 会保留现有行为;beforeRequest 仍然是按请求的钩子,而不是文件发布守卫。

受保护的 fetch 还接受同步的 resolveDispatcherPolicy(url) 覆盖,并会为每个重定向重新评估。未定义的结果会使用 dispatcherPolicy,或者在未提供默认策略时使用直接路由。需要保留操作员配置的代理路由的提供者可以使用来自 openclaw/plugin-sdk/fetch-runtime 的 resolveEnvHttpProxyAgentOptions 和 matchesNoProxy 来选择每一跳。trusted_explicit_proxy 模式允许 HTTP、HTTPS、socks: 和 socks5: 代理 URL,并将目标 DNS 委托给显式信任的代理;代理主机验证和目标主机策略仍然适用。直接跳保持 DNS 固定。严格模式拒绝 SOCKS 代理,而独立的 trusted-env-proxy 门控仍然仅限 HTTP(S)。

api.runtime.channel.mentions 是使用运行时注入的捆绑通道插件共享的入站提及策略接口:

const mentionMatch = api.runtime.channel.mentions.matchesMentionWithExplicit(text, {
  mentionRegexes,
  mentionPatterns,
});

const decision = api.runtime.channel.mentions.resolveInboundMentionDecision({
  facts: {
    canDetectMention: true,
    wasMentioned: mentionMatch.matched,
    implicitMentionKinds: api.runtime.channel.mentions.implicitMentionKindWhen(
      "reply_to_bot",
      isReplyToBot,
    ),
  },
  policy: {
    isGroup,
    requireMention,
    allowTextCommands,
    hasControlCommand,
    commandAuthorized,
  },
});

可用的提及辅助函数:

  • buildMentionRegexes
  • matchesMentionPatterns
  • matchesMentionWithExplicit
  • implicitMentionKindWhen
  • resolveInboundMentionDecision

对于提及决策,请使用规范化的 { facts, policy } 路径。

reply、session 和 inbound 下的若干字段带有按字段的 @deprecated 说明,指向当前的通道轮次内核或通道出站适配器;在基于某个具体辅助函数构建新代码之前,请检查其内联 JSDoc。它们共享同一个 plugin-runtime-api-compat-aliases 注册表记录和 removeAfter 日期 2026-10-01。

回复选项接受 onVisibleWorkSessions(sessions),以便在最终回复投递前接收已接受的可见工作会话,包括已结算的运行失败的情况。每个描述符携带 sessionKey、规范的 url 以及可选的 label;描述符按会话键在接受顺序去重。

等待的会话绑定变更

从 openclaw/plugin-sdk/conversation-binding-runtime 导入路由和服务辅助函数。

在记录绑定活动时,等待 getSessionBindingService().touchAsync(bindingId, at, scope)。适配器实现 touchAsync,返回一个 Promise,该 Promise 会结算其已接受的变更。异步分发优先使用该方法并传播其失败;它不会同时调用旧版 touch。在调用每个选定的适配器之前,分发会检查其注册是否仍然有效。它会跳过已退役的注册,而不会采用其替代项。

对于需要记录活动的路由,使用 resolveRuntimeConversationBindingRouteAsync。它会等待选定的变更,然后在返回其路由之前重新检查当前绑定。使用 await service.inspectByConversationAsync(conversation) 准备所有权事实,然后将这些事实传递给 inspectRuntimeConversationBindingRoute({ route, inspection })。此同步投影不执行存储访问。检查会保留“绑定缺失”与“适配器不可用”之间的区别,而不会创建缺失的存储或修剪过期行。

inspectRuntimeConversationBindingRoute 和同步的 resolveRuntimeConversationBindingRoute 也接受一个延迟的 resolveRoute 回调,而不是一个已完成的 route。必须恰好传递 route 或 resolveRoute 之一;输入类型会拒绝同时提供两者或都不提供。现有调用方可以继续传递已完成的路由。在所有者对绑定进行分类之后、普通代理选择之前,回调会接收 { inspection, bindingOwnerAvailable, bindingRecord, boundAgentId }:

const result = inspectRuntimeConversationBindingRoute({
  inspection,
  resolveRoute: ({ bindingOwnerAvailable, boundAgentId }) => {
    if (!bindingOwnerAvailable) {
      throw new Error("Conversation binding owner is unavailable; retry the message.");
    }
    return resolveAgentRoute({
      channel: "acme-chat",
      accountId,
      peer,
      cfg: boundAgentId ? { session: cfg.session } : cfg,
      defaultAgentId: boundAgentId,
    });
  },
});

从 openclaw/plugin-sdk/routing 导入 resolveAgentRoute。因此,即使普通名册需要显式选择,已绑定的代理也可以提供路由。代理作用域的会话键优先于元数据;无作用域的目标可以使用 metadata.agentId。缺失的、被忽略的 cron-run 以及插件拥有的绑定不会提供已绑定的代理。没有非空白元数据代理 ID 的无作用域目标也会使 boundAgentId 保持未定义;它不会虚构一个默认代理。插件绑定会保留其记录,以便通道能够区分插件回退和未绑定的父级查找。inspection 会保留已准备的会话身份,以便在读取绑定存储之前,为其选定的父级组合线程观察。回调负责构建路由;核心仍会投影选定的会话和所有权事实。如果代理拥有的绑定选择了不同的代理,核心会为该代理重建 mainSessionKey,同时保留基础路由的主键名称,然后针对已绑定代理的主会话推导 lastRoutePolicy。这也适用于已完成路由的输入,并且保持普通路由不变,用于通道特定的过期绑定比较。在上下文构建过程中保留这些事实,以便回复准入可以拒绝已撤销、已重新分配或不可用的所有者。当活动必须保留已捕获的选择时,在投影之后等待作用域化的 touchAsync,并保留该路由用于准入,而不是静默选择替代项。

适配器提供 inspectByConversationAsync 用于只读检查,并提供 resolveByConversationAsync 用于普通查找。宿主服务公开这两种方法。通用绑定和捆绑的账户作用域适配器在共享状态读取工作线程中运行检查;查找修复和活动写入使用现有的写入代理。它们的交易谓词、过期规则和账户所有权保持不变。宿主资格在 IPC 之前准备,并在读取之后以及写入准入时重新检查当前适配器和注册表所有权。

生命周期设置器具有显式返回 Promise 的对应方法:channel.threadBindings.setIdleTimeoutBySessionKeyAsync 和 setMaxAgeBySessionKeyAsync。通道适配器公开相同后缀的方法。调用方在报告受影响的绑定之前等待其结果。

现有的同步查找、touch、路由解析器和生命周期设置器契约将在下一个 Plugin SDK 主版本中保持弃用。解析器的分阶段迁移记录在此处以及兼容性注册表中;其宽泛的 barrel 已弃用,而其逐函数 IDE 注释则推迟到调用方迁移完成之后。同步入口点只调用同步实现;它们永远不会启动一个结果会丢失的异步变更。公开两种变体的适配器会将它们保持在同一状态所有者之下。

在分阶段迁移期间,当异步对应方法不存在时,异步分发会回退到适配器现有的同步方法。这保留了外部插件兼容性;该回退不会使旧版适配器变为非阻塞。通用和账户作用域的绑定/解绑操作、列表操作以及独立的生命周期设置器仍需要各自的持久化迁移。其他捆绑存储也会保留其现有行为,直到各自的切换完成。由工作线程支持的路由读取和活动更新并不意味着绑定服务已完全迁移,也不意味着这些剩余操作具有更强的持久性。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw