Skip to content

[bug] channel 未实现 messaging.inferTargetChatType,heartbeat target="owner" 无法解析投递路由(status 显示 waiting for delivery route) #321

Description

@lizimeng-pro

环境

  • OpenClaw 2026.9.5(Windows)
  • @tencent-weixin/openclaw-weixin 2.4.9
  • 微信渠道已扫码配对成功,收发消息正常

现象

渠道已配对,且 commands.ownerAllowFrom 已配置该渠道 owner:

{
  "commands": { "ownerAllowFrom": ["openclaw-weixin:<owner-wechat-id>@im.wechat"] },
  "agents": { "defaults": { "heartbeat": { "target": "owner", "every": "2h" } } }
}

openclaw status 的 Heartbeat 行:

Heartbeat   2h (main; waiting for delivery route — set commands.ownerAllowFrom=[...] or channel allowFrom;
            explicit delivery: heartbeat.target="openclaw-weixin" with heartbeat.to="...")

提示让去配置已经配好的 commands.ownerAllowFrom(或插件未提供的 channel allowFrom),文案误导;实际是 owner 路由判定 fail closed,心跳投递以 no-route 被丢弃。

期望

agents.defaults.heartbeat.target = "owner" 能解析出直聊投递路由,与内置渠道(telegram / reef / a2a 等)行为一致。

根因

框架 openclaw/dist/targets-*.mjs:

function isPositivelyDirectHeartbeatOwnerTarget(params) {
  const to = params.plugin
    ? stripTargetProviderPrefix(params.to, params.plugin.id, ...params.plugin.messaging?.targetPrefixes ?? [])
    : params.to.trim();
  return (normalizeChatType(params.chatType) ?? params.plugin?.messaging?.inferTargetChatType?.({ to })) === "direct";
}

owner 目标不携带 chatType(status 探针与运行时解析路径都是如此),因此该判定完全依赖插件的 messaging.inferTargetChatType;框架不会从 capabilities.chatTypes 反推(源码中 12 处 inferTargetChatType 引用无一从 capabilities 推导,未证明的目标一律 fail closed)。

而本插件 channel 定义只声明了:

capabilities: { chatTypes: ["direct"], media: true, blockStreaming: true },
messaging: { targetResolver: { looksLikeId: (raw) => raw.endsWith("@im.wechat") } },

缺少 inferTargetChatType(也没有 resolveAllowFrom / resolveOutboundSessionRoute)。内置渠道均实现了该钩子;官方文档亦将这一分类列为渠道插件职责:

docs/plugins/architecture-internals/channel-surfaces.md → Channel target resolution:
messaging.inferTargetChatType({ to }) decides whether a normalized target should be treated as direct, group, or channel before directory lookup. Implicit owner heartbeat delivery requires this direct classification; without it, Gateway status reports waiting for route.

最小复现

  1. 安装 2.4.9,完成微信扫码配对;
  2. commands.ownerAllowFrom = ["openclaw-weixin:<owner-wechat-id>@im.wechat"];
  3. agents.defaults.heartbeat = { target: "owner", every: "2h" };
  4. openclaw status → Heartbeat 行显示 waiting for delivery route;
  5. 对照:改为显式路由 heartbeat.target = "openclaw-weixin" + heartbeat.to = "<owner-wechat-id>@im.wechat" + heartbeat.accountId = "<account-id>" → 立即正常(不回显 waiting for route),说明渠道投递本身没问题,只是 owner 分类缺失。

建议修复

在 channel 定义的 messaging 块补一行(微信 ID 形态恒为 1:1):

messaging: {
  inferTargetChatType: ({ to }) => (typeof to === "string" && to.trim().endsWith("@im.wechat") ? "direct" : undefined),
  targetResolver: { looksLikeId: (raw) => raw.endsWith("@im.wechat") },
},

语义:凡以 @im.wechat 结尾的目标即 direct,其余返回 undefined(不猜测 group / channel)。如需支持群聊,可再按 ID 形态扩展分类。

影响面

  • 仅影响 owner 目标解析(如 heartbeat.target="owner");显式 target + to + accountId 路由不受影响。
  • 对使用默认/owner 心跳投递的微信渠道用户,该配置会静默降级为 no-route,且 status 提示文案指向错误方向,排查成本高。
  • 已验证的 workaround:agents.defaults.heartbeat = { target: "openclaw-weixin", to: "<owner-wechat-id>@im.wechat", accountId: "<account-id>" }。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions