# Any framework

> Two calls give any model a memory of each user, context() before it answers and memories.add() after. Every integration is this pattern.

Geniffy works with any model and any framework, because it doesn't wrap your model. You add two calls
around the model call you already make: one before it answers, and one after.

## The two calls

### 1. Before the model answers, recall


`context()` returns what is known about this user that bears on their message, written out for a prompt,
each line with where it came from. Put it in your system prompt or instructions.

### 2. After it answers, remember


Add the exchange with `memories.add()`. Geniffy learns from what the user said, so their next
conversation starts knowing it.


Both calls go through a client bound to one of your users with [`space()`](https://docs.geniffy.com/keys-and-spaces), so what one
user said never reaches another.

```python
from geniffy import Geniffy

geniffy = Geniffy()                      # reads GENIFFY_API_KEY


def answer(user_id: str, message: str, generate) -> str:
    """generate(system, message) is your own model call, with any provider."""
    mem = geniffy.space(f"user_{user_id}")
    context = mem.context(message)       # what is known that bears on the message
    system = f"You are a helpful assistant.\n\n<memory>\n{context}\n</memory>"
    reply = generate(system, message)
    mem.memories.add(messages=[{"role": "user", "content": message},
                               {"role": "assistant", "content": reply}])
    return reply
```

```ts
import { Geniffy } from "geniffy";

const geniffy = new Geniffy();               // reads GENIFFY_API_KEY

// generate is your own model call, with any provider or framework.
type Generate = (system: string, message: string) => Promise<string>;

export async function answer(userId: string, message: string, generate: Generate) {
  const mem = geniffy.space(`user_${userId}`);
  const context = await mem.context(message);  // what is known that bears on the message
  const system = `You are a helpful assistant.\n\n<memory>\n${context}\n</memory>`;
  const reply = await generate(system, message);
  await mem.memories.add({
    messages: [
      { role: "user", content: message },
      { role: "assistant", content: reply },
    ],
  });
  return reply;
}
```

When nothing is known yet, `context()` says so in one sentence instead of coming back empty, so the model
says it doesn't know rather than guessing. See [When nothing is known](https://docs.geniffy.com/recall/when-nothing-is-known).

## With your stack

Each page has the same two calls in the shape that framework expects, tested against the framework itself.

### Model providers

- [Anthropic](https://docs.geniffy.com/integrations/anthropic)
- [OpenAI](https://docs.geniffy.com/integrations/openai)
- [Google Gemini](https://docs.geniffy.com/integrations/gemini)

### Python agents

- [LangChain](https://docs.geniffy.com/integrations/langchain)
- [LangGraph](https://docs.geniffy.com/integrations/langgraph)
- [OpenAI Agents SDK](https://docs.geniffy.com/integrations/openai-agents-sdk)
- [Pydantic AI](https://docs.geniffy.com/integrations/pydantic-ai)
- [LlamaIndex](https://docs.geniffy.com/integrations/llamaindex)
- [CrewAI](https://docs.geniffy.com/integrations/crewai)
- [Agno](https://docs.geniffy.com/integrations/agno)
- [Microsoft Agent Framework](https://docs.geniffy.com/integrations/microsoft-agent-framework)
- [Google ADK](https://docs.geniffy.com/integrations/google-adk)

### TypeScript agents

- [Vercel AI SDK](https://docs.geniffy.com/integrations/vercel-ai-sdk)
- [Mastra](https://docs.geniffy.com/integrations/mastra)

### Voice and no-code

- [Pipecat](https://docs.geniffy.com/integrations/pipecat)
- [Zapier](https://docs.geniffy.com/integrations/zapier)
- [n8n](https://docs.geniffy.com/integrations/n8n)
- [Make](https://docs.geniffy.com/integrations/make)

Using a framework that isn't listed? Put `context()` wherever it builds the system prompt or instructions,
and `memories.add()` wherever it hands you the finished reply.

## Recall first, or as a tool

There are two ways to put memory in front of a model, and most apps want the first.

| | Recall first | Recall as a tool |
| --- | --- | --- |
| How it works | `context()` runs before every reply | The model calls `recall` when it decides to |
| Model calls per reply | One | Two or more when it looks something up |
| The model always sees what is known | Yes | Only when it asks |
| Best for | Assistants, support and companions | Agents that plan and look things up as they go |

They also work together: recall first for what bears on the message, and the tool for when the model
needs to look further. Every model provider and agent framework page shows both.

## A recall tool

Give the model one tool, named `recall`, and answer each call with `mem.context(query)`:

```json
{
  "name": "recall",
  "description": "Look up what is known about the user, with where it came from.",
  "parameters": {
    "type": "object",
    "properties": { "query": { "type": "string", "description": "What to look up" } },
    "required": ["query"]
  }
}
```

Anthropic calls the schema `input_schema`, OpenAI calls it `parameters`, and the Vercel AI SDK takes it as
`inputSchema`. Tell the model when to use it in your instructions, for example: *Use recall before
answering anything that depends on what the user said before.*

## Saving what was said

- **Save each exchange once, after the reply.** `memories.add()` returns as soon as the conversation is
  stored, and learning happens after, so saving never holds up the reply.
- **Send messages as your framework holds them.** Anthropic content blocks, OpenAI parts and Vercel AI SDK
  parts all go in as they are. Only text is read: images, tool calls and tool results are skipped, and so
  are system and developer messages.
- **Who said what is kept.** What your user says becomes a fact about them, and what your assistant says
  stays the assistant's.

See [Conversations](https://docs.geniffy.com/add-memories/conversations) for everything `memories.add()` accepts.

Source: https://docs.geniffy.com/integrations
