# Vapi

> Give a Vapi phone assistant a memory of each caller, from your own server URL. What matters about the caller goes into its prompt when a call starts, it can look things up mid-call, and the call is saved when it ends.

Give a Vapi phone assistant a memory of each caller. Vapi calls your server at three moments: when a call
starts, when the assistant uses a tool, and when the call ends. Answer the first with what matters about the
caller, the second with a lookup, and save the call at the third. The next call starts knowing what was said in
this one.

## Install

```bash
pip install fastapi uvicorn geniffy
```

```bash
uv add fastapi uvicorn geniffy
```

Set `GENIFFY_API_KEY` from **API keys** in the Geniffy app, and `VAPI_SECRET` to a secret you also give Vapi.

## Your server

```python
import hmac
import json
import os

from fastapi import FastAPI, Header, HTTPException, Request
from geniffy import AsyncGeniffy

geniffy = AsyncGeniffy()                          # reads GENIFFY_API_KEY
app = FastAPI()
ASSISTANT_ID = os.environ.get("VAPI_ASSISTANT_ID", "your-assistant-id")


def space_of(message: dict) -> str:
    """The caller, by the digits of their number. If you know callers as customers, use your customer id, and
    the same memory serves their calls, chats and emails."""
    number = ((message.get("call") or {}).get("customer") or {}).get("number") or ""
    digits = "".join(ch for ch in number if ch.isdigit())
    if not digits:                                # never fall back to one shared memory for unknown callers
        raise HTTPException(400, "This call has no caller number.")
    return f"user_{digits}"


@app.post("/vapi")
async def vapi(request: Request, x_vapi_secret: str = Header("")):
    if not hmac.compare_digest(x_vapi_secret, os.environ["VAPI_SECRET"]):
        raise HTTPException(401)
    message = (await request.json())["message"]
    mem = geniffy.space(space_of(message))

    if message["type"] == "assistant-request":    # a call is starting: what to know before talking to them
        brief = await mem.brief(limit=12)
        known = "\n".join(f"- {m['text']}" for m in brief["memories"]) or (
            "Nothing is known about this caller yet. If they mention an earlier call, say so rather than guessing.")
        return {"assistantId": ASSISTANT_ID, "assistantOverrides": {"variableValues": {"memory": known}}}

    if message["type"] == "tool-calls":           # the assistant looks something up mid-call
        results = []
        for call in message.get("toolCallList") or []:
            args = call.get("parameters") or call.get("arguments") or {}
            args = json.loads(args) if isinstance(args, str) else args
            results.append({"name": call.get("name"), "toolCallId": call["id"],
                            "result": await mem.context(args.get("query", ""))})
        return {"results": results}

    if message["type"] == "end-of-call-report":   # the call is over: save who said what
        turns = [{"role": "assistant" if m["role"] in ("assistant", "bot") else "user", "content": m["message"]}
                 for m in (message.get("artifact") or {}).get("messages") or []
                 if m.get("role") in ("user", "assistant", "bot") and m.get("message")]
        if turns:
            await mem.memories.add(messages=turns, title="Call")
    return {}
```

Run it with `uvicorn server:app`, somewhere Vapi can reach over HTTPS.

A call starts with no question yet, so the assistant is given `brief()`: the caller's most load-bearing
memories, newest first. Once the caller asks something, `recall` answers with `context()`, which holds only
what bears on the question, each line with where it came from.

## In Vapi

In your assistant's system prompt, put the memory where you want it:

```text
You are a friendly phone assistant. Keep answers short.

<memory>
{{memory}}
</memory>
```

1. Add a **function tool** named `recall`, with one string parameter, `query`, and the description *Look up what
   is known about the caller, with where it came from.* Point its server URL at `https://your-server/vapi`.
2. On your phone number, set the **server URL** to `https://your-server/vapi`, so each call asks it for the
   assistant, and turn on the **end-of-call report**.
3. Make a **credential** for the header `X-Vapi-Secret` with your `VAPI_SECRET`, and use it on both server URLs.

When nothing is known about a caller, the memory says so in one sentence, and so does `recall`, so the
assistant says it doesn't know instead of guessing. Each call is added as one conversation titled `Call`.
Geniffy keeps who said what, so what the caller said becomes a fact about them, and what your assistant said
stays the assistant's.

Source: https://docs.geniffy.com/integrations/vapi
