Configuration#
Learn how to configure EngiAI for your environment.
Environment Variables#
The assistant uses environment variables for configuration. These are stored in a .env file in the project root.
Creating Your Configuration#
Copy the example file:
cp .env.example .env
Edit
.envwith your settings:nano .env # or use your preferred editor
Required Variables#
These must be set for the assistant to function:
# OpenAI API Key (Required for all LLM operations)
OPENAI_API_KEY=sk-your-openai-api-key-here
# Web search (DuckDuckGo is keyless and is the default)
SEARCH_PROVIDER=duckduckgo
SEARCH_REGION=us-en
SEARCH_TIMEOUT_SECONDS=10
# Optional Tavily backend
# SEARCH_PROVIDER=tavily
# TAVILY_API_KEY=tvly-your-tavily-api-key-here
# Google API Key (Required for all LLM operations)
GOOGLE_API_KEY=sk-your-google-api-key-here
# MMORE RAG Service (Required for document retrieval)
MMORE_RAG_URL=http://localhost:8000
Where to get keys:
Tavily (optional): https://tavily.com/
External Services:
MMORE: runs from the official upstream image as part of the Docker stack, through a small local layer (
services/mmore/Dockerfile). No clone, no manual setup.
MMORE variables:
Variable |
Default |
Purpose |
|---|---|---|
|
|
Where the app and scripts reach the service. Docker overrides it to |
|
pinned |
Which upstream image to run. Read |
|
|
Disable RAG entirely — the RAG tools are not created at all. |
|
|
Benchmark control condition: the tools exist but the index answers nothing. Set automatically by |
|
|
Seconds to wait for a background indexing job. MMORE v2 indexes asynchronously, so uploads return a job id that the client polls. |
|
|
Score floor for the |
Note
MMORE_PATH is obsolete — it pointed at a local MMORE checkout that no longer
exists. Remove it from your .env.
Optional Variables#
These enhance functionality but aren’t required:
# LLM Configuration
LLM_MODEL=openai:gpt-4.1 # Default model
LLM_MODEL_OPTIONS=openai:gpt-4.1,ollama:qwen3.5:9b-mxfp8
LLM_MODEL_LABELS={"openai:gpt-4.1":"Cloud","ollama:qwen3.5:9b-mxfp8":"Local 9B"}
LLM_ROUTER_MODEL=ollama:qwen3.5:4b-mxfp8
LLM_ROUTER_TEMPERATURE=0.1
LLM_TEMPERATURE=0.7 # Temperature for responses (0.0-2.0)
# HPC Cluster Configuration
HPC_HOST_ALIAS=euler # SSH alias for your HPC cluster
HPC_HOSTNAME=euler.ethz.ch # Cluster hostname
HPC_USERNAME=username # Your cluster username
# Weights & Biases (for ML tracking)
WANDB_API_KEY=your-wandb-key
WANDB_ENTITY=your-team
# Prusa 3D Printer Integration (optional)
SKIP_MCP=true # Set to false to enable Prusa integration
PRUSA_MCP_URL=http://localhost:8765 # URL of a running Prusa MCP server
PRUSA_MCP_HOST=0.0.0.0 # Host for the standalone MCP server
PRUSA_MCP_PORT=8765 # Port for the standalone MCP server
# Database (optional, uses SQLite by default)
DATABASE_URL=sqlite:///data/conversations.db
For Prusa 3D printer integration:
The Prusa MCP server is installed as a pip dependency from git (
prusa-mcp @ git+https://github.com/gioelemo/prusa-mcp.git), declared inservices/prusa_mcp_server/requirements-mcp.txt.It is installed automatically by the Prusa MCP Dockerfile or by
./services/prusa_mcp_server/run.sh. No submodule initialization is required.See
services/prusa_mcp_server/README.mdfor setup and credential handling.Set
SKIP_MCP=falseto enable. This also enables the whiteboard canvas — see Whiteboard Canvas.
Voice Integration#
The assistant supports voice interaction (speech-to-text and text-to-speech) using three providers:
# Voice Provider Selection
# An unrecognised value falls back to "elevenlabs" with a warning.
VOICE_PROVIDER=elevenlabs # Options: "elevenlabs", "openai" or "google"
# ElevenLabs Configuration (default provider)
ELEVENLABS_API_KEY=your-elevenlabs-api-key
ELEVENLABS_STT_MODEL=scribe_v2
ELEVENLABS_TTS_MODEL=eleven_multilingual_v2
ELEVENLABS_DEFAULT_VOICE=George
ELEVENLABS_VOICES=Rachel:21m00Tcm4TlvDq8ikWAM,Domi:AZnzlk1XvdvUeBnXmlld,Bella:EXAVITQu4vr4xnSDxMaL,Antoni:ErXwobaYiN019PkySvjV,Josh:TxGEqnHWrfWFTfGW9XjX,George:JBFqnCBsd6RMkjVDRZzb
# OpenAI Voice Configuration (alternative provider)
OPENAI_TTS_MODEL=gpt-4o-mini-tts # Options: "gpt-4o-mini-tts", "tts-1", "tts-1-hd"
OPENAI_TTS_VOICE=alloy # See the voice/model note below
OPENAI_STT_MODEL=whisper-1 # OpenAI Whisper for speech-to-text
# Google Gemini Voice Configuration (text-to-speech only, uses GOOGLE_API_KEY)
GOOGLE_TTS_MODEL=gemini-3.1-flash-tts-preview
GOOGLE_TTS_VOICE=Kore
Voice Provider Options:
ElevenLabs (Recommended for quality):
High-quality, natural-sounding voices
Supports 6 preset voices (Rachel, Domi, Bella, Antoni, Josh, George)
Multilingual support with
eleven_multilingual_v2modelGet API key at elevenlabs.io
OpenAI (Good for simplicity):
Uses OpenAI Whisper for accurate speech-to-text
Three TTS models:
gpt-4o-mini-tts: the default, and the only model that accepts every voicetts-1: standard quality, faster, cheapertts-1-hd: high definition quality
13 voices: alloy, ash, coral, echo, fable, nova, onyx, sage and shimmer work everywhere; ballad, verse, marin and cedar are
gpt-4o-mini-ttsonly and are rejected bytts-1/tts-1-hd. The Settings page narrows the voice list to match the selected model.Requires OpenAI API key (same as
OPENAI_API_KEY)
Google Gemini (text-to-speech only):
Reuses
GOOGLE_API_KEY— no separate credential or GCP project needed30 prebuilt voices (Zephyr, Puck, Charon, Kore, Fenrir, Leda, Orus, Aoede, …)
No speech-to-text. Selecting Google for voice output leaves microphone input to OpenAI Whisper, or ElevenLabs when no OpenAI key is configured. The Settings page and the chat input both say which provider will transcribe.
Default model is
gemini-3.1-flash-tts-previewfor a measured reason: the 2.5 models return an empty response most of the time on short inputs (1 success in 5 forgemini-2.5-flash-preview-tts, against 5/5 for 3.1-flash), and short assistant replies are common.Gemini returns raw PCM, which the app wraps in a WAV container. WAV is roughly three times the size of MP3 and audio is stored base64-encoded in the message history, so long replies are truncated (see below).
Input length: each provider rejects over-long input outright rather than truncating it, so the app truncates first — at a sentence boundary — and shows a caption saying how much was read. The caps are 4096 characters for OpenAI and 10000 for ElevenLabs, both set by the API.
Google’s cap is the tightest at 2000, and it bounds stored bytes rather than the
request: Gemini’s own limit is the loosest of the three, but its WAV output is
48 KB/s and gets base64-encoded into both the session history and the
messages.audio column, so ~2000 characters is already ~3.5 minutes of speech
and ~13 MB in a single row.
Usage:
Select provider in Settings UI (⚙️ Settings > Voice Interaction)
Provider, voice and per-provider TTS model persist per conversation
Switch providers anytime without losing conversation history
Document Processing Variables#
For PDF and document processing features:
# Paper Import Configuration
PAPERS_SOURCE_DIR=/path/to/papers # Directory containing PDFs to import
PAPERS_STATE_FILE=data/local_import_state.json # Tracks imported papers
Paper Import:
PAPERS_SOURCE_DIR: Point to your local papers directory (or network share)Papers are automatically uploaded to MMORE service
Progress tracked in
PAPERS_STATE_FILESee Paper Import Guide for details
Observability & Debugging#
For monitoring and debugging:
# LangSmith Tracing (optional)
LANGCHAIN_TRACING=false # Set to true to enable
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
LANGSMITH_API_KEY=your-langsmith-key
LANGCHAIN_PROJECT=engiai
# Host Service (Docker GUI integration)
HOST_SERVICE_PORT=9999 # Port for opening GUI apps from Docker
LangSmith Setup:
Create account at smith.langchain.com
Get API key from settings
Monitor LLM calls, costs, and performance
Debug conversation flows and tool usage
Weave and log level:
Variable |
Default |
Purpose |
|---|---|---|
|
|
Trace the interactive Streamlit app in Weave (benchmark runs are governed by |
|
|
Root log level for the benchmark harness only — read in |
Warning
USE_WEAVE_CHATBOT silently requires USE_WEAVE. It only decides whether
init_weave() is called; setup_weave_tracing() returns immediately when
USE_WEAVE is false (the guard is in config.py; weave_integration.init_weave
just delegates to it), and the return value is discarded, so setting
USE_WEAVE_CHATBOT=true on its own traces nothing and reports no error.
Agent availability flags#
Each disables one routing target on the supervisor. The benchmark harness sets them per run; set them here only to disable a route permanently.
Variable |
Default |
Purpose |
|---|---|---|
|
|
Disables web search. The |
|
|
Web-search backend: keyless |
|
|
DuckDuckGo result region. |
|
|
Timeout for each DuckDuckGo request. One retry is attempted after a transient failure. |
|
|
Disables the ArXiv route. Unlike |
|
|
Master switch over both MCP integrations — the Prusa printer and the whiteboard canvas. |
|
|
Disables the whiteboard agent on its own, leaving the printer integration alone. |
|
|
Where the agent reaches the canvas server. Docker sets |
|
|
Bind address and port for the standalone canvas server. |
|
Host-header allowlist for the canvas SSE transport. The un-namespaced |
|
|
unset locally, |
Where the canvas server persists scenes. Unset means memory-only. The durable per-conversation copy lives in the EngiAI database regardless. |
|
|
Resource bounds on the canvas server. |
Hugging Face Integration#
For ML model downloads:
# Hugging Face
HF_TOKEN=your-huggingface-token
HF_HOME=$HOME/.cache/huggingface/hub
HF_DATASETS_CACHE=$HOME/.cache/huggingface/datasets
Getting HF Token:
Create account at huggingface.co
Go to Settings → Access Tokens
Create token with “Read” permission
Advanced SLURM Configuration#
For HPC job submission (advanced users):
# SLURM Job Defaults
SLURM_TIME=00:45:00 # Max job duration
SLURM_NTASKS=1 # Number of tasks
SLURM_CPUS_PER_TASK=4 # CPUs per task
SLURM_MEM_PER_CPU=7GB # Memory per CPU
SLURM_GPUS=rtx_4090:1 # GPU specification
# Module Loading
SLURM_STACK_MODULE=stack/2024-06
SLURM_GCC_MODULE=gcc/12.2.0
SLURM_PYTHON_MODULE=python_cuda/3.11.6
SLURM_CUDA_MODULE=cuda/12.8.0
Note: Many SLURM settings can be configured via the Settings UI (⚙️ Settings > SLURM Cluster Configuration). Environment variables serve as fallback defaults.
Guardrails. These are caps, not defaults: they never change what the agent
asks for, they reject a request that exceeds them. All four are checked together
in _check_hard_limits() in src/tools/engiopt.py, and the comparison
is strictly greater-than, so a request equal to the cap passes.
Variable |
Default |
Purpose |
|---|---|---|
|
|
Maximum GPUs the agent may request |
|
|
Maximum wall-clock hours |
|
|
Maximum CPUs |
|
|
Maximum memory per CPU, in GB |
|
|
Omit |
Warning
All four caps are parsed with a bare int(os.getenv(...)). A non-integer value
raises ValueError when a job is validated, not at startup.
LLM Models#
You can configure which language model to use:
Supported Models#
# OpenAI Models
LLM_MODEL=openai:gpt-4.1 # GPT-4.1 (recommended)
LLM_MODEL=openai:gpt-4o # GPT-4o
LLM_MODEL=openai:gpt-4o-mini # GPT-4o Mini (faster, cheaper)
# Google Models
LLM_MODEL=google_genai:gemini-2.5-flash # Gemini 2.5 Flash
# Ollama (local models)
LLM_MODEL=ollama:qwen3.5:4b # Qwen 3.5 4B (local)
To let each browser session switch between a small set of deployed models,
provide a comma-separated allow-list. LLM_MODEL remains the default:
LLM_MODEL=ollama:qwen3.5:4b-mxfp8
LLM_MODEL_OPTIONS=ollama:qwen3.5:4b-mxfp8,ollama:qwen3.5:9b-mxfp8,ollama:qwen3.8:27b-mxfp8
LLM_ROUTER_MODEL=ollama:qwen3.5:4b-mxfp8
Changing the mode in the sidebar rebuilds only that browser session’s agent on
its next message. It does not change the model selected by other users.
LLM_ROUTER_MODEL can keep the small structured routing step on a fast model
while the selected model handles the actual work and response.
Model Parameters#
# Temperature: Controls randomness in responses (0.0 to 2.0)
LLM_TEMPERATURE=0.0 # Deterministic, focused (recommended for engineering)
LLM_TEMPERATURE=0.7 # Balanced creativity (default)
LLM_TEMPERATURE=1.0 # More creative and varied responses
# Note: Higher temperature increases creativity but may reduce accuracy
# For engineering tasks, use 0.0-0.3 for precision
# For brainstorming, use 0.7-1.0 for variety
HPC Configuration#
For cluster computing features:
SSH Setup#
Configure SSH access to your cluster:
# In ~/.ssh/config Host euler HostName euler.ethz.ch User your-username IdentityFile ~/.ssh/id_rsa
Test connection:
ssh eulerSet in
.env:HPC_HOST_ALIAS=euler HPC_HOSTNAME=euler.ethz.ch HPC_USERNAME=your-username
Fabric Configuration#
The assistant uses Fabric for HPC interactions. Configuration is automatic based on your .env settings.
Weights & Biases#
For experiment tracking:
Create account at wandb.ai
Get API key from https://wandb.ai/authorize
Add to
.env:WANDB_API_KEY=your-key-here WANDB_ENTITY=your-username-or-team
Variable |
Default |
Purpose |
|---|---|---|
|
|
Project that HPC training runs log to |
|
unset |
Pins the project for the training-code-generation track, on both the submit and the evaluate side. Set it to isolate a grid: without it, |
Prusa MCP#
Variable |
Default |
Purpose |
|---|---|---|
|
|
Where the agent reaches the MCP server. Docker sets |
|
|
Bind address and port for the standalone server. |
|
see below |
Host-header allowlist for the SSE transport. The un-namespaced |
|
|
OAuth2 token file, written by |
Warning
PRUSA_MCP_ALLOWED_HOSTS replaces the default list rather than extending it. The
default is localhost, 127.0.0.1 and prusa-mcp-server, each in bare and
:PORT form. Since the server binds 0.0.0.0, this allowlist is what stops
other machines reaching the printer-control tools — widen it only to a host you
control, and list hosts explicitly rather than using a wildcard. See
Transport security.
Database Setup#
See the Database Setup Guide for detailed instructions on:
Setting up PostgreSQL or SQLite for conversation history
Configuring the MMORE RAG service for document retrieval
Variable |
Default |
Purpose |
|---|---|---|
|
|
Consumed by |
|
|
Context window passed as |
|
selected model |
Comma-separated allow-list shown in the per-session model selector. The default model is inserted automatically if omitted. |
|
|
Optional JSON object mapping model identifiers to friendly selector labels. Unknown models fall back to their identifier. |
|
selected model |
Optional model used only for supervisor routing. A small local model reduces latency while the selected profile still performs the actual task. |
|
|
Temperature used only for structured supervisor routing. Kept separate from response creativity because some small local models fail to emit structured output at exactly zero. |
VS Code Settings#
Recommended settings are in .vscode/settings_template.json:
{
"python.defaultInterpreterPath": "./venv/bin/python",
"python.analysis.extraPaths": [
"${workspaceFolder}/benchmarks/evaluations/plots"
],
"python.linting.enabled": true,
"python.linting.ruffEnabled": true,
"python.linting.mypyEnabled": true,
"mypy-type-checker.importStrategy": "fromEnvironment",
"python.formatting.provider": "none",
"ruff.importStrategy": "fromEnvironment",
"ruff.organizeImports": true,
"ruff.fixAll": true,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
},
"editor.rulers": [
88
],
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
}
}
}
Validating Configuration#
Check your configuration:
# Test API keys
python -c "from config import config; print('OpenAI Key:', config.openai_api_key[:10])"
# Test database connection
python -c "from src.ui.database import DatabaseManager; db = DatabaseManager(); print('DB OK')"
# Run all tests
pytest
Troubleshooting#
API Key Issues#
Error: openai.AuthenticationError
Check your API key in
.envEnsure no extra spaces or quotes
Verify key is active in OpenAI dashboard
HPC Connection Issues#
Error: Connection refused
Verify SSH config
Test manual SSH connection
Check firewall/VPN requirements
Database Issues#
Error: database is locked
Close other applications using the database
Use PostgreSQL for concurrent access
Security Best Practices#
Never commit
.env- It’s in.gitignorefor a reasonUse environment-specific keys - Different keys for dev/prod
Rotate keys regularly - Change API keys periodically
Limit key permissions - Use minimal required scopes
Use secrets manager - For production deployments (AWS Secrets Manager, etc.)
Next Steps#
Quick Start - Start using the assistant
Usage Guide - Learn about agents
API Reference - Developer docs