Korely

OpenAI Agents SDK

The OpenAI Agents SDK is a small Python framework for agents. Its main pieces are Agent, Runner and function tools. A function tool is a Python function with the @function_tool decorator: the function name becomes the tool name, the docstring becomes the description and the type hints become the JSON schema. This page adds three tools that call the Korely Python SDK. Once they are attached to an Agent, the model recalls, searches and saves on its own.

Facts, not just snippets

A search returns the memories that match a question. get_context returns more: a context block with the facts that are true now. When a user upgrades from Free to Pro, the old fact is not deleted. It is closed, the new one replaces it, and both keep their dates. So the recall tool below gives the model a settled view ("Luca is on Pro", "prefers async standups") and not a pile of snippets to re-read each turn.

Install

You need Python 3.10 or later, the OpenAI Agents SDK and the Korely Python package. The install name and the import name of the Agents SDK differ: you run pip install openai-agents but import from agents.

Terminal window
pip install openai-agents korely-memory

The examples were run with openai-agents 0.24.0 and korely-memory 0.1.28, with a fake model server, so no OpenAI call was made. You need two keys: your OpenAI key (the model runs on OpenAI) and your Korely API key (copy it from API Keys in the dashboard at agent.korely.ai). Export both:

Terminal window
export OPENAI_API_KEY="sk-..."
export KORELY_API_KEY="kor_live_..."

Define the memory tools

Three tools cover the loop: recall (the facts that are true now; the model should use it first), save (write something worth remembering) and search (find the one memory that mentioned a thing). Each is a plain function with @function_tool. The docstring is what the model reads to decide when to call the tool, so write it for the model.

memory_tools.py
from agents import function_tool
from korely_memory import Korely
korely = Korely() # reads KORELY_API_KEY from the environment
@function_tool
def recall_memory(query: str) -> str:
"""Recall settled facts and relevant memories about the user.
Reach for this first, before answering anything personal. It returns an
assembled block of the user's active typed facts plus relevant memories.
Args:
query: What you want to remember about, e.g. "where the user lives".
"""
ctx = korely.get_context(query=query, token_budget=800)
return ctx.context
@function_tool
def save_memory(content: str) -> str:
"""Save something worth remembering for later turns.
Args:
content: A short, self-contained statement to remember,
e.g. "User just moved to Berlin".
"""
memory = korely.add(content)
return f"Saved (id={memory.id})."
@function_tool
def search_memory(query: str) -> str:
"""Find the exact memory that mentioned something.
Use this when you need a specific past detail rather than a settled fact.
Args:
query: A keyword-style query, 1 to 5 words.
"""
hits = korely.search(query, limit=5)
if not hits:
return "No matching memories."
return "\n".join(f"- ({h.score:.2f}) {h.snippet}" for h in hits)

Why recall comes first. search_memory returns matching snippets, which suits "find the memory that mentioned the Lisbon hotel". recall_memory calls get_context, which returns the current facts already reconciled. With both tools, the model uses recall to know the user and search to find one exact past detail.

Attach them to an agent

Pass the decorated functions in the tools list of Agent. The instructions string is the system prompt, and it is where you tell the model to consult memory before it answers. Run the agent with Runner.run_sync in a plain script, or with await Runner.run(...) inside an async function. The answer is in result.final_output.

agent.py
from agents import Agent, Runner
from memory_tools import recall_memory, save_memory, search_memory
agent = Agent(
name="Assistant",
instructions=(
"You are a helpful assistant with long-term memory. "
"Call recall_memory before answering anything about the user. "
"When the user tells you something durable, call save_memory."
),
tools=[recall_memory, save_memory, search_memory],
)
# --- Option A: synchronous (no event loop needed) ---
result = Runner.run_sync(agent, "Where do I live now?")
print(result.final_output)

Inside a server, a notebook, or anywhere an event loop is already running, use the async runner instead of run_sync:

import asyncio
from agents import Agent, Runner
from memory_tools import recall_memory, save_memory, search_memory
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant with long-term memory.",
tools=[recall_memory, save_memory, search_memory],
)
async def main() -> None:
result = await Runner.run(
agent,
input="Where do I live now?",
)
print(result.final_output)
asyncio.run(main())

run_sync and a running event loop. Runner.run_sync starts the async runner for you, which is fine in a plain script. Do not call it from inside a running event loop (a Jupyter cell, an async web handler). There, use await Runner.run(agent, input=...). The first argument is always the agent. The user message is the second argument, or input=....

What comes back

Korely answers a read by looking things up: get_context assembles facts and memories, and search compares meaning. No language model runs on Korely's side when you read. Your OpenAI model does all the reasoning over the block it receives. Reads are cheap for us, so every plan allows at least 100 times more queries than writes per month (see the pricing page). The terminal below is an example, not your output.

terminal python agent.py
$ python agent.py

# example output. Earlier sessions saved "User lives in Lisbon", then "User just moved to Berlin"
→ tool call recall_memory(query="where the user lives")
← _The facts below are a compact profile of the user; [...]_

   ## Known facts
   - user lives_in Berlin (since 2026-06-16)

   ## Relevant memories
   _A time in square brackets [...] is the day it was said._
   - [2026-06-16] User just moved to Berlin
   ...

Agent › You live in Berlin now; you told me you just moved there.

Facts arrive after the write. korely.add(...) returns when the memory is stored. The facts are written by extraction, usually about ten seconds later. A recall_memory right after a save_memory in the same turn may not see the new fact. For a chat agent that is usually fine, because the fact is there by the next message. korely.events() tells you when a write has finished processing. Do not poll get_context in a tight loop waiting for the fact; let it land between turns.

One memory per end user

The tools above read and write the whole project. A read without a user_id covers every end user of the project. When each person who uses your product needs a private memory, bind a user_id on your server and pass it on every Korely call. Capture it in a closure, so the model can neither see nor change it:

from agents import Agent, Runner, function_tool
from korely_memory import Korely
korely = Korely() # reads KORELY_API_KEY from the environment
def build_agent(user_id: str) -> Agent:
"""user_id is bound here, server-side. The model never sees it."""
@function_tool
def recall_memory(query: str) -> str:
"""Recall settled facts and memories about this user."""
return korely.get_context(query=query, user_id=user_id).context
@function_tool
def save_memory(content: str) -> str:
"""Save something worth remembering about this user."""
memory = korely.add(content, user_id=user_id, agent_id="support-bot")
return f"Saved (id={memory.id})."
return Agent(
name="Support bot",
instructions="Recall memory before answering. Save durable facts.",
tools=[recall_memory, save_memory],
)
# Per request, bound to the authenticated session:
agent = build_agent(user_id=current_user.id) # your own login object
result = Runner.run_sync(agent, user_message)
print(result.final_output)

A read that carries a user_id returns only that user's data. agent_id labels which application wrote the memory, and run_id can tag one session.

Where to go next

  • Memory as a tool: the end-to-end pattern of giving an agent recall, save and search, with tips for getting the model to call them.
  • Get context: how the fact block is built, what token_budget controls, and what each source in the response means.

Something not working? Email [email protected] with your openai-agents and korely-memory versions and the error output. We read every message.