> Full SurrealDB documentation index: https://surrealdb.com/docs/llms.txt

# LiveKit

Adding SurrealDB Agent Memory to a LiveKit voice agent.

[LiveKit Agents](https://docs.livekit.io/agents/) build realtime voice agents from a speech-to-text, LLM, and text-to-speech pipeline. SurrealDB Agent Memory gives that agent long-term memory: recall what the caller said in past sessions before the model speaks, and store each turn afterwards. Use the [Python SDK](/docs/agent-memory/integrations/sdks/python.md) (`surrealdb`); there is no dedicated LiveKit adapter. The pipeline's speech stages are pluggable; for a pipeline built on Gradium's speech models, see [Gradium](/docs/agent-memory/integrations/voice/gradium.md).

> [!NOTE]
> This is an integration guide. The code shows where SurrealDB Agent Memory fits in a LiveKit agent's turn lifecycle; adapt the hook names to your installed `livekit-agents` version.

## Installation

```bash
pip install "livekit-agents[openai,silero]"
pip install --pre surrealdb
```

Set the connection details:

**Bash**

```bash
export AGENT_MEMORY_ENDPOINT="https://memory.example.com"
export AGENT_MEMORY_CONTEXT="acme-prod"
export AGENT_MEMORY_API_KEY="sk-mem-..."
```

**PowerShell**

```powershell
$env:AGENT_MEMORY_ENDPOINT = "https://memory.example.com"
$env:AGENT_MEMORY_CONTEXT = "acme-prod"
$env:AGENT_MEMORY_API_KEY = "sk-mem-..."
```

## Recall before the model, store after

LiveKit calls `on_user_turn_completed` once the caller's speech has been transcribed, before the LLM runs. Recall relevant memory there and add it to the turn context; store the exchange when the turn finishes:

```python
import os
from livekit import agents
from livekit.agents import Agent, AgentServer, AgentSession, ChatContext, ChatMessage
from livekit.plugins import openai, silero
from surrealdb import AsyncAgentMemory

class MemoryAgent(Agent):
    def __init__(self, memory: AsyncAgentMemory, scope: list[str]):
        super().__init__(instructions="You are a helpful voice assistant.")
        self._memory = memory
        self._scope = scope

    async def on_user_turn_completed(self, turn_ctx: ChatContext, new_message: ChatMessage):
        # Recall relevant memory and inject it as context for this turn.
        block = await self._memory.query_context(
            new_message.text_content, k=8, lens=self._scope,
        )
        if block:
            turn_ctx.add_message(role="system", content=f"## Memory\n{block}")

        # Store the caller's turn for future recall (non-blocking).
        await self._memory.remember(new_message.text_content, scopes=self._scope)


server = AgentServer()

@server.rtc_session()
async def entrypoint(ctx: agents.JobContext):
    memory = AsyncAgentMemory(
        endpoint=os.environ["AGENT_MEMORY_ENDPOINT"],
        context=os.environ["AGENT_MEMORY_CONTEXT"],
        api_key=os.environ["AGENT_MEMORY_API_KEY"],
    )

    session = AgentSession(
        stt=openai.STT(),
        llm=openai.LLM(model="gpt-4o"),
        tts=openai.TTS(),
        vad=silero.VAD.load(),
    )

    await session.start(
        agent=MemoryAgent(memory, scope=["org/acme/user/alice"]),
        room=ctx.room,
    )

if __name__ == "__main__":
    agents.cli.run_app(server)
```

## Scope per caller

Bind a `scope` to the caller's identity so each person's memory stays isolated. It is a slash path or an array of paths, for example `["org/acme/user/alice"]`. Derive it from the LiveKit participant identity when the room connects. Register paths with `agent-memory scopes create` before first use.

## Latency

Voice turns are latency-sensitive. Keep recall to a single `query_context` call with a modest `k`, and let the write to `remember` run without blocking the response. For heavier synthesis, run `reflect` or `consolidate` between calls rather than inside a turn.

## Next steps

- [Python SDK](/docs/agent-memory/integrations/sdks/python.md): the full client surface
- [Recalling memories](/docs/agent-memory/retrieve/recall.md): recall modes and filters
