Skip to content

[Bug] Short-memory: OpenClaw 使用 nvm/global 安装时,tdai 无法解析 native compaction delegate 并错误降级到 self-emergency 压缩 #383

Description

@Veteran-ChengQin

OpenClaw Version | OpenClaw 版本

2026.6.8

Plugin Version | 插件版本

0.3.6

包名:

@tencentdb-agent-memory/memory-tencentdb

插件 ID:

memory-tencentdb

Operating System | 操作系统

Linux

具体环境:

Windows 11 + WSL2 Ubuntu 22.04

System Specification | 系统配置

Node.js: v24.17.0
Node 管理方式: nvm
OpenClaw 安装方式: npm global under nvm prefix
OpenClaw 实际安装路径:
  /home/veteran/.nvm/versions/node/v24.17.0/lib/node_modules/openclaw
contextEngine:
  memory-tencentdb

用于复现的主要 OpenClaw 配置特征:

{
  "agents": {
    "defaults": {
      "contextTokens": 28000,
      "contextEngine": "memory-tencentdb",
      "compaction": {
        "mode": "safeguard",
        "reserveTokens": 12000,
        "reserveTokensFloor": 8000,
        "midTurnPrecheck": {
          "enabled": true
        }
      }
    }
  }
}

注:该问题不依赖特定模型 API key。推荐使用 midTurnPrecheck.enabled=true 快速触发;长会话或 SWE-bench 任务在 post-turn / CLI compaction 阶段也可能命中同一问题。

当前本地 WSL /home/veteran/.openclaw/openclaw.json 已被后续 40k 验证实验调整过;上面的 28k 配置仍是更快触发失败的复现配置。该文件中与 tdai 相关的插件配置如下,它是 short-term-only / offload-only 复现配置:长期记忆、capture、embedding、recall、persona 等均关闭,重点触发 context engine 的 assemble/compact 路径。

{
  "plugins": {
    "allow": ["memory-tencentdb"],
    "slots": {
      "contextEngine": "memory-tencentdb"
    },
    "entries": {
      "memory-tencentdb": {
        "enabled": true,
        "hooks": {
          "allowConversationAccess": true
        },
        "config": {
          "timezone": "Asia/Shanghai",
          "storeBackend": "sqlite",
          "embedding": {
            "enabled": false,
            "provider": "none"
          },
          "report": {
            "enabled": true,
            "type": "local"
          },
          "llm": {
            "enabled": false
          },
          "capture": {
            "enabled": false,
            "excludeAgents": {}
          },
          "extraction": {
            "enabled": false,
            "enableDedup": false,
            "maxMemoriesPerSession": 0
          },
          "recall": {
            "enabled": false,
            "maxResults": 0,
            "maxTotalRecallChars": 0,
            "timeoutMs": 1000
          },
          "pipeline": {
            "everyNConversations": 1000000,
            "enableWarmup": false,
            "l1IdleTimeoutSeconds": 1000000,
            "l2DelayAfterL1Seconds": 1000000,
            "l2MinIntervalSeconds": 1000000,
            "l2MaxIntervalSeconds": 1000000,
            "sessionActiveWindowHours": 1
          },
          "persona": {
            "triggerEveryN": 1000000,
            "maxScenes": 0
          },
          "offload": {
            "enabled": true,
            "mode": "local",
            "model": "bailian/deepseek-v4-flash",
            "temperature": 0.2,
            "l15Enabled": true,
            "prePromptProcessingEnabled": true,
            "dataDir": "/home/veteran/swebench-openclaw/tencent-memory/openclaw-shortmem-midturn-precheck-pylint-ctx40000-bailian-schemeB-20260702-164200/short-term-only/offload",
            "defaultContextWindow": 128000,
            "forceTriggerThreshold": 4,
            "maxPairsPerBatch": 4,
            "l2NullThreshold": 4,
            "l2TimeoutSeconds": 300,
            "mildOffloadRatio": 0.35,
            "aggressiveCompressRatio": 0.85,
            "emergencyCompressRatio": 0.95,
            "emergencyTargetRatio": 0.65,
            "mmdMaxTokenRatio": 0.2,
            "backendTimeoutMs": 120000,
            "offloadRetentionDays": 0,
            "logMaxSizeMb": 200,
            "userId": "swebench-short-term-only",
            "profile": "compact-repro-relaxed"
          }
        }
      }
    }
  }
}

其中 offload.dataDir 是本地 batch 目录,复现时可以替换为任意可写路径;该配置不包含实际 API key。

Describe the bug | 问题描述

memory-tencentdb 作为 OpenClaw 的 contextEngine 使用,并且 OpenClaw 安装在 nvm 管理的 global npm 路径下时,tdai 的 compact() 无法解析 OpenClaw plugin SDK 暴露的:

delegateCompactionToRuntime

tdai 因此无法把 compaction 委派回 OpenClaw 原生 runtime,而是降级到自己的 self-emergency / aggressive compression 路径:

[context-offload] compact: delegateCompactionToRuntime unavailable, self-executing emergency compression

根因在于当前 delegate resolver 对 OpenClaw 安装位置的假设过窄。相关代码位于:

src/offload/index.ts

compact() 中主要依赖固定的系统级 global npm 路径解析 OpenClaw SDK:

const globalRequire = createRequire("/usr/local/lib/node_modules/openclaw/");
const sdk = globalRequire("openclaw/plugin-sdk");
delegateFn = sdk.delegateCompactionToRuntime;

const paths = [
  "/usr/local/lib/node_modules/openclaw/dist/plugin-sdk/index.js",
  "/usr/lib/node_modules/openclaw/dist/plugin-sdk/index.js",
];

这覆盖了 /usr/local/lib/node_modules/usr/lib/node_modules 这类安装方式,但没有从当前 Node.js executable、NODE_PATH 或插件自身 module base 推导 OpenClaw 的实际 module root。

在 nvm 环境中,OpenClaw 实际安装在:

/home/veteran/.nvm/versions/node/v24.17.0/lib/node_modules/openclaw

该路径不在当前探测范围内。因此 openclaw/plugin-sdk 没有被解析到,delegateCompactionToRuntime 不可用,tdai 被迫进入 fallback。

To Reproduce | 复现步骤

推荐使用 Mid-Turn Precheck 作为快速复现方式。它不需要先累积很长的历史 session,而是在单次 openclaw agent --message ... 内部的 assistant/tool loop 中触发 overflow precheck 和 auto-compaction。

  1. 在 WSL2 Ubuntu 中通过 nvm 使用 Node.js:

    Node.js v24.17.0
    
  2. 通过 npm global 安装 OpenClaw,使其落在 nvm 的 global prefix 下:

    /home/<user>/.nvm/versions/node/v24.17.0/lib/node_modules/openclaw
    
  3. 安装并启用 @tencentdb-agent-memory/memory-tencentdb@0.3.6,将 OpenClaw context engine 配置为 memory-tencentdb,并使用上文的 short-term-only / offload-only tdai 插件配置:

    {
      "agents": {
        "defaults": {
          "contextTokens": 28000,
          "contextEngine": "memory-tencentdb",
          "compaction": {
            "mode": "safeguard",
            "reserveTokens": 12000,
            "reserveTokensFloor": 8000,
            "midTurnPrecheck": {
              "enabled": true
            }
          }
        }
      }
    }
  4. 运行一个会在 assistant/tool loop 中产生较大 tool result 或较大 assembled prompt 的任务。我们的快速复现使用了 SWE-bench instance:

    pylint-dev__pylint-4551
    
  5. 观察 OpenClaw stderr / trace 日志。确认先出现 mid-turn overflow precheck,然后进入 tdai compact()

    [context-overflow-midturn-precheck] ... route=compact_then_truncate ...
    [context-offload] compact: delegateCompactionToRuntime unavailable, self-executing emergency compression
    

补充:如果不启用 Mid-Turn Precheck,也可以通过长会话在 post-turn / CLI transcript compaction 阶段触发同一 delegate 解析失败;但这种方式需要先累积较长 transcript,复现速度和稳定性不如 Mid-Turn Precheck。

Expected behavior | 预期行为

tdai 在 compact() 中应优先稳定解析并调用 OpenClaw runtime 提供的:

delegateCompactionToRuntime(params)

解析逻辑应兼容常见安装方式,包括但不限于:

  1. 插件自身运行环境的 module resolution。

  2. 当前 process.cwd()

  3. 当前 Node.js executable 所在 prefix,例如 nvm 下的:

    ~/.nvm/versions/node/<version>/lib/node_modules
    
  4. NODE_PATH

  5. 常见系统 global npm root:

    /usr/local/lib/node_modules
    /usr/lib/node_modules
    

当 delegate 可用时,tdai 应把 compaction 交给 OpenClaw 原生 runtime,而不是进入 self-emergency fallback。

Error Logs / Screenshots | 报错日志/截图

失败路径中的关键日志:

[context-overflow-midturn-precheck] ... route=compact_then_truncate estimatedPromptTokens=25271 promptBudgetBeforeReserve=11616 overflowTokens=13655 toolResultReducibleChars=8330 effectiveReserveTokens=16384 ...
[context-offload] compact: delegateCompactionToRuntime unavailable, self-executing emergency compression
[agent/embedded] auto-compaction failed for custom-deepseek/deepseek-v4-flash: no_messages
[agents/cli-compaction] CLI transcript compaction did not reduce context for custom-deepseek/deepseek-v4-flash: no_messages
Error: CLI transcript compaction failed for custom-deepseek/deepseek-v4-flash: no_messages

这里的核心问题是第一行:

delegateCompactionToRuntime unavailable

后续 no_messages 是 fallback 路径中的下游症状。该 issue 只跟踪 delegate 解析失败问题。

Additional context | 补充信息

影响范围

该问题会影响通过 nvm、非系统 global npm prefix、或其它非 /usr/local / /usr/lib 路径安装 OpenClaw 的用户。

Mid-Turn Precheck 是目前更短的确认路径:它能在一次 assistant/tool loop 中触发 OpenClaw embedded overflow recovery,使日志直接呈现:

context-overflow-midturn-precheck
  -> tdai compact()
  -> delegateCompactionToRuntime unavailable
  -> self-emergency fallback

相比等待长会话触发 post-turn / CLI transcript compaction,这条路径更适合作为 issue 复现步骤。

一旦 delegateCompactionToRuntime 解析失败:

  • tdai 无法使用 OpenClaw 原生 compaction / transcript rotation。
  • compaction 会退回 tdai self-emergency / aggressive compression。
  • fallback 结果即使返回 compressed messages,也不一定会被 OpenClaw 作为新的 session/transcript 采纳。
  • 如果 OpenClaw 没有传入 params.messages,fallback 还可能继续触发误导性的 no_messages

建议修复

建议在 tdai 中新增一个小型 resolver,例如:

resolveOpenClawDelegateCompactionToRuntime(logger)

解析目标:

openclaw/plugin-sdk

推荐解析顺序:

  1. 从插件 bundle 自身 import.meta.url 创建 require

  2. 从当前工作目录创建 require

  3. NODE_PATH 中的每个 module root 尝试解析。

  4. 从当前 Node executable 推导 global npm root:

    path.resolve(path.dirname(process.execPath), "..", "lib", "node_modules")
    
  5. 最后尝试 /usr/local/lib/node_modules/usr/lib/node_modules 等系统路径。

如果解析成功,则调用:

delegateCompactionToRuntime(params)

如果解析失败,再进入 fallback compaction,并输出明确日志。

建议 PR 范围

建议 PR 只包含 delegate resolver 相关最小改动:

src/offload/openclaw-runtime-delegate.ts
src/offload/openclaw-runtime-delegate.test.ts
src/offload/index.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions