# OpenAI Agents SDK

> Give an OpenAI agent a memory of each of your users, through dynamic instructions or a recall function tool, with the async client.

Give an agent built with the OpenAI Agents SDK a memory of each of your users. What is known goes into the
agent's instructions through its run context, or the agent looks it up with a function tool; either way,
each exchange is saved when the run ends.

## Install

```bash
pip install openai-agents geniffy
```

```bash
uv add openai-agents geniffy
```

Set `OPENAI_API_KEY`, and `GENIFFY_API_KEY` from **API keys** in the Geniffy app. The SDK is async, so these
examples use `AsyncGeniffy`, the same client with every method awaited.

## Remember each user

```python
from dataclasses import dataclass

from agents import Agent, RunContextWrapper, Runner
from geniffy import AsyncGeniffy

geniffy = AsyncGeniffy()                 # reads GENIFFY_API_KEY


@dataclass
class Turn:
    memory: str


def instructions(ctx: RunContextWrapper[Turn], agent: Agent[Turn]) -> str:
    return f"You are a helpful assistant.\n\n<memory>\n{ctx.context.memory}\n</memory>"


agent = Agent[Turn](name="Assistant", instructions=instructions, model="gpt-5.5")


async def chat(user_id: str, message: str) -> str:
    mem = geniffy.space(f"user_{user_id}")
    turn = Turn(memory=await mem.context(message))     # what bears on the message
    result = await Runner.run(agent, message, context=turn)
    reply = result.final_output
    await mem.memories.add(messages=[{"role": "user", "content": message},
                                     {"role": "assistant", "content": reply}])
    return reply
```

Call it with the user from your own sign-in:

```python
reply = await chat(user.id, "Who signs the Lumen renewal?")
```

The agent sees what is known about this user, each line with where it came from. When nothing is known, the
block says so in one sentence, so the agent says it doesn't know instead of guessing.

## Let the agent look things up

To let the agent decide when to look something up, give it a `recall` function tool. The tool reads the
user from the run context, so the model never sees or chooses whose memory it reads.

```python
from dataclasses import dataclass

from agents import Agent, RunContextWrapper, Runner, function_tool
from geniffy import AsyncGeniffy

geniffy = AsyncGeniffy()
INSTRUCTIONS = ("You are a helpful assistant. Use recall before answering anything "
                "that depends on what the user said before.")


@dataclass
class User:
    id: str


@function_tool
async def recall(ctx: RunContextWrapper[User], query: str) -> str:
    """Look up what is known about the user, with where it came from.

    Args:
        query: What to look up
    """
    return await geniffy.space(f"user_{ctx.context.id}").context(query)


agent = Agent[User](
    name="Assistant", instructions=INSTRUCTIONS, model="gpt-5.5", tools=[recall],
)


async def chat(user_id: str, message: str) -> str:
    result = await Runner.run(agent, message, context=User(id=user_id))
    reply = result.final_output
    await geniffy.space(f"user_{user_id}").memories.add(messages=[
        {"role": "user", "content": message},
        {"role": "assistant", "content": reply},
    ])
    return reply
```

## Memory across sessions

A session keeps one conversation's history between runs. Geniffy is what the agent knows about the user
across every session: what they said last month, in another app, or in a file you added, with where each
fact came from.

Source: https://docs.geniffy.com/integrations/openai-agents-sdk
