No description
Find a file
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
data Emergence-Mini: minimaler Klon von Emergence-World 2026-06-15 01:07:38 +02:00
engine Time Dilation framework + OpenRouter multi-LLM 2026-06-15 02:27:11 +02:00
tests Time Dilation framework + OpenRouter multi-LLM 2026-06-15 02:27:11 +02:00
web Time Dilation framework + OpenRouter multi-LLM 2026-06-15 02:27:11 +02:00
.env.example Time Dilation framework + OpenRouter multi-LLM 2026-06-15 02:27:11 +02:00
.gitignore Time Dilation framework + OpenRouter multi-LLM 2026-06-15 02:27:11 +02:00
README.md Time Dilation framework + OpenRouter multi-LLM 2026-06-15 02:27:11 +02:00
requirements.txt Emergence-Mini: minimaler Klon von Emergence-World 2026-06-15 01:07:38 +02:00
run.sh Emergence-Mini: minimaler Klon von Emergence-World 2026-06-15 01:07:38 +02:00
server.py Time Dilation framework + OpenRouter multi-LLM 2026-06-15 02:27:11 +02:00
smoke_test.py Emergence-Mini: minimaler Klon von Emergence-World 2026-06-15 01:07:38 +02:00
smoke_test_llm.py Add Ollama LLM integration with rule-based fallback 2026-06-15 01:30:58 +02:00

Emergence-Mini

Ein minimaler, lauffähiger Klon von Emergence-World. Kein LLM nötig, keine externen API-Keys, alles lokal in Python + SQLite.

status python license deps


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

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):

# 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:

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:8080nicht 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 (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

# 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:

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-LimitsPOST /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

# 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

# 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):

# .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. 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. 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