Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4cb2112
docs(spec): design for Strands MemoryStore integration
Andy2003 Aug 19, 2026
8260d45
docs(spec): condense to facts
Andy2003 Aug 19, 2026
71a5779
chore(strands): require strands-agents>=1.44.0 for the LTM MemoryStore
Andy2003 Aug 19, 2026
7e9626f
feat(strands): add _retrieve_entries long-term fan-out
Andy2003 Aug 19, 2026
1b41697
fix(strands): read similarity score for preference/fact rows too
Andy2003 Aug 19, 2026
5be895e
docs(spec): score is set for all three long-term kinds on bolt
Andy2003 Aug 19, 2026
7443d54
feat(strands): add Neo4jMemoryStore skeleton
Andy2003 Aug 19, 2026
a1ac791
fix(strands): for_nams mirrors session manager, cover settings-owned …
Andy2003 Aug 19, 2026
6973428
feat(strands): resolve a deterministic memory-store sink conversation
Andy2003 Aug 19, 2026
52c3bb4
fix(strands): skip the conversation list scan on bolt in _resolve_sink
Andy2003 Aug 19, 2026
95de5f5
fix(strands): drop the pointless bolt create_conversation call in _re…
Andy2003 Aug 19, 2026
078d4c2
docs(spec): bolt cannot tag the sink conversation at all
Andy2003 Aug 19, 2026
ab58232
feat(strands): implement Neo4jMemoryStore.search
Andy2003 Aug 19, 2026
7724569
test(strands): fix round 1 on Neo4jMemoryStore.search tests
Andy2003 Aug 19, 2026
31fd7df
feat(strands): implement Neo4jMemoryStore.add
Andy2003 Aug 19, 2026
32b3c50
fix(strands): fix round 1 on Neo4jMemoryStore.add
Andy2003 Aug 19, 2026
e82cdbf
feat(strands): implement Neo4jMemoryStore.add_messages
Andy2003 Aug 19, 2026
9d62da7
docs(changelog): record Neo4jMemoryStore and the strands floor bump
Andy2003 Aug 19, 2026
40b8459
fix(strands): tenant-scope the bulk message write path
Andy2003 Aug 20, 2026
484dd92
refactor(strands): Neo4jMemoryStoreConfig as a checked dataclass
Andy2003 Aug 20, 2026
5000a81
feat(strands): expose graph-native store tools
Andy2003 Aug 20, 2026
cd20791
fix(strands): narrow store-tools casts to concrete backend classes
Andy2003 Aug 20, 2026
fa1f7f4
fix(strands): scope get_user_preferences to the store's user
Andy2003 Aug 20, 2026
a684c0f
feat(strands): guard session-manager / memory-store overlaps
Andy2003 Aug 20, 2026
239a7cb
test(strands): strengthen foreign-store coexistence test
Andy2003 Aug 20, 2026
d10c7a3
docs(strands): document the memory store as the preferred memory cons…
Andy2003 Aug 20, 2026
fba1f53
fix(strands): clear guidance for stale vector indexes on the shared c…
Andy2003 Aug 20, 2026
8422708
fix(strands): rebind an owned client when Strands changes the event loop
Andy2003 Aug 20, 2026
d2aadfd
style: ruff format the three files failing CI's format gate
Andy2003 Aug 20, 2026
64b5614
fix(strands): store-tool naming, search budget, tenant-scoped writes,…
Andy2003 Aug 20, 2026
55b5254
fix(strands): drop unneeded cast, clarify tool typing, simplify sink …
Andy2003 Aug 20, 2026
fda9d2b
test(strands): drive NAMS-mode unit tests through the real NAMS classes
Andy2003 Aug 20, 2026
537903b
fix(strands): narrow the NAMS long-term layer with isinstance, not a …
Andy2003 Aug 20, 2026
808f609
fix(nams): correct stale metadata docstring; add key-gated sink-reuse…
Andy2003 Aug 20, 2026
6dd782b
test(strands): drive a real Agent against live NAMS on the synchronou…
Andy2003 Aug 20, 2026
34b8c4e
test(nams): gate live-NAMS tests on a throwaway workspace; stop resol…
Andy2003 Aug 20, 2026
6bbd911
docs: changelog entry for build_nams_settings workspace_id
Andy2003 Aug 20, 2026
7ddadba
test(strands): drop the hardware-specific live-NAMS e2e test
Andy2003 Aug 20, 2026
af4d456
fix(py/strands): address PR review findings
Andy2003 Aug 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,13 @@ jobs:
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

# The `strands` extra is needed for the Strands integration's unit tests:
# tests/unit/integrations/test_strands_*.py all begin with
# `pytest.importorskip("strands")`, so without it they silently skip and
# this job reports green on code it never ran. Kept to that one extra --
# the rest of the suite is designed to run on the dev group alone.
- name: Install dependencies
run: uv sync --group dev
run: uv sync --group dev --extra strands

- name: Run unit tests
run: uv run pytest tests/unit -v --cov=neo4j_agent_memory --cov-report=xml --cov-report=term-missing
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **Strands MemoryStore** (`Neo4jMemoryStore`) — cross-session recall for Strands
agents via `MemoryManager(stores=[...])`: long-term search, plus writes that feed
server-side extraction. Entities only on NAMS. Needs `strands-agents>=1.44.0`.
`get_tools()` adds `{name}_get_entity_graph` (multi-hop bolt, 1-hop NAMS) and, bolt-only with a configured user_id, the user-scoped `{name}_get_user_preferences`.
A store built from `settings=` owns its client and rebinds it when the event
loop changes (Strands' synchronous `Agent(...)` runs every call on a fresh
loop); a client passed as `client=` is never closed or reconnected, and a
loop change raises a named error instead of an opaque driver `RuntimeError`.
With a `user_id` set, preference recall is scoped to that user in both the
store and `Neo4jSessionManager` injection (`search_preferences` applies no
user filter, so an unscoped call could surface another tenant's
preferences).
Tool names are prefixed with the store's `name` so they coexist with
`context_graph_tools`' identically-named tools rather than silently
replacing them in the agent's registry, and `max_search_results` caps the
*total* rows per `search()` — shared across entities, preferences and facts
so no kind is crowded out.
- **Strands SessionManager** (`Neo4jSessionManager`) — automatic conversation
persistence/restore for AWS Strands agents via `Agent(session_manager=...)`,
backed by any `MemoryClient` (bolt or NAMS). Includes opt-in long-term
Expand Down Expand Up @@ -50,8 +67,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
they raised `AttributeError`). This lets `client.short_term` / `client.long_term`
type-check without per-call-site `attr-defined` suppressions.

### Fixed

- **`add_messages_batch` now accepts `user_identifier`**, enforcing `multi_tenant`
and linking the conversation to its `:User`; previously the bulk path silently
wrote unscoped, unlinked conversations — so a bulk write that used to succeed
now raises `ValueError` when `multi_tenant=True` and `user_identifier` is omitted.

### Changed

- `strands` extra requires `strands-agents>=1.44.0` (was `>=0.1.0`).
- **`Neo4jSessionManager` now guards against a paired `Neo4jMemoryStore` duplicating its work**: raises if both would extract the same turns (always, on NAMS), warns once if both would inject context.
- `ShortTermProtocol.bulk_add_messages` takes explicit keyword-only params
(`generate_embeddings`, `extract_entities`, `extract_relations`, `user_identifier`)
instead of `**kwargs`.
- **`MemoryClient` is now generic over its backend memory types**
(`MemoryClient[ST, LT, RT]`, PEP 696 defaults). `client.short_term` /
`.long_term` / `.reasoning` return the base `ShortTermProtocol` /
Expand Down
Loading
Loading