GeniffyDocs
Changelog Log In Get a key

Pydantic AI

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

Terminal
pip install "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

agent.py
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:

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.

agent.py
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.

Last updated October 5, 2026