Skip to content

Add LangGraph + Memanto cross-session memory example with MemantoStore(BaseStore)#571

Merged
Xenogents merged 23 commits into
moorcheh-ai:feat/langgraph-integrationfrom
Suraj-kumar00:add/langgraph
Jun 8, 2026
Merged

Add LangGraph + Memanto cross-session memory example with MemantoStore(BaseStore)#571
Xenogents merged 23 commits into
moorcheh-ai:feat/langgraph-integrationfrom
Suraj-kumar00:add/langgraph

Conversation

@Suraj-kumar00

@Suraj-kumar00 Suraj-kumar00 commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #397

A LangGraph customer-support agent that uses Memanto as a real langgraph.store.base.BaseStore subclass, 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 for InMemoryStore / PostgresStore / RedisStore. Nodes use *, store: BaseStore injection, zero Memanto-specific code inside node bodies.
  • Customer-support graphSTART → recall_context → respond → extract_and_store → END, compiled with both InMemorySaver (short-term thread state) and MemantoStore (long-term cross-thread memory).
  • KIND::CONTENT line-based extraction — replaces with_structured_output which was unreliable on free OpenRouter models; one bad line costs at most one memory instead of the whole extraction.
  • Multi-anchor namespace listing — Memanto's recall is semantic top-100, so single queries can rank a user's own memories out of the result set when the agent has many cross-namespace memories. _do_search fans out across four diverse semantic anchors and unions the strictly namespace-filtered results.
  • 30-second result cache + last-good fallback — cuts recall calls per chat turn from ~50 to ~6, and keeps the UI panel populated during transient rate-limit / auth windows instead of flashing to zero.
  • Streamlit UI — two tabs (Session 1 stores preferences, Session 2 opens a fresh thread_id), live memory panel, "Reset demo" to rotate the user namespace.
  • CLI scriptsrun_session_1.py, run_session_2.py, run_full_demo.py, run_contradiction.py.

Architecture

image

Demo

langgraph-memanto-demo.mp4

Test plan

  • pip install -r examples/langgraph-memanto/requirements.txt
  • Copy .env.example to .env, fill in MOORCHEH_API_KEY and OPENROUTER_API_KEY
  • streamlit run app.py → click Reset demo → send Bob's intro in Session 1 → confirm 4-5 memories appear in the panel
  • Switch to Session 2 → ask the snack question → confirm the agent recommends peanut-free options
  • python run_session_1.py && python run_session_2.py → confirm cross-process recall works from the CLI
  • python run_contradiction.py → confirm conflict-detection note surfaces

Social 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

    • Added a new customer-support agent example demonstrating cross-session memory persistence with Memanto integration for LangGraph, enabling agents to recall user information across separate conversations.
  • Documentation

    • Included comprehensive setup documentation, configuration templates, and multiple runnable demo scripts showcasing memory recall, conflict resolution, and long-term customer context retention.

Review Change Stack

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.
@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 877cb3eb-7597-4b87-a41c-90f7dcaa2e00

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds 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.

Changes

LangGraph + Memanto Integration Example

Layer / File(s) Summary
Project infrastructure and configuration
examples/langgraph-memanto/.env.example, .gitignore, requirements.txt, README.md
Environment template, gitignore rules, runtime dependencies, and full documentation covering architecture, setup, store integration, limitations, and troubleshooting.
Graph state definition
examples/langgraph-memanto/state.py
SupportState TypedDict with messages field configured for LangGraph's add_messages accumulation; user_id and thread_id flow via config, not state.
Memanto agent lifecycle helper
examples/langgraph-memanto/memanto_setup.py
MemantoSetup provides idempotent agent creation, session activation (returns SdkClient), and teardown with tolerant error logging.
MemantoStore bridge implementation
examples/langgraph-memanto/memanto_store.py
BaseStore adapter implementing GetOp (tag-filtered recall), PutOp (normalized memory persist with cache invalidation), SearchOp (namespace-aware semantic fan-out with caching and rate-limit fallback), and ListNamespacesOp (best-effort namespace discovery); includes tag encoding/decoding, value stringification, and Memanto↔LangGraph conversion helpers.
LangGraph graph construction
examples/langgraph-memanto/graph.py
Defines ExtractedMemory Pydantic models, robust extractor parsing (KIND::CONTENT with JSON fallback), OpenRouter-backed LLM construction, and a three-node graph (recall_context → respond → extract_and_store) wired with RetryPolicy and InMemorySaver.
Interactive Streamlit UI
examples/langgraph-memanto/app.py
Streamlit app with cached graph/store, session-state namespace generation, memory panel fetching and rendering, two-tab chat (Session 1 stores memories, Session 2 relies on cross-session recall), async graph invocation with timeouts, and memory-index polling before UI refresh.
CLI demonstration scripts
examples/langgraph-memanto/run_session_1.py, run_session_2.py, run_full_demo.py, run_contradiction.py
Four executable examples: run_session_1 stores user preferences, run_session_2 uses fresh thread and validates cross-session recall, run_full_demo chains both with verdict, run_contradiction demonstrates conflict detection via daily summary and resolution workflow.

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
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • het0814

Poem

🐰 A rabbit scribbles on a tree,

"I store your facts for you and me,"
LangGraph chats, Memanto keeps score,
Memories hop back through the door.
Two sessions, one bright shared core.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main addition: a LangGraph + Memanto cross-session memory example with MemantoStore implementing BaseStore.
Linked Issues check ✅ Passed PR successfully implements all technical criteria from issue #397: demonstrates cross-session recall via MemantoStore (BaseStore subclass), provides clean documented code in examples/langgraph-memanto folder, and includes comprehensive README with setup/demo details.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue #397: the new MemantoStore implementation, customer-support graph, CLI scripts, and Streamlit UI are all required components for demonstrating Memanto-LangGraph integration.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5053ec2 and 323f219.

⛔ Files ignored due to path filters (1)
  • examples/langgraph-memanto/langgraph-architecture-diagram.png is excluded by !**/*.png
📒 Files selected for processing (13)
  • examples/langgraph-memanto/.env.example
  • examples/langgraph-memanto/.gitignore
  • examples/langgraph-memanto/README.md
  • examples/langgraph-memanto/app.py
  • examples/langgraph-memanto/graph.py
  • examples/langgraph-memanto/memanto_setup.py
  • examples/langgraph-memanto/memanto_store.py
  • examples/langgraph-memanto/requirements.txt
  • examples/langgraph-memanto/run_contradiction.py
  • examples/langgraph-memanto/run_full_demo.py
  • examples/langgraph-memanto/run_session_1.py
  • examples/langgraph-memanto/run_session_2.py
  • examples/langgraph-memanto/state.py

Comment thread examples/langgraph-memanto/app.py Outdated
Comment thread examples/langgraph-memanto/app.py
Comment thread examples/langgraph-memanto/graph.py
Comment thread examples/langgraph-memanto/graph.py
Comment thread examples/langgraph-memanto/memanto_store.py Outdated
Comment thread examples/langgraph-memanto/memanto_store.py Outdated
Comment thread examples/langgraph-memanto/memanto_store.py Outdated
@Suraj-kumar00 Suraj-kumar00 changed the title Add/langgraph Add LangGraph + Memanto cross-session memory example with MemantoStore(BaseStore May 26, 2026
@Suraj-kumar00 Suraj-kumar00 changed the title Add LangGraph + Memanto cross-session memory example with MemantoStore(BaseStore Add LangGraph + Memanto cross-session memory example with MemantoStore(BaseStore) May 26, 2026
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

Hi @mjfekri @Xenogents, Can I get review on this?

@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

Hi @mjfekri @Xenogents, Can I get review on this?

@Xenogents

Copy link
Copy Markdown
Collaborator

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.

@Suraj-kumar00

Suraj-kumar00 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @Xenogents, also could you check the X thread and questions people asking, i have replied them as per my understanding.
Please to theme if i have missed anything there.
X thread: https://x.com/i/status/2059628516694790260

cc: @mjfekri

@Xenogents

Xenogents commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

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.

@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

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!
I work in IST timzone, I don't know in which timezone guys work?

@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

Thanks @Xenogents, also could you check the X thread and questions people asking, i have replied them as per my understanding. Please to theme if i have missed anything there. X thread: https://x.com/i/status/2059628516694790260

cc: @mjfekri

Also have you looked at this?

@Xenogents

Copy link
Copy Markdown
Collaborator

I have, I don't really know the answer to their question so I'll ask Majid next opportunity I get.

@Xenogents

Copy link
Copy Markdown
Collaborator

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!

@Xenogents Xenogents changed the base branch from main to feat/langgraph-integration June 2, 2026 16:26
@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

Hello @Xenogents, why these merge conflicts?

Could you please help me here, I should keep the current my changes right?

@Xenogents

Xenogents commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

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.

@Xenogents

Copy link
Copy Markdown
Collaborator

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.

@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

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!

@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

Hi @Xenogents,

I've removed the anchor fan-out from _do_search and switched wildcard queries to use recall_recent. Also updated _do_put to pass None for the type so the auto-parser kicks in instead of defaulting to fact. Skipped agent swapping for now since you mentioned discussing it with the team.

Are we good with merging the PR?

Or, Let me know if anything else needs adjusting!

@Xenogents

Copy link
Copy Markdown
Collaborator

Yep! You're all good.

@Xenogents Xenogents merged commit d980108 into moorcheh-ai:feat/langgraph-integration Jun 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOUNTY $100] 🐜 The Memanto + LangGraph Integration Challenge: Give Your Graph a Permanent Brain

3 participants