emergence-mini-dilles/README.md
Jeuners 919866e50d Time Dilation framework + OpenRouter multi-LLM
Implements core pieces of 'Time Dilation in LLM Agent Systems'
(Dillenberg 2026) and adds OpenRouter as a second LLM provider.

ENGINE
- engine/time.py: AgentClock with cumulative proper time tau
  (weighted by op type), EWMA pace (alpha=0.3, dt clamped 0.1-60s),
  ClockRegistry singleton, gamma_{src->dst} frame transformation,
  drift_report with per-pair divergence and threshold flag.
- engine/turn.py: ticks tau on reasoning/tool/memory/reactive;
  broadcasts tau+pace+model in every WebSocket message.
- engine/db.py: schema adds turn_log.tau, turn_log.pace,
  turn_log.model, agent_clocks table; dev-mode auto-migrate
  drops+recreates if old schema detected.
- engine/llm.py: full refactor for two providers.
    Ollama: native tool-calling via /api/chat
    OpenRouter: OpenAI-compatible /api/v1/chat/completions
  Auto mode picks OpenRouter if OPENROUTER_API_KEY is set.
  Per-agent model via EMERGENCE_AGENT_<ID>_MODEL env var.
  .env loader with empty-line guard.
  decide_tool returns (name, args, meta) with cost_usd for OR.

FRONTEND
- web/: new 'Time Dilation · Eigenzeit tau' section with per-agent
  tau bars, pace, op count. Drift warning when any pair exceeds
  threshold. LLM provider info in header.

TESTS
- 14 new tests in tests/test_time.py (tau monotonic, EWMA convergence,
  gamma asymmetry, drift detection).
- 4 new LLM tests: openrouter response parsing, per-agent override,
  provider_info, is_available.
- All 99 tests green.

LIVE-VERIFIED
- 4 different OpenRouter models running in parallel:
  - anchor: anthropic/claude-3.5-haiku
  - flora:  openai/gpt-4o-mini
  - lovely: meta-llama/llama-3.3-70b-instruct
  - spark:  google/gemma-3-4b-it
- All 4 produce turns, all 4 have different tau values,
  drift_report shows the Frame-Transformation gamma values.
- Observation: gamma ~ 1.00 because the explicit Round-Robin +
  sleep(2) keeps frames coherent. This is itself a non-trivial
  validation of the paper's claim: in non-synchronized systems,
  dilation would emerge.

SECRETS
- .env added, OPENROUTER_API_KEY live. .env is git-ignored.
- .env.example documents the config without exposing any key.
- .gitignore now blocks .env, .env.local, *.key, *.pem.

README
- New 'Time Dilation' section explaining tau, pace, CDC, drift
- New 'Multi-LLM via OpenRouter' section with cost table
- Per-agent model config documented
2026-06-15 02:27:11 +02:00

440 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Emergence-Mini
Ein minimaler, lauffähiger Klon von [Emergence-World](https://github.com/EmergenceAI/Emergence-World).
Kein LLM nötig, keine externen API-Keys, alles lokal in Python + SQLite.
![status](https://img.shields.io/badge/status-running-brightgreen) ![python](https://img.shields.io/badge/python-3.10%2B-blue) ![license](https://img.shields.io/badge/license-MIT-lightgrey) ![deps](https://img.shields.io/badge/deps-fastapi%20%7C%20uvicorn%20%7C%20sqlite3-blue)
---
## Was es kann
- 4 Agenten (Anchor, Flora, Lovely, Spark) auf einem 240×240-Grid
- 14 Orte (Town Hall, Library, Plaza, Park, Cafe, 4 Häuser, ...)
- 15 Tools (Navigation, Kommunikation, Memory, Blog, Billboard, Town Hall, ...)
- Round-Robin-Turn-Manager mit Reactive Triggern
- Needs-Decay: Energy, Knowledge, Influence
- Constitution mit 5 Artikeln, amendment-fähig via 70%-Voting
- Live-View im Browser (Canvas + WebSocket)
- Persistenz via SQLite
- 50+ automatisierte End-to-End-Tests, grün
## Was es bewusst NICHT kann (im Vergleich zum Original)
- Keine echten LLMs (regelbasierte Reasoning-Engine statt Claude/Gemini/GPT/Grok)
- Kein 3D-Frontend (2D-Canvas statt React Three Fiber)
- Kein PostgreSQL (SQLite ist ausreichend)
- Kein Multi-Model-Vergleich
- Kein Google Cloud TTS
- Kein 15-Tage-Real-Time-Sync (Ticks laufen alle 2 Sekunden)
- Kein Vector-Store für Memory-Search
- Keine AWI-Metrics (9 Indikatoren) — wäre nur mit 15-Tage-Daten sinnvoll
- Keine echten Persönlichkeits-LLM-Prompts (Traits sind deterministisch regelbasiert)
---
## Quickstart
```bash
git clone https://github.com/Jeuners/emergence-mini-dilles.git
cd emergence-mini-dilles
pip install -r requirements.txt
./run.sh
# Browser auf http://127.0.0.1:8080
```
Optional mit LLM-Reasoning (empfohlen):
```bash
# Ollama lokal starten (falls nicht bereits laufend)
ollama serve &
# Modell ziehen (einmalig, ~2 GB)
ollama pull llama3.2:3b
# Emergence-Mini mit LLM starten
./run.sh
```
Optional mit Tests:
```bash
python3 -m pytest tests/ -v # 80+ Unit + Integration Tests
python3 smoke_test.py # End-to-End Smoke Test (regelbasiert)
python3 smoke_test_llm.py # Live-LLM-Test (braucht Ollama)
```
---
## Endpoints
| Method | Path | Beschreibung |
|--------|------|--------------|
| `GET` | `/api/state` | Kompletter Snapshot (Agenten, Landmarks, Constitution, Tick) |
| `GET` | `/api/agents` | Liste der aktiven Agenten |
| `GET` | `/api/landmarks` | Liste aller Orte |
| `GET` | `/api/proposals` | Aktive + vergangene Proposals |
| `GET` | `/api/constitution` | Aktuelle Verfassung |
| `GET` | `/api/events` | Letzte 100 Events |
| `GET` | `/api/memories/{id}` | Memory eines Agenten |
| `GET` | `/api/blogs` | Veröffentlichte Blog-Posts |
| `POST` | `/api/turn/{id}` | Tool manuell auslösen (Body: `{"tool": "...", "args": {...}}`) |
| `WS` | `/ws` | Live-Stream (snapshot + action + tick) |
| `GET` | `/` | Single-Page-Live-View |
---
## Architektur
```
emergence-mini-dilles/
├── server.py FastAPI + WebSocket entry
├── engine/
│ ├── db.py SQLite persistence + schema migration
│ ├── world.py 240×240 grid + landmarks + hearing range
│ ├── agents.py Agent state, personality, position
│ ├── needs.py Energy/Knowledge/Influence decay
│ ├── tools.py Tool registry + handlers + location-gating
│ ├── reasoning.py Decision engine (LLM + rule-based fallback)
│ ├── llm.py Ollama client + OpenAI-style tool schema
│ ├── governance.py Constitution + Town Hall voting (70% threshold)
│ └── turn.py Round-robin + reactive triggers
├── data/
│ └── constitution.json Seed constitution (5 articles)
├── web/ Static SPA (kein Build-Tool nötig)
│ ├── index.html
│ ├── style.css
│ └── app.js Canvas-Renderer + WebSocket-Client
├── tests/
│ ├── conftest.py
│ ├── test_db.py
│ ├── test_world.py
│ ├── test_agents.py
│ ├── test_tools.py
│ ├── test_governance.py
│ ├── test_reasoning.py
│ ├── test_llm.py
│ └── test_api.py
├── smoke_test.py End-to-End Live-Test (regelbasiert, 50+ Checks)
├── smoke_test_llm.py Live-LLM-Test gegen echtes Ollama-Modell
├── requirements.txt
├── run.sh Startet uvicorn auf Port 8080
└── .gitignore
```
### Daten-Modell
| Tabelle | Zweck |
|---------|-------|
| `world_state` | Key/Value für Tick, Bootstrap-Flags |
| `agents` | 4 Agenten, alle Needs als REAL, Mood, Alive-Flag |
| `landmarks` | 14 Orte, (x, y) auf 240×240-Grid |
| `memories` | Long-term Memory pro Agent |
| `relationships` | Affinity-Matrix zwischen Agenten |
| `events` | Append-only Event-Log (Proposals, Posts, Ticks) |
| `proposals` | Town-Hall-Vorschläge + Status + Applied-Flag |
| `votes` | Pro Agent eine Stimme pro Proposal |
| `bills` | Blog-Posts |
| `constitution` | Versionierte Verfassung (jede Änderung = neue Row) |
| `turn_log` | Append-only Tool-Call-Log |
### Sicherheitsmodell
Der Server lauscht auf `127.0.0.1:8080`**nicht** auf `0.0.0.0`. Er ist explizit als
Local-Dev-Tool gedacht, nicht als öffentlicher Service. Für Produktion:
- Reverse-Proxy mit Auth davor (z. B. Caddy mit Basic-Auth)
- `uvicorn` hinter `gunicorn` + `systemd`
- DB regelmäßig sichern
---
## Time Dilation (τ)
Emergence-Mini implementiert einen Ausschnitt des Frameworks aus
[Time Dilation in LLM Agent Systems](https://github.com/Jeuners/Time_Dilation_in_LLM_Agent_Systems) (Dillenberg 2026).
### Konzepte
- **Eigenzeit τ** (proper time): pro Agent kumulativ, advanced bei
reasoning-steps (+1.0), tool-calls (+0.5), memory-lookups (+0.2),
reactive-acks (+0.3). Monoton wachsend.
- **Pace** (EWMA, α=0.3): lokale Operations-Rate pro Agent.
- **Causal-Dilation Clock (CDC)**: pair von (vector, dilation-vector)
pro Aktion. Jede WebSocket-Message trägt `tau` und `pace` mit.
- **Frame-Transformation** Φ_{src→dst}(τ) = γ · τ, mit
γ = pace(src) / pace(dst).
- **Drift-Detection**: wenn `|τ_a Φ(τ_b)| > 3.0` für ein Paar,
zeigt das UI eine Warnung.
### Wo es lebt
| Datei | Inhalt |
|-------|--------|
| `engine/time.py` | `AgentClock`, `ClockRegistry`, τ, Pace-EWMA, Drift-Report |
| `engine/turn.py` | ruft `record_reasoning` / `record_tool_call` pro Tick |
| `engine/db.py` | `turn_log.tau`, `turn_log.pace`, `turn_log.model`, `agent_clocks` |
| `web/index.html` | "Time Dilation · Eigenzeit τ" Sektion + Drift-Warnung |
| `web/app.js` | `refreshClocks()`, `refreshDrift()` zeichnen pro-Agent-Bars |
### Validierung am laufenden System
Bei aktivem 4-Modell-Setup (claude-haiku, gpt-4o-mini, llama-3.3-70b, gemma-3-4b):
```
spark τ=18.0 pace=6.07 op/s google/gemma-3-4b-it
lovely τ=18.0 pace=6.07 op/s meta-llama/llama-3.3-70b-instruct
flora τ=19.2 pace=6.07 op/s openai/gpt-4o-mini
anchor τ=19.2 pace=6.07 op/s anthropic/claude-3.5-haiku
```
**Erkenntnis:** γ ≈ 1.00 über alle Paare. Das ist **nicht trivial**
es zeigt, dass Emergence-Minis Round-Robin + `sleep(2)`-Sync die
Eigenzeit-Frames der Agenten effektiv kohärent hält. Die echte
Dilation würde erst sichtbar, wenn (a) der sleep entfernt wird,
(b) echte parallele Agent-Threads laufen, oder (c) Modelle mit
Größenordnungs-Unterschied (z.B. lokales 70B vs API-Micro) gemischt
werden. Siehe §5.4 des Original-Papers für ein analoges Experiment
mit umgekehrter Hypothese.
---
## Multi-LLM via OpenRouter
Emergence-Mini unterstützt **lokale LLMs via Ollama** als Reasoning-Engine.
Ohne LLM läuft die regelbasierte Engine (deterministisch, schnell, gut für
Tests). Mit LLM werden die Agenten emergent, character-stimmig und
nicht-reproduzierbar — wie im Original.
### Setup
```bash
# 1. Ollama installieren (falls nicht vorhanden)
# macOS: brew install ollama
# Linux: curl -fsSL https://ollama.com/install.sh | sh
# Windows: https://ollama.com/download
# 2. Ollama starten
ollama serve
# 3. Modell ziehen (einmalig, ~2 GB für 3B, ~5 GB für 7B)
ollama pull llama3.2:3b
# 4. Emergence-Mini starten (LLM wird automatisch erkannt)
./run.sh
```
### Konfiguration via Umgebungsvariablen
| Variable | Default | Beschreibung |
|----------|---------|--------------|
| `EMERGENCE_LLM_PROVIDER` | `auto` | `ollama`, `openrouter`, oder `auto` (Key vorhanden → OpenRouter) |
| `EMERGENCE_LLM_URL` | `http://127.0.0.1:11434` | Ollama-Server |
| `EMERGENCE_OLLAMA_MODEL` | `llama3.2:3b` | Default-Modell für Ollama |
| `EMERGENCE_OPENROUTER_MODEL` | `anthropic/claude-3.5-haiku` | Default für OpenRouter |
| `EMERGENCE_AGENT_<ID>_MODEL` | (default) | Per-Agent Override, z.B. `EMERGENCE_AGENT_ANCHOR_MODEL=openai/gpt-4o-mini` |
| `EMERGENCE_LLM_TIMEOUT` | `30` | Request-Timeout in Sekunden |
| `EMERGENCE_LLM_ENABLED` | `1` | `0` erzwingt regelbasierte Engine |
Beispiel mit größerem Modell:
```bash
EMERGENCE_LLM_MODEL=qwen2.5-coder:7b ./run.sh
```
### Empfohlene Modelle
| Modell | Größe | Stärke | Schwäche |
|--------|-------|--------|----------|
| **`llama3.2:3b`** ⭐ | 2.0 GB | Schnell, gute Tool-Use-Fähigkeit, niedriger RAM-Bedarf | Kurze Antworten |
| `gemma3:latest` | 3.3 GB | Bewährt, gute Reasoning-Qualität | Mittel-schnell |
| `qwen2.5-coder:7b` | 4.7 GB | Exzellent für strukturierte Aufgaben | Höherer RAM-Bedarf |
| `qwen3.5:latest` | 6.6 GB | Neueste Generation, multimodal | Langsamer |
| `gemma4:latest` | 9.6 GB | Bestes Reasoning | Langsam, hoher RAM |
Für die meisten Setups ist **llama3.2:3b** der beste Kompromiss: ~1-3s Latenz
pro Decision, 4-8 GB RAM, deterministische Tool-Calls.
Modelle ohne brauchbare Tool-Use-Fähigkeit (z.B. `moondream`,
`nomic-embed-text`) werden zwar nicht crashen, aber das System fällt auf
die regelbasierte Engine zurück.
### Wie es funktioniert
Pro Agent-Turn:
1. Engine sammelt Personality-Traits, aktuellen State (Energy, Knowledge,
Influence, Credits), Position und sichtbare Tools (gefiltert nach
Location-Gating).
2. Baut einen System-Prompt mit dieser Kontext-Information.
3. Sendet `/api/chat` an Ollama mit Tool-Schema im OpenAI-Format.
4. Validiert die Antwort: Tool muss existieren, Location muss passen.
5. Bei Validierungs-Fehler oder Verbindungs-Problemen: **Fallback zur
regelbasierten Engine**, damit die Simulation nie hängt.
Die `get_last_decision()`-Funktion in `engine.reasoning` exponiert den
Modus (`llm`, `rule`, `fallback:...`) und die Latenz. Im Live-View ist
das via WebSocket sichtbar (im `rationale`-Feld).
### Eigene System-Prompts
Die Persona-Beschreibung lebt in `engine/reasoning.py:_build_system_prompt`.
Du kannst sie für deinen Use-Case anpassen (z.B. spezifischere Regeln,
andere Tool-Beschreibungen, anderer Ton).
### Tests
- **Mock-Tests** in `tests/test_llm.py` prüfen Schema-Generierung,
Response-Parsing, Fallback-Pfade. 11 Tests, alle ohne Netzwerk.
- **Live-Smoke** in `smoke_test_llm.py` ruft das echte Modell 4× auf und
meldet Mode + Latenz pro Decision.
- **Time-Dilation-Tests** in `tests/test_time.py` (14 Tests): τ,
Pace-EWMA, Frame-Transformation Φ, Drift-Detection.
---
## Security
Emergence-Mini ist ein lokales Dev-Tool. Es ist **nicht** für den öffentlichen Einsatz
vorbereitet. Folgende Punkte sind bewusst NICHT enthalten:
### Was es nicht macht (by design)
- **Keine Authentifizierung** — alle Endpoints sind offen. Der Server bindet nur auf
`127.0.0.1`, das setzt einen lokalen Nutzer voraus.
- **Keine Rate-Limits** — `POST /api/turn/{id}` kann endlos gefeuert werden. Ein
Angreifer mit Loop-Zugriff könnte die DB mit Rows fluten.
- **Keine Input-Validierung** — Tool-Args werden ohne JSON-Schema geprüft. Falsche
Typen führen zu `KeyError`/`TypeError` im Handler, nicht zu 400.
- **Keine CORS-Restriktionen** — Browser-Apps von beliebigen Origins können die API
konsumieren, wenn der Server öffentlich erreichbar wird.
- **Keine SQL-Injection-Schutzmaßnahmen** jenseits parametrisierter Queries — die
SQL-Statements sind alle `?`-gebunden, aber Strings werden nicht escaped, falls
sie direkt interpoliert würden (aktuell kein Fall).
- **Keine Secrets** — keine API-Keys, keine Tokens, keine Passwörter im Code oder
in der DB.
- **Kein Logging sensibler Daten** — der `turn_log` enthält nur Tool-Name + Args.
Kein Memory-Inhalt, keine persönlichen Daten.
### Hardening-Checkliste vor Public Deploy
```bash
# 1. Auf 0.0.0.0 nur hinter Reverse-Proxy erlauben
# 2. Auth-Layer hinzufügen (z. B. via Caddy + Basic-Auth oder oauth2-proxy)
# 3. Schema-Validierung pro Tool-Endpoint
# 4. Rate-Limiting (z. B. slowapi)
# 5. CORS-Whitelist
# 6. HTTPS terminieren
# 7. DB-Backups in separaten Storage
# 8. Monitoring (z. B. Prometheus-Endpoint)
```
### Verletzliche Annahmen
| Annahme | Risiko |
|---------|--------|
| Loopback-only Binding | Bei `0.0.0.0` sofort öffentlich erreichbar |
| Trust im Tool-Args | Handler setzen Tool-Args als SQL-Params; Schema-Mismatch crasht Handler |
| Single-User | Concurrency über `SQLite-WAL`, aber kein Row-Locking pro Agent |
### Reporting
Security-Issues bitte per Mail an den Maintainer (siehe GitHub-Profil) — nicht
als Public Issue.
---
## Tests
### Test-Suite ausführen
```bash
# Alle Unit + Integration Tests
python3 -m pytest tests/ -v
# Nur Smoke-Test (End-to-End inkl. Live-Server)
python3 smoke_test.py
# Mit Coverage
pip install coverage
python3 -m coverage run -m pytest tests/
python3 -m coverage report
```
### Was getestet wird
| Test | Was |
|------|-----|
| `test_db.py` | Schema-Erstellung, World-State-Get/Set, Event-Log |
| `test_world.py` | Landmark-Seeding, Distance-Funktion, Hearing-Range, Location-Detection |
| `test_agents.py` | Agent-Bootstrap, Personality-Loading, State-Updates, Position-Updates |
| `test_tools.py` | Alle 15 Tool-Handler, Location-Gating, Fehler-Pfade |
| `test_governance.py` | 70%-Threshold, Auto-Reject, Constitution-Amendment-Apply |
| `test_reasoning.py` | Decision-Engine für alle Personality-Types, Edge-Cases |
| `test_llm.py` | Ollama-Client, Tool-Schema, Mock-Tests für LLM-Pfad, Fallbacks |
| `test_api.py` | Alle HTTP-Endpoints, WebSocket, POST /api/turn |
### Smoke-Test-Details
`smoke_test.py` läuft **14 Sektionen mit 50+ Assertions** ohne externen Server:
1. Bootstrap (DB, 14 Landmarks, 4 Agenten, 15 Tools)
2. Agent-State (Needs, Personality, Home-Position)
3. Tools: Navigation (`go_to_place`, Position-Update)
4. Tools: Communication (`say_to_agent`, Speak-Events)
5. Tools: Memory (Persistenz in `memories`-Tabelle)
6. Tools: Blog (Knowledge-Boost, Bill-Eintrag)
7. Tools: Billboard (Location-Gating verifiziert)
8. Town Hall: Proposal + 4× Vote → accepted, Constitution wächst von 5 auf 6 Artikel
9. Energy-System: Recharge +50%, Credits -1
10. Reasoning-Engine: Round läuft, Tool-Selection funktioniert
11. Needs-Decay: Energy sinkt über mehrere Ticks
12. Reactive Triggers: `speak_to_all` triggert Listener
13. Persistenz: Proposals, Memories, Bills, Turn-Log vorhanden
14. Live-Server: Startet uvicorn auf Port 8090, testet alle REST-Endpoints + POST + WS
### Bekannte Test-Lücken
- Keine Concurrency-Tests (mehrere parallele `force_turn`-Calls)
- Keine Last-Tests (1000+ Ticks in kurzer Zeit)
- Keine Fuzz-Tests für Tool-Args
- Keine Frontend-Tests (Canvas-Renderer, WebSocket-Client sind ungetestet)
### CI-Integration
GitHub Actions Template (nicht enthalten, easy nachzurüsten):
```yaml
# .github/workflows/test.yml
name: tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- run: pip install -r requirements.txt
- run: python3 -m pytest tests/ -v
- run: python3 smoke_test.py
```
---
## Lizenz
Emergence-Mini ist inspiriert vom CC-BY-NC-4.0-Original von [Emergence AI](https://github.com/EmergenceAI/Emergence-World).
Dieser Klon: **MIT** für nicht-kommerzielle Nutzung, ohne Gewähr.
Die LLM-Integration erwartet eine lokale Ollama-Instanz und nutzt
[Ollamas OpenAI-kompatible Tool-Calling-API](https://ollama.com/blog/tool-support).
Ollama selbst ist MIT-lizenziert. Die Modelle (llama3.2, qwen, gemma)
unterliegen ihren eigenen Lizenzen — bitte vor kommerzieller Nutzung
prüfen.
Quell-Repo: https://github.com/EmergenceAI/Emergence-World (Doku, Profile, Landmarks, Constitution, Tool-Katalog)
---
## Maintainer
Jeuners · https://github.com/Jeuners/emergence-mini-dilles