feat: add local memory store - #2859
opieter-aws merged 2 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
6fd41fe to
5a5f6ee
Compare
|
Issue: This introduces a new public class ( A couple of API-design points worth an explicit reviewer decision while you're at it:
Suggestion: Add |
|
Assessment: Comment A polished, well-documented addition that genuinely lowers the barrier to trying memory — zero-infra, cross-SDK parity, and the design rationale in the description is excellent. The main action item is process (API-review label), not code; the inline notes are minor. Review Categories
Nice work — the single-class-with- |
5a5f6ee to
69aba8a
Compare
|
Re-review of commit
Updated assessment unchanged: Comment — the code is in good shape; the remaining action is process, not code. |
69aba8a to
adaf59a
Compare
|
Re-review of commit
Assessment: Approve (code-wise) — no remaining code-level action items. The only thing left is the API reviewer's actual approval, which the label now correctly routes. Nicely done. |
notowen333
left a comment
There was a problem hiding this comment.
Just commenting on TS
adaf59a to
83cc2f3
Compare
|
Re-review of commit @notowen333 has raised some good design-discussion questions on the TS file — those are the author's to work through, so I won't pile on. Two quick context notes that may help that conversation, since the rationale is already implicit in the code:
No new action items from me — assessment stays Approve (code-wise), pending the human API + design discussion. |
|
Re-review of commit
One light, non-blocking suggestion on the new docs: the memory Assessment: Approve (code-wise) — no code-level action items. Remaining items are the human API-review sign-off and the optional docs nicety above. |
Both surfaced on the Python 3.14 linux job after a sequence of merges today: 1. test_format_request_maps_3gp_video_formats (from strands-agents#2306) called a non-existent _format_request; the public method is format_request. 2. test_ingests_extracted_facts_through_add (from strands-agents#2859) called the async MemoryManager.init_agent without awaiting it, so the extractor was never wired up and assert_called_once failed.
Description
The memory feature ships only one concrete
MemoryStore:BedrockKnowledgeBaseStore, which requires an AWS account, a provisioned Knowledge Base, and a data source. That gates the first experience of memory behind cloud setup — a developer can't tryMemoryManager,search_memory/add_memory, context injection, or extraction without standing up infrastructure first.This adds
LocalMemoryStore, a zero-infrastructureMemoryStoreshipped in both SDKs. It persists to disk by default (~/.strands/memory/<name>.json), so an agent remembers across restarts with no setup, and can be made ephemeral for tests and throwaway runs.MemoryManageris backend-agnostic — it talks to stores only through theMemoryStoreinterface — so this is purely additive: drop the store intostores: [...]and everything (tools, injection, client-side extraction) works unchanged.A few design decisions worth calling out for review:
addalso flushes to disk. Rather than two classes, persistence is a single internal seam (persistflag → load-on-init + atomic flush). One construct to learn, one copy of the search code.BedrockKnowledgeBaseStore. Not added to the top-level barrel.The store reads the whole file into memory and rewrites it atomically on each
add, so it suits prototyping and personal memory (hundreds to low thousands of entries), not a production corpus — documented on the class. Writes within a process are serialized so concurrentadds can't clobber one another; cross-process writers are not coordinated.Public API Changes
A new
LocalMemoryStore, exported from a subpath in each SDK alongside the existing Bedrock store.TypeScript (
@strands-agents/sdk/vended-memory-stores/local):Python (
strands.vended_memory_stores.local):LocalMemoryStoredefaultswritable=true(the point is a store you can write to) and implementssearch+add. With anextractionconfig it uses the manager's client-side path (model extractor →addper fact); it does not implementaddMessages. Constructor config:name(required),description,maxSearchResults/max_search_results,writable,extraction,persist(defaulttrue),path.Related Issues
Documentation PR
team/designs/0011-memory-manager.mdstill sketches this store under the nameInMemoryMemoryStore, imported from the top-level barrel. The shipped store isLocalMemoryStore(persists by default, so "InMemory" would mislead) exported via subpath (matchingBedrockKnowledgeBaseStore). The design doc and any how-to/example docs should be reconciled in a follow-up; nosite/docs are included here.Type of Change
New feature
Testing
Unit suites added in both SDKs covering: persistence round-trip across a fresh instance ("survives restart"), ephemeral mode (no file written, a new instance forgets), lexical ranking + recency tiebreak, empty/token-less query, empty/non-writable
adderrors, content dedup,maxSearchResultscap +<1validation, and corrupt/missing-file handling. Each SDK also has MemoryManager integration tests asserting the manager stampsstoreName, theaddAPI writes through, and a client-side extraction run persists the extracted fact.Beyond the automated suites, I exercised the store end-to-end in both SDKs across two separate processes: one writes a fact, a second (fresh process) recalls it from the on-disk JSON — confirming the across-restart behavior, not just in-process mocks. I also confirmed the new subpath export specifier resolves and the TS browser bundle still builds (the store's
node:*imports are dynamic).hatch run prepareChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.