# Open WebUI Filter — Automatic Memory

A filter function that automatically recalls memories before each LLM response and stores new memories after each exchange. No LLM tool-calling required.

## How It Works

1. **Inlet** (before LLM): Calls `/api/recall` with the user's message. Injects memories and instructions into the system prompt.
2. **Outlet** (after LLM): Calls `/api/remember` with the last user + assistant messages. Fire-and-forget — the LLM response is not delayed.

The filter tracks sessions per `chat_id` so subsequent turns only receive NEW relevant memories.

## Setup

### 1. Install the Filter

1. In Open WebUI, go to **Workspace > Functions > Add Function**
2. Paste the contents of `mnemory_filter.py`
3. Save and enable the function

### 2. Configure Valves

Click the gear icon on the filter to set:

| Valve | Default | Description |
|---|---|---|
| `mnemory_url` | `http://localhost:8050` | mnemory server URL |
| `api_key` | (empty) | API key for authentication |
| `agent_id` | `open-webui` | Agent ID sent to mnemory |
| `recall_mode` | `always` | When to recall: `always` (every message) or `first_only` (first message only) |
| `recall_search_mode` | `search` | Search mode: `search` (fast, no LLM) or `find` (AI-powered, thorough) |
| `recall_find_first` | `true` | When search mode is `search`, use `find` for the first message |
| `recall_score_threshold` | `0.5` | Minimum relevance score (0.0-1.0) for recalled memories. Prevents context bloat from weak matches. |
| `show_status` | `true` | Show memory status messages in chat (can be overridden per-user) |
| `request_timeout` | `30` | HTTP request timeout in seconds for mnemory API calls |

### 3. Multi-User Setup (Recommended)

Enable user identity forwarding in Open WebUI so each user gets their own memories:

```bash
# Open WebUI environment
ENABLE_FORWARD_USER_INFO_HEADERS=true

# mnemory environment
MCP_API_KEYS='{"shared-openwebui-key": "*"}'
```

Set `api_key` in the filter valves to `shared-openwebui-key`.

### 4. Single-User Setup

Use a non-wildcard API key that binds to a specific user:

```bash
MCP_API_KEYS='{"your-api-key": "your-username"}'
```

### 5. Optional: Add OpenAPI Tool

For LLM-driven operations (explicit search, delete, etc.), add the OpenAPI spec as a tool:

1. Go to **Workspace > Tools > Add Tool**
2. Import from URL: `http://mnemory:8050/api/openapi.json`
3. Enable on your models

This gives the LLM access to search, update, and delete operations alongside the automatic filter.

## User Valves

Each user can configure:

| Valve | Default | Description |
|---|---|---|
| `enabled` | `true` | Enable/disable memory for this user |
| `show_status` | `true` | Show "Recalling memories..." status in chat |

## Recall Configuration

Three valves control recall behavior. The defaults (`always` + `search` + `find_first=true`) give the best balance of speed and quality.

### `recall_mode` — When to recall

| Mode | Behavior |
|---|---|
| `always` (default) | Recall on every message. New relevant memories are injected as context. |
| `first_only` | Recall on first message only. Subsequent messages add zero latency. |

### `recall_search_mode` — How to search

| Mode | Behavior | Latency |
|---|---|---|
| `search` (default) | Fast: single vector similarity search, no LLM calls. | ~50-200ms |
| `find` | AI-powered: LLM generates up to 5 targeted queries, searches each, reranks by relevance. Can return 0 queries for irrelevant input (e.g., "ok", "format as table") — skipping search entirely. | ~200-500ms (or ~100ms when skipped) |

### `recall_find_first` — Thorough first message

When `recall_search_mode=search` and `recall_find_first=true` (default), the first message in a session uses `find` mode for thorough initial context loading. Subsequent messages use fast `search`. Ignored when `recall_search_mode=find`.

### `recall_score_threshold` — Relevance filtering

Controls the minimum relevance score (0.0-1.0) for memories injected into context. Default `0.5` filters out weak matches that would bloat context without adding value — especially on follow-up messages like "ok", "format as table", etc.

- **Lower** (e.g., 0.3): More memories injected, may include tangentially related ones
- **Higher** (e.g., 0.7): Fewer but highly relevant memories only

This threshold is applied on top of the server's `SEARCH_SCORE_THRESHOLD` (default 0.30), which filters at the vector search level.

### Behavior matrix

| `recall_mode` | `recall_search_mode` | `recall_find_first` | First message | Subsequent |
|---|---|---|---|---|
| `always` | `search` | `true` | find + core | search |
| `always` | `search` | `false` | search + core | search |
| `always` | `find` | — | find + core | find |
| `first_only` | `search` | `true` | find + core | (skipped) |
| `first_only` | `search` | `false` | search + core | (skipped) |
| `first_only` | `find` | — | find + core | (skipped) |

## Troubleshooting

- **No memories appearing**: Check that `mnemory_url` is reachable from Open WebUI. If both run in Docker, use the container name (e.g., `http://mnemory:8050`).
- **All users share memories**: Enable `ENABLE_FORWARD_USER_INFO_HEADERS=true` in Open WebUI and use a wildcard API key in mnemory.
- **Filter not running**: Ensure the filter is enabled and assigned to the model. Check Open WebUI logs for errors.
