
Hindsight OpenClaw 集成修复默认 Main 会话上 Retain 与 Recall 的静默跳过【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight本文以 Hindsight 仓库中《Fix OpenClaw Retention and Recall on Default Main Sessions》指南为主线讲解 OpenClaw 插件中一个隐蔽的默认配置不一致问题agent:main:main这类默认主会话在dynamicBankGranularity未配置时会因“Bank 派生路径”与“身份跳过路径”对默认值理解不同而被静默跳过导致记忆看起来“丢了”。读完本文你将掌握该修复的源码级原理共享默认粒度常量与agentBanking默认值对齐、两种可显式固化的配置写法以及一套可复制的验证流程与限流 skip 日志排查方法。快速结论先用三个要点概括这次修复旧版本中OpenClaw 的默认agent:main:main会话可能静默跳过 retain 和 recall因为两条默认值处理路径对“是否启用 agent 维度分 Bank”的判断不一致修复方案是让两条路径共享同一个默认动态 Bank 粒度常量使未配置时的行为与运行时实际意图一致插件同时新增了限流throttled的 info 级 skip 日志让“会话被有意跳过”这件事不再需要开 debug 模式才能发现。这个 Bug 的典型症状是没有任何报错retention 和 recall 就是消失了。表面看像“记忆缺失”根因却是配置逻辑。根因两条默认值路径互相矛盾问题出在插件内部两段逻辑的默认值假设不一致Bank 派生路径deriveBankId在未配置dynamicBankGranularity时已经默认使用[agent, channel, user]——也就是说 agent 维度的 Bank 路由实际上是开启的身份跳过路径getIdentitySkipReason处理“哪些会话应该跳过”时却把“未设置”当作 agent banking 关闭来处理。于是agent:main:main这类默认主会话在跳过逻辑眼中是“非法/应跳过”的而 Bank 派生路径其实已经准备好为它路由 Bank。两条路径各说各话结果就是 retain 和 recall 双双消失且没有任何显式错误。源码级修复共享常量与 agentBanking 默认值修复后的实现集中在 OpenClaw 插件入口核心改动有三处。1. 共享的默认粒度常量index.ts#L578-L585 中定义// Default granularity fields used by deriveBankId when not explicitly configured. // This constant is shared between getPluginConfig (normalisation) and deriveBankId // (fallback) so the skip-reason check and the bank-routing logic always agree. const DEFAULT_DYNAMIC_BANK_GRANULARITY: Arrayagent | provider | channel | user [ agent, channel, user, ];注释写得很直接这个常量被配置归一化和deriveBankId的兜底逻辑共同引用目的是让“跳过原因检查”与“Bank 路由逻辑永远达成一致”。deriveBankId在 index.ts#L1400-L1402 处使用该常量兜底const fields pluginConfig.dynamicBankGranularity?.length ? pluginConfig.dynamicBankGranularity : DEFAULT_DYNAMIC_BANK_GRANULARITY;2. agentBanking 未配置时默认为 true身份跳过判断在 index.ts#L1282-L1335 的getIdentitySkipReason中关键的修复行是// When dynamicBankGranularity is unset, the default is [agent,channel,user] // which includes agent, so agentBanking defaults to true to match deriveBankId. const agentBanking pluginConfig?.dynamicBankGranularity?.includes(agent) ?? true;?? true就是修复本身当dynamicBankGranularity未设置时agentBanking取true与deriveBankId的默认行为对齐。源码注释还说明了这些“内部 main / 运营类 provider / 匿名发送者”过滤器的设计意图——它们本是为了避免默认多租户 Bank 被没有稳定身份的 CLI/main 会话污染但当用户显式选择了一种“期望这类会话存在”的路由方案时就不应生效dynamicBankGranularity包含agent默认情况→ 每个 agent包括main各有一个 BankdynamicBankId false且配置了bankId→ 用户钉住单一命名 Bank希望所有会话都保留进去。修复后跳过规则的行为边界见 index.ts#L1305-L1335agent:id:cron|heartbeat|subagent:运营会话 → 始终最终跳过agent:id:main内部主会话 → 仅当既非 agent banking 也非静态 Bank 时才跳过temp:临时会话 → 始终跳过messageProvider缺失 → 可重试跳过等待后续轮次补齐身份senderId缺失/anonymous→ 在 agent banking 或静态 Bank 场景下会补一个agent-user:agentId的合成身份继续处理否则可重试跳过。3. 限流的 info 级 skip 日志logSkipOnceindex.ts#L1152-L1166 负责让跳过行为“可被发现但不可被刷爆”function logSkipOnce( operation: recall | retain | dispatch, sessionKey: string | undefined, reason: IdentitySkipReason ): void { if (!sessionKey) return; const cacheKey ${operation}:${sessionKey}; if (loggedSkipSessions.has(cacheKey)) return; loggedSkipSessions.add(cacheKey); const hint reason.kind final ? . If unexpected, set dynamicBankGranularity to [agent,channel,user] or use static banking (dynamicBankId: false bankId: name) : ; log.info(Skipping ${operation} on session ${sessionKey}: ${reason.detail}${hint}); }限流通过模块级loggedSkipSessionsSet 实现每个操作:会话Key组合每个进程生命周期内只打一条 info 日志。这样即使路由规则真的坏了也不会在每一轮对话上刷屏而运营者仍能第一时间看到“为什么这个会话被跳过”。对final类跳过日志还附带了排障提示——直接把上面两种显式配置写法写给了操作者。reason.detail的取值例如internal main session agent:main:main、operational provider cron、missing stable message provider等足以定位问题而无需 debug 模式。想显式化行为时的两种配置默认值现在已经是正确的如果你想让路由策略在配置里一目了然有两种等价于“固定行为”的写法。方案一显式声明动态 Bank 粒度与修复后的默认值一致{ dynamicBankGranularity: [agent, channel, user] }方案二完全关闭动态路由钉住静态 Bank{ dynamicBankId: false, bankId: team-memory }这两种方案差异很大但都是合法且常见的选择前者按agent::channel::user组合动态生成 Bank后者让所有会话写入同一个命名 Bank。修复前的真正问题不在于哪种模型错了而在于未设置的配置会被插件的不同部分解读成不同含义。配置字段定义见 types.ts#L115-L123dynamicBankId?: boolean—— 启用按渠道的动态 Bank默认truebankId?: string—— 静态 Bank ID仅在dynamicBankId: false时生效bankIdPrefix?: string—— Bank ID 前缀如prod→prod-agent-123::channel-456::user-789dynamicBankGranularity?: Arrayagent | provider | channel | user—— 参与 Bank ID 派生的字段默认[agent, channel, user]。从 deriveBankId 的实现index.ts#L1386-L1440 看动态 Bank 的生成规则是每个粒度字段从会话上下文中取值缺失时兜底为default/unknown/anonymous字段值经encodeURIComponent编码后用::连接最后可选加上bankIdPrefix前缀。derive-bank-id.test.ts 用 13 个用例覆盖了这条链路包括未指定粒度时默认产出agent-123::channel-456::user-789[agent,user]、[user]、[provider]等各种粒度组合的输出dynamicBankId: false时回退到openclaw或配置了bankId时为prod-shared-bank这类静态值Discord 场景下channelId是 provider 名时应回退解析sessionKeyissue #854段内含::分隔符冲突时编码保证 Bank ID 不碰撞。另外index.ts#L1241-L1264 还有一道“dispatch surface gate”仅当 Bank 路由依赖 dispatch 表面粒度包含channel或provider且未钉住静态 Bank 时才会在会话 provider 与实际 dispatch 表面不一致时跳过——它显式豁免了默认agent:id:main会话和静态 Bank 部署避免“每一轮都被静默跳过”。验证 retain 是否已恢复按顺序执行以下检查更新集成后重启 OpenClaw 侧使用正常的主会话不要用路由异常的“一次性测试面”触发一轮应该产生持久记忆的内容检查目标 Bank 是否收到了新记忆如果仍未写入查找新增的 info 级 skip 日志——现在日志会告诉你跳过的具体原因Skipping retain on session agent:main:main: ...并且日志自带的提示会指回上面两种显式配置。这些日志的意义在于它让跳过行为不依赖 debug 模式即可被发现。如果插件仍在跳过某个会话原因应该已经清晰到可以直接采取行动。记忆缺失的其他原因依然成立本修复只覆盖“默认值矛盾导致的静默跳过”这一类问题并不消除所有其他可能让记忆“看似不存在”的原因。排查时仍应检查被排除的 provider某些消息来源未被纳入处理范围无状态会话模式会话没有稳定的senderId/channelId上下文身份解析补不齐缺少发送者身份senderId缺失时会走可重试跳过retryable skip等后续轮次补齐Bank 作用域不匹配你查看的 Bank 与当前会话实际路由到的 Bank 不是同一个比如按[agent,channel,user]派生出的是agent:main::webchat::123这样的组合 Bank而非你以为的单一 Bank。一旦集成文档、配置与 recall 三者讨论的是同一套会话与 Bank 边界周围的排查行为会容易理解得多。OpenClaw 集成的安装与配置说明可参考仓库内的 OpenClaw 集成文档 与 OpenClaw 插件 README插件能力清单见 openclaw.plugin.json。FAQ现在我必须手动设置 dynamicBankGranularity 吗不一定。修复让“未设置”的默认值本身就正确了。只有当你希望路由策略在配置里显而易见时才需要显式设置。为什么新的 skip 日志要做限流因为一条坏掉的路由规则如果不加限制会在每一轮都打一条日志。限流后的 info 日志每个会话只出现一次既让问题浮出水面又不会淹没运营者的日志流。这只影响 retain 吗不是。同一个默认值矛盾会同时影响 retain 和 recall 两条链路这也是指南把两者放在一起讲的原因——skip 判断发生在两条链路共享的身份解析路径上见 index.ts#L1266-L1277 中 retain 与 recall 都经过getIdentitySkipReason并写入skipHindsightTurnBySession。小结根因是deriveBankId的默认粒度含agent与getIdentitySkipReason的默认判断视为无 agent banking互相矛盾修复通过共享DEFAULT_DYNAMIC_BANK_GRANULARITY常量并把agentBanking兜底为true让未配置时两条路径语义一致新增的限流 info 日志让跳过原因可被发现、可被处置若需显式行为二选一dynamicBankGranularity: [agent, channel, user]或dynamicBankId: false, bankId: name验证时按“重启 → 正常主会话 → 触发持久内容 → 查 Bank → 查 skip 日志”的顺序排查。【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考