# Microsoft Agent Framework

> Give an Agent Framework agent a memory of each of your users with a context provider that recalls before each run and remembers after it.

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

```bash
pip install agent-framework-core agent-framework-anthropic geniffy
```

```bash
uv add 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

```python
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:

```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, the provider hands it a `recall` tool bound to the user,
so the model never sees or chooses whose memory it reads.

```python
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.

Source: https://docs.geniffy.com/integrations/microsoft-agent-framework
