Skip to content

feat: perUserContext — per-user conversation isolation in group chats#324

Open
HuaweiREN wants to merge 13 commits into
xvirobotics:mainfrom
HuaweiREN:pr/per-user-context
Open

feat: perUserContext — per-user conversation isolation in group chats#324
HuaweiREN wants to merge 13 commits into
xvirobotics:mainfrom
HuaweiREN:pr/per-user-context

Conversation

@HuaweiREN

Copy link
Copy Markdown

Summary

When a bot opts in via perUserContext: true, conversation state (Claude session, persistent executor, message queue, running task) is keyed by chatId:userId instead of bare chatId. Each Feishu member in a group chat gets their own independent Claude thread.

Motivation

In the default MetaBot group chat mode, all members share a single Claude session. This causes:

  • User A's /reset wipes User B's conversation
  • /model switch affects everyone
  • Context pollution: personal queries mix with team discussions

The perUserContext flag solves this while preserving backward compatibility.

Changes

1. Scope Key Composition (src/session/compose-key.ts — new)

composeScopeKey(chatId, userId, perUserContext) → composite key with helpers chatIdFromScopeKey() and userIdFromScopeKey().

2. Session Manager (src/engines/claude/session-manager.ts)

All methods accept opaque scopeKey. JSON persistence unchanged — backward compatible.

3. Executor Registry (src/engines/claude/executor-registry.ts)

Pool keyed by scopeKey; cap bumped 20→50 for per-user multiplier.

4. Message Bridge (src/bridge/message-bridge.ts)

All conversation-state Maps keyed by scopeKey. isBusy(chatId) scans scopeKey prefixes.

5. Command Handler (src/bridge/command-handler.ts)

/reset, /stop, /status, /model all scoped by caller. /status shows User field.

6. System Prompt (src/engines/claude/executor.ts, persistent-executor.ts)

userId threaded through ApiContext into system prompt: The current user's ID is "ou_xxx".

7. Config (src/config.ts)

BotConfigBase.perUserContext?: boolean — defaults to false. Wired through JSON loader.

Backward Compatibility

  • perUserContext: false → byte-for-byte identical
  • Existing session JSON files load unchanged
  • p2p chats unaffected (1:1 chatId↔userId mapping)

Tests

  • tests/compose-key.test.ts: 8 tests
  • tests/per-user-context.test.ts: 12 tests

Files Changed

  • src/session/compose-key.ts (new)
  • src/config.ts
  • src/bridge/command-handler.ts
  • src/bridge/message-bridge.ts
  • src/engines/claude/session-manager.ts
  • src/engines/claude/executor-registry.ts
  • src/engines/claude/executor.ts
  • src/engines/claude/persistent-executor.ts
  • src/api/routes/executor-routes.ts
  • tests/compose-key.test.ts (new)
  • tests/per-user-context.test.ts (new)

11 files, +716 −283

floodsung and others added 13 commits May 15, 2026 01:46
* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* feat(cluster): add federated identity foundation

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* feat(memory): add namespace scoped instance token

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* feat(skills): track owner metadata and hashes

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* feat(cluster): bootstrap peers from cluster url

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* docs: document federated memory and skill hub

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* fix(cli): use instance memory token

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* Cache peer Skill Hub artifacts

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
* Mirror peer MetaMemory documents

* Add stable bot memory namespaces

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
* Mirror peer MetaMemory documents

* Add stable bot memory namespaces

* Update lark CLI via metabot update

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
When a bot opts in via `perUserContext: true`, conversation state
(session, persistent executor, message queue, running task) is keyed
by `chatId:userId` instead of `chatId`. This gives each Feishu member
in a group chat their own Claude thread.

Changes:
- composeScopeKey / chatIdFromScopeKey / userIdFromScopeKey helpers
- SessionManager, ExecutorRegistry: opaque scopeKey parameter
- MessageBridge: thread scopeKey through all conversation-state Maps
- CommandHandler: /reset, /stop, /status, /model scoped by caller
- ExecutorRoutes: adjusted for scopeKey
- Config: perUserContext bot flag wired through JSON loader
- Tests: compose-key (8 tests) + per-user-context (12 tests)
- Bump default executor pool cap 20 -> 50 for per-user multiplier

Back-compat: default false/undefined preserves byte-for-byte identical
behavior. Existing session JSON files load unchanged.
- Add perUserContext to CLAUDE.md Configuration section
- Add perUserContext example to bots.example.json
- Enable perUserContext: true for Baymax in bots.json
Thread msg.userId through ApiContext so the Claude executor (and the
persistent variant) can mention "The current user's ID is <open_id>" in
the system prompt appendix. Groundwork for per-user context keying — the
userId is now reliably available on the wire end-to-end.
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.

2 participants