# Pydantic AI

> Give a Pydantic AI agent a memory of each of your users, through dynamic instructions or a recall tool, with the user as the agent's dependency.

Give a Pydantic AI agent a memory of each of your users. The user is the agent's dependency, so the same
agent serves everyone: what is known goes in through dynamic instructions, or the agent looks it up with a
tool, and each exchange is saved after the run.

## Install

```bash
pip install "pydantic-ai-slim[anthropic]" geniffy
```

```bash
uv add "pydantic-ai-slim[anthropic]" geniffy
```

Set `ANTHROPIC_API_KEY`, and `GENIFFY_API_KEY` from **API keys** in the Geniffy app. Any model Pydantic AI
supports works the same way. These examples use `AsyncGeniffy`, the same client with every method awaited.

## Remember each user

```python
from dataclasses import dataclass

from geniffy import AsyncGeniffy
from pydantic_ai import Agent, RunContext

geniffy = AsyncGeniffy()                 # reads GENIFFY_API_KEY


@dataclass
class User:
    id: str


agent = Agent("anthropic:claude-opus-5-5", deps_type=User,
              instructions="You are a helpful assistant.")


@agent.instructions
async def memory(ctx: RunContext[User]) -> str:
    context = await geniffy.space(f"user_{ctx.deps.id}").context(str(ctx.prompt))
    return f"<memory>\n{context}\n</memory>"


async def chat(user_id: str, message: str) -> str:
    result = await agent.run(message, deps=User(id=user_id))
    await geniffy.space(f"user_{user_id}").memories.add(messages=[
        {"role": "user", "content": message},
        {"role": "assistant", "content": result.output},
    ])
    return result.output
```

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` tool. The tool reads the user from the
run's dependency, so the model never sees or chooses whose memory it reads.

```python
from dataclasses import dataclass

from geniffy import AsyncGeniffy
from pydantic_ai import Agent, RunContext

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


agent = Agent("anthropic:claude-opus-5-5", deps_type=User, instructions=INSTRUCTIONS)


@agent.tool
async def recall(ctx: RunContext[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.deps.id}").context(query)


async def chat(user_id: str, message: str) -> str:
    result = await agent.run(message, deps=User(id=user_id))
    await geniffy.space(f"user_{user_id}").memories.add(messages=[
        {"role": "user", "content": message},
        {"role": "assistant", "content": result.output},
    ])
    return result.output
```

The tool answers with `context()`, so the agent reads the same lines, with their sources, that the
instructions would hold, and the same sentence when nothing is known.

Source: https://docs.geniffy.com/integrations/pydantic-ai
