Features: - AsyncQdrantClient for non-blocking Qdrant operations - Singleton pattern for QdrantService - Monthly full curation (day 1 at 03:00) - Configurable UID/GID for Docker - Timezone support via TZ env var - Configurable log directory (VERA_LOG_DIR) - Volume mounts for config/, prompts/, logs/ - Standard Docker format with .env file Fixes: - Removed unused system_token_budget - Added semantic_score_threshold config - Fixed streaming response handling - Python-based healthcheck (no curl dependency)
4.3 KiB
4.3 KiB
Vera-AI: Persistent Memory Proxy for Ollama
Vera-AI is a transparent proxy for Ollama that adds persistent memory using Qdrant vector storage.
Quick Start
# Clone or copy the project
git clone https://github.com/your-org/vera-ai.git
cd vera-ai
# Create environment file
cp .env.example .env
# Edit .env with your settings
nano .env
# Build and run
docker compose build
docker compose up -d
# Test
curl http://localhost:11434/
Configuration
Environment Variables (.env)
| Variable | Default | Description |
|---|---|---|
APP_UID |
999 |
User ID for container user (match your host UID) |
APP_GID |
999 |
Group ID for container group (match your host GID) |
TZ |
UTC |
Timezone for scheduler (e.g., America/Chicago) |
OPENROUTER_API_KEY |
- | API key for cloud model routing (optional) |
Getting UID/GID
# Get your UID and GID
id -u # UID
id -g # GID
# Set in .env
APP_UID=1000
APP_GID=1000
Volume Mappings
| Host Path | Container Path | Mode | Purpose |
|---|---|---|---|
./config/ |
/app/config/ |
ro |
Configuration files |
./prompts/ |
/app/prompts/ |
rw |
Curator and system prompts |
Directory Structure
vera-ai/
├── config/
│ └── config.toml # Main configuration
├── prompts/
│ ├── curator_prompt.md # Prompt for memory curator
│ └── systemprompt.md # System context (curator can append)
├── app/
│ ├── main.py
│ ├── config.py
│ ├── curator.py
│ ├── proxy_handler.py
│ ├── qdrant_service.py
│ └── utils.py
├── static/ # Legacy (symlinks to prompts/)
├── .env.example # Environment template
├── docker-compose.yml # Docker Compose config
├── Dockerfile # Container definition
└── requirements.txt # Python dependencies
Docker Compose
services:
vera-ai:
build:
context: .
dockerfile: Dockerfile
args:
APP_UID: ${APP_UID:-999}
APP_GID: ${APP_GID:-999}
image: vera-ai:latest
container_name: vera-ai
env_file:
- .env
volumes:
- ./config:/app/config:ro
- ./prompts:/app/prompts:rw
network_mode: "host"
restart: unless-stopped
Build & Run
# Build with custom UID/GID
APP_UID=$(id -u) APP_GID=$(id -g) docker compose build
# Run with timezone
TZ=America/Chicago docker compose up -d
# Or use .env file
docker compose build
docker compose up -d
Timezone Configuration
The TZ environment variable sets the container timezone, which affects the scheduler:
# .env file
TZ=America/Chicago
# Scheduler runs at:
# - Daily curator: 02:00 Chicago time
# - Monthly curator: 03:00 Chicago time on 1st
Common timezones:
UTC- Coordinated Universal TimeAmerica/New_York- Eastern TimeAmerica/Chicago- Central TimeAmerica/Los_Angeles- Pacific TimeEurope/London- GMT/BST
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Health check |
/api/chat |
POST | Chat completion (augmented with memory) |
/api/tags |
GET | List models |
/api/generate |
POST | Generate completion |
/curator/run |
POST | Trigger curator manually |
Manual Curator Trigger
# Daily curation (recent 24h)
curl -X POST http://localhost:11434/curator/run
# Full curation (all raw memories)
curl -X POST "http://localhost:11434/curator/run?full=true"
Troubleshooting
Permission Denied
If you see permission errors on /app/prompts/:
# Check your UID/GID
id
# Rebuild with correct UID/GID
APP_UID=$(id -u) APP_GID=$(id -g) docker compose build --no-cache
docker compose up -d
Timezone Issues
If curator runs at wrong time:
# Check container timezone
docker exec vera-ai date
# Set correct timezone in .env
TZ=America/Chicago
Health Check Failing
# Check container logs
docker logs vera-ai --tail 50
# Check Ollama connectivity
docker exec vera-ai python -c "import urllib.request; print(urllib.request.urlopen('http://10.0.0.10:11434/').read())"
License
MIT License - see LICENSE file for details.