From 16da766fde38825ac67ea4f11336880eaae650ac Mon Sep 17 00:00:00 2001 From: nexxeln <95541290+nexxeln@users.noreply.github.com> Date: Tue, 3 Feb 2026 01:00:59 +0000 Subject: [PATCH] langgraph integration (#719) --- apps/docs/docs.json | 1 + apps/docs/images/langgraph.svg | 1 + apps/docs/integrations/langgraph.mdx | 426 +++++++++++++++++++++++++++ 3 files changed, 428 insertions(+) create mode 100644 apps/docs/images/langgraph.svg create mode 100644 apps/docs/integrations/langgraph.mdx diff --git a/apps/docs/docs.json b/apps/docs/docs.json index a6546bfd..4f171147 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -153,6 +153,7 @@ "integrations/supermemory-sdk", "integrations/ai-sdk", "integrations/openai", + "integrations/langgraph", "integrations/openai-agents-sdk", "integrations/mastra", "integrations/langchain", diff --git a/apps/docs/images/langgraph.svg b/apps/docs/images/langgraph.svg new file mode 100644 index 00000000..fd740400 --- /dev/null +++ b/apps/docs/images/langgraph.svg @@ -0,0 +1 @@ +LangGraph \ No newline at end of file diff --git a/apps/docs/integrations/langgraph.mdx b/apps/docs/integrations/langgraph.mdx new file mode 100644 index 00000000..e67cdaec --- /dev/null +++ b/apps/docs/integrations/langgraph.mdx @@ -0,0 +1,426 @@ +--- +title: "LangGraph" +sidebarTitle: "LangGraph" +description: "Add persistent memory to LangGraph agents with Supermemory" +icon: "/images/langgraph.svg" +--- + +Build stateful agents with LangGraph that remember context across sessions. Supermemory handles memory storage and retrieval while LangGraph manages your graph-based conversation flow. + +## Overview + +This guide shows how to integrate Supermemory with LangGraph to create agents that: + +- Maintain user context through automatic profiling +- Store and retrieve relevant memories at each node +- Use conditional logic to decide what's worth remembering +- Combine short-term (session) and long-term (cross-session) memory + +## Setup + +Install the required packages: + +```bash +pip install langgraph langchain-openai supermemory python-dotenv +``` + +Configure your environment: + +```bash +# .env +SUPERMEMORY_API_KEY=your-supermemory-api-key +OPENAI_API_KEY=your-openai-api-key +``` + +Get your Supermemory API key from [console.supermemory.ai](https://console.supermemory.ai). + +## Basic integration + +A minimal agent that fetches user context before responding and stores the conversation after: + +```python +from typing import Annotated, TypedDict +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langchain_openai import ChatOpenAI +from langchain_core.messages import SystemMessage, HumanMessage +from supermemory import Supermemory +from dotenv import load_dotenv + +load_dotenv() + +llm = ChatOpenAI(model="gpt-4o") +memory = Supermemory() + +class State(TypedDict): + messages: Annotated[list, add_messages] + user_id: str + +def agent(state: State): + user_id = state["user_id"] + messages = state["messages"] + user_query = messages[-1].content + + # Fetch user profile with relevant memories + profile_result = memory.profile(container_tag=user_id, q=user_query) + + # Build context from profile + static_facts = profile_result.profile.static or [] + dynamic_context = profile_result.profile.dynamic or [] + search_results = profile_result.search_results.results if profile_result.search_results else [] + + context = f""" +User Background: +{chr(10).join(static_facts) if static_facts else 'No profile yet.'} + +Recent Context: +{chr(10).join(dynamic_context) if dynamic_context else 'No recent activity.'} + +Relevant Memories: +{chr(10).join([r.memory or r.chunk for r in search_results]) if search_results else 'None found.'} +""" + + system = SystemMessage(content=f"You are a helpful assistant.\n\n{context}") + response = llm.invoke([system] + messages) + + # Store the interaction + memory.add( + content=f"User: {user_query}\nAssistant: {response.content}", + container_tag=user_id + ) + + return {"messages": [response]} + +# Build the graph +graph = StateGraph(State) +graph.add_node("agent", agent) +graph.add_edge(START, "agent") +graph.add_edge("agent", END) +app = graph.compile() + +# Run it +result = app.invoke({ + "messages": [HumanMessage(content="Hi! I'm working on a Python project.")], + "user_id": "user_123" +}) +print(result["messages"][-1].content) +``` + +--- + +## Core concepts + +### User profiles + +Supermemory automatically builds user profiles from stored memories: + +- **Static facts**: Long-term information (preferences, expertise, background) +- **Dynamic context**: Recent activity and current focus + +```python +result = memory.profile( + container_tag="user_123", + q="optional search query" # Also returns relevant memories +) + +print(result.profile.static) # ["User is a Python developer", "Prefers functional style"] +print(result.profile.dynamic) # ["Working on async patterns", "Debugging rate limiting"] +``` + +### Memory storage + +Content you add gets processed into searchable memories: + +```python +# Store a conversation +memory.add( + content="User asked about graph traversal. Explained BFS vs DFS.", + container_tag="user_123", + metadata={"topic": "algorithms", "type": "conversation"} +) + +# Store a document +memory.add( + content="https://langchain-ai.github.io/langgraph/", + container_tag="user_123" +) +``` + +### Memory search + +Search returns both extracted memories and document chunks: + +```python +results = memory.search.memories( + q="graph algorithms", + container_tag="user_123", + search_mode="hybrid", + limit=5 +) + +for r in results.results: + print(r.memory or r.chunk, r.similarity) +``` + +--- + +## Complete example: support agent + +A support agent that learns from past tickets and adapts to each user's technical level: + +```python +from typing import Annotated, TypedDict, Optional +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langgraph.checkpoint.memory import MemorySaver +from langchain_openai import ChatOpenAI +from langchain_core.messages import SystemMessage, HumanMessage +from supermemory import Supermemory +from dotenv import load_dotenv + +load_dotenv() + +class SupportAgent: + def __init__(self): + self.llm = ChatOpenAI(model="gpt-4o", temperature=0.3) + self.memory = Supermemory() + self.app = self._build_graph() + + def _build_graph(self): + class State(TypedDict): + messages: Annotated[list, add_messages] + user_id: str + context: str + category: Optional[str] + + def retrieve_context(state: State): + """Fetch user profile and relevant past tickets.""" + user_id = state["user_id"] + query = state["messages"][-1].content + + result = self.memory.profile( + container_tag=user_id, + q=query, + threshold=0.5 + ) + + static = result.profile.static or [] + dynamic = result.profile.dynamic or [] + memories = result.search_results.results if result.search_results else [] + + context = f""" +## User Profile +{chr(10).join(f"- {fact}" for fact in static) if static else "New user, no history."} + +## Current Context +{chr(10).join(f"- {ctx}" for ctx in dynamic) if dynamic else "No recent activity."} + +## Related Past Tickets +{chr(10).join(f"- {m.memory}" for m in memories[:3]) if memories else "No similar issues found."} +""" + return {"context": context} + + def categorize(state: State): + """Determine ticket category for routing.""" + query = state["messages"][-1].content.lower() + + if any(word in query for word in ["billing", "payment", "charge", "invoice"]): + return {"category": "billing"} + elif any(word in query for word in ["bug", "error", "broken", "crash"]): + return {"category": "technical"} + else: + return {"category": "general"} + + def respond(state: State): + """Generate a response using context.""" + category = state.get("category", "general") + context = state.get("context", "") + + system_prompt = f"""You are a support agent. Category: {category} + +{context} + +Guidelines: +- Match explanation depth to the user's technical level +- Reference past interactions when relevant +- Be direct and helpful""" + + system = SystemMessage(content=system_prompt) + response = self.llm.invoke([system] + state["messages"]) + + return {"messages": [response]} + + def store_interaction(state: State): + """Save the ticket for future context.""" + user_msg = state["messages"][-2].content + ai_msg = state["messages"][-1].content + category = state.get("category", "general") + + self.memory.add( + content=f"Support ticket ({category}): {user_msg}\nResolution: {ai_msg[:300]}", + container_tag=state["user_id"], + metadata={"type": "support_ticket", "category": category} + ) + + return {} + + # Build the graph + graph = StateGraph(State) + graph.add_node("retrieve", retrieve_context) + graph.add_node("categorize", categorize) + graph.add_node("respond", respond) + graph.add_node("store", store_interaction) + + graph.add_edge(START, "retrieve") + graph.add_edge("retrieve", "categorize") + graph.add_edge("categorize", "respond") + graph.add_edge("respond", "store") + graph.add_edge("store", END) + + checkpointer = MemorySaver() + return graph.compile(checkpointer=checkpointer) + + def handle(self, user_id: str, message: str, thread_id: str) -> str: + """Process a support request.""" + config = {"configurable": {"thread_id": thread_id}} + + result = self.app.invoke( + {"messages": [HumanMessage(content=message)], "user_id": user_id}, + config=config + ) + + return result["messages"][-1].content + + +# Usage +if __name__ == "__main__": + agent = SupportAgent() + + # First interaction + response = agent.handle( + user_id="customer_alice", + message="The API is returning 429 errors when I make requests", + thread_id="ticket_001" + ) + print(response) + + # Follow-up (agent remembers context) + response = agent.handle( + user_id="customer_alice", + message="I'm only making 10 requests per minute though", + thread_id="ticket_001" + ) + print(response) +``` + +--- + +## Advanced patterns + +### Conditional memory storage + +Not everything is worth remembering. Use conditional edges to filter: + +```python +def should_store(state: State) -> str: + """Skip storing trivial messages.""" + last_msg = state["messages"][-1].content.lower() + + skip_phrases = ["thanks", "ok", "got it", "bye"] + if len(last_msg) < 20 or any(p in last_msg for p in skip_phrases): + return "skip" + return "store" + +graph.add_conditional_edges("respond", should_store, { + "store": "store", + "skip": END +}) +``` + +### Parallel memory operations + +Fetch memories and categorize at the same time: + +```python +from langgraph.graph import StateGraph, START, END + +graph = StateGraph(State) +graph.add_node("retrieve", retrieve_context) +graph.add_node("categorize", categorize) +graph.add_node("respond", respond) + +# Both run in parallel after START +graph.add_edge(START, "retrieve") +graph.add_edge(START, "categorize") + +# Both must complete before respond +graph.add_edge("retrieve", "respond") +graph.add_edge("categorize", "respond") +graph.add_edge("respond", END) +``` + +### Metadata filtering + +Organize memories by project, topic, or any custom field: + +```python +# Store with metadata +memory.add( + content="User prefers detailed error messages with stack traces", + container_tag="user_123", + metadata={ + "type": "preference", + "project": "api-v2", + "priority": "high" + } +) + +# Search with filters +results = memory.search.memories( + q="error handling preferences", + container_tag="user_123", + filters={ + "AND": [ + {"key": "type", "value": "preference"}, + {"key": "project", "value": "api-v2"} + ] + } +) +``` + +### Combining session and long-term memory + +LangGraph's checkpointer handles within-session state. Supermemory handles cross-session memory. Use both: + +```python +from langgraph.checkpoint.memory import MemorySaver + +# Session memory (cleared when thread ends) +checkpointer = MemorySaver() +app = graph.compile(checkpointer=checkpointer) + +# Long-term memory (persists across sessions) +# Handled by Supermemory in your nodes +``` + +--- + +## Next steps + + + + Deep dive into automatic user profiling + + + + Advanced search patterns and filtering + + + + Native OpenAI integration with memory tools + + + + Memory middleware for Next.js apps + +