--- title: "OpenAI Agents SDK" sidebarTitle: "OpenAI Agents SDK" description: "Add persistent memory to OpenAI agents with Supermemory" icon: "/images/openai.svg" --- OpenAI's Agents SDK gives you a straightforward way to build agents with tools, handoffs, and guardrails. But agents don't remember users between sessions. Supermemory adds that missing piece: your agents can store what they learn and recall it later. ## What you can do - Pull user profiles and relevant memories before an agent runs - Store agent outputs and decisions for future sessions - Give agents tools to search and add memories on their own ## Setup Install the packages: ```bash pip install openai-agents supermemory python-dotenv ``` Set up 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 The simplest approach: fetch user context and pass it in the agent's instructions. ```python import os from agents import Agent, Runner from supermemory import Supermemory from dotenv import load_dotenv load_dotenv() memory = Supermemory() def get_user_context(user_id: str, query: str) -> str: """Fetch profile and relevant memories for a user.""" profile = memory.profile(user_id).profile memories = memory.search(user_id, query=query, limit=5).results static = [m.memory for m in profile.static] dynamic = [m.memory for m in profile.dynamic] return f""" User background: {chr(10).join(static) if static else 'No profile yet.'} Current focus: {chr(10).join(dynamic) if dynamic else 'No recent activity.'} Related memories: {chr(10).join([m.memory or m.chunk for m in memories[:5]]) if memories else 'None.'} """ def create_agent(user_id: str, task: str) -> Agent: """Create an agent with user context in its instructions.""" context = get_user_context(user_id, task) return Agent( name="assistant", instructions=f"""You are a helpful assistant. Here's what you know about this user: {context} Use this to personalize your responses.""", model="gpt-4o" ) async def run_with_memory(user_id: str, message: str) -> str: """Run an agent and store the interaction.""" agent = create_agent(user_id, message) result = await Runner.run(agent, message) # Save for next time memory.add( user_id, content=f"User asked: {message}\nResponse: {result.final_output}", dreaming="instant" ) return result.final_output ``` --- ## Core concepts ### User profiles Supermemory keeps two buckets of user info: - **Static facts**: Stuff that doesn't change much (preferences, job, expertise) - **Dynamic context**: What they're working on right now ```python result = memory.profile("user_123") print([m.memory for m in result.profile.static]) # ["Prefers window seats", "Vegetarian"] print([m.memory for m in result.profile.dynamic]) # ["Planning trip to Japan", "Traveling in March"] ``` ### Storing memories Save agent interactions so future sessions have context: ```python def store_interaction(user_id: str, task: str, result: str): memory.add( user_id, content=f"Task: {task}\nOutcome: {result}", metadata={"type": "agent_run"}, dreaming="instant" ) ``` ### Searching memories Look up past interactions before running an agent: ```python results = memory.search( "user_123", query="previous travel recommendations", search_mode="hybrid", # Searches memories + document chunks limit=5 ) for r in results.results: print(r.memory or r.chunk) ``` --- ## Adding memory tools to agents You can give agents direct access to memory operations. They'll decide when to search or store information. ```python from agents import Agent, Runner, function_tool from supermemory import Supermemory memory = Supermemory() @function_tool def search_memories(query: str, user_id: str) -> str: """Search the user's memories for relevant information. Args: query: What to search for user_id: The user's identifier """ results = memory.search(user_id, query=query, limit=5) if not results.results: return "No relevant memories found." return "\n".join([ r.memory or r.chunk for r in results.results ]) @function_tool def save_memory(content: str, user_id: str) -> str: """Store something important about the user for later. Args: content: The information to remember user_id: The user's identifier """ memory.add(user_id, content=content, dreaming="instant") return f"Saved: {content}" agent = Agent( name="assistant", instructions="""You are a helpful assistant with memory. When users share preferences or important information, save it. When they ask questions, search your memories first.""", tools=[search_memories, save_memory], model="gpt-4o" ) ``` --- ## Example: support agent with memory A support agent that knows who it's talking to. Past tickets, account info, communication preferences - all available without the customer repeating themselves. ```python import os from agents import Agent, Runner, function_tool from supermemory import Supermemory from dotenv import load_dotenv load_dotenv() class SupportAgent: def __init__(self): self.memory = Supermemory() def get_customer_context(self, customer_id: str, issue: str) -> dict: """Pull customer profile and past support interactions.""" profile = self.memory.profile(customer_id).profile memories = self.memory.search(customer_id, query=issue, threshold=0.5).results return { "profile": [m.memory for m in profile.static], "recent": [m.memory for m in profile.dynamic], "history": [m.memory or m.chunk for m in memories[:3]] } def build_instructions(self, context: dict) -> str: """Turn customer context into agent instructions.""" parts = ["You are a customer support agent."] if context["profile"]: parts.append(f"Customer info: {', '.join(context['profile'])}") if context["recent"]: parts.append(f"Recent activity: {', '.join(context['recent'])}") if context["history"]: parts.append(f"Past issues: {'; '.join(context['history'])}") parts.append("Be helpful and reference past interactions when relevant.") return "\n\n".join(parts) @function_tool def escalate_to_human(self, reason: str) -> str: """Escalate the issue to a human agent. Args: reason: Why escalation is needed """ return f"Escalated: {reason}. A human agent will follow up." @function_tool def check_order_status(self, order_id: str) -> str: """Check the status of an order. Args: order_id: The order identifier """ # In reality, this would call your order system return f"Order {order_id}: Shipped, arriving Thursday" def create_agent(self, context: dict) -> Agent: return Agent( name="support", instructions=self.build_instructions(context), tools=[self.escalate_to_human, self.check_order_status], model="gpt-4o" ) async def handle(self, customer_id: str, message: str) -> str: """Handle a support request.""" context = self.get_customer_context(customer_id, message) agent = self.create_agent(context) result = await Runner.run(agent, message) # Store the interaction self.memory.add( customer_id, content=f"Support request: {message}\nResolution: {result.final_output}", metadata={"type": "support", "resolved": True}, dreaming="instant" ) return result.final_output async def main(): support = SupportAgent() # Add some customer context support.memory.add( "customer_456", content="Premium customer since 2021. Prefers email communication.", dreaming="instant" ) response = await support.handle( "customer_456", "My order hasn't arrived yet. Order ID is ORD-789." ) print(response) if __name__ == "__main__": import asyncio asyncio.run(main()) ``` --- ## Multi-agent handoffs with shared memory Agents handing off to each other usually lose context. Not if they're sharing a memory store. ```python from agents import Agent, Runner class AgentTeam: def __init__(self, user_id: str): self.user_id = user_id self.memory = Supermemory() def get_shared_context(self, topic: str) -> str: """Get context that all agents can use.""" result = self.memory.search(self.user_id, query=topic, limit=5) return "\n".join([m.memory or m.chunk for m in result.results]) def create_researcher(self) -> Agent: context = self.get_shared_context("research preferences") return Agent( name="researcher", instructions=f"""You research topics and gather information. User context: {context}""", model="gpt-4o" ) def create_writer(self) -> Agent: context = self.get_shared_context("writing style preferences") return Agent( name="writer", instructions=f"""You write clear, helpful content. User context: {context}""", model="gpt-4o" ) async def research_and_write(self, topic: str) -> str: """Research a topic, then write about it.""" # Research phase researcher = self.create_researcher() research = await Runner.run(researcher, f"Research: {topic}") # Store research for the writer self.memory.add( self.user_id, content=f"Research on {topic}: {research.final_output[:500]}", metadata={"type": "research", "topic": topic}, dreaming="instant" ) # Writing phase writer = self.create_writer() article = await Runner.run( writer, f"Write about {topic} using this research:\n{research.final_output}" ) return article.final_output ``` --- ## Metadata for filtering Tags let you narrow down searches later: ```python # Store with metadata memory.add( "user_123", content="User prefers detailed technical explanations", dreaming="instant", metadata={ "type": "preference", "category": "communication_style", "source": "support_chat" } ) # Search with filters results = memory.search( "user_123", query="communication preferences", filter={ "operator": "and", "operands": [ {"field": "type", "operator": "eq", "value": "preference"}, {"field": "category", "operator": "eq", "value": "communication_style"} ] } ) ``` --- ## Related docs How automatic profiling works Filtering and search modes Function calling with the regular OpenAI SDK Memory for LangChain apps