Skip to content

Windows: host sharp dlopen fails after memos-local-plugin loads (libvips-42.dll name collision) #2495

Open

Description

@MechDesign618

Pre-submission checklist | 提交前检查

  • I have searched existing issues and this hasn't been mentioned before | 我已搜索现有问题,确认此问题尚未被提及
  • I have read the project documentation and confirmed this issue doesn't already exist | 我已阅读项目文档并确认此问题尚未存在
  • This issue is specific to MemOS and not a general software issue | 该问题是针对 MemOS 的,而不是一般软件问题

Bug Description | 问题描述

给 MemTensor 的 issue 文案(可直接贴)

环境:Windows 11 25H2 / Electron 44(Node 24.18.1)/ DSH(DeepSeek Harness)0.2.0-rc.2
包:@memtensor/memos-local-plugin@2.0.20(npm 上的 latest,2026-09-21 发布;无更新版本)
场景:作为 DSH 的 bundle 加载,dsh.profile.bundles 里挂 @memtensor/memos-local-plugin


Issue 1(阻塞级)插件加载后,宿主的模型请求会在本地崩掉(Windows 同名 libvips-42.dll 抢占)

现象

插件在 DSH 里加载后,长会话的每一次模型请求都在 7–31 ms 内失败(正常一次往返要 172 ms ⇒ 根本没出网),
DSH 界面上显示 DeepSeek Messages transport failed。新建的短会话正常,长会话(事件数 2600+)必崩。

根因(已用加载钩子抓到原始错误)

插件的依赖链会先把一份旧的 libvips 装进进程:

memos-local-plugin
 └─ @huggingface/transformers 4.2.0
     └─ onnxruntime-node
         └─ sharp 0.34.5  → libvips-cpp-8.17.3.dll + libvips-42.dll(8.17.3)   ← 先加载,占住 libvips-42.dll

随后宿主侧 sharp 0.35.5(libvips-cpp-8.18.7)再 dlopen,它也要用同名 libvips-42.dll
⇒ Windows 上"同名 DLL 先加载者赢" ⇒ 后加载者报:

Could not load the "sharp" module using the win32-x64 runtime
ERR_DLOPEN_FAILED: The specified procedure could not be found.

sharp 把底层错误吞成 generic 文案,宿主适配器再兜底 catch ⇒ 用户只看到一句 TRANSPORT。

最小复现(不依赖 DSH)

  1. 装上 memos-local-plugin 的依赖闭包(含 @huggingface/transformers → onnxruntime-node → sharp@0.34.5);
  2. 在同一进程里先 require 那份 sharp@0.34.5(或 require('onnxruntime-node') 触发它);
  3. 再 require 一份 sharp@0.35.5(其 libvips-cpp-8.18.7 与上面共用 libvips-42.dll);
  4. ⇒ 第 3 步报 ERR_DLOPEN_FAILED: The specified procedure could not be found。

⚠ 注意:干净进程里两份 sharp 各自都能加载,所以"小实验"证伪不了这个 bug —— 必须复刻真实加载顺序
(这也是它极难排查的原因)。另外抓原生模块错误要用 CJS 加载钩子(--require 包 Module._load),
node:module 的 register() 只覆盖 ESM,而 sharp 是 require 进来的。

期望 / 建议

  • 不要把 onnxruntime-node(它把 sharp 当可选依赖拉进来)放在插件的必经路径上,或把它改成
    按需动态加载(本地向量模型不可用时不要把它拉进进程);
  • 或者给 sharp 依赖显式钉版本,与宿主保持一致(本例对齐到宿主的 libvips 8.18.7 后问题消失);
  • 或者不要依赖 sharp:本地向量化那条链只需要 onnxruntime,图像处理能力并非必要。

我们的临时处置

把 MemOS 侧那份 libvips-42.dll 换成宿主同一份(8.18.7)后恢复正常,并登记了本地补丁基线
(sha256=877B59AD49…7BCED)。但这是用户侧绕过:宿主升级换掉 libvips 就会复发。


Issue 2(兼容性)DSH V4 会话格式:适配器写的 source.kind 被拒

现象

DSH 会话格式 V4 的准入断言要求 source.kind 是生产者自有 kind,并显式拒绝 V3 的 { kind: "plugin" }:

SessionFormatError: format v4 message requires a producer-owned source kind

召回命中时整个 turn 在第一个 step 之前失败。

位置与建议

  • dist/adapters/deepseek-harness/index.js 的 createRecallMessage
    与 …/host-llm.js 的 toDshMessage 都写 source: { kind: "plugin", plugin: "memos-local-memory" };
  • 官方换算规则(DSH 自带文档):未知插件名 → plugin:<完整名字> ⇒ 建议改成
    kind: `plugin:${PLUGIN_NAME}` (我们已本地这样修,召回恢复正常)。

Issue 3(体验)本地向量模型首次下载在墙内必然失败

  • @huggingface/transformers 4.2.0 的解析顺序是 fs cache → 本地 models/ → 远程 huggingface.co,
    且没有 HF_ENDPOINT 之类的环境变量可配;
  • 在内地网络下 huggingface.co 不可达 ⇒ 首次使用必然
    embedding_unavailable: local failed: fetch failed,语义检索静默退化(记忆仍能存);
  • 建议:认 HF_ENDPOINT(或 env.remoteHost),或允许配置本地模型目录、或随包带一份量化模型。
    我们的绕法是把模型文件从 ModelScope 取到 models/Xenova/all-MiniLM-L6-v2/(该目录是本地优先分支)。

附:我们这边已核实的一些事实(便于你们定位)

  • npm 上 latest = 2.0.20(2026-09-21),**与本机安装版本一致,# 给 MemTensor 的 issue 文案(可直接贴)

环境:Windows 11 25H2 / Electron 44(Node 24.18.1)/ DSH(DeepSeek Harness)0.2.0-rc.2
包:@memtensor/memos-local-plugin@2.0.20(npm 上的 latest,2026-09-21 发布;无更新版本)
场景:作为 DSH 的 bundle 加载,dsh.profile.bundles 里挂 @memtensor/memos-local-plugin


Issue 1(阻塞级)插件加载后,宿主的模型请求会在本地崩掉(Windows 同名 libvips-42.dll 抢占)

现象

插件在 DSH 里加载后,长会话的每一次模型请求都在 7–31 ms 内失败(正常一次往返要 172 ms ⇒ 根本没出网),
DSH 界面上显示 DeepSeek Messages transport failed。新建的短会话正常,长会话(事件数 2600+)必崩。

根因(已用加载钩子抓到原始错误)

插件的依赖链会先把一份旧的 libvips 装进进程:

memos-local-plugin
 └─ @huggingface/transformers 4.2.0
     └─ onnxruntime-node
         └─ sharp 0.34.5  → libvips-cpp-8.17.3.dll + libvips-42.dll(8.17.3)   ← 先加载,占住 libvips-42.dll

随后宿主侧 sharp 0.35.5(libvips-cpp-8.18.7)再 dlopen,它也要用同名 libvips-42.dll
⇒ Windows 上"同名 DLL 先加载者赢" ⇒ 后加载者报:

Could not load the "sharp" module using the win32-x64 runtime
ERR_DLOPEN_FAILED: The specified procedure could not be found.

sharp 把底层错误吞成 generic 文案,宿主适配器再兜底 catch ⇒ 用户只看到一句 TRANSPORT。

最小复现(不依赖 DSH)

  1. 装上 memos-local-plugin 的依赖闭包(含 @huggingface/transformers → onnxruntime-node → sharp@0.34.5);
  2. 在同一进程里先 require 那份 sharp@0.34.5(或 require('onnxruntime-node') 触发它);
  3. 再 require 一份 sharp@0.35.5(其 libvips-cpp-8.18.7 与上面共用 libvips-42.dll);
  4. ⇒ 第 3 步报 ERR_DLOPEN_FAILED: The specified procedure could not be found。

⚠ 注意:干净进程里两份 sharp 各自都能加载,所以"小实验"证伪不了这个 bug —— 必须复刻真实加载顺序
(这也是它极难排查的原因)。另外抓原生模块错误要用 CJS 加载钩子(--require 包 Module._load),
node:module 的 register() 只覆盖 ESM,而 sharp 是 require 进来的。

期望 / 建议

  • 不要把 onnxruntime-node(它把 sharp 当可选依赖拉进来)放在插件的必经路径上,或把它改成
    按需动态加载(本地向量模型不可用时不要把它拉进进程);
  • 或者给 sharp 依赖显式钉版本,与宿主保持一致(本例对齐到宿主的 libvips 8.18.7 后问题消失);
  • 或者不要依赖 sharp:本地向量化那条链只需要 onnxruntime,图像处理能力并非必要。

我们的临时处置

把 MemOS 侧那份 libvips-42.dll 换成宿主同一份(8.18.7)后恢复正常,并登记了本地补丁基线
(sha256=877B59AD49…7BCED)。但这是用户侧绕过:宿主升级换掉 libvips 就会复发。


Issue 2(兼容性)DSH V4 会话格式:适配器写的 source.kind 被拒

现象

DSH 会话格式 V4 的准入断言要求 source.kind 是生产者自有 kind,并显式拒绝 V3 的 { kind: "plugin" }:

SessionFormatError: format v4 message requires a producer-owned source kind

召回命中时整个 turn 在第一个 step 之前失败。

位置与建议

  • dist/adapters/deepseek-harness/index.js 的 createRecallMessage
    与 …/host-llm.js 的 toDshMessage 都写 source: { kind: "plugin", plugin: "memos-local-memory" };
  • 官方换算规则(DSH 自带文档):未知插件名 → plugin:<完整名字> ⇒ 建议改成
    kind: `plugin:${PLUGIN_NAME}` (我们已本地这样修,召回恢复正常)。

Issue 3(体验)本地向量模型首次下载在墙内必然失败

  • @huggingface/transformers 4.2.0 的解析顺序是 fs cache → 本地 models/ → 远程 huggingface.co,
    且没有 HF_ENDPOINT 之类的环境变量可配;
  • 在内地网络下 huggingface.co 不可达 ⇒ 首次使用必然
    embedding_unavailable: local failed: fetch failed,语义检索静默退化(记忆仍能存);
  • 建议:认 HF_ENDPOINT(或 env.remoteHost),或允许配置本地模型目录、或随包带一份量化模型。
    我们的绕法是把模型文件从 ModelScope 取到 models/Xenova/all-MiniLM-L6-v2/(该目录是本地优先分支)。

附:我们这边已核实的一些事实(便于你们定位)

  • npm 上 latest = 2.0.20(2026-09-21),与本机安装版本一致,没有更新版本可试;
  • package.json 里没有 repository / homepage / bugs 字段 ⇒ 我们只能通过你们自己的渠道反馈;
  • 导入接口 POST /api/v1/import(bundle 形状 = GET /api/v1/export)可用,但 /api/v1/* 多数需要
    你们自己的登录会话(.auth.json 只有 hash/salt/sessionSecret,无明文 API key)——
    我们最终是在进程内直接调核心 importBundle() 完成批量导入的;如果这是预期用法,建议在 README 里写清。
  • 两处"静默失败"建议加日志:① 导入时 traces 是 STRICT 表,浮点 ts 会被 SQLite 拒绝,
    而导入器逐行 catch{} ⇒ 现象是 imported:0 skipped:N 而库里 0 行;
    ② 导入的行默认 share_scope='private' 且 owner = 播种命名空间,写进库了却谁也召回不到(向量也在、FTS 也索引了)。
    没有更新版本可试**;
  • package.json 里没有 repository / homepage / bugs 字段 ⇒ 我们只能通过你们自己的渠道反馈;
  • 导入接口 POST /api/v1/import(bundle 形状 = GET /api/v1/export)可用,但 /api/v1/* 多数需要
    你们自己的登录会话(.auth.json 只有 hash/salt/sessionSecret,无明文 API key)——
    我们最终是在进程内直接调核心 importBundle() 完成批量导入的;如果这是预期用法,建议在 README 里写清。
  • 两处"静默失败"建议加日志:① 导入时 traces 是 STRICT 表,浮点 ts 会被 SQLite 拒绝,
    而导入器逐行 catch{} ⇒ 现象是 imported:0 skipped:N 而库里 0 行;
    ② 导入的行默认 share_scope='private' 且 owner = 播种命名空间,写进库了却谁也召回不到(向量也在、FTS 也索引了)。

How to Reproduce | 如何重现

给 MemTensor 的 issue 文案(可直接贴)

环境:Windows 11 25H2 / Electron 44(Node 24.18.1)/ DSH(DeepSeek Harness)0.2.0-rc.2
包:@memtensor/memos-local-plugin@2.0.20(npm 上的 latest,2026-09-21 发布;无更新版本)
场景:作为 DSH 的 bundle 加载,dsh.profile.bundles 里挂 @memtensor/memos-local-plugin


Issue 1(阻塞级)插件加载后,宿主的模型请求会在本地崩掉(Windows 同名 libvips-42.dll 抢占)

现象

插件在 DSH 里加载后,长会话的每一次模型请求都在 7–31 ms 内失败(正常一次往返要 172 ms ⇒ 根本没出网),
DSH 界面上显示 DeepSeek Messages transport failed。新建的短会话正常,长会话(事件数 2600+)必崩。

根因(已用加载钩子抓到原始错误)

插件的依赖链会先把一份旧的 libvips 装进进程:

memos-local-plugin
 └─ @huggingface/transformers 4.2.0
     └─ onnxruntime-node
         └─ sharp 0.34.5  → libvips-cpp-8.17.3.dll + libvips-42.dll(8.17.3)   ← 先加载,占住 libvips-42.dll

随后宿主侧 sharp 0.35.5(libvips-cpp-8.18.7)再 dlopen,它也要用同名 libvips-42.dll
⇒ Windows 上"同名 DLL 先加载者赢" ⇒ 后加载者报:

Could not load the "sharp" module using the win32-x64 runtime
ERR_DLOPEN_FAILED: The specified procedure could not be found.

sharp 把底层错误吞成 generic 文案,宿主适配器再兜底 catch ⇒ 用户只看到一句 TRANSPORT。

最小复现(不依赖 DSH)

  1. 装上 memos-local-plugin 的依赖闭包(含 @huggingface/transformers → onnxruntime-node → sharp@0.34.5);
  2. 在同一进程里先 require 那份 sharp@0.34.5(或 require('onnxruntime-node') 触发它);
  3. 再 require 一份 sharp@0.35.5(其 libvips-cpp-8.18.7 与上面共用 libvips-42.dll);
  4. ⇒ 第 3 步报 ERR_DLOPEN_FAILED: The specified procedure could not be found。

⚠ 注意:干净进程里两份 sharp 各自都能加载,所以"小实验"证伪不了这个 bug —— 必须复刻真实加载顺序
(这也是它极难排查的原因)。另外抓原生模块错误要用 CJS 加载钩子(--require 包 Module._load),
node:module 的 register() 只覆盖 ESM,而 sharp 是 require 进来的。

期望 / 建议

  • 不要把 onnxruntime-node(它把 sharp 当可选依赖拉进来)放在插件的必经路径上,或把它改成
    按需动态加载(本地向量模型不可用时不要把它拉进进程);
  • 或者给 sharp 依赖显式钉版本,与宿主保持一致(本例对齐到宿主的 libvips 8.18.7 后问题消失);
  • 或者不要依赖 sharp:本地向量化那条链只需要 onnxruntime,图像处理能力并非必要。

我们的临时处置

把 MemOS 侧那份 libvips-42.dll 换成宿主同一份(8.18.7)后恢复正常,并登记了本地补丁基线
(sha256=877B59AD49…7BCED)。但这是用户侧绕过:宿主升级换掉 libvips 就会复发。


Issue 2(兼容性)DSH V4 会话格式:适配器写的 source.kind 被拒

现象

DSH 会话格式 V4 的准入断言要求 source.kind 是生产者自有 kind,并显式拒绝 V3 的 { kind: "plugin" }:

SessionFormatError: format v4 message requires a producer-owned source kind

召回命中时整个 turn 在第一个 step 之前失败。

位置与建议

  • dist/adapters/deepseek-harness/index.js 的 createRecallMessage
    与 …/host-llm.js 的 toDshMessage 都写 source: { kind: "plugin", plugin: "memos-local-memory" };
  • 官方换算规则(DSH 自带文档):未知插件名 → plugin:<完整名字> ⇒ 建议改成
    kind: `plugin:${PLUGIN_NAME}` (我们已本地这样修,召回恢复正常)。

Issue 3(体验)本地向量模型首次下载在墙内必然失败

  • @huggingface/transformers 4.2.0 的解析顺序是 fs cache → 本地 models/ → 远程 huggingface.co,
    且没有 HF_ENDPOINT 之类的环境变量可配;
  • 在内地网络下 huggingface.co 不可达 ⇒ 首次使用必然
    embedding_unavailable: local failed: fetch failed,语义检索静默退化(记忆仍能存);
  • 建议:认 HF_ENDPOINT(或 env.remoteHost),或允许配置本地模型目录、或随包带一份量化模型。
    我们的绕法是把模型文件从 ModelScope 取到 models/Xenova/all-MiniLM-L6-v2/(该目录是本地优先分支)。

附:我们这边已核实的一些事实(便于你们定位)

  • npm 上 latest = 2.0.20(2026-09-21),与本机安装版本一致,没有更新版本可试;
  • package.json 里没有 repository / homepage / bugs 字段 ⇒ 我们只能通过你们自己的渠道反馈;
  • 导入接口 POST /api/v1/import(bundle 形状 = GET /api/v1/export)# 给 MemTensor 的 issue 文案(可直接贴)

环境:Windows 11 25H2 / Electron 44(Node 24.18.1)/ DSH(DeepSeek Harness)0.2.0-rc.2
包:@memtensor/memos-local-plugin@2.0.20(npm 上的 latest,2026-09-21 发布;无更新版本)
场景:作为 DSH 的 bundle 加载,dsh.profile.bundles 里挂 @memtensor/memos-local-plugin


Issue 1(阻塞级)插件加载后,宿主的模型请求会在本地崩掉(Windows 同名 libvips-42.dll 抢占)

现象

插件在 DSH 里加载后,长会话的每一次模型请求都在 7–31 ms 内失败(正常一次往返要 172 ms ⇒ 根本没出网),
DSH 界面上显示 DeepSeek Messages transport failed。新建的短会话正常,长会话(事件数 2600+)必崩。

根因(已用加载钩子抓到原始错误)

插件的依赖链会先把一份旧的 libvips 装进进程:

memos-local-plugin
 └─ @huggingface/transformers 4.2.0
     └─ onnxruntime-node
         └─ sharp 0.34.5  → libvips-cpp-8.17.3.dll + libvips-42.dll(8.17.3)   ← 先加载,占住 libvips-42.dll

随后宿主侧 sharp 0.35.5(libvips-cpp-8.18.7)再 dlopen,它也要用同名 libvips-42.dll
⇒ Windows 上"同名 DLL 先加载者赢" ⇒ 后加载者报:

Could not load the "sharp" module using the win32-x64 runtime
ERR_DLOPEN_FAILED: The specified procedure could not be found.

sharp 把底层错误吞成 generic 文案,宿主适配器再兜底 catch ⇒ 用户只看到一句 TRANSPORT。

最小复现(不依赖 DSH)

  1. 装上 memos-local-plugin 的依赖闭包(含 @huggingface/transformers → onnxruntime-node → sharp@0.34.5);
  2. 在同一进程里先 require 那份 sharp@0.34.5(或 require('onnxruntime-node') 触发它);
  3. 再 require 一份 sharp@0.35.5(其 libvips-cpp-8.18.7 与上面共用 libvips-42.dll);
  4. ⇒ 第 3 步报 ERR_DLOPEN_FAILED: The specified procedure could not be found。

⚠ 注意:干净进程里两份 sharp 各自都能加载,所以"小实验"证伪不了这个 bug —— 必须复刻真实加载顺序
(这也是它极难排查的原因)。另外抓原生模块错误要用 CJS 加载钩子(--require 包 Module._load),
node:module 的 register() 只覆盖 ESM,而 sharp 是 require 进来的。

期望 / 建议

  • 不要把 onnxruntime-node(它把 sharp 当可选依赖拉进来)放在插件的必经路径上,或把它改成
    按需动态加载(本地向量模型不可用时不要把它拉进进程);
  • 或者给 sharp 依赖显式钉版本,与宿主保持一致(本例对齐到宿主的 libvips 8.18.7 后问题消失);
  • 或者不要依赖 sharp:本地向量化那条链只需要 onnxruntime,图像处理能力并非必要。

我们的临时处置

把 MemOS 侧那份 libvips-42.dll 换成宿主同一份(8.18.7)后恢复正常,并登记了本地补丁基线
(sha256=877B59AD49…7BCED)。但这是用户侧绕过:宿主升级换掉 libvips 就会复发。


Issue 2(兼容性)DSH V4 会话格式:适配器写的 source.kind 被拒

现象

DSH 会话格式 V4 的准入断言要求 source.kind 是生产者自有 kind,并显式拒绝 V3 的 { kind: "plugin" }:

SessionFormatError: format v4 message requires a producer-owned source kind

召回命中时整个 turn 在第一个 step 之前失败。

位置与建议

  • dist/adapters/deepseek-harness/index.js 的 createRecallMessage
    与 …/host-llm.js 的 toDshMessage 都写 source: { kind: "plugin", plugin: "memos-local-memory" };
  • 官方换算规则(DSH 自带文档):未知插件名 → plugin:<完整名字> ⇒ 建议改成
    kind: `plugin:${PLUGIN_NAME}` (我们已本地这样修,召回恢复正常)。

Issue 3(体验)本地向量模型首次下载在墙内必然失败

  • @huggingface/transformers 4.2.0 的解析顺序是 fs cache → 本地 models/ → 远程 huggingface.co,
    且没有 HF_ENDPOINT 之类的环境变量可配;
  • 在内地网络下 huggingface.co 不可达 ⇒ 首次使用必然
    embedding_unavailable: local failed: fetch failed,语义检索静默退化(记忆仍能存);
  • 建议:认 HF_ENDPOINT(或 env.remoteHost),或允许配置本地模型目录、或随包带一份量化模型。
    我们的绕法是把模型文件从 ModelScope 取到 models/Xenova/all-MiniLM-L6-v2/(该目录是本地优先分支)。

附:我们这边已核实的一些事实(便于你们定位)

  • npm 上 latest = 2.0.20(2026-09-21),与本机安装版本一致,没有更新版本可试;
  • package.json 里没有 repository / homepage / bugs 字段 ⇒ 我们只能通过你们自己的渠道反馈;
  • 导入接口 POST /api/v1/import(bundle 形状 = GET /api/v1/export)可用,但 /api/v1/* 多数需要
    你们自己的登录会话(.auth.json 只有 hash/salt/sessionSecret,无明文 API key)——
    我们最终是在进程内直接调核心 importBundle() 完成批量导入的;如果这是预期用法,建议在 README 里写清。
  • 两处"静默失败"建议加日志:① 导入时 traces 是 STRICT 表,浮点 ts 会被 SQLite 拒绝,
    而导入器逐行 catch{} ⇒ 现象是 imported:0 skipped:N 而库里 0 行;
    ② 导入的行默认 share_scope='private' 且 owner = 播种命名空间,写进库了却谁也召回不到(向量也在、FTS 也索引了)。
    可用,但 /api/v1/* 多数需要
    你们自己的登录会话(.auth.json 只有 hash/salt/sessionSecret,无明文 API key)——
    我们最终是在进程内直接调核心 importBundle() 完成批量导入的;如果这是预期用法,建议在 README 里写清。
  • 两处"静默失败"建议加日志:① 导入时 traces 是 STRICT 表,浮点 ts 会被 SQLite 拒绝,
    而导入器逐行 catch{} ⇒ 现象是 imported:0 skipped:N 而库里 0 行;
    ② 导入的行默认 share_scope='private' 且 owner = 播种命名空间,写进库了却谁也召回不到(向量也在、FTS 也索引了)。

Environment | 环境信息

给 MemTensor 的 issue 文案(可直接贴)

环境:Windows 11 25H2 / Electron 44(Node 24.18.1)/ DSH(DeepSeek Harness)0.2.0-rc.2
包:@memtensor/memos-local-plugin@2.0.20(npm 上的 latest,2026-09-21 发布;无更新版本)
场景:作为 DSH 的 bundle 加载,dsh.profile.bundles 里挂 @memtensor/memos-local-plugin


Issue 1(阻塞级)插件加载后,宿主的模型请求会在本地崩掉(Windows 同名 libvips-42.dll 抢占)

现象

插件在 DSH 里加载后,长会话的每一次模型请求都在 7–31 ms 内失败(正常一次往返要 172 ms ⇒ 根本没出网),
DSH 界面上显示 DeepSeek Messages transport failed。新建的短会话正常,长会话(事件数 2600+)必崩。

根因(已用加载钩子抓到原始错误)

插件的依赖链会先把一份旧的 libvips 装进进程:

memos-local-plugin
 └─ @huggingface/transformers 4.2.0
     └─ onnxruntime-node
         └─ sharp 0.34.5  → libvips-cpp-8.17.3.dll + libvips-42.dll(8.17.3)   ← 先加载,占住 libvips-42.dll

随后宿主侧 sharp 0.35.5(libvips-cpp-8.18.7)再 dlopen,它也要用同名 libvips-42.dll
⇒ Windows 上"同名 DLL 先加载者赢" ⇒ 后加载者报:

Could not load the "sharp" module using the win32-x64 runtime
ERR_DLOPEN_FAILED: The specified procedure could not be found.

sharp 把底层错误吞成 generic 文案,宿主适配器再兜底 catch ⇒ 用户只看到一句 TRANSPORT。

最小复现(不依赖 DSH)

  1. 装上 memos-local-plugin 的依赖闭包(含 @huggingface/transformers → onnxruntime-node → sharp@0.34.5);
  2. 在同一进程里先 require 那份 sharp@0.34.5(或 require('onnxruntime-node') 触发它);
  3. 再 require 一份 sharp@0.35.5(其 libvips-cpp-8.18.7 与上面共用 libvips-42.dll);
  4. ⇒ 第 3 步报 ERR_DLOPEN_FAILED: The specified procedure could not be found。

⚠ 注意:干净进程里两份 sharp 各自都能加载,所以"小实验"证伪不了这个 bug —— 必须复刻真实加载顺序
(这也是它极难排查的原因)。另外抓原生模块错误要用 CJS 加载钩子(--require 包 Module._load),
node:module 的 register() 只覆盖 ESM,而 sharp 是 require 进来的。

期望 / 建议

  • 不要把 onnxruntime-node(它把 sharp 当可选依赖拉进来)放在插件的必经路径上,或把它改成
    按需动态加载(本地向量模型不可用时不要把它拉进进程);
  • 或者给 sharp 依赖显式钉版本,与宿主保持一致(本例对齐到宿主的 libvips 8.18.7 后问题消失);
  • 或者不要依赖 sharp:本地向量化那条链只需要 onnxruntime,图像处理能力并非必要。

我们的临时处置

把 MemOS 侧那份 libvips-42.dll 换成宿主同一份(8.18.7)后恢复正常,并登记了本地补丁基线
(sha256=877B59AD49…7BCED)。但这是用户侧绕过:宿主升级换掉 libvips 就会复发。


Issue 2(兼容性)DSH V4 会话格式:适配器写的 source.kind 被拒

现象

DSH 会话格式 V4 的准入断言要求 source.kind 是生产者自有 kind,并显式拒绝 V3 的 { kind: "plugin" }:

SessionFormatError: format v4 message requires a producer-owned source kind

召回命中时整个 turn 在第一个 step 之前失败。

位置与建议

  • dist/adapters/deepseek-harness/index.js 的 createRecallMessage
    与 …/host-llm.js 的 toDshMessage 都写 source: { kind: "plugin", plugin: "memos-local-memory" };
  • 官方换算规则(DSH 自带文档):未知插件名 → plugin:<完整名字> ⇒ 建议改成
    kind: `plugin:${PLUGIN_NAME}` (我们已本地这样修,召回恢复正常)。

Issue 3(体验)本地向量模型首次下载在墙内必然失败

  • @huggingface/transformers 4.2.0 的解析顺序是 fs cache → 本地 models/ → 远程 huggingface.co,
    且没有 HF_ENDPOINT 之类的环境变量可配;
  • 在内地网络下 huggingface.co 不可达 ⇒ 首次使用必然
    embedding_unavailable: local failed: fetch failed,语义检索静默退化(记忆仍能存);
  • 建议:认 HF_ENDPOINT(或 env.remoteHost),或允许配置本地模型目录、或随包带一份量化模型。
    我们的绕法是把模型文件从 ModelScope 取到 models/Xenova/all-MiniLM-L6-v2/(该目录是本地优先分支)。

附:我们这边已核实的一些事实(便于你们定位)

  • npm 上 latest = 2.0.20(2026-09-21),与本机安装版本一致,没有更新版本可试;
  • package.json 里没有 repository / homepage / bugs 字段 ⇒ 我们只能通过你们自己的渠道反馈;
  • 导入接口 POST /api/v1/import(bundle 形状 = GET /api/v1/export)可用,但 /api/v1/* 多数需要
    你们自己的登录会话(.auth.json 只有 hash/salt/sessionSecret,无明文 API key)——
    我们最终是在进程内直接调核心 importBundle() 完成批量导入的;如果这是预期用法,建议在 README 里写清。
  • 两处"静默失败"建议加日志:① 导入时 traces 是 STRICT 表,浮点 ts 会被 SQLite 拒绝,
    而导入器逐行 catch{} ⇒ 现象是 imported:0 skipped:N 而库里 0 行;
    ② 导入的行默认 share_scope='private' 且 owner = 播种命名空间,写进库了却谁也召回不到(向量也在、FTS 也索引了)。

Additional Context | 其他信息

No response

Willingness to Implement | 实现意愿

  • I'm willing to implement this myself | 我愿意自己解决
  • I would like someone else to implement this | 我希望其他人来解决
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:pluginOpenClaw & Hermesstatus:needs-product-reviewRequires product owner confirmation before deciding public repo, transfer, or internal backlog.types:bugSomething isn't working | 功能异常

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions