Conversation
memory_store and memory_recall both write to a single fixed `shared_memory_agent_id()` namespace, shared by every agent, every channel, and every end user of the whole installation. In practice this means: person A messaging the bot via a Telegram DM, person B in an unrelated Discord server, and a completely different agent can all read and overwrite the same memory keys. There is no isolation at all beyond whatever key text the LLM happens to choose. This adds a `sender_id` plumbed from the channel bridge down through the agent loop into the tool-execution layer, and a new `ChannelBridgeHandle::send_message_from()` (default falls back to the existing `send_message()`, so this is non-breaking for any other implementer of the trait) that carries the real channel actor's identity. `tool_memory_store`/`tool_memory_recall` now prefix keys as `user:<sender_id>:<key>` whenever a sender identity is available, leaving dashboard/API/cron callers (which are already owner-trusted and have no channel sender) on the previous unprefixed behavior. ## Test plan - Verified end-to-end against a real Nextcloud Talk instance: a memory_store call from a message now shows up in `GET /api/memory/agents/:id/kv` as `user:<actor_id>:<key>` instead of the bare key. - Verified the direct dashboard/API message path (no sender identity) is unaffected and still stores/recalls under the plain key. - `cargo build --release` succeeds with no new warnings. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
memory_store/memory_recallboth write to a single fixedshared_memory_agent_id()namespace — documented in-code as intentional ("so all agents read/write to the same namespace"), but in practice this means any end user messaging any agent through any channel can read and overwrite every other user's memory entries. There's no isolation beyond whatever key text the model happens to pick (e.g.self.*vsshared.*is a naming convention, not an enforced boundary).Concretely: person A messaging the bot from a Nextcloud Talk / Telegram / Discord conversation, and person B in a completely unrelated conversation, currently share one flat KV store.
Fix
Threads a
sender_id(the real channel actor's identity, e.g. Nextcloud Talk'sactor_id) from the channel bridge down through the agent loop into the tool-execution layer:ChannelBridgeHandle::send_message_from(agent_id, message, sender_id)— default implementation falls back to the existingsend_message(), so this is non-breaking for any other implementer of the trait.OpenFangKernel::send_message_from(...)mirrorssend_message(...)but resolves the handle the same way and threadssender_idthrough toexecute_llm_agent/streaming.execute_tool(...)gains acaller_sender_id: Option<&str>parameter.tool_memory_store/tool_memory_recallnow prefix keys asuser:<sender_id>:<key>whenever a sender identity is available, via a smallscoped_memory_key()helper. Dashboard/API/cron callers (already owner-trusted, no channel sender) keep the previous unprefixed behavior.execute_toolcall site (routes.rs, MCP-over-HTTP) to passNonefor the new parameter.Test plan
memory_storecall triggered from a chat message now shows up inGET /api/memory/agents/:id/kvasuser:<actor_id>:<key>instead of the bare key.cargo build --releasesucceeds with no new warnings.🤖 Generated with Claude Code