Skip to content

fix(memory): enforce compatible runtime dependencies and refresh bridge#268

Open
End0rph1nww wants to merge 2 commits into
RachelForster:mainfrom
End0rph1nww:fix/hf-runtime-compat
Open

fix(memory): enforce compatible runtime dependencies and refresh bridge#268
End0rph1nww wants to merge 2 commits into
RachelForster:mainfrom
End0rph1nww:fix/hf-runtime-compat

Conversation

@End0rph1nww

@End0rph1nww End0rph1nww commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • replace the broad mem0ai[extras] repair with one version-aware runtime dependency contract shared by Tauri startup and the memory settings page
  • pin the compatible stack used by both long-term memory and Moondream: huggingface-hub==0.36.2, Transformers 4, Sentence Transformers 5, mem0ai[nlp], spaCy, Click, and FastEmbed
  • repair missing and incompatible packages, then restart the Python bridge so newly installed versions are visible without restarting the desktop app
  • keep dependency readiness separate from embedding-model readiness; the automatic-memory switch now checks both and directs users to the download action when needed
  • harden first-time Windows model downloads against Hugging Face symlink-probe races and headless pythonw.exe tqdm deadlocks while preserving application progress callbacks
  • disable mem0 PostHog telemetry by default while preserving explicit environment opt-in

Root cause

mem0ai[extras] can install Transformers 5, while the bundled Moondream integration requires transformers>=4.51.1,<5. Transformers 4 also requires Hugging Face Hub below 1.0, but the desktop core runtime previously pinned Hub 1.24.0. The old checks only verified whether selected modules were importable, so upgrades and repairs could leave an installed-but-incompatible runtime, and the running bridge continued to expose stale module versions after installation.

On Windows, Hugging Face Hub 0.x has two additional first-download edge cases:

  1. concurrent snapshot workers can observe the optimistic symlink-support cache before the privilege probe finishes, causing WinError 1314 on systems without Developer Mode or administrator privileges;
  2. under the packaged pythonw.exe, sys.stderr is unavailable. Hugging Face's internal per-file tqdm bars can then block on tqdm's global lock, leaving the UI at 0 / 11 files while zero-byte .incomplete files remain.

The downloader now completes the symlink probes before starting workers and disables only Hugging Face's terminal bars when no writable stderr exists. Shinsekai's own byte/file progress callback remains active.

User impact

  • existing installations are repaired automatically at Tauri startup when core package versions are missing or incompatible
  • the settings check validates the complete memory dependency set instead of only mem0
  • long-term memory and Moondream coexist in the bundled runtime
  • dependency installation becomes effective immediately after the bridge refresh
  • the UI no longer reports the memory feature as ready before the embedding model is present
  • first-time Windows downloads complete without an administrator retry and continue to report progress
  • explicit MEM0_TELEMETRY=True still enables mem0 telemetry when requested

Validation

  • clean isolated dependency install, pip check, actual mem0 disk-Qdrant add/search, and spaCy model loading
  • installed the complete Moondream requirements into the same environment and reran both Moondream imports/model setup and mem0 add/search
  • packaged pythonw.exe regression probe: the formerly stuck parallel download completed normally after the terminal-progress guard
  • fresh Tauri release download completed all 11 embedding-model files (499,557,447 bytes) with no .incomplete files; the UI ended at mem0 已就绪 · 模型已就绪
  • Tauri release build passed
  • full pre-push Python suite passed (1,531 tests collected)
  • frontend formatting and TypeScript checks passed
  • frontend tests: 109 files, 718 tests passed

Refs #252

Summary by Ameath

小爱先把需要留意的部分整理出来,方便快速查看。

该 PR 将长期记忆的运行时依赖改为版本感知校验,并调整 Windows 模型下载和 Tauri bridge 刷新;审阅发现 Windows symlink 探测仍未覆盖 Hugging Face worker 使用的缓存目录,且设置页修复依赖会静默终止正在进行的聊天。

Enhancements

  • 新增版本感知的运行时依赖校验,并统一 mem0、Transformers、Sentence Transformers 与 Hugging Face Hub 的兼容约束。
  • 长期记忆设置页在修复依赖后刷新 Tauri bridge;无 stderr 时禁用 Hugging Face 终端进度条。
  • 默认关闭 mem0 telemetry,同时保留启动前显式环境变量。

Tests

  • 增加运行时版本校验、依赖修复、Windows symlink 探测和长期记忆设置流程的单元测试。
Original summary in English

This PR makes long-term-memory dependency checks version-aware and changes Windows model downloading and Tauri bridge refresh. The review found that the Windows symlink probe still misses the cache directories used by Hugging Face workers, and that repairing dependencies from Settings silently ends an active chat.

Enhancements

  • Adds version-aware runtime requirement checks and aligns the compatibility constraints for mem0, Transformers, Sentence Transformers, and Hugging Face Hub.
  • Refreshes the Tauri bridge after repairing long-term-memory dependencies and disables Hugging Face terminal progress when stderr is unavailable.
  • Disables mem0 telemetry by default while preserving an explicit launch-time environment value.

Tests

  • Adds unit coverage for runtime version checks, dependency repair, Windows symlink probing, and the long-term-memory Settings flow.

@End0rph1nww
End0rph1nww marked this pull request as ready for review July 23, 2026 15:38
@ameath-review

ameath-review Bot commented Jul 23, 2026

Copy link
Copy Markdown

Reviewer's Guide by Ameath

小爱会顺着关键路径看下去,尽量让核对更清楚。

关键调用链为:frontend_bridge_core.memory 先通过 core.runtime.requirements 评估 mem0 依赖组,MemorySettingsSection 在安装后于 Tauri 中调用 restartDesktopBridge;模型资产下载经 core.model_assets.downloads.preload_huggingface_snapshot 进入 Hugging Face。请优先处理已标注的 worker symlink 缓存键预热,以及 bridge 刷新时活跃聊天的关闭和删除生命周期。

文件级变更

Change Details Files
新增文件 2 个文件,+200 / -0 core/runtime/requirements.py
test/unit/core/test_runtime_requirements.py
修改文件(1/3) 10 个文件,+87 / -25 ai/memory/runtime.py
core/model_assets/downloads.py
frontend/src-tauri/src/lib.rs
frontend/src-tauri/src/runtime/resolver.rs
frontend/src-tauri/src/runtime/resolver/tests.rs
frontend/src/features/api-settings/MemorySettingsSection.tsx
frontend/src/shared/i18n/messages.ts
frontend/src/shared/i18n/messages/en.ts
frontend/src/shared/i18n/messages/ja.ts
frontend/src/shared/i18n/messages/zh_CN.ts
修改文件(2/3) 10 个文件,+334 / -96 frontend/src/test/features/api-settings/ApiSettingsSections.test.tsx
frontend/src/test/features/character-editor/useCharacterMemoryController.test.tsx
frontend_bridge.py
frontend_bridge_core/memory.py
frontend_bridge_core/runtime_dependencies.py
requirements-runtime-core.txt
requirements-runtime-local-ai.txt
requirements.txt
sdk/exception/types.py
test/unit/core/model_assets/test_downloads.py
修改文件(3/3) 3 个文件,+208 / -5 test/unit/frontend_bridge_core/test_frontend_bridge_memory.py
test/unit/frontend_bridge_core/test_frontend_runtime_check.py
test/unit/sdk/test_sdk_runtime_errors.py

关联 Issue

  • #252 Long-term memory model path error after download:PR 正文明确引用;完成度分析见上方审查指南。

Tips and commands
  • 重新审查: @Ame4th review
  • 重新生成摘要: @Ame4th summary
  • 重新生成指南: @Ame4th guide
  • 生成标题: @Ame4th title
  • 解决本机器人线程: @Ame4th resolve
  • 清理本机器人审查: @Ame4th dismiss
  • 从行级评论创建 Issue: 回复 @Ame4th issue
  • 继续讨论: 直接回复任一行级评论。
  • 反馈偏好: 对行级评论点 👍 或 👎。
Original review guide in English

The key call paths are: frontend_bridge_core.memory evaluates the mem0 dependency group through core.runtime.requirements; MemorySettingsSection calls restartDesktopBridge after installation in Tauri; model-asset downloads reach Hugging Face through core.model_assets.downloads.preload_huggingface_snapshot. Prioritize the annotated worker symlink-cache priming issue and the active-chat close/delete lifecycle during bridge refresh.

@ameath-review ameath-review Bot changed the title fix(memory): align Hugging Face runtime compatibility fix(memory): align Hugging Face runtime dependencies Jul 23, 2026

@ameath-review ameath-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

小爱从行间细节开始逐处确认,有需要留意的地方会直接说明。

小爱已完成全部变更审查,共发布 1 条行级建议(高风险 0,中风险 1)。

Prompt for AI Agents

请逐项处理以下审查问题;修改前先核实上下文,修改后运行相关测试。

1. Windows symlink 预热使用了不同的缓存键 / Prime the snapshot workers' cache key

core/model_assets/downloads.py:46 (RIGHT)
<issue_to_address>are_symlinks_supported 会以传入目录作为缓存键。snapshot_download 的 worker 创建 .../snapshots/<revision>/... pointer 时传入的是 pointer 的父目录;这里预热的是 storage_folder<cache>/<repo>),因此不是同一个键。没有 symlink 权限的 Windows 首次多文件下载仍可能让一个 worker 在探测完成前读到乐观的 True,并在创建 pointer 时触发 WinError 1314

are_symlinks_supported caches by its directory argument. Snapshot workers call it for the parent of each .../snapshots/<revision>/... pointer, while this code primes storage_folder (<cache>/<repo>). The keys differ, so first multi-file downloads on Windows without symlink privileges can still race into WinError 1314.</issue_to_address>

repo_type=str(repo_type or "model"),
)
with _HUGGINGFACE_SYMLINK_PROBE_LOCK:
are_symlinks_supported(storage_folder)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM · correctness] Windows symlink 预热使用了不同的缓存键 / Prime the snapshot workers' cache key

are_symlinks_supported 会以传入目录作为缓存键。snapshot_download 的 worker 创建 .../snapshots/<revision>/... pointer 时传入的是 pointer 的父目录;这里预热的是 storage_folder<cache>/<repo>),因此不是同一个键。没有 symlink 权限的 Windows 首次多文件下载仍可能让一个 worker 在探测完成前读到乐观的 True,并在创建 pointer 时触发 WinError 1314

are_symlinks_supported caches by its directory argument. Snapshot workers call it for the parent of each .../snapshots/<revision>/... pointer, while this code primes storage_folder (<cache>/<repo>). The keys differ, so first multi-file downloads on Windows without symlink privileges can still race into WinError 1314.

置信度 94% · 可直接回复讨论 · 👍/👎 会影响后续审查

@End0rph1nww

Copy link
Copy Markdown
Collaborator Author

@Ame4th review

@ameath-review ameath-review Bot changed the title fix(memory): align Hugging Face runtime dependencies fix(memory): enforce compatible runtime dependencies and refresh bridge Jul 23, 2026

@ameath-review ameath-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

小爱从这里开始逐处看看,把想确认的地方说清楚。

小爱已完成全部变更审查,共发布 2 条行级建议(高风险 0,中风险 2)。

Prompt for AI Agents

请逐项处理以下审查问题;修改前先核实上下文,修改后运行相关测试。

1. 依赖修复会静默结束正在进行的聊天

frontend/src/features/api-settings/MemorySettingsSection.tsx:209 (RIGHT)
<issue_to_address>安装成功后这里无条件重启完整 bridge。BridgeProcess::stop 会先 POST /api/chat/close,而 _close_chat 会终止 active chat child、关闭并删除 stream session;独立的 chat 窗口仍停留在 /chat-stage,随后只能重连到新 bridge 的空会话。因此,用户在对话进行中从设置页修复长期记忆依赖会无提示终止当前对话。请在重启前保留/协调会话,或明确确认这一破坏性操作。

Original in English

After a successful install this unconditionally restarts the whole bridge. BridgeProcess::stop first posts /api/chat/close; _close_chat terminates the active chat child and closes and deletes its stream session. The independent chat window remains at /chat-stage and can only reconnect to an empty session on the new bridge. Repairing long-term-memory dependencies while a conversation is live therefore silently ends it. Preserve or coordinate the session, or require explicit confirmation before this destructive restart.

2. Windows symlink 预热未覆盖 worker 缓存目录

core/model_assets/downloads.py:63 (RIGHT)
<issue_to_address>are_symlinks_supported 按传入目录缓存结果,但这里预热的是仓库的 models--... 存储目录。Hugging Face Hub 0.36.2 的并发下载 worker 在创建 snapshots/<revision> 指针时会按该指针父目录再次查询;首次无创建 symlink 权限的 Windows 下载因此仍可让多个 worker 命中乐观缓存并抛出 WinError 1314。这使本 PR 试图修复的首下载失败路径仍然可达。请将预热/同步范围对齐到 worker 实际使用的指针目录。

Original in English

are_symlinks_supported caches by its input directory, while this only primes the models--... storage folder. Hugging Face Hub 0.36.2 concurrent download workers query it again for the parent of each snapshots/<revision> pointer. On a first Windows download without symlink privileges, workers can still observe the optimistic cache and raise WinError 1314, so the intended first-download failure remains reachable. Prime or synchronize the actual pointer-directory key used by the workers.

},
);
if (isTauriDesktop()) {
await restartDesktopBridge();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM · bug] 依赖修复会静默结束正在进行的聊天

安装成功后这里无条件重启完整 bridge。BridgeProcess::stop 会先 POST /api/chat/close,而 _close_chat 会终止 active chat child、关闭并删除 stream session;独立的 chat 窗口仍停留在 /chat-stage,随后只能重连到新 bridge 的空会话。因此,用户在对话进行中从设置页修复长期记忆依赖会无提示终止当前对话。请在重启前保留/协调会话,或明确确认这一破坏性操作。

Original in English

After a successful install this unconditionally restarts the whole bridge. BridgeProcess::stop first posts /api/chat/close; _close_chat terminates the active chat child and closes and deletes its stream session. The independent chat window remains at /chat-stage and can only reconnect to an empty session on the new bridge. Repairing long-term-memory dependencies while a conversation is live therefore silently ends it. Preserve or coordinate the session, or require explicit confirmation before this destructive restart.

置信度 99% · 可直接回复讨论 · 👍/👎 会影响后续审查

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里是有意的维护行为,不作为 bug 处理。依赖修复会替换当前 Python 运行时中的核心包;如果不重启 bridge,当前进程仍会持有旧模块,甚至形成新旧依赖混用的状态。该重启只发生在用户从设置页主动触发依赖修复且安装成功之后,因此活跃聊天随 bridge 生命周期结束是此操作的预期结果。本 PR 不尝试跨运行时替换保留旧会话;若后续需要额外的 UX 提示,可以作为独立改进处理。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这边已经顺着讨论整理好了,小爱就先把话题轻轻收在这里。

重启 bridge 以加载替换后的 Python 依赖是合理且必要的;问题不在于“是否应重启”,而在于这个会终止聊天的副作用对用户不可见。

当前触发入口是设置页的依赖修复操作,用户无法从该按钮及现有流程得知它会:

  • 终止正在运行的 chat child;
  • 删除 stream session;
  • 使独立聊天窗口重连到空会话。

“用户主动安装依赖”并不等同于“用户已确认丢弃当前对话”。尤其安装完成后才执行重启,此时再发现对话被终止已经无法撤销。

不要求本 PR 实现跨 bridge 的会话迁移,但至少应在开始安装前(或检测到活跃会话时)明确告知并要求确认,例如提示“修复完成后将重启服务并结束当前对话,是否继续?”。用户取消时不应开始安装,以避免安装已完成却无法安全应用的状态。

因此,重启作为维护机制可以保留,但无提示终止活动聊天的审查结论仍然成立。

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要不听话,小爱

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这边已经接上了,小爱把话题轻轻收回来。

该重启用于加载新依赖是必要的,这一点没有异议;但当前实现的用户可见行为仍是:点击“安装/修复依赖”后,安装成功才无条件调用 restartDesktopBridge(),并在未提示的情况下结束活跃聊天、删除流会话。

“用户主动修复依赖”不能替代对丢弃当前会话的确认,尤其该副作用发生在安装完成后,用户已无法取消。无需在本 PR 实现跨 bridge 会话迁移,但建议在开始安装前检测活跃聊天,明确提示“修复完成后将重启服务并结束当前对话”,并允许取消;取消时不应启动安装。

若产品明确接受此破坏性行为,至少也应在按钮说明或确认弹窗中告知。否则该问题仍建议修复后再关闭。

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

再怼停你token

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这边已经收束好了,小爱把话题轻轻接回来了。

重启以加载新依赖是必要的,但这不消除其破坏性副作用:当前代码会在安装成功后无条件关闭活跃 chat child 并删除 stream session,而用户在操作前没有得到提示或取消机会。

建议在启动安装前,针对活跃会话显示明确确认:“修复完成后将重启服务并结束当前对话,是否继续?”。用户取消则不安装、不重启。若决定接受此行为,也应在界面中明确告知;否则该问题仍建议保留。

repo_type=str(repo_type or "model"),
)
with _HUGGINGFACE_SYMLINK_PROBE_LOCK:
are_symlinks_supported(storage_folder)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM · bug] Windows symlink 预热未覆盖 worker 缓存目录

are_symlinks_supported 按传入目录缓存结果,但这里预热的是仓库的 models--... 存储目录。Hugging Face Hub 0.36.2 的并发下载 worker 在创建 snapshots/<revision> 指针时会按该指针父目录再次查询;首次无创建 symlink 权限的 Windows 下载因此仍可让多个 worker 命中乐观缓存并抛出 WinError 1314。这使本 PR 试图修复的首下载失败路径仍然可达。请将预热/同步范围对齐到 worker 实际使用的指针目录。

Original in English

are_symlinks_supported caches by its input directory, while this only primes the models--... storage folder. Hugging Face Hub 0.36.2 concurrent download workers query it again for the parent of each snapshots/<revision> pointer. On a first Windows download without symlink privileges, workers can still observe the optimistic cache and raise WinError 1314, so the intended first-download failure remains reachable. Prime or synchronize the actual pointer-directory key used by the workers.

置信度 98% · 可直接回复讨论 · 👍/👎 会影响后续审查

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这条在本 PR 固定的 huggingface-hub 0.36.2 中不成立。该版本的 _create_symlink() 正常缓存路径并不是直接把 pointer 的父目录传给 are_symlinks_supported(),而是:

commonpath = os.path.commonpath([abs_src, abs_dst])
_support_symlinks = are_symlinks_supported(commonpath)

Hub 缓存中的 abs_src<storage_folder>/blobs/...abs_dst<storage_folder>/snapshots/<revision>/...,所以两者的 commonpath 正好就是本 PR 预热的 storage_folderare_symlinks_supported() 还会对两边执行相同的 Path(...).resolve() 规范化。我也用当前实际的 D 盘缓存路径核对过,预热键与 worker 键完全相同(same_key=True)。

源码中改用 abs_dst_folder 的分支仅发生在计算 common path 出现 PermissionError 或只读文件系统错误时;Windows 无 symlink 权限是在 are_symlinks_supported() 自身的探测中被捕获并将同一个 storage_folder 键缓存为 False,不会进入上述 fallback。实际全新缓存的首次并发下载也已完成。因此这里不需要修改。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

小爱把这段回应接住了,后面的交流就顺着往下走吧。

感谢澄清。基于你给出的 huggingface-hub==0.36.2 调用路径,这条意见不成立:

  • 正常 _create_symlink() 路径以 abs_srcblobs/...)和 abs_dstsnapshots/<revision>/...)计算 commonpath
  • 对同一仓库缓存而言,该值就是 <cache_dir>/models--... 存储目录,与这里预热传入 are_symlinks_supported() 的路径一致;
  • 两处还会经过相同的 Path.resolve() 规范化,因此缓存键一致;
  • 无 Windows 创建 symlink 权限的情形由 are_symlinks_supported() 的探测处理并缓存为 False,不需要进入 commonpath 计算失败时的 fallback。

在调用预热发生于 snapshot_download 创建并发 worker 之前的前提下,现有全局锁足以保证该存储目录对应的探测完成后,worker 才会读取稳定结果。已提供全新缓存的并发下载验证。

撤回此 finding,无需针对此项修改。

@RachelForster RachelForster added p0 p1 and removed p1 labels Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants