Skip to content

fix: isolate sessions by workspace to prevent cross-workspace memory leak#634

Closed
Kokeip wants to merge 2 commits intoHKUDS:mainfrom
Kokeip:fix/workspace-memory-isolation
Closed

fix: isolate sessions by workspace to prevent cross-workspace memory leak#634
Kokeip wants to merge 2 commits intoHKUDS:mainfrom
Kokeip:fix/workspace-memory-isolation

Conversation

@Kokeip
Copy link
Copy Markdown

@Kokeip Kokeip commented Feb 14, 2026

Problem

When switching between workspaces, nanobot continued using the same conversation session, causing memory contamination across workspaces:

  1. Chat in workspace A (e.g., "I like chips")
  2. Switch to workspace B
  3. Session history from workspace A still loaded
  4. Running /new in workspace B would consolidate workspace A's history into workspace B's MEMORY.md

This made workspace memory unreliable and mixed unrelated contexts.

Root Cause

Session files were stored globally at ~/.nanobot/sessions/ and keyed only by channel:chat_id, with no workspace isolation. Different workspaces using the same channel/chat_id would share the same session file.

Solution

Added workspace-specific subdirectories using an MD5 hash of the workspace path:

ws_hash = hashlib.md5(str(workspace.resolve()).encode()).hexdigest()[:8]
self.sessions_dir = Path.home() / ".nanobot" / "sessions" / ws_hash

Now each workspace maintains its own isolated session storage.

Changes

  • Modified: manager.py  (+3 lines, -1 line)
  • Added workspace hash calculation using hashlib (Python standard library, no additional dependencies required)
  • No breaking changes to APIs or config

Testing

Verified the fix works correctly:

  1. ✅ Started agent in workspace A, created conversation with personal info
  2. ✅ Switched to workspace B, confirmed clean session (no workspace A history)
  3. ✅ Used /new in workspace B, verified no workspace A content leaked into workspace B memory files
  4. ✅ Session files properly isolated under different hash subdirectories

The issue is resolved and workspaces now maintain independent memory contexts.

@Kokeip
Copy link
Copy Markdown
Author

Kokeip commented Feb 15, 2026

@Re-bin 大佬有空review一下吗

@Re-bin
Copy link
Copy Markdown
Collaborator

Re-bin commented Feb 15, 2026

我来啦,这就review

@Re-bin
Copy link
Copy Markdown
Collaborator

Re-bin commented Feb 15, 2026

感谢这个 PR!workspace 隔离 session 的方向是对的。

不过目前 nanobot 主要还是单用户单 workspace 的使用场景,多 workspace 并行的需求还不多。另外合入后现有用户的 session 路径会变化,升级后旧的对话历史会找不到。

@Kokeip
Copy link
Copy Markdown
Author

Kokeip commented Feb 15, 2026

感谢这个 PR!workspace 隔离 session 的方向是对的。

不过目前 nanobot 主要还是单用户单 workspace 的使用场景,多 workspace 并行的需求还不多。另外合入后现有用户的 session 路径会变化,升级后旧的对话历史会找不到。

感谢大佬反馈!我已经补充了后向兼容的迁移逻辑。

实现思路:
在首次加载 session 时,如果在新路径(workspace-isolated)下找不到,会自动检查旧路径(global)是否存在。如果存在就自动迁移过去,记录日志后正常使用。这样升级后用户无需任何操作,现有对话会无感知延续。

代码改动:

第一个 commit:workspace 隔离(+3 行)
第二个 commit:后向兼容迁移(+9 行)
总共只增加了 12 行代码,无破坏性变更
关于使用场景:
我个人在本地开发时会用多个 workspace 分别测试不同项目,这个 PR 正好解决了我遇到的记忆串台问题。虽然目前单 workspace 场景更常见,但相信随着 nanobot 能力增强,多 workspace 甚至多用户协作的玩法会越来越多。

当然,这只是我的一点想法。如果您觉得当前时机不太合适或有其他考虑,完全理解,可以暂时先不合并,等后续有需求再说 :)

@Re-bin
Copy link
Copy Markdown
Collaborator

Re-bin commented Feb 15, 2026

甭客气,感谢修改,我再review下😄

@Re-bin
Copy link
Copy Markdown
Collaborator

Re-bin commented Feb 15, 2026

我有个想法:与其用 hash 子目录(~/.nanobot/sessions/<ws_hash>/),不如直接把 sessions 放到 workspace 目录下面?现在 memory/、skills/ 已经在 workspace 里了,sessions/ 放进去更一致:

{workspace}/
├── memory/
├── skills/
└── sessions/ ← 直接放这里

代码也更简单,不需要 hashlib,直接 ensure_dir(workspace / "sessions") 就行。

迁移逻辑还是需要的,把 ~/.nanobot/sessions/ 下面的旧文件 move 过来。你觉得呢🤔?

@Kokeip
Copy link
Copy Markdown
Author

Kokeip commented Feb 16, 2026

我有个想法:与其用 hash 子目录(~/.nanobot/sessions/<ws_hash>/),不如直接把 sessions 放到 workspace 目录下面?现在 memory/、skills/ 已经在 workspace 里了,sessions/ 放进去更一致:

{workspace}/
├── memory/
├── skills/
└── sessions/ ← 直接放这里

代码也更简单,不需要 hashlib,直接 ensure_dir(workspace / "sessions") 就行。

迁移逻辑还是需要的,把 ~/.nanobot/sessions/ 下面的旧文件 move 过来。你觉得呢🤔?

很好的建议,我再补充一个观察,想一起确认下方向:

我看了下现有生态(比如 Codex / Claude Code),运行时状态基本都放在全局配置目录里,而不是项目 workspace。这个做法在隐私和“避免项目检索误命中”上更稳一些,防止模型把session和memory也和用户预期比较一致。
基于这个,我这边更倾向于:

  1. skills,memory和session统一放到全局 ~/.nanobot/ 下
  2. 做 workspace 级隔离,避免跨 workspace 串会话
  3. 目录命名不用纯 md5(对用户不友好),改成可读命名,例如:
    • workspace_name__shorthash/
    • 或 host/path 规范化后的 slug
  4. 保留旧路径迁移逻辑,确保升级后用户历史无感延续
    这样可以同时满足:
  • 不污染项目目录
  • 降低隐私和误检索风险
  • 继续解决跨 workspace 混入问题
  • 用户也能直观看懂每个目录对应哪个 workspace
    你认为这样如何?🤔

@Re-bin
Copy link
Copy Markdown
Collaborator

Re-bin commented Feb 18, 2026

你说的隐私顾虑有道理。不过目前 memory/ 已经在 workspace 下了,sessions 放进去跟现有结构一致,代码也更简单。如果以后要把运行时状态统一挪到全局目录,memory 和 sessions 可以一起迁移,那是一个更大的架构调整。当前阶段先保持一致性比较好。🤔

@tianzhipengfei
Copy link
Copy Markdown

感谢这个 PR!workspace 隔离 session 的方向是对的。
不过目前 nanobot 主要还是单用户单 workspace 的使用场景,多 workspace 并行的需求还不多。另外合入后现有用户的 session 路径会变化,升级后旧的对话历史会找不到。

感谢大佬反馈!我已经补充了后向兼容的迁移逻辑。

实现思路: 在首次加载 session 时,如果在新路径(workspace-isolated)下找不到,会自动检查旧路径(global)是否存在。如果存在就自动迁移过去,记录日志后正常使用。这样升级后用户无需任何操作,现有对话会无感知延续。

代码改动:

第一个 commit:workspace 隔离(+3 行) 第二个 commit:后向兼容迁移(+9 行) 总共只增加了 12 行代码,无破坏性变更 关于使用场景: 我个人在本地开发时会用多个 workspace 分别测试不同项目,这个 PR 正好解决了我遇到的记忆串台问题。虽然目前单 workspace 场景更常见,但相信随着 nanobot 能力增强,多 workspace 甚至多用户协作的玩法会越来越多。

当然,这只是我的一点想法。如果您觉得当前时机不太合适或有其他考虑,完全理解,可以暂时先不合并,等后续有需求再说 :)

请教一下,现在多个workspace的切换是手动切换的,还是根据channel/chat_id来进行workspace区分的啊?

@Kokeip
Copy link
Copy Markdown
Author

Kokeip commented Feb 28, 2026

感谢这个 PR!workspace 隔离 session 的方向是对的。
不过目前 nanobot 主要还是单用户单 workspace 的使用场景,多 workspace 并行的需求还不多。另外合入后现有用户的 session 路径会变化,升级后旧的对话历史会找不到。

感谢大佬反馈!我已经补充了后向兼容的迁移逻辑。
实现思路: 在首次加载 session 时,如果在新路径(workspace-isolated)下找不到,会自动检查旧路径(global)是否存在。如果存在就自动迁移过去,记录日志后正常使用。这样升级后用户无需任何操作,现有对话会无感知延续。
代码改动:
第一个 commit:workspace 隔离(+3 行) 第二个 commit:后向兼容迁移(+9 行) 总共只增加了 12 行代码,无破坏性变更 关于使用场景: 我个人在本地开发时会用多个 workspace 分别测试不同项目,这个 PR 正好解决了我遇到的记忆串台问题。虽然目前单 workspace 场景更常见,但相信随着 nanobot 能力增强,多 workspace 甚至多用户协作的玩法会越来越多。
当然,这只是我的一点想法。如果您觉得当前时机不太合适或有其他考虑,完全理解,可以暂时先不合并,等后续有需求再说 :)

请教一下,现在多个workspace的切换是手动切换的,还是根据channel/chat_id来进行workspace区分的啊?

应该还是手动在config里面切换的

@Kokeip Kokeip closed this Feb 28, 2026
@chengyongru
Copy link
Copy Markdown
Collaborator

Because this issue has been inactive for a long time, I will close it. If there are any other problems, please feel free to open a new issue.

WTHDonghai pushed a commit to WTHDonghai/nanobot that referenced this pull request Mar 22, 2026
…KUDS#661)

When tiktoken is unavailable, the fallback `len(text) // 3` severely
underestimates tokens for CJK text (Chinese/Japanese/Korean characters
are ~1-2 tokens each, not 0.33). This causes text exceeding the 8192-token
API limit to bypass chunking, resulting in BadRequestError.

Use `max(len(text) // 3, len(text.encode("utf-8")) // 4)` instead, which
picks the more conservative estimate. For ASCII-heavy text the char-based
estimate still wins; for CJK text the byte-based estimate correctly
produces ~0.75 tokens per character.

Fixes HKUDS#616, fixes HKUDS#634

Signed-off-by: JiangNan <1394485448@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants