Conversation
4 tasks
memtomem
pushed a commit
that referenced
this pull request
Apr 24, 2026
Addresses three nits from the PR #457 review: 1. Drop the unused CLAUDE_/GEMINI_/CODEX_MEMORY_NAMESPACE_PREFIX exports from `constants.py`. Promoting them while `cli/ingest_cmd.py` still hardcodes the literals would have created a *new* parallel-literal seam — exactly what `feedback_drift_close_must_derive` warns against. Wiring the ingest CLI is a separate change, not this PR's scope. 2. Drop the `_AGENT_NAMESPACE_PREFIX = AGENT_NAMESPACE_PREFIX` re-export alias in `multi_agent.py`. The "Re-export for callers that previously imported the local-private symbol" comment was misleading — underscore-private symbols have no external callers by definition, and grep confirms zero in-repo references on this branch. Stacked PRs (#459 / #461) that import the underscore-private symbol get updated when they rebase onto this PR; the public `AGENT_NAMESPACE_PREFIX` is the right import target. 3. Update the comment above `config.search.system_namespace_prefixes = ["archive:"]` in `test_trust_ux.py:68`. After this PR's default flip the override is *narrowing* (default has both `archive:` and `agent-runtime:`), not "spelling out" — the new comment says so and notes that multi-agent isolation has its own coverage in `test_multi_agent`. No behavior change. 2335 tests still pass. Co-Authored-By: Claude <[email protected]>
memtomem
added a commit
that referenced
this pull request
Apr 24, 2026
* fix(multi-agent): hide agent-runtime: from default mem_search `search.system_namespace_prefixes` default was `["archive:"]` only, so agent A's private chunks (created by `mem_agent_register` / `mem_agent_search`) leaked into agent B's `mem_search(namespace=None)` results — directly contradicting the namespace-based isolation guarantee documented on the multi-agent guide. Extends the default to `["archive:", "agent-runtime:"]` and consolidates the literal in a new `memtomem.constants` module so config, MCP tools, and CLI all derive the prefix from one source. `mem_agent_search` is unaffected because it builds an explicit namespace filter; the hidden count surfaces through the existing `hidden_system_ns` hint. Behavior change: callers relying on plain `mem_search` to read `agent-runtime:*` chunks must now either pin `namespace=` or override `search.system_namespace_prefixes: []` in `config.json`. Documented under [Unreleased] / Changed. Threat model: `agent-runtime:<id>` is a *convenience* isolation boundary, not a security boundary. Direct storage access (raw `namespace=`, ingest `--namespace`, list_namespaces) still reaches private chunks; this PR closes the default-search UX leak only. Test surface (test_multi_agent.py): - `TestDefaultIsolation` pins constants, default factory freshness, and `Mem2MemConfig` default — derives from the constant per `feedback_pin_test_constant_over_source_scan`. - `TestAgentRuntimeIsolationPipeline` end-to-end: `agent-runtime:planner` chunks excluded from `namespace=None` search but reachable via pinned `namespace=`; `shared` namespace stays surfaceable. Co-Authored-By: Claude <[email protected]> * review fixup: drop dead alias/symbols + correct trust_ux comment Addresses three nits from the PR #457 review: 1. Drop the unused CLAUDE_/GEMINI_/CODEX_MEMORY_NAMESPACE_PREFIX exports from `constants.py`. Promoting them while `cli/ingest_cmd.py` still hardcodes the literals would have created a *new* parallel-literal seam — exactly what `feedback_drift_close_must_derive` warns against. Wiring the ingest CLI is a separate change, not this PR's scope. 2. Drop the `_AGENT_NAMESPACE_PREFIX = AGENT_NAMESPACE_PREFIX` re-export alias in `multi_agent.py`. The "Re-export for callers that previously imported the local-private symbol" comment was misleading — underscore-private symbols have no external callers by definition, and grep confirms zero in-repo references on this branch. Stacked PRs (#459 / #461) that import the underscore-private symbol get updated when they rebase onto this PR; the public `AGENT_NAMESPACE_PREFIX` is the right import target. 3. Update the comment above `config.search.system_namespace_prefixes = ["archive:"]` in `test_trust_ux.py:68`. After this PR's default flip the override is *narrowing* (default has both `archive:` and `agent-runtime:`), not "spelling out" — the new comment says so and notes that multi-agent isolation has its own coverage in `test_multi_agent`. No behavior change. 2335 tests still pass. Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: pandas-studio <[email protected]> Co-authored-by: Claude <[email protected]>
dc59cc0 to
a1f47e4
Compare
…earch `mem_session_start` only stored `current_session_id` while `mem_agent_search(agent_id=None)` fell back to `current_namespace` — a different axis altogether. The multi-agent guide's "agent_id is not auto-detected, but inherited via session context" promise silently broke: an agent that started a session still had to repeat its agent_id on every search, or got results from `current_namespace` instead of its own private namespace. This PR threads agent_id through the session lifecycle and gives multi-agent search a documented resolution priority. Changes: * New `current_agent_id` field on `AppContext`. Set by `mem_session_start(agent_id=...)`, reset by `mem_session_end`. Lives behind a new `_session_lock` distinct from `_config_lock` so a long-running config write can't block a session update and vice versa. * `_resolve_agent_namespace(app, agent_id)` helper documents the priority: explicit `agent_id` arg > `current_agent_id` > `current_namespace` (legacy fallback). Extracted as a top-level function so the contract is unit-testable without standing up MCP components. * `mem_session_start` now handles the "active session already exists" case explicitly. The previous session is auto-ended (warning logged + inline notice in the return string) instead of silently overwritten — the storage row for the auto-ended session is closed with an `auto_ended: true` metadata flag for audit. The new agent_id replaces the old; agents do not stack. * `mem_session_end` resets both `current_session_id` and `current_agent_id`. The "no active session" branch is preserved. Test surface: * `TestResolveAgentNamespace` (test_multi_agent.py) — 5 cases for the priority order (explicit wins, current_agent_id, legacy namespace, all-None, override-while-active). * `TestSessionAgentInheritance` (test_sessions.py) — fresh start records agent, second start auto-ends previous, end resets both fields, end without active is no-op, the two locks are not aliased. Co-Authored-By: Claude <[email protected]>
a1f47e4 to
b63422d
Compare
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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
mem_session_startonly storedcurrent_session_idwhilemem_agent_search(agent_id=None)fell back tocurrent_namespace— adifferent axis altogether. The multi-agent guide's
"agent_id is not auto-detected, but inherited via session context"
promise silently broke: an agent that started a session still had to
repeat its
agent_idon every search, or got results fromcurrent_namespaceinstead of its own private namespace.This PR threads
agent_idthrough the session lifecycle and givesmulti-agent search a documented resolution priority.
Changes
current_agent_idfield onAppContext. Set bymem_session_start(agent_id=...), reset bymem_session_end.Lives behind a new
_session_lockdistinct from_config_locksolong-running config writes can't block session updates and vice versa.
_resolve_agent_namespace(app, agent_id)helper documents thepriority: explicit
agent_idarg >current_agent_id>current_namespace(legacy fallback). Top-level so the contract isunit-testable without standing up MCP components.
mem_session_starthandles "active session already exists" explicitly.The previous session is auto-ended (warning logged + inline notice
in the return string) instead of silently overwritten — the storage
row is closed with an
auto_ended: truemetadata flag for audit. Thenew
agent_idreplaces the old; agents do not stack.mem_session_endresets bothcurrent_session_idandcurrent_agent_id. "No active session" branch preserved.State transition table
current_session_idcurrent_agent_idmem_session_start("a"), no active"a"mem_session_start("b"), active "a""b"mem_session_end(), activeNoneNonemem_session_end(), no activeNoneNonemem_agent_search(agent_id="x")agent-runtime:xmem_agent_search(agent_id=None), session activeagent-runtime:<current_agent_id>mem_agent_search(agent_id=None), no sessioncurrent_namespace(legacy)Test plan
TestResolveAgentNamespace(test_multi_agent.py) — 5 cases forthe priority order: explicit wins, current_agent_id, legacy namespace,
all-None, override-while-active.
TestSessionAgentInheritance(test_sessions.py) — fresh startrecords agent, second start auto-ends previous, end resets both
fields, end without active is no-op, the two locks are not aliased.
uv run pytest -m "not ollama"— 2339 passed, 46 deselected.uv run ruff check+ruff format --check— clean.🤖 Generated with Claude Code