Add LangGraph + Memanto cross-session memory example with MemantoStore(BaseStore)#571
Conversation
Line-based KIND::CONTENT extraction, multi-anchor namespace search, 30s result cache with last-good fallback, and max_tokens plumbing make the demo work end-to-end on free OpenRouter models within Memanto Community plan rate limits.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdds a complete LangGraph customer-support agent example using Memanto for long-term cross-thread memory, with a MemantoStore adapter, MemantoSetup helper, Streamlit UI, CLI demos, requirements, and full README documentation. ChangesLangGraph + Memanto Integration Example
Sequence Diagram(s)sequenceDiagram
participant User
participant LangGraph as LangGraph Graph
participant Memanto as Memanto SdkClient
participant LLM as OpenRouter LLM
User->>LangGraph: send HumanMessage (thread_id, user_id)
LangGraph->>Memanto: asearch namespace tags (recall_context)
Memanto-->>LangGraph: recalled memories (system injection)
LangGraph->>LLM: respond node (conversation + system)
LLM-->>LangGraph: assistant reply
LangGraph->>LLM: extractor prompt (extract_and_store)
LLM-->>LangGraph: extracted KIND::CONTENT lines
LangGraph->>Memanto: aput remembered memories (remember)
Memanto-->>LangGraph: ack
LangGraph-->>User: assistant reply returned
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/langgraph-memanto/app.py`:
- Around line 274-276: The call to st.progress uses conf directly and can crash
if Memanto returns malformed or out-of-range values; before calling st.progress
(the block that checks "if conf is not None" and calls st.progress(float(conf),
text=...)), validate and sanitize conf: attempt to coerce to float inside a
try/except, on failure skip or set a safe default (e.g., 0.0), then clamp the
numeric value to the [0.0, 1.0] range (min(max(value, 0.0), 1.0)) and use that
clamped value in st.progress and the formatted text to avoid exceptions and
out-of-range progress values.
- Around line 168-171: The current suffix generation uses second-level
timestamps which can collide; replace the suffix logic so reset namespaces are
collision-resistant (e.g., set suffix = ts or a UUID4 hex or a high-precision
timestamp+UUID) and update st.session_state.user_id, st.session_state.s1_thread,
and st.session_state.s2_thread to use that new suffix (refer to the existing
suffix variable and the three session_state assignments to locate where to
change it).
In `@examples/langgraph-memanto/graph.py`:
- Around line 311-315: The current _user_id_from_config function silently
returns "anonymous" when config or configurable.user_id is missing; change it to
fail fast by validating that config is provided and that
config["configurable"]["user_id"] exists and is non-empty, and if not raise a
clear exception (e.g., ValueError) rather than returning "anonymous"; update all
callers of _user_id_from_config to handle the exception or validate earlier as
needed so unrelated users are not merged into a single namespace.
- Around line 154-158: In _parse_memories_response, avoid logging raw extracted
content at info level; change the logger call so that only metadata (e.g.,
length) is logged at info and move the raw or potentially sensitive text to
logger.debug (or redact it) — reference the logger usage in
_parse_memories_response and replace the logger.info call that prints text with
an info-level message containing only the length/metadata and a debug-level
message that emits the truncated text when debug is enabled (or redact the text
entirely).
In `@examples/langgraph-memanto/memanto_store.py`:
- Around line 399-404: The sample_limit calculation can exceed the store/server
cap (_MEMANTO_RECALL_CAP) causing failures; change the logic in the block that
computes sample_limit (currently using op.limit and constant 200) to bound it by
_MEMANTO_RECALL_CAP before calling self._client.recall (i.e., compute requested
= op.limit or default, then set sample_limit = min(requested,
_MEMANTO_RECALL_CAP, 200) or similar so the call to self._client.recall never
requests more than _MEMANTO_RECALL_CAP).
- Around line 296-297: The cache key built for search results (constructed as
cache_key and used with self._search_cache.get) only includes
op.namespace_prefix, query, op.limit and tuple(extra_tags) and therefore ignores
active filters like op.type and op.min_confidence (and any other filter fields
on op), causing stale/wrong cache hits; update the cache key construction to
include all active filter fields (e.g., op.type, op.min_confidence and any other
op.<filter> attributes or a normalized representation of op.filters) so the key
uniquely represents the full search request before calling
self._search_cache.get.
- Around line 154-159: The recall call in result = self._client.recall(...) can
miss the keyed item because limit=10 may return many namespace matches before
the specific key is included; update the logic in the GetOp path (referencing
self._client.recall, op.key, ns_tags, key_tag, and result) to ensure the keyed
item is not dropped: either remove/raise the limit (e.g. a much larger limit or
unlimited if supported) or implement pagination (loop calling
self._client.recall with offset/page tokens until you either find the item
matching key_tag or exhaust results), then apply the existing post-filtering
against key_tag/ns_tags on the aggregated results. Ensure the change preserves
existing tag usage and stops once the keyed item is found to avoid unbounded
retrieval.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a4c09698-870c-4bf2-994e-8c0823d7ad89
⛔ Files ignored due to path filters (1)
examples/langgraph-memanto/langgraph-architecture-diagram.pngis excluded by!**/*.png
📒 Files selected for processing (13)
examples/langgraph-memanto/.env.exampleexamples/langgraph-memanto/.gitignoreexamples/langgraph-memanto/README.mdexamples/langgraph-memanto/app.pyexamples/langgraph-memanto/graph.pyexamples/langgraph-memanto/memanto_setup.pyexamples/langgraph-memanto/memanto_store.pyexamples/langgraph-memanto/requirements.txtexamples/langgraph-memanto/run_contradiction.pyexamples/langgraph-memanto/run_full_demo.pyexamples/langgraph-memanto/run_session_1.pyexamples/langgraph-memanto/run_session_2.pyexamples/langgraph-memanto/state.py
✅ Actions performedReview triggered.
|
|
Hi @mjfekri @Xenogents, Can I get review on this? |
|
Hi @mjfekri @Xenogents, Can I get review on this? |
|
Hi Suraj, thanks again for your effort on the PR! There’s a lot to unpack here but I might be able to do a full review tomorrow. The bounties closing tomorrow though so anything I list out might just be for recordkeeping. |
|
Thanks @Xenogents, also could you check the X thread and questions people asking, i have replied them as per my understanding. cc: @mjfekri |
|
Ok I've given a look through the repo, mainly just the memantostore file. I can see there's been a lot of difficulties trying to implement all the abstract methods properly. _do_get: There is the whole issue with or matching on tags but an even bigger issue is that Moorcheh only does key filtering after semantic search, and results initially gotten through semantic search are subject to the recall limit, so the key value matching is going to be very weak. _do_put: Very recently (probably while you were working on this) we've introduced a memory type auto-parser based off of regex keyword matching and fuzzy logic, instead of defaulting to fact this can be the new default. There might be some similar logic for confidence level (will have to check). Resolving deletes to conflict resolution is a good idea and we indeed don't support delete options at the moment. _do_search: I get why the semantic anchors were introduced, but I feel its too much of a bandaid solution and introduces too much overhead. The caching and anchors are good for the demo but more than just showing demos we want to have this as the actual installable langgraph integration and don't want users to have to go into their build files to mess around with the anchoring. There's also a function for recalling most recent memories without performing semantic search called recall recent, though I'm not sure the exact differences between that and searching recall with a * query which I'll have to check later. Regarding solutions, I think it's at least better to go through the tedious agent swapping to gain access to multiple namespaces. That would make key value pair matching easier, remove the need for semantic anchoring, and resolve the list namespaces issue. Though it's still not a super ideal solution so I'll be discussing it with the team. The caching is unnecessary for the actual integration (I think) but we do still want to have the examples at hand so we could just leave it there as I don't think it changes functionality, will also discuss with the team. The auto-parser is more of a low priority thing so that can be dealt with later. We're probably wrapping up the bounty today so I'm not sure if you'll still be able to work on the PR afterwards though. |
Sure, could you please allow me time I'll do this by tonight! |
Also have you looked at this? |
|
I have, I don't really know the answer to their question so I'll ask Majid next opportunity I get. |
|
Regarding the actual bounty, congratulations on winning again! We didn't find any other submission put quite as much effort and thought into this as you did, only 1 other PR even attempted a Basestore integration but because they didn't provide any examples or demos I couldn't give them credit for it. I think I can actually leave this PR open for you to continue working on it so no need to rush too hard. So once again we very much appreciate your contributions towards Memanto and thanks for your hard work! |
|
Hello @Xenogents, why these merge conflicts? Could you please help me here, I should keep the current my changes right? |
|
Yeah don't worry about the conflicts, the plan was to merge multiple PR's so we could use their examples but all of their changes are into the same folder so I have to do some shenanigans and move things around. Your changes are fine and I can resolve the conflicts later. |
…tegration Feat/langgraph integration
UI/add connection
feat: add memory history in ui with timeline
|
Hi Suraj, just checking how your changes are going, if you're busy you can leave your work as is and I can apply my own suggestions. You already won the bounty so it's no problem. |
Hi @Xenogents, sorry for the delay. I got into something. I'll push the changes tonight! |
|
Hi @Xenogents, I've removed the anchor fan-out from Are we good with merging the PR? Or, Let me know if anything else needs adjusting! |
|
Yep! You're all good. |
d980108
into
moorcheh-ai:feat/langgraph-integration
Summary
Closes #397
A LangGraph customer-support agent that uses Memanto as a real
langgraph.store.base.BaseStoresubclass, demonstrating cross-thread, cross-session, cross-process memory recall. Includes a Streamlit UI, three CLI demo scripts, and a contradiction-resolution bonus.This iteration adds the robustness fixes that make extraction and recall actually reliable on free-tier OpenRouter models with a shared-quota Memanto Community plan.
What's in the PR
MemantoStore(BaseStore)— the integration point. Drop-in replacement forInMemoryStore/PostgresStore/RedisStore. Nodes use*, store: BaseStoreinjection, zero Memanto-specific code inside node bodies.START → recall_context → respond → extract_and_store → END, compiled with bothInMemorySaver(short-term thread state) andMemantoStore(long-term cross-thread memory).KIND::CONTENTline-based extraction — replaceswith_structured_outputwhich was unreliable on free OpenRouter models; one bad line costs at most one memory instead of the whole extraction._do_searchfans out across four diverse semantic anchors and unions the strictly namespace-filtered results.thread_id), live memory panel, "Reset demo" to rotate the user namespace.run_session_1.py,run_session_2.py,run_full_demo.py,run_contradiction.py.Architecture
Demo
langgraph-memanto-demo.mp4
Test plan
pip install -r examples/langgraph-memanto/requirements.txt.env.exampleto.env, fill inMOORCHEH_API_KEYandOPENROUTER_API_KEYstreamlit run app.py→ click Reset demo → send Bob's intro in Session 1 → confirm 4-5 memories appear in the panelpython run_session_1.py && python run_session_2.py→ confirm cross-process recall works from the CLIpython run_contradiction.py→ confirm conflict-detection note surfacesSocial Media Posts:
X: https://x.com/surajk_umar01/status/2059628516694790260
Reddit: https://www.reddit.com/user/Basic_Pie_1537/comments/1tojp3x/i_gave_my_langgraph_agent_permanent_crosssession/
Summary by CodeRabbit
Release Notes
New Features
Documentation