GeniffyDocs
Changelog Log In Get a key

Microsoft Agent Framework

Give a Microsoft Agent Framework agent a memory of each of your users. Memory is a context provider: before each run it adds what is known about the user to the agent's instructions, and after each run it saves the exchange. Or it can hand the agent a recall tool instead.

Install

Terminal
pip install agent-framework-core agent-framework-anthropic geniffy

Set ANTHROPIC_API_KEY, and GENIFFY_API_KEY from API keys in the Geniffy app. Any chat client the framework supports works the same way. These examples use AsyncGeniffy, the same client with every method awaited.

Remember each user

agent.py
from agent_framework import Agent, ContextProvider
from agent_framework.anthropic import AnthropicClient
from geniffy import AsyncGeniffy

geniffy = AsyncGeniffy()                 # reads GENIFFY_API_KEY
client = AnthropicClient(model="claude-opus-5-5")


class GeniffyMemory(ContextProvider):
    """What is known about one user before each run, and the exchange saved after it."""

    def __init__(self, user_id: str):
        super().__init__("geniffy")
        self.mem = geniffy.space(f"user_{user_id}")

    async def before_run(self, *, agent, session, context, state) -> None:
        known = await self.mem.context(context.input_messages[-1].text)
        context.extend_instructions(self.source_id, f"<memory>\n{known}\n</memory>")

    async def after_run(self, *, agent, session, context, state) -> None:
        await self.mem.memories.add(messages=[
            {"role": "user", "content": context.input_messages[-1].text},
            {"role": "assistant", "content": context.response.text},
        ])


async def chat(user_id: str, message: str) -> str:
    memory = GeniffyMemory(user_id)
    agent = Agent(client, "You are a helpful assistant.", context_providers=[memory])
    return (await agent.run(message)).text

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, the provider hands it a recall tool bound to the user, so the model never sees or chooses whose memory it reads.

agent.py
from agent_framework import Agent, ContextProvider
from agent_framework.anthropic import AnthropicClient
from geniffy import AsyncGeniffy

geniffy = AsyncGeniffy()
client = AnthropicClient(model="claude-opus-5-5")
INSTRUCTIONS = ("You are a helpful assistant. Use recall before answering anything "
                "that depends on what the user said before.")


class GeniffyRecall(ContextProvider):
    """A recall tool for one user on each run, and the exchange saved after it."""

    def __init__(self, user_id: str):
        super().__init__("geniffy")
        self.mem = geniffy.space(f"user_{user_id}")

    async def before_run(self, *, agent, session, context, state) -> None:
        mem = self.mem

        async def recall(query: str) -> str:
            """Look up what is known about the user, with where it came from."""
            return await mem.context(query)

        context.extend_tools(self.source_id, [recall])

    async def after_run(self, *, agent, session, context, state) -> None:
        await self.mem.memories.add(messages=[
            {"role": "user", "content": context.input_messages[-1].text},
            {"role": "assistant", "content": context.response.text},
        ])


async def chat(user_id: str, message: str) -> str:
    agent = Agent(client, INSTRUCTIONS, context_providers=[GeniffyRecall(user_id)])
    return (await agent.run(message)).text

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