GeniffyDocs
Changelog Log In Get a key

OpenAI

Give your OpenAI app a memory of each of your users. Before the model answers, what is known about the user goes in the instructions; after it answers, the exchange is saved, so the next conversation starts knowing it.

Install

Terminal
pip install openai geniffy

Set OPENAI_API_KEY, and GENIFFY_API_KEY from API keys in the Geniffy app.

Remember each user

chat.py
from geniffy import Geniffy
from openai import OpenAI

client = OpenAI()                        # reads OPENAI_API_KEY
geniffy = Geniffy()                      # reads GENIFFY_API_KEY


def chat(user_id: str, message: str, history: list) -> str:
    """history is the conversation so far, as {"role", "content"} messages."""
    mem = geniffy.space(f"user_{user_id}")
    turn = {"role": "user", "content": message}
    context = mem.context(message)       # what is known that bears on the message

    response = client.responses.create(
        model="gpt-5.5",
        instructions=f"You are a helpful assistant.\n\n<memory>\n{context}\n</memory>",
        input=[*history, turn],
    )
    reply = response.output_text

    mem.memories.add(messages=[turn, {"role": "assistant", "content": reply}])
    return reply

The model now sees what is known about this user before every reply, each line with where it came from. When nothing is known, the block says so in one sentence, so the model says it doesn't know instead of guessing.

On Chat Completions, put the same block in a developer message at the start of messages, and save the exchange the same way.

Let the model look things up

To let the model decide when to look something up, give it a recall function, and answer each call with context().

agent.py
import json

from geniffy import Geniffy
from openai import OpenAI

client = OpenAI()
geniffy = Geniffy()
INSTRUCTIONS = ("You are a helpful assistant. Use recall before answering anything "
                "that depends on what the user said before.")
RECALL = {
    "type": "function",
    "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"],
        "additionalProperties": False,
    },
    "strict": True,
}


def chat(user_id: str, message: str) -> str:
    mem = geniffy.space(f"user_{user_id}")
    response = client.responses.create(
        model="gpt-5.5", instructions=INSTRUCTIONS, tools=[RECALL], input=message,
    )
    while calls := [item for item in response.output if item.type == "function_call"]:
        outputs = [
            {"type": "function_call_output", "call_id": call.call_id,
             "output": mem.context(json.loads(call.arguments)["query"])}
            for call in calls
        ]
        response = client.responses.create(
            model="gpt-5.5", instructions=INSTRUCTIONS, tools=[RECALL],
            previous_response_id=response.id, input=outputs,
        )
    reply = response.output_text

    mem.memories.add(messages=[{"role": "user", "content": message},
                               {"role": "assistant", "content": reply}])
    return reply

Instructions are not carried over from the previous response, so each follow-up sends them again. The tool answers with context(), so the model reads the same lines, with their sources, that the instructions would hold.

Last updated October 5, 2026